You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As a developer installing the NetEvolve.Pulse.PostgreSql schema, I want the shipped scripts to run as the README and script headers describe, so that I get a complete schema without editing the scripts by hand.
Problem
The headers of all four scripts and the package README say to run the scripts with psql (psql -h your-host -d your-database -f OutboxMessage.sql) or to open them in pgAdmin or DBeaver and execute them. Neither works as documented.
src/NetEvolve.Pulse.PostgreSql/Scripts/OutboxMessage.sql:19-20 defines the values with \set schema_name 'pulse' and \set table_name 'OutboxMessage'.
OutboxMessage.sql:23 has CREATE SCHEMA IF NOT EXISTS :schema_name;. This is the only unquoted use, so it is the only place psql expands the variable.
OutboxMessage.sql:26 has CREATE TABLE IF NOT EXISTS ":schema_name".":table_name" (. psql does not interpolate inside quoted identifiers, so the server receives the literal schema name :schema_name. The statement fails with schema ":schema_name" does not exist.
OutboxMessage.sql:63-64, :122 and :178 (DROP/CREATE FUNCTION ":schema_name"...) and the $$ ... $$ bodies fail or keep the literal placeholder in the same way. Dollar-quoted bodies are string literals to psql.
The same quoted pattern appears in IdempotencyKey.sql:25,40,52,59,68,76,83,92, CommandDeadLetter.sql:26,40,44 and AuditEntry.sql:27,42,46.
psql runs with ON_ERROR_STOP off by default, so it keeps going. The user ends up with an empty pulse schema and a list of errors.
pgAdmin and DBeaver do not understand the \set meta-commands. src/NetEvolve.Pulse.PostgreSql/README.md:40-50 still says to "Open the script and execute it against your database".
The unquoted CREATE SCHEMA at line 23 also folds a mixed-case schema name to lowercase, while every later reference is quoted. This does not affect the default pulse.
The integration tests do not catch this because they never use psql. tests/NetEvolve.Pulse.Tests.Integration/Internals/Outbox/PostgreSqlAdoNetOutboxInitializer.cs:50 removes the \set lines with a regex. Lines 53-59 then use .Replace(":schema_name", schema).Replace(":table_name", tableName). The comment at lines 54-55 says the placeholders appear "within quotes". The Audit, DeadLetter and Idempotency initializers work the same way.
A related naming issue affects only textual substitution. OutboxMessage.sql:39 names the primary key "PK_:schema_name", and lines 43 and 48 name the indexes "IX_:schema_name_Status_CreatedAt" and "IX_:schema_name_Status_ProcessedAt". None of these names includes the table name. The other scripts use PK_:schema_name_:table_name (IdempotencyKey.sql:28, CommandDeadLetter.sql:35, AuditEntry.sql:37). After substitution, a second outbox table in the same schema gets PK_pulse again, which collides because index names are unique per schema. Because of CREATE INDEX IF NOT EXISTS, the second table also silently gets no indexes.
Open PR #799 edits OutboxMessage.sql but keeps the quoted-placeholder pattern.
The value of a variable can be substituted into an SQL statement by writing a colon followed by the variable name. [...] The value of a variable can also be quoted as an SQL literal or identifier by writing :'variable_name' or :"variable_name" respectively.
Variable interpolation will not be performed within quoted SQL literals and identifiers. Therefore, a construction such as ':foo' doesn't work to produce a quoted literal from a variable's value.
PostgreSQL documentation, CREATE INDEX: the index name must be distinct from the name of any other relation in the same schema. A primary key constraint creates an index with the constraint's name.
Requirements
Make every script runnable as documented with psql -v ON_ERROR_STOP=1 -f <script>.sql:
Use :"schema_name" / :"table_name" for identifiers in plain DDL, including CREATE SCHEMA.
For objects inside $$ function bodies, generate the DDL with format('%I.%I', ...) and \gexec, or use another approach that psql actually expands.
Alternatively, if the scripts are meant as placeholder templates, say so in the headers and README, describe the manual substitution, and remove the claim that psql, pgAdmin or DBeaver can run them unchanged.
Include the table name in the primary key and index names in OutboxMessage.sql (PK_<schema>_<table>, IX_<schema>_<table>_...), matching the other scripts.
Update the script headers and src/NetEvolve.Pulse.PostgreSql/README.md to match the chosen approach. Remove the pgAdmin/DBeaver instructions unless those clients can run the scripts.
Keep the integration-test initializers working. Ideally they execute the same statements psql would, instead of a raw string.Replace.
A failing test or CI step runs each of OutboxMessage.sql, IdempotencyKey.sql, CommandDeadLetter.sql and AuditEntry.sql through psql -v ON_ERROR_STOP=1 against a PostgreSQL container. It fails on the current scripts.
After the fix, all four scripts complete under psql and create the schema, table, indexes and functions under the configured schema_name / table_name, including a mixed-case schema name.
Two outbox tables with different table_name values can be created in the same schema, each with its own primary key and indexes.
The README and script headers describe only supported ways to run the scripts.
User Story
As a developer installing the
NetEvolve.Pulse.PostgreSqlschema, I want the shipped scripts to run as the README and script headers describe, so that I get a complete schema without editing the scripts by hand.Problem
The headers of all four scripts and the package README say to run the scripts with psql (
psql -h your-host -d your-database -f OutboxMessage.sql) or to open them in pgAdmin or DBeaver and execute them. Neither works as documented.src/NetEvolve.Pulse.PostgreSql/Scripts/OutboxMessage.sql:19-20defines the values with\set schema_name 'pulse'and\set table_name 'OutboxMessage'.OutboxMessage.sql:23hasCREATE SCHEMA IF NOT EXISTS :schema_name;. This is the only unquoted use, so it is the only place psql expands the variable.OutboxMessage.sql:26hasCREATE TABLE IF NOT EXISTS ":schema_name".":table_name" (. psql does not interpolate inside quoted identifiers, so the server receives the literal schema name:schema_name. The statement fails withschema ":schema_name" does not exist.OutboxMessage.sql:63-64,:122and:178(DROP/CREATE FUNCTION ":schema_name"...) and the$$ ... $$bodies fail or keep the literal placeholder in the same way. Dollar-quoted bodies are string literals to psql.IdempotencyKey.sql:25,40,52,59,68,76,83,92,CommandDeadLetter.sql:26,40,44andAuditEntry.sql:27,42,46.ON_ERROR_STOPoff by default, so it keeps going. The user ends up with an emptypulseschema and a list of errors.\setmeta-commands.src/NetEvolve.Pulse.PostgreSql/README.md:40-50still says to "Open the script and execute it against your database".CREATE SCHEMAat line 23 also folds a mixed-case schema name to lowercase, while every later reference is quoted. This does not affect the defaultpulse.The integration tests do not catch this because they never use psql.
tests/NetEvolve.Pulse.Tests.Integration/Internals/Outbox/PostgreSqlAdoNetOutboxInitializer.cs:50removes the\setlines with a regex. Lines 53-59 then use.Replace(":schema_name", schema).Replace(":table_name", tableName). The comment at lines 54-55 says the placeholders appear "within quotes". The Audit, DeadLetter and Idempotency initializers work the same way.A related naming issue affects only textual substitution.
OutboxMessage.sql:39names the primary key"PK_:schema_name", and lines 43 and 48 name the indexes"IX_:schema_name_Status_CreatedAt"and"IX_:schema_name_Status_ProcessedAt". None of these names includes the table name. The other scripts usePK_:schema_name_:table_name(IdempotencyKey.sql:28,CommandDeadLetter.sql:35,AuditEntry.sql:37). After substitution, a second outbox table in the same schema getsPK_pulseagain, which collides because index names are unique per schema. Because ofCREATE INDEX IF NOT EXISTS, the second table also silently gets no indexes.Open PR #799 edits
OutboxMessage.sqlbut keeps the quoted-placeholder pattern.Specification
PostgreSQL documentation, psql, SQL Interpolation:
PostgreSQL documentation, CREATE INDEX: the index name must be distinct from the name of any other relation in the same schema. A primary key constraint creates an index with the constraint's name.
Requirements
psql -v ON_ERROR_STOP=1 -f <script>.sql::"schema_name"/:"table_name"for identifiers in plain DDL, includingCREATE SCHEMA.$$function bodies, generate the DDL withformat('%I.%I', ...)and\gexec, or use another approach that psql actually expands.OutboxMessage.sql(PK_<schema>_<table>,IX_<schema>_<table>_...), matching the other scripts.src/NetEvolve.Pulse.PostgreSql/README.mdto match the chosen approach. Remove the pgAdmin/DBeaver instructions unless those clients can run the scripts.string.Replace.OutboxMessage.sql.Acceptance Criteria
OutboxMessage.sql,IdempotencyKey.sql,CommandDeadLetter.sqlandAuditEntry.sqlthroughpsql -v ON_ERROR_STOP=1against a PostgreSQL container. It fails on the current scripts.schema_name/table_name, including a mixed-case schema name.table_namevalues can be created in the same schema, each with its own primary key and indexes.