带有测试容器的未终止美元报价初始化脚本

Posted

技术标签:

【中文标题】带有测试容器的未终止美元报价初始化脚本【英文标题】:Unterminated dollar quote init script with testcontainers 【发布时间】:2021-07-20 14:58:32 【问题描述】:

我有一个要在 testcontainers (postgres) 启动时执行的初始化脚本。 我的设置是:

弹簧靴 spring 数据 jdbc docker 上的测试容器 postgresql

截至今天,所有框架都是最新的。

这是脚本的摘录:

create or replace function check_registration_limits() returns trigger
    language plpgsql
as $$
BEGIN
    IF(SELECT count(*) FROM applicationusersubjectregistration ausr WHERE NEW.campus = ausr.campus and NEW.subject = ausr.subject)
        >= (SELECT s.maxparticipants FROM subject s WHERE s.subjectid = NEW.subject) THEN
        RAISE EXCEPTION 'Registration limits reached! No more voting allowed!';
    END IF;
    RETURN NEW;
END
$$;

当我触发我的测试时,会出现此堆栈跟踪:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceInitializer' defined in de.thd.awp.TestDataSourceConfiguration: Invocation of init method failed; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #30 of class path resource [schema.sql]: create or replace function check_registration_limits() returns trigger language plpgsql as $$ BEGIN IF(SELECT count(*) FROM applicationusersubjectregistration ausr WHERE NEW.campus = ausr.campus and NEW.subject = ausr.subject) >= (SELECT s.maxparticipants FROM subject s WHERE s.subjectid = NEW.subject) THEN RAISE EXCEPTION 'Registration limits reached! No more voting allowed!'; nested exception is org.postgresql.util.PSQLException: Unterminated dollar quote started at position 91 in SQL create or replace function check_registration_limits() returns trigger language plpgsql as $$ BEGIN IF(SELECT count(*) FROM applicationusersubjectregistration ausr WHERE NEW.campus = ausr.campus and NEW.subject = ausr.subject) >= (SELECT s.maxparticipants FROM subject s WHERE s.subjectid = NEW.subject) THEN RAISE EXCEPTION 'Registration limits reached! No more voting allowed!'. Expected terminating $$
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1786) ~[spring-beans-5.3.6.jar:5.3.6]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602) ~[spring-beans-5.3.6.jar:5.3.6]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.6.jar:5.3.6]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.6.jar:5.3.6]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.6.jar:5.3.6]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.6.jar:5.3.6]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.6.jar:5.3.6]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.6.jar:5.3.6]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.6.jar:5.3.6]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.6.jar:5.3.6]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:782) ~[spring-boot-2.4.5.jar:2.4.5]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:774) ~[spring-boot-2.4.5.jar:2.4.5]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) ~[spring-boot-2.4.5.jar:2.4.5]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:339) ~[spring-boot-2.4.5.jar:2.4.5]
    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:123) ~[spring-boot-test-2.4.5.jar:2.4.5]
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99) ~[spring-test-5.3.6.jar:5.3.6]
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) ~[spring-test-5.3.6.jar:5.3.6]
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124) ~[spring-test-5.3.6.jar:5.3.6]
    at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190) ~[spring-test-5.3.6.jar:5.3.6]
    at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132) ~[spring-test-5.3.6.jar:5.3.6]
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244) ~[spring-test-5.3.6.jar:5.3.6]
    at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138) ~[spring-test-5.3.6.jar:5.3.6]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassBasedTestDescriptor.java:350) ~[junit-jupiter-engine-5.7.1.jar:5.7.1]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:355) ~[junit-jupiter-engine-5.7.1.jar:5.7.1]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$7(ClassBasedTestDescriptor.java:350) ~[junit-jupiter-engine-5.7.1.jar:5.7.1]
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na]
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177) ~[na:na]
    at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na]
    at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312) ~[na:na]
    at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735) ~[na:na]
    at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734) ~[na:na]
    at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658) ~[na:na]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:349) ~[junit-jupiter-engine-5.7.1.jar:5.7.1]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$4(ClassBasedTestDescriptor.java:270) ~[junit-jupiter-engine-5.7.1.jar:5.7.1]
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:269) ~[junit-jupiter-engine-5.7.1.jar:5.7.1]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:259) ~[junit-jupiter-engine-5.7.1.jar:5.7.1]
    at java.base/java.util.Optional.orElseGet(Optional.java:362) ~[na:na]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:258) ~[junit-jupiter-engine-5.7.1.jar:5.7.1]
    at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31) ~[junit-jupiter-engine-5.7.1.jar:5.7.1]
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:101) ~[junit-jupiter-engine-5.7.1.jar:5.7.1]
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:100) ~[junit-jupiter-engine-5.7.1.jar:5.7.1]
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:65) ~[junit-jupiter-engine-5.7.1.jar:5.7.1]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:111) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:111) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:79) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51) ~[junit-platform-engine-1.7.1.jar:1.7.1]
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108) ~[junit-platform-launcher-1.7.1.jar:1.7.1]
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88) ~[junit-platform-launcher-1.7.1.jar:1.7.1]
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54) ~[junit-platform-launcher-1.7.1.jar:1.7.1]
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67) ~[junit-platform-launcher-1.7.1.jar:1.7.1]
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52) ~[junit-platform-launcher-1.7.1.jar:1.7.1]
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96) ~[junit-platform-launcher-1.7.1.jar:1.7.1]
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75) ~[junit-platform-launcher-1.7.1.jar:1.7.1]
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71) ~[junit5-rt.jar:na]
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) ~[junit-rt.jar:na]
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221) ~[junit-rt.jar:na]
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54) ~[junit-rt.jar:na]
Caused by: org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #30 of class path resource [schema.sql]: create or replace function check_registration_limits() returns trigger language plpgsql as $$ BEGIN IF(SELECT count(*) FROM applicationusersubjectregistration ausr WHERE NEW.campus = ausr.campus and NEW.subject = ausr.subject) >= (SELECT s.maxparticipants FROM subject s WHERE s.subjectid = NEW.subject) THEN RAISE EXCEPTION 'Registration limits reached! No more voting allowed!'; nested exception is org.postgresql.util.PSQLException: Unterminated dollar quote started at position 91 in SQL create or replace function check_registration_limits() returns trigger language plpgsql as $$ BEGIN IF(SELECT count(*) FROM applicationusersubjectregistration ausr WHERE NEW.campus = ausr.campus and NEW.subject = ausr.subject) >= (SELECT s.maxparticipants FROM subject s WHERE s.subjectid = NEW.subject) THEN RAISE EXCEPTION 'Registration limits reached! No more voting allowed!'. Expected terminating $$
    at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:622) ~[spring-jdbc-5.3.6.jar:5.3.6]
    at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) ~[spring-jdbc-5.3.6.jar:5.3.6]
    at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:49) ~[spring-jdbc-5.3.6.jar:5.3.6]
    at org.springframework.jdbc.datasource.init.DataSourceInitializer.execute(DataSourceInitializer.java:111) ~[spring-jdbc-5.3.6.jar:5.3.6]
    at org.springframework.jdbc.datasource.init.DataSourceInitializer.afterPropertiesSet(DataSourceInitializer.java:96) ~[spring-jdbc-5.3.6.jar:5.3.6]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845) ~[spring-beans-5.3.6.jar:5.3.6]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782) ~[spring-beans-5.3.6.jar:5.3.6]
    ... 83 common frames omitted
Caused by: org.postgresql.util.PSQLException: Unterminated dollar quote started at position 91 in SQL create or replace function check_registration_limits() returns trigger language plpgsql as $$ BEGIN IF(SELECT count(*) FROM applicationusersubjectregistration ausr WHERE NEW.campus = ausr.campus and NEW.subject = ausr.subject) >= (SELECT s.maxparticipants FROM subject s WHERE s.subjectid = NEW.subject) THEN RAISE EXCEPTION 'Registration limits reached! No more voting allowed!'. Expected terminating $$
    at org.postgresql.core.Parser.checkParsePosition(Parser.java:1328) ~[postgresql-42.2.19.jar:42.2.19]
    at org.postgresql.core.Parser.parseSql(Parser.java:1227) ~[postgresql-42.2.19.jar:42.2.19]
    at org.postgresql.core.Parser.replaceProcessing(Parser.java:1179) ~[postgresql-42.2.19.jar:42.2.19]
    at org.postgresql.core.CachedQueryCreateAction.create(CachedQueryCreateAction.java:43) ~[postgresql-42.2.19.jar:42.2.19]
    at org.postgresql.core.QueryExecutorBase.createQueryByKey(QueryExecutorBase.java:337) ~[postgresql-42.2.19.jar:42.2.19]
    at org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:300) ~[postgresql-42.2.19.jar:42.2.19]
    at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:284) ~[postgresql-42.2.19.jar:42.2.19]
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:279) ~[postgresql-42.2.19.jar:42.2.19]
    at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:601) ~[spring-jdbc-5.3.6.jar:5.3.6]
    ... 89 common frames omitted

这可能是一些脚本构建巫毒转义错误吗? 还是我必须转义脚本的某些部分? 提前谢谢你

编辑 我尝试使用 Spring Boot 测试资源 schema.sqlDataSourceInitializer 初始化 docker/testcontainers/postgres 数据库:

@Bean
    @Primary
    public DataSourceInitializer testDataSourceInitializer() 
        ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator();
        resourceDatabasePopulator.addScript(new ClassPathResource("/schema.sql"));

        DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
        dataSourceInitializer.setDataSource(testDataSource());
        dataSourceInitializer.setDatabasePopulator(resourceDatabasePopulator);
        return dataSourceInitializer;
    

【问题讨论】:

您在何处、何时以及如何运行此脚本?它是项目中的 sql 文件还是带有 jdbc 调用或其他东西的一些 init 方法? 根据日志,由于某种原因,函数的文本不完整被识别为要执行的脚本 谢谢。我编辑了我的帖子。希望这可以帮助。我认为$$ 在某种程度上是脚本解释器的问题。但这只是一个建议 Yuriy Tsarkov 是对的,ResourceDatabasePopulator 使用; 分隔符将您的大 sql 脚本拆分为多个部分,并尝试逐个执行它们。这会破坏您的存储过程声明。看看这个方法:docs.spring.io/spring-framework/docs/current/javadoc-api/org/… 这能回答你的问题吗? Spring and mysql stored procedure 【参考方案1】:

当您使用 postgresql 时,您可以尝试将初始化脚本放在 /docker-entrypoint-initdb.d 下,如 here 解释的那样

【讨论】:

【参考方案2】:

我已经省略了上面的 DataSourceInitializer bean,因为 testcontainers 也提供了一个 init 脚本。 所以我的解决方案是使用 testcontainer 的 postgres 容器正确配置这个初始化脚本:

@Bean
        @Primary
        DataSource testDataSource() 

            if (POSTGRESQL_CONTAINER == null) 
                PostgreSQLContainer<?> container = new PostgreSQLContainer<>();
                container.withInitScript("schema.sql");
                container.start();
                POSTGRESQL_CONTAINER = container;
            
            PGSimpleDataSource dataSource = new PGSimpleDataSource();
            dataSource.setUrl(POSTGRESQL_CONTAINER.getJdbcUrl());
            dataSource.setUser(POSTGRESQL_CONTAINER.getUsername());
            dataSource.setPassword(POSTGRESQL_CONTAINER.getPassword());

            return dataSource;


        

container.withInitScript("schema.sql"); 完成这项工作。请注意schema.sql必须放在.\src\test\resources

【讨论】:

【参考方案3】:

添加第二个触发器时事情变得非常奇怪:

create or replace function check_registration_limits() returns trigger
    language plpgsql
as $$
BEGIN
    IF(SELECT count(*) FROM applicationusersubjectregistration ausr WHERE NEW.campus = ausr.campus and NEW.subject = ausr.subject)
        >= (SELECT s.maxparticipants FROM subject s WHERE s.subjectid = NEW.subject) THEN
        RAISE EXCEPTION 'Registration limits reached! No more voting allowed!';
    END IF;
    RETURN NEW;
END
$$;

这会导致另一个Unterminated dollar quote,即使我使用与第一个触发器相同的表示法,一切正常。

所以在这里找到了这个答案:https://***.com/a/55596701/7320372

使用' 作为$$ 替换后解决了我的问题,如下所示:

create or replace function check_registration_limits() returns trigger
as
'
BEGIN
    IF (SELECT count(*)
        FROM applicationusersubjectregistration ausr
        WHERE NEW.campus = ausr.campus
          and NEW.subject = ausr.subject)
        >= (SELECT s.maxparticipants FROM subject s WHERE s.subjectid = NEW.subject) THEN
        RAISE EXCEPTION ''Registration limits reached! No more voting allowed!'';
    END IF;
    RETURN NEW;
END
' language plpgsql;

【讨论】:

以上是关于带有测试容器的未终止美元报价初始化脚本的主要内容,如果未能解决你的问题,请参考以下文章

带有基本 jQuery 的未定义类型错误“defaultView”

Liquibase : $BODY$ 或附近的未终止的美元引号字符串

Docker.io init.d 脚本在启动容器上不起作用

docker容器启动Mysql执行初始化sql脚本实现

docker容器启动Mysql执行初始化sql脚本实现

docker容器启动Mysql执行初始化sql脚本实现