Re: [sqlalchemy] Custom in-query-only rendering for TypeDecorator types?

2012-07-17 Thread Russ
For future reference, it is not actually a great idea to use @compiles to 
render with AT TIME ZONE as I did above.  When done this way, SQLAlchemy 
renders all references to that column using this, *including* any 
references in a WHERE clause.  eg: when looking for log events later than 
some date you would get:

SELECT
  log.blah
 ,log.time AT TIME ZONE 'EST' -- intended use
FROM
  log
WHERE
  log.time AT TIME ZONE 'EST'  foo   -- not intended

As said above, the problem here is that the custom compilation happened in 
both the column specification *and* the WHERE clause.  This is not 
surprising (with hindsight), but it prevents any index on log.time from 
being used (unless there is an appropriate functional index).

For this case, I only wanted it applied to the column spec, not the WHERE, 
but I don't think this is currently possible to differentiate this and 
compile differently in each location...  or is it?  I looked into 
compiler.statement et al to figure out the compilation context, but could 
not.

Russ

PS: For what it's worth, for this specific case in PostgreSQL, this type of 
functionality is better suited to appropriate use of the timestamp with 
time zone data type, and correct session usage of SET TIME ZONE and/or 
PGTZ usage.  I'm currently wrestling with the use cases here instead.


-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/G99byYSmjoQJ.
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.



Re: [sqlalchemy] Custom in-query-only rendering for TypeDecorator types?

2012-07-17 Thread Michael Bayer

On Jul 17, 2012, at 2:25 PM, Russ wrote:

 For future reference, it is not actually a great idea to use @compiles to 
 render with AT TIME ZONE as I did above.  When done this way, SQLAlchemy 
 renders all references to that column using this, including any references in 
 a WHERE clause.  eg: when looking for log events later than some date you 
 would get:
 
 SELECT
   log.blah
  ,log.time AT TIME ZONE 'EST' -- intended use
 FROM
   log
 WHERE
   log.time AT TIME ZONE 'EST'  foo   -- not intended
 
 As said above, the problem here is that the custom compilation happened in 
 both the column specification and the WHERE clause.  This is not surprising 
 (with hindsight), but it prevents any index on log.time from being used 
 (unless there is an appropriate functional index).
 
 For this case, I only wanted it applied to the column spec, not the WHERE, 
 but I don't think this is currently possible to differentiate this and 
 compile differently in each location...  or is it?  I looked into 
 compiler.statement et al to figure out the compilation context, but could not.

it is, you need to look in the **kw passed to your custom compile function for 
the flag within_columns_clause=True, which indicates it's rendering the 
columns clause.




-- 
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.



[sqlalchemy] Custom in-query-only rendering for TypeDecorator types?

2012-07-12 Thread Russ
I currently define a custom column type for ensuring that dates stored to 
the DB are offset-aware UTC, and convert to to the appropriate timezone on 
retrieval, using a class something like this:

import pytz
import sqlalchemy as sa

class UTCEnforcedDateTime(sa.types.TypeDecorator):
DateTime type that ensures that stored datetime objects are
offset-aware UTC. Values retrieved from the database are converted to 
the
local_tz (if class var is set).


impl = sa.types.DateTime
local_tz = None  #eg: pytz.timezone(EST)

def process_bind_param(self, value, engine):
if (value is not None) and (value.tzinfo != UTC):
raise ValueError(only offset-aware UTC datetimes are allowed.)
return value

def process_result_value(self, value, engine):
if value and self.local_tz:
#Make the DB value UTC right away (because it is!)...
utcDT = UTC.localize(value)
value = utcDT.astimezone(self.local_tz)
return value
###

This has worked extremely well to date, but I'm now finding that the 
process_result_value way of doing things is (relatively) slow for large 
numbers of records because the conversion happens in python after the data 
is retrieved.  ie: process_result_value is called for each appropriate 
value in the resulting records.  For example, a profile run showing 600 ms 
total SQLAlchemy query time, with ~500 ms spent in process_result_value 
doing tz conversions (!!).

I'm trying to figure out how to change this so that, rather than converting 
in python, the conversion happens at the database layer using AT TIME ZONE 
syntax.  I've tried using @compiles as follows:

#THIS CODE DOES NOT WORK...
@compiles(UTCEnforcedDateTime)
def compile_UTCEnforcedDateTime(element, compiler, **kwargs):
tz = UTCEnforcedDateTime.local_tz
if tz:
ret = %s AT TIMEZONE '%s' % (element.name, str(tz))
else:
ret = compiler.process(element) #NOT RIGHT - what is?
return ret

However, this is not right for a few reasons...

The first problem is that the special compilation is executed when the 
table is created that has this column type.  I only want the special 
compilation when the compilation is for rendering a query, but I can't 
figure out how to determine this.  The docs http://goo.gl/N4igi state 
that teh compiler argument can be inspected for any information about the 
in-progress compilation, including compiler.dialect, compiler.statement, 
but I can't figure it out.

The second problem is that I'm not certain how to pass through to the 
default compilation that would have been done without my interception.  Is 
there a generic passthrough?  compiler.visit_type_decorator seems 
promising, but I really want carry_on_like_I_never_intercepted_this(). 
 Or should I call visit_datetime?

How do I fix this?

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/AZ0K4D5PaFoJ.
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.



Re: [sqlalchemy] Custom in-query-only rendering for TypeDecorator types?

2012-07-12 Thread Michael Bayer

On Jul 12, 2012, at 2:58 PM, Russ wrote:

 
 I'm trying to figure out how to change this so that, rather than converting 
 in python, the conversion happens at the database layer using AT TIME ZONE 
 syntax.  I've tried using @compiles as follows:
 
 #THIS CODE DOES NOT WORK...
 @compiles(UTCEnforcedDateTime)
 def compile_UTCEnforcedDateTime(element, compiler, **kwargs):
 tz = UTCEnforcedDateTime.local_tz
 if tz:
 ret = %s AT TIMEZONE '%s' % (element.name, str(tz))
 else:
 ret = compiler.process(element) #NOT RIGHT - what is?
 return ret
 
 However, this is not right for a few reasons...

There is no functionality right now that allows special SQL to be automatically 
associated with a type, as associated with an enclosing column expression, at 
query time.  There's a ticket to begin making this kind of thing possible which 
is http://www.sqlalchemy.org/trac/ticket/1534.   When using @compiles for a 
type, the only time that compilation takes effect is when the type itself is 
rendered, not its containing column - that means, only CREATE TABLE and CAST 
expressions.

Your best option here is to compose that SQL expression explicitly when you 
emit a query.  There's many ways to make this happen depending on if you're 
dealing with Core only or ORM.

There might be some ways to use @compiles around Column expressions which check 
the type too, but this might be a little tricky (or not).

I'd also look into why the in-python TZ conversion is so slow, it seems a 
little suspect that it is 5x slower than the rest of the entire operation 
overall.   I'd check things like, the result processor isn't being called 
repeatedly for the same value, stuff like that.


-- 
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.



Re: [sqlalchemy] Custom in-query-only rendering for TypeDecorator types?

2012-07-12 Thread Russ
On Thursday, July 12, 2012 3:12:26 PM UTC-4, Michael Bayer wrote:

 There is no functionality right now that allows special SQL to be 
 automatically associated with a type, as associated with an enclosing 
 column expression, at query time.  There's a ticket to begin making this 
 kind of thing possible which is http://www.sqlalchemy.org/trac/ticket/1534. 
   When using @compiles for a type, the only time that compilation takes 
 effect is when the type itself is rendered, not its containing column - 
 that means, only CREATE TABLE and CAST expressions.

 
On Thursday, July 12, 2012 3:12:26 PM UTC-4, Michael Bayer wrote:

 There is no functionality right now that allows special SQL to be 
 automatically associated with a type, as associated with an enclosing 
 column expression, at query time.  There's a ticket to begin making this 
 kind of thing possible which is http://www.sqlalchemy.org/trac/ticket/1534. 
   When using @compiles for a type, the only time that compilation takes 
 effect is when the type itself is rendered, not its containing column - 
 that means, only CREATE TABLE and CAST expressions.


I now understand this more now, thanks.  Am I right in understanding that, 
after the initial type is passed to the Column constructor, there is no 
real connection between the ColumnClause specified in table definition and 
the column type (TypeEngine)?

There might be some ways to use @compiles around Column expressions which 
 check the type too, but this might be a little tricky (or not).


I've got it mostly working using this method, but have hit a few 
roadblocks.  It was pretty easy to intercept Column definitions that were 
given the UTCEnforcedDateTime type and, with this done, then use DTColumn 
wrapper type instead with an associated compiler something like this:

class DTColumn(sa.Column):
pass

@compiles(DTColumn)
def compile_DTColumn(element, compiler, **kw):
tz = UTCEnforcedDateTime.local_tz
elementName = '%s.%s' % (element.table.name, element.name)
ret = %s AT TIME ZONE '%s' % (elementName, str(tz))
return ret

This does what I want (great!)... but this isn't quite right, yet.

At first I followed the example [1] for @compiles usage with ColumnClause 
classes.  This indicates to use element.name.  This worked for many 
queries, until I ran into a query where the column name became ambiguous 
and I needed to specify the table name as well.  Digging around the 
'element' properties, I then added in element.table.name (as per the code 
above) to handle this.  This worked for many more queries.

However... element.table.name doesn't seem like it can be used directly. 
 It occasionally comes up with strings like %(79508240 log_event)s, which 
clearly is getting substituted in the guts somewhere when I don't do this.

What is the proper way to get the fully qualified element name?

Also, I put in the wrapping quotes on column name since I needed to for a 
few columns, but is there a proper way to do escape this in SQLAlchemy? 
 I expect this is dialect-specific, since it only seems to get done when 
needed when left alone.

I'd also look into why the in-python TZ conversion is so slow, it seems a 
 little suspect that it is 5x slower than the rest of the entire operation 
 overall.   I'd check things like, the result processor isn't being called 
 repeatedly for the same value, stuff like that.


I was also quite surprised, but it is legit.  On re-profile just now it is 
not 80% of my operation, but more like 40%.  See the light green part to 
the left of this runsnakerun output:
http://static.inky.ws/image/2379/image.jpg

There is some other stuff happening there (which only increase the 
tz-conversion percentage when considered), but the upshot of it all is that 
I do want to ditch the process_result_value overhead for this particular 
query, and learn more about the SQLAlchemy internals in the process. :)

Russ

[1] http://docs.sqlalchemy.org/en/rel_0_7/core/compiler.html#synopsis

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/udDuAdJqGzQJ.
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.



Re: [sqlalchemy] Custom in-query-only rendering for TypeDecorator types?

2012-07-12 Thread Michael Bayer

On Jul 12, 2012, at 5:15 PM, Russ wrote:

 
 I've got it mostly working using this method, but have hit a few roadblocks.  
 It was pretty easy to intercept Column definitions that were given the 
 UTCEnforcedDateTime type and, with this done, then use DTColumn wrapper type 
 instead with an associated compiler something like this:
 
 class DTColumn(sa.Column):
 pass
 
 @compiles(DTColumn)
 def compile_DTColumn(element, compiler, **kw):
 tz = UTCEnforcedDateTime.local_tz
 elementName = '%s.%s' % (element.table.name, element.name)
 ret = %s AT TIME ZONE '%s' % (elementName, str(tz))
 return ret
 
 This does what I want (great!)... but this isn't quite right, yet.
 
 At first I followed the example [1] for @compiles usage with ColumnClause 
 classes.  This indicates to use element.name.  This worked for many queries, 
 until I ran into a query where the column name became ambiguous and I needed 
 to specify the table name as well.  Digging around the 'element' properties, 
 I then added in element.table.name (as per the code above) to handle this.  
 This worked for many more queries.
 
 However... element.table.name doesn't seem like it can be used directly.  It 
 occasionally comes up with strings like %(79508240 log_event)s, which 
 clearly is getting substituted in the guts somewhere when I don't do this.
 
 What is the proper way to get the fully qualified element name?

let the compiler do it:

elementName = compiler.process(element, **kw)

that will give you the SQL for the column as it would be rendered anyway.   
But, this might give you problems specifically if the element is a _Label(), in 
which case the expression is element.element,  so you might have to poke to 
see if that's what you've got, then substitute that for a _Label() that is 
around your SQL expression.

something like:

if isinstance(element, _Label):
my_elem = literal_column(%s AT TIME ZONE ... % 
compiler.process(element.element)).label(element.name)
return compiler.process(my_elem)
else:
ret = %s AT TIME ZONE % compiler.process(element) 

the above isn't totally accurate but something along those lines.I could be 
off here too, I'd need to screw with it (this is why I said it might be 
tricky).   There might be some recipe approach I could come up with here that 
works more generically.

 Also, I put in the wrapping quotes on column name since I needed to for a few 
 columns, but is there a proper way to do escape this in SQLAlchemy?  I 
 expect this is dialect-specific, since it only seems to get done when needed 
 when left alone.

yeah all of that should be handled by the compiler.



 
 I'd also look into why the in-python TZ conversion is so slow, it seems a 
 little suspect that it is 5x slower than the rest of the entire operation 
 overall.   I'd check things like, the result processor isn't being called 
 repeatedly for the same value, stuff like that.
 
 I was also quite surprised, but it is legit.  On re-profile just now it is 
 not 80% of my operation, but more like 40%.  See the light green part to the 
 left of this runsnakerun output:
 http://static.inky.ws/image/2379/image.jpg
 
 There is some other stuff happening there (which only increase the 
 tz-conversion percentage when considered), but the upshot of it all is that I 
 do want to ditch the process_result_value overhead for this particular query, 
 and learn more about the SQLAlchemy internals in the process. :)
 
 Russ
 
 [1] http://docs.sqlalchemy.org/en/rel_0_7/core/compiler.html#synopsis
 
 -- 
 You received this message because you are subscribed to the Google Groups 
 sqlalchemy group.
 To view this discussion on the web visit 
 https://groups.google.com/d/msg/sqlalchemy/-/udDuAdJqGzQJ.
 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.

-- 
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.



Re: [sqlalchemy] Custom in-query-only rendering for TypeDecorator types?

2012-07-12 Thread Russ


 However... element.table.name doesn't seem like it can be used directly. 
  It occasionally comes up with strings like %(79508240 log_event)s, which 
 clearly is getting substituted in the guts somewhere when I don't do this.


To clarify, I've just determined that this is specifically happening when 
type(element.table) == sa.sql.expression.Alias.  I'm still stumped, but 
that is more info, anyway.


-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/jcnVOxkGPaIJ.
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.



Re: [sqlalchemy] Custom in-query-only rendering for TypeDecorator types?

2012-07-12 Thread Russ
On Thursday, July 12, 2012 5:42:12 PM UTC-4, Michael Bayer wrote:

 let the compiler do it:

 elementName = compiler.process(element, **kw)


That causes an infinite loop since it tries to compile DTColumn itself.

I've tried stuff like super(DTColumn, element).compile(), but that doesn't 
help (and was a guess anyway).

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/2eZs0B2dct0J.
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.



Re: [sqlalchemy] Custom in-query-only rendering for TypeDecorator types?

2012-07-12 Thread Michael Bayer
oh right.   yeah call compiler.visit_column(element, **kw).




On Jul 12, 2012, at 5:59 PM, Russ wrote:

 On Thursday, July 12, 2012 5:42:12 PM UTC-4, Michael Bayer wrote:
 let the compiler do it:
 
 elementName = compiler.process(element, **kw)
 
 That causes an infinite loop since it tries to compile DTColumn itself.
 
 I've tried stuff like super(DTColumn, element).compile(), but that doesn't 
 help (and was a guess anyway).
 
 -- 
 You received this message because you are subscribed to the Google Groups 
 sqlalchemy group.
 To view this discussion on the web visit 
 https://groups.google.com/d/msg/sqlalchemy/-/2eZs0B2dct0J.
 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.

-- 
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.



Re: [sqlalchemy] Custom in-query-only rendering for TypeDecorator types?

2012-07-12 Thread Russ


 oh right.   yeah call compiler.visit_column(element, **kw).


Perfect... that did the trick, thanks!!!

Since the end result isn't much more than this example:
http://docs.sqlalchemy.org/en/rel_0_7/core/compiler.html#synopsis

it may be worth updating it to replace 'element.name' with 
'compiler.visit_column(element, **kw)', since it may help future people.

Russ

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/sqlalchemy/-/bdCRfquAUd4J.
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.