带有测试容器的未终止美元报价初始化脚本
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.sql
和 DataSourceInitializer
初始化 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”