On 9/29/15 9:50 AM, Ralph Heinkel wrote:
Hi everybody,

oracle 12c has received the long awaited possibility to properly provide LIMIT and OFFSET parameters to a select query. See https://oracle-base.com/articles/12c/row-limiting-clause-for-top-n-queries-12cr1 for details.

wow!


In short this looks like:

SELECT val FROM some_table ORDER BY val OFFSET 4 ROWS FETCH NEXT 4 ROWS ONLY;
it's like OK we can add a LIMIT/OFFSET feature, but first! Let's send it off to the Oracle department of "make this syntax as awkward and obtuse as possible - OraTuse! (tm)"



and is so much faster than the nested approach that has been used so far (at least on my system).

I am sure.

I've successfully implemented some code for SA in order to apply the new paging method but I'm not sure whether this is the best way to go. It looks like:
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import Select
from sqlalchemy.dialects.oracle.base import OracleCompiler

@compiles(Select, 'oracle')
def compile_select(element, compiler, **kw):
# The following line basically suppresses the original, nested approach in SA for limit/offset:
    element._oracle_visit = True
    return compiler.visit_select(element, **kw)

def limit_clause(self, select):
    # This code overrides the empty method in OracleCompiler:
    my_limit_clause = ""
    if select._offset:
        my_limit_clause += " OFFSET %d ROWS" % select._offset
    if select._limit:
        my_limit_clause += " FETCH FIRST %d ROWS ONLY" % select._limit
    return my_limit_clause

OracleCompiler.limit_clause = limit_clause

I did not find out how to use the @compile directive for overriding the 'limit_clause()' method - is there a way to properly do this?
Well first off, SQLAlchemy *has* to add this properly, so let me add a ticket: https://bitbucket.org/zzzeek/sqlalchemy/issues/3543/support-new-oracle-12c-offset-top-n

Secondly, OK I think the monkeypatch you're doing is almost as good as we can do for the moment, though we can make this a little cleaner since we can in fact make a new compiler class totally and associate it with a dialect:

from sqlalchemy.sql import compiler


def patch_engine(engine):
    class Oracle12CCompiler(engine.dialect.statement_compiler):
        def visit_select(self, element, **kw):
            return compiler.SQLCompiler.visit_select(self, element, **kw)

        def limit_clause(self, select):
            # This code overrides the empty method in OracleCompiler:
            my_limit_clause = ""
            if select._offset:
                my_limit_clause += " OFFSET %d ROWS" % select._offset
            if select._limit:
my_limit_clause += " FETCH FIRST %d ROWS ONLY" % select._limit
            return my_limit_clause
    engine.dialect.statement_compiler = Oracle12CCompiler


if __name__ == '__main__':
    from sqlalchemy import create_engine, select, table, column
    import mock

    e = create_engine(
        "oracle://",

        # only because I don't have cx_oracle installed here, this
        # is not part of the example
        module=mock.Mock(version="10.2", paramstyle="named")
    )
    patch_engine(e)

    t = table('foo', column('bar'))
    stmt = select([t]).limit(5).offset(12)

    """
    SELECT foo.bar
    FROM foo OFFSET 12 ROWS FETCH FIRST 5 ROWS ONLY
    """
    print stmt.compile(e)


thanks for bringing this to my attention!






Thanks,

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

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

Reply via email to