fukamachi / mito

An ORM for Common Lisp with migrations, relationships and PostgreSQL support
292 stars 31 forks source link

Some recent changes broke migrations when there is a dollar-quoted literal #135

Closed svetlyak40wt closed 7 months ago

svetlyak40wt commented 8 months ago

For example, in my db/schema.sql I have following statement:

CREATE OR REPLACE FUNCTION project_exists(id BIGINT)
RETURNS BOOLEAN AS
$$
BEGIN
IF id IN (SELECT project2.id FROM project2)
THEN RETURN true;
ELSE RETURN false;
END IF;
END
$$ LANGUAGE PLpgSQL;

But when I run MIGRATE, it fails with error:

DB Error: syntax error at or near "(" (Code: 42601)
   [Condition of type DBI.ERROR:DBI-PROGRAMMING-ERROR]

Restarts:
 0: [RETRY] Retry #<TEST-OP > on #<PACKAGE-INFERRED-SYSTEM "ultralisp-test">.
 1: [ACCEPT] Continue, treating #<TEST-OP > on #<PACKAGE-INFERRED-SYSTEM "ultralisp-test"> as having been successful.
 2: [RETRY] Retry ASDF operation.
 3: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the configuration.
 4: [RETRY] Retry SLY mREPL evaluation request.
 5: [*ABORT] Return to SLY's top level.
 --more--

Backtrace:
 0: ((:METHOD DBI.DRIVER:PREPARE (DBD.POSTGRES:DBD-POSTGRES-CONNECTION STRING)) #<DBD.POSTGRES:DBD-POSTGRES-CONNECTION {10050B18F3}> "CREATE $
 1: (MITO.UTIL::CALL-WITH-PREPARED-QUERY #<DBD.POSTGRES:DBD-POSTGRES-CONNECTION {10050B18F3}> "CREATE OR REPLACE FUNCTION project_exists(id B$
 2: ((:METHOD MITO.DB:EXECUTE-SQL (STRING)) "CREATE OR REPLACE FUNCTION project_exists(id BIGINT) ..) [fast-method]
 3: ((SB-PCL::EMF MITO.DB:EXECUTE-SQL) #<unused argument> #<unused argument> "CREATE OR REPLACE FUNCTION project_exists(id BIGINT) ..)
      Locals:
        SB-PCL::.ARG0. = "CREATE OR REPLACE FUNCTION project_exists(id BIGINT)\nRETURNS BOOLEAN AS\n($ $)\nBEGIN\nIF id IN (SELECT project2.i$
        SB-DEBUG::MORE = NIL
 4: (MITO.MIGRATION.VERSIONS:MIGRATE #P"./db/" :DRY-RUN NIL :FORCE NIL)
      Locals:
        #:.DEFAULTING-TEMP. = NIL
        #:.DEFAULTING-TEMP.#1 = NIL
        #:CONN-VAR9 = #<DBD.POSTGRES:DBD-POSTGRES-CONNECTION {10050B18F3}>
        #:CONNECTION5 = #<DBD.POSTGRES:DBD-POSTGRES-CONNECTION {10050B18F3}>
        CONTENT = "CREATE TABLE "user" ( .....[sly-elided string of length 7717]"
        CURRENT-VERSION = NIL
        DIRECTORY = #P"./db/"
        DRY-RUN = NIL
        FILE = #P"./db/schema.sql"
        FORCE = NIL
        SB-C::ITEM = :POSTGRES
        #:LIST16 = NIL
        #:LIST18 = ("create table \"project_index\" (\n       \"id\" bigserial not null primary key,\n       \"project_id\" bigint not null,\$
        #:LOCK-ID3 = 4034584004913610560
        #:SAVEPOINT-IDENTIFIER-VAR12 = "savepoint_RF6DISR1"
        #:SAVEPOINT-OK10 = NIL
        SCHEMA.SQL = #P"./db/schema.sql"
        SQL-FILES-TO-APPLY = (#P"./db/schema.sql")
        #:STATE-VAR11 = #<DBI.DRIVER::SAVEPOINT-STATE {1003C820B3}>
        STMT = "CREATE OR REPLACE FUNCTION project_exists(id BIGINT)\nRETURNS BOOLEAN AS\n($ $)\nBEGIN\nIF id IN (SELECT project2.id FROM pro$
 5: ((FLET "CONNECTED-FUNC0" :IN "/home/art/projects/ultralisp/t/models/dist.lisp"))

I tries to execute this statement like:

CREATE OR REPLACE FUNCTION project_exists(id BIGINT)
RETURNS BOOLEAN AS
($ $)
BEGIN
IF id IN (SELECT project2.id FROM project2)
THEN RETURN true;
ELSE RETURN false;
END IF;
END
($ $) LANGUAGE PLpgSQL;

The problem in the $ signs, separated and surrounded with parens.

I believe this problem was introduced in this commit:

https://github.com/fukamachi/mito/commit/6a9ac65454073b0f0895eb28ab72ac389b438bab

Here are a few test cases:

CL-USER> (mito.migration.sql-parse:parse-statements "$$foo$$")
("($ $)foo($ $)") ;; BAD
CL-USER> (mito.migration.sql-parse:parse-statements " $$ foo $ bar $$ ")
("$$ foo $ bar $$ ") ;; GOOD
CL-USER> (mito.migration.sql-parse:parse-statements " $$ foo  bar $$ ")
("($ $) foo  bar ($ $) ") ;; BAD
CL-USER> (mito.migration.sql-parse:parse-statements " $blah$ foo  bar $blah$ ")
("$blah$ foo  bar $blah$ ") ;; GOOD
CL-USER> (mito.migration.sql-parse:parse-statements " $blah$ foo $ bar $blah$ ")
("$blah$ foo $ bar $blah$ ") ;; GOOD

For now as a workaround I'll use $Name$ as a wrapper.

fukamachi commented 7 months ago

Thanks for reporting! Just fixed by the above commit.