On Fri, Jun 26, 2015 at 11:49 AM, Mike Bayer <mike...@zzzcomputing.com>
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.

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 sqlalchemy-alembic+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to