psycopg2在“ $ body $”或附近抛出未终止的美元报价的字符串错误

时间:2018-11-09 15:58:13

标签: python-3.x postgresql sqlalchemy psycopg2 alembic

我正在尝试构建一个迁移版本,以在PostgreSQL服务器版本10.2中创建用户定义函数,但是脚本不断抛出错误:

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) unterminated dollar-quoted string at or near "$body$
                select string_agg(convert_to(coalesce(r[2], length(length(r[1])::text) || length(r[1])::text || r[1]), 'SQL_ASCII'), '"
    LINE 6:         as $body$
                       ^
     [SQL: "\n        create or replace function naturalsort(text)\n          returns bytea\n          language sql\n          immutable strict\n        as $body$ \n            select string_agg(convert_to(coalesce(r[2], length(length(r[1])::text) || length(r[1])::text || r[1]), 'SQL_ASCII'), '\x00') from regexp_matches($1, '0*([0-9]+)|([^0-9]+)', 'g') r; \n        $body$;\n    "] (Background on this error at: http://sqlalche.me/e/f405)

我正在运行的脚本:

def upgrade():
    conn = op.get_bind()

    conn.execute('DROP FUNCTION IF EXISTS "naturalsort"')

    conn.execute("""
        create or replace function naturalsort(text)
          returns bytea
          language sql
          immutable strict
        as $body$ 
            select string_agg(convert_to(coalesce(r[2], length(length(r[1])::text) || length(r[1])::text || r[1]), 'SQL_ASCII'), '\x00') from regexp_matches($1, '0*([0-9]+)|([^0-9]+)', 'g') r; 
        $body$;
    """)

该代码应允许对列进行自然排序,并且是从rhodium toad复制/粘贴的代码。

由于用美元引号引起来的字符串是重写字符串常量的一种方式,因此替代方法是(请注意,按照PostgreSQL文档中的双单引号引起来:“要在字符串常量中包含单引号字符,请写两个相邻的单引号,例如“ Dianne's horse”。请注意,这与双引号字符(“)。”)不同:

conn.execute("""
    create or replace function naturalsort(text)
      returns bytea
      language sql
      immutable strict
    as 'select string_agg(convert_to(coalesce(r[2], length(length(r[1])::text) || length(r[1])::text || r[1]), ''SQL_ASCII''), ''\x00'') from regexp_matches($1, ''0*([0-9]+)|([^0-9]+)'', ''g'') r;';
""")

但是这会引发类似的错误:

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) unterminated quoted string at or near "'select string_agg(convert_to(coalesce(r[2], length(length(r[1])::text) || length(r[1])::text || r[1]), ''SQL_ASCII''), ''"
LINE 6:         as 'select string_agg(convert_to(coalesce(r[2], leng...
                   ^
 [SQL: "\n        create or replace function naturalsort(text)\n          returns bytea\n          language sql\n          immutable strict\n        as 'select string_agg(convert_to(coalesce(r[2], length(length(r[1])::text) || length(r[1])::text || r[1]), ''SQL_ASCII''), ''\x00'') from regexp_matches($1, ''0*([0-9]+)|([^0-9]+)'', ''g'') r;';\n    "] (Background on this error at: http://sqlalche.me/e/f405)

奇怪的是,这些查询在pgAdmin中执行得很好,而alembic似乎会生成有效的SQL(高级升级:--sql):

DROP FUNCTION IF EXISTS "naturalsort";

create or replace function naturalsort(text)
          returns bytea
          language sql
          immutable strict
        as $body$
            select string_agg(convert_to(coalesce(r[2], length(length(r[1])::text) || length(r[1])::text || r[1]), 'SQL_ASCII'), '') from regexp_matches($1, '0*([0-9]+)|([^0-9]+)', 'g') r;
        $body$;;

UPDATE alembic_version SET version_num='ad99fdcb28bc' WHERE alembic_version.version_num = 'ff00ac684617';

COMMIT;

有什么线索可以解释为什么psycopg2不断抛出unterminated dollar-quoted string at or near "$body$错误?

2 个答案:

答案 0 :(得分:1)

def upgrade():
    op.execute('DROP FUNCTION IF EXISTS "naturalsort"')

    op.execute("""
      create or replace function naturalsort(text)
      returns bytea
      language sql
      immutable strict
    as $my_body$
        select string_agg(convert_to(coalesce(r[2], length(length(r[1])::text) || length(r[1])::text || r[1]), 'SQL_ASCII'), '') from regexp_matches($1, '0*([0-9]+)|([^0-9]+)', 'g') r;
    $my_body$;;
    """)


def downgrade():
    op.execute('DROP FUNCTION IF EXISTS "naturalsort"')

执行升级时,升级成功,语法没有错误。 实际上在postgres中执行该函数还会使用以下查询返回所需的naturalsort结果:

SELECT * FROM public.requirement ORDER BY naturalsort(eid) asc

使用PvdL关于my_body的评论部分起作用,如果我在空字符串现在(在'\x00'之后)添加SQL_ASCII,则会引发语法错误 >

答案 1 :(得分:0)

$body是一个别名,不能包含$,将$body$替换为my_body之类的名称,它应该可以工作