On 6/30/15 6:40 PM, Jonathon Nelson wrote:


On Fri, Jun 26, 2015 at 11:49 AM, Mike Bayer <[email protected] <mailto:[email protected]>> wrote:



    On 6/26/15 12:23 PM, Jonathon Nelson wrote:
    Greetings!

    I am trying to use alembic to drop and re-create a PL/pgSQL
    function, and the function has embedded percentile (for use in
    RAISE but also present in comments, etc...).

    When rendering the upgrade as an 'offline' sql upgrade script,
    the percentiles end up escaped (with percentile):

    Thus:

    RAISE 'Param foo (%) has some badness to it.', foo;

    turns into:

    RAISE 'Param foo (%%) has some badness to it.', foo;

    I'm creating the function like this:

    op.execute( sa.text( sql_function_body ) )

    What am I doing wrong?

    the compiler for the Psycopg2 backend doubles up percent signs
    because they aren't otherwise accepted by the DBAPI.

    you can have your offline SQL use the generic Postgresql backend
    instead which won't do this.  But it requires a monkeypatch:

    Where your env.py says something like:

        context.configure(
            url=url, target_metadata=target_metadata, literal_binds=True)


    for the url, do this:

        from sqlalchemy.engine import url
        from sqlalchemy.dialects.postgresql import PGDialect
        u = url.make_url("postgresql://")
        u.get_dialect = PGDialect

        context.configure(
            url=u, target_metadata=target_metadata, literal_binds=True)


    Alternatively you can make a compile rule on text() that reverses
    the escaping:

    from sqlalchemy.ext.compiler import compiles
    from sqlalchemy.sql.expression import TextClause

    @compiles(TextClause, "postgresql")
    def _reverse_escaping(element, compiler, **kw):
        text = compiler.process_text(element, **kw)
        text = text.replace("%%", "%")
        return text


I had to make some modifications to the first approach to make it work:

...
    from sqlalchemy.engine import url
    from sqlalchemy.dialects.postgresql.base import PGDialect

    my_url = config.get_main_option("sqlalchemy.url")
    u = url.make_url(my_url)
    u.get_dialect = lambda: PGDialect
    context.configure(
        url=u, target_metadata=target_metadata, literal_binds=True)

    with context.begin_transaction():
        context.run_migrations()
...

For completeness, I also tried the patch to text-clause compiling, but I couldn't get it to work:

did you mean 'post_process_text' in place of 'process_text'? If so, then post_process_text doesn't take any keyword args. The other thing is that post_process_text returns an instance of TextClause and it's at this point I get lost as to what I should have done.

ah, what I meant here was visit_textclause(), in fact.




Still, the first approach is working just great!


--
Jon Nelson
Dyn / Senior Software Engineer
p. +1 (603) 263-8029
--
You received this message because you are subscribed to the Google Groups "sqlalchemy-alembic" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected] <mailto:[email protected]>.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups 
"sqlalchemy-alembic" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to