On Feb 7, 2011, at 11:26 AM, Kent wrote: > For whatever reason I couldn't use compiler.is_subquery(): > return len(self.stack) > 1 > > I guess from this context I need: len(self.stack) > 0 > > Not sure why, except that I'm "one stack level" off when the @compiles > function is invoked to be able to use compiler.is_subquery(). > > > @compiles(Select) > def compile_forupdateof(select, compiler, **kw): > rendered = compiler.visit_select(select, **kw) > if not compiler.stack and hasattr(select, '_for_update_of'): > mapper = class_mapper(select._for_update_of) > name = mapper.mapped_table.name > if compiler.dialect.name == 'oracle': > # Oracle makes us specify the column name (for views, I > guess, since it locks entire row) > name += '.' + mapper.primary_key[0].name > rendered = "%s FOR UPDATE OF %s" % (rendered, name) > return rendered
Oh, because the stack increment/decrement is inside of visit_select(), and you're wrapping outside of that. I can assure you, you know more about the internals of the compiler now than is needed for that patch ;) > > > On Feb 7, 11:20 am, Michael Bayer <[email protected]> wrote: >> On Feb 7, 2011, at 11:16 AM, Kent wrote: >> >>> On Feb 4, 12:04 pm, Kent <[email protected]> wrote: >>>> Excellent, it is working for the simpler case, but for oracle 8 (who >>>> isn't as smart when indexing) I also need it to work for >>>> subqueryload(). >> >>>> So the problem is that my FOR UPDATE OF is also being added for >>>> subqueryload selects. >> >>>> * Can I tell within the compiles context if this is for subqueryload? >>>> (Or can the Query tell?) >> >>> What I worked out based on compiler.is_subquery() is that >>> compiler.stack (in other words, bool(compiler.stack)) should tell me >>> if this is a subqueryload. Does that sound accurate? >> >> yes that is actually the appropriate way to detect if the current context is >> that of a subquery. (is_subquery() that is. I'd prefer that over peeking >> into the stack itself). >> >> >> >>>> * Are there other cases where the query is "reused" that I need to be >>>> careful of? >> >>>> I restructured this way (as you're original suggestion to fix another >>>> issue): >> >>>> @compiles(Select) >>>> def compile_forupdateof(select, compiler, **kw): >>>> rendered = compiler.visit_select(select, **kw) >>>> if hasattr(select, '_for_update_of'): >>>> mapper = class_mapper(select._for_update_of) >>>> name = mapper.mapped_table.name >>>> if compiler.dialect.name == 'oracle': >>>> # Oracle makes us specify the column name (for views, I >>>> guess, since it locks entire row) >>>> name += '.' + mapper.primary_key[0].name >>>> rendered = "%s FOR UPDATE OF %s" % (rendered, name) >>>> return rendered >> >>>> On Feb 3, 9:51 pm, Michael Bayer <[email protected]> wrote: >> >>>>> On Feb 3, 2011, at 9:29 PM, Kent wrote: >> >>>>>> Yeah, I wanted to apologize because my heart wants to contribute to >>>>>> the project (really), but I'm working overtime like mad swamped >>>>>> because our product is live in use now and I've got a backload of >>>>>> tickets to solve! I also feel my level of understanding currently is >>>>>> more hacking than contributing. I hope to be of more help to the >>>>>> project in the future. >> >>>>>> Is "simpler than you had in mind" a good thing or am I over >>>>>> simplifying and it won't work for bunch of cases? >> >>>>>> I note that the simple case is working, but something like this fails: >> >>>>>> DBSession.query(Order).for_update_of(Order).limit(10).all() >> >>>>>> since I really need to have the for update inside in this case... any >>>>>> advise or is this what you meant by "There's not a great way to >>>>>> intercept the middle of the SELECT compilation with a new kind of >>>>>> clause in this case."? >> >>>>> i think if it works for what you need right now, then its great. >>>>> @compiles is meant to give you what you need to get out of a jam. >> >>>>>> On Feb 3, 9:07 pm, Michael Bayer <[email protected]> wrote: >>>>>>> oh OK this is a little simpler than what I had in mind, you just have >>>>>>> to add the mixin expression.Executable to your ForUpdateOf class. >> >>>>>>> On Feb 3, 2011, at 9:05 PM, Kent wrote: >> >>>>>>>> Here is a crude outline (need to properly escape table name, etc.), of >>>>>>>> what I think might work, and it seems to render properly, but crashes >>>>>>>> with: >> >>>>>>>> File "/home/rarch/tg2env/lib/python2.6/site-packages/ >>>>>>>> SQLAlchemy-0.6.4.2kbdev-py2.6-linux-x86_64.egg/sqlalchemy/engine/ >>>>>>>> default.py", line 353, in __init__ >>>>>>>> raise exc.ArgumentError("Not an executable clause: %s" % compiled) >>>>>>>> ArgumentError: Not an executable clause: >>>>>>>> ... >> >>>>>>>> class MyQuery(Query): >>>>>>>> _for_update_of = None >> >>>>>>>> @_generative() >>>>>>>> def for_update_of(self, arg): >>>>>>>> """Keep track that we want to for update of this""" >>>>>>>> self._for_update_of = class_mapper(arg).mapped_table.name >> >>>>>>>> def _compile_context(self, labels=True): >>>>>>>> context = super(MyQuery, self)._compile_context(labels) >>>>>>>> if self._for_update_of: >>>>>>>> context.statement = ForUpdateOf(context.statement, >>>>>>>> self._for_update_of) >>>>>>>> return context >> >>>>>>>> class ForUpdateOf(ClauseElement): >>>>>>>> def __init__(self, statement, for_update_of): >>>>>>>> self.statement = statement >>>>>>>> self.for_update_of = for_update_of >> >>>>>>>> @compiles(ForUpdateOf) >>>>>>>> def compile_forupdateof(element, compiler, **kw): >>>>>>>> return "%s FOR UPDATE OF %s" % >>>>>>>> (compiler.process(element.statement), element.for_update_of) >> >>>>>>>> -- >>>>>>>> You received this message because you are subscribed to the Google >>>>>>>> Groups "sqlalchemy" group. >>>>>>>> To post to this group, send email to [email protected]. >>>>>>>> To unsubscribe from this group, send email to >>>>>>>> [email protected]. >>>>>>>> For more options, visit this group >>>>>>>> athttp://groups.google.com/group/sqlalchemy?hl=en. >> >>>>>> -- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "sqlalchemy" group. >>>>>> To post to this group, send email to [email protected]. >>>>>> To unsubscribe from this group, send email to >>>>>> [email protected]. >>>>>> For more options, visit this group >>>>>> athttp://groups.google.com/group/sqlalchemy?hl=en. >> >>> -- >>> You received this message because you are subscribed to the Google Groups >>> "sqlalchemy" group. >>> To post to this group, send email to [email protected]. >>> To unsubscribe from this group, send email to >>> [email protected]. >>> For more options, visit this group >>> athttp://groups.google.com/group/sqlalchemy?hl=en. >> >> > > -- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]. > For more options, visit this group at > http://groups.google.com/group/sqlalchemy?hl=en. > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
