I'd like to find (or make) the time for a patch.  Having said that, I
made what will work for my use case, and I think it is severely
lacking for what would be proper for the sqla project:
 * I've only studied Oracle/Postgres for "FOR UPDATE OF", so it would
only work for oracle/postgresql
 * My solution makes blaring assumptions, like that it can use the
table name (would that break if it is aliased? probably)
 * My solution doesn't know how to properly escape (quote) tokens that
need to be (table/column name)
 * My solution breaks the second it is in a subquery, for example, you
can't say session.query(Order).for_update_of(Order).limit(10)
 * My solution doesn't provide for specifying columns (it assumes you
want the whole table row (which is actually what oracle does even when
you provide a column), so you can't render a FOR UPDATE OF
orders.orderdate, orders.orderid,...

Would you want something this incomplete/be willing to help me get it
right?  (concern I'd take as much of your time as it would take you to
do it...)

Let me know.
Kent

On Feb 7, 11:32 am, Michael Bayer <mike...@zzzcomputing.com> wrote:
> 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 <mike...@zzzcomputing.com> wrote:
> >> On Feb 7, 2011, at 11:16 AM, Kent wrote:
>
> >>> On Feb 4, 12:04 pm, Kent <jkentbo...@gmail.com> 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 <mike...@zzzcomputing.com> 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 <mike...@zzzcomputing.com> 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 sqlalchemy@googlegroups.com.
> >>>>>>>> To unsubscribe from this group, send email to 
> >>>>>>>> sqlalchemy+unsubscr...@googlegroups.com.
> >>>>>>>> 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 sqlalchemy@googlegroups.com.
> >>>>>> To unsubscribe from this group, send email to 
> >>>>>> sqlalchemy+unsubscr...@googlegroups.com.
> >>>>>> 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 sqlalchemy@googlegroups.com.
> >>> To unsubscribe from this group, send email to 
> >>> sqlalchemy+unsubscr...@googlegroups.com.
> >>> 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 sqlalchemy@googlegroups.com.
> > To unsubscribe from this group, send email to 
> > sqlalchemy+unsubscr...@googlegroups.com.
> > 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 sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to