In case anyone tries to use the compile visitor below, I'll document a couple snags I ran into. For now, I think I'm satisfied to go back to my original patch and deal with any merge conflicts during upgrades.

The hook has false positives when it runs on inner queries that correlate to tables from outer queries. I think these could be addressed by borrowing most of the logic from _get_display_froms having to do with dropping extra FROMs to make this work right, although you would need to get the values for explicit_correlate_froms and implicit_correlate_froms from somewhere. I'm sure it could be made to work eventually.

Additionally, it raises even in contexts where no sql is being executed. For example, if someone renders a yet-to-be-nested select to a string for debugging purposes, they might get an exception. It's also a bit confusing to the client, because if they render the selectable, it will show them the FROM entity that it simultaneously claims it missing (that is, if you had a way of preventing the exception in the rendering process). Sending the bad SQL to the RDBMS avoids these two caveats.

Also, I found it necessary to use col._from_objects instead of col.table for non-trivial column elements.


After all that, what I can suggest for you is that since you are looking to "raise an error", that is actually easy to do here using events or compiles. All you need to do is compare the calculated FROM list to the explicit FROM list:

from sqlalchemy import table, column, select
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql import Select
from sqlalchemy import exc


@compiles(Select)
def _strict_froms(stmt, compiler, **kw):
    actual_froms = stmt.froms

    # TODO: tune this as desired
    if stmt._from_obj:
        # TODO: we can give you non-underscored access to
        # _from_obj
        legal_froms = stmt._from_obj
    else:
        legal_froms = set([
            col.table for col in stmt.inner_columns
        ])
    if len(legal_froms) != len(actual_froms):
        raise exc.CompileError("SELECT has implicit froms")

    return compiler.visit_select(stmt, **kw)


t1 = table('t1', column('a'))
t2 = table('t2', column('b'))


# works
print select([t1]).where(t2.c.b == 5).select_from(t1).select_from(t2)

# raises
print select([t1]).where(t2.c.b == 5)

The issue of "FROM with comma" *is* a problem I'd like to continue to explore solutions towards. I've long considered various rules in _display_froms but none have ever gotten through the various issues I've detailed above. I hope this helps to clarify the complexity and depth of this situation.



--
SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to