sqlobject-cvs Mailing List for SQLObject (Page 93)
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
You can subscribe to this list here.
| 2003 |
Jan
|
Feb
|
Mar
(9) |
Apr
(74) |
May
(29) |
Jun
(16) |
Jul
(28) |
Aug
(10) |
Sep
(57) |
Oct
(9) |
Nov
(29) |
Dec
(12) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2004 |
Jan
(7) |
Feb
(14) |
Mar
(6) |
Apr
(3) |
May
(12) |
Jun
(34) |
Jul
(9) |
Aug
(29) |
Sep
(22) |
Oct
(2) |
Nov
(15) |
Dec
(52) |
| 2005 |
Jan
(47) |
Feb
(78) |
Mar
(14) |
Apr
(35) |
May
(33) |
Jun
(16) |
Jul
(26) |
Aug
(63) |
Sep
(40) |
Oct
(96) |
Nov
(96) |
Dec
(123) |
| 2006 |
Jan
(159) |
Feb
(144) |
Mar
(64) |
Apr
(31) |
May
(88) |
Jun
(48) |
Jul
(16) |
Aug
(64) |
Sep
(87) |
Oct
(92) |
Nov
(56) |
Dec
(76) |
| 2007 |
Jan
(94) |
Feb
(103) |
Mar
(126) |
Apr
(123) |
May
(85) |
Jun
(11) |
Jul
(130) |
Aug
(47) |
Sep
(65) |
Oct
(70) |
Nov
(12) |
Dec
(11) |
| 2008 |
Jan
(30) |
Feb
(55) |
Mar
(88) |
Apr
(20) |
May
(50) |
Jun
|
Jul
(38) |
Aug
(1) |
Sep
(9) |
Oct
(5) |
Nov
(6) |
Dec
(39) |
| 2009 |
Jan
(8) |
Feb
(16) |
Mar
(3) |
Apr
(33) |
May
(44) |
Jun
(1) |
Jul
(10) |
Aug
(33) |
Sep
(74) |
Oct
(22) |
Nov
|
Dec
(15) |
| 2010 |
Jan
(28) |
Feb
(22) |
Mar
(46) |
Apr
(29) |
May
(1) |
Jun
(1) |
Jul
(27) |
Aug
(8) |
Sep
(5) |
Oct
(33) |
Nov
(24) |
Dec
(41) |
| 2011 |
Jan
(4) |
Feb
(12) |
Mar
(35) |
Apr
(29) |
May
(19) |
Jun
(16) |
Jul
(32) |
Aug
(25) |
Sep
(5) |
Oct
(11) |
Nov
(21) |
Dec
(12) |
| 2012 |
Jan
(3) |
Feb
(4) |
Mar
(20) |
Apr
(4) |
May
(25) |
Jun
(13) |
Jul
|
Aug
|
Sep
(2) |
Oct
(25) |
Nov
(9) |
Dec
(1) |
| 2013 |
Jan
(6) |
Feb
(8) |
Mar
|
Apr
(10) |
May
(31) |
Jun
(7) |
Jul
(18) |
Aug
(33) |
Sep
(4) |
Oct
(16) |
Nov
|
Dec
(27) |
| 2014 |
Jan
(2) |
Feb
|
Mar
|
Apr
(11) |
May
(39) |
Jun
(8) |
Jul
(11) |
Aug
(4) |
Sep
|
Oct
(27) |
Nov
|
Dec
(71) |
| 2015 |
Jan
(17) |
Feb
(47) |
Mar
(33) |
Apr
|
May
|
Jun
(9) |
Jul
(7) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(8) |
| 2016 |
Jan
(4) |
Feb
(4) |
Mar
|
Apr
|
May
(12) |
Jun
(7) |
Jul
(9) |
Aug
(31) |
Sep
(8) |
Oct
(3) |
Nov
(15) |
Dec
(1) |
| 2017 |
Jan
(13) |
Feb
(7) |
Mar
(14) |
Apr
(8) |
May
(10) |
Jun
(4) |
Jul
(2) |
Aug
(1) |
Sep
|
Oct
(8) |
Nov
(4) |
Dec
(5) |
| 2018 |
Jan
(2) |
Feb
(8) |
Mar
|
Apr
(4) |
May
|
Jun
(6) |
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
(1) |
Dec
|
| 2019 |
Jan
(1) |
Feb
(16) |
Mar
(1) |
Apr
(3) |
May
(5) |
Jun
(1) |
Jul
|
Aug
|
Sep
(2) |
Oct
|
Nov
(1) |
Dec
(3) |
| 2020 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
(1) |
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
(2) |
Nov
|
Dec
(2) |
| 2021 |
Jan
|
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
(1) |
Dec
|
| 2022 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(6) |
Oct
(1) |
Nov
(1) |
Dec
(4) |
| 2023 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
(3) |
Sep
(2) |
Oct
(2) |
Nov
(4) |
Dec
|
| 2024 |
Jan
|
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
(1) |
Oct
|
Nov
|
Dec
(9) |
| 2025 |
Jan
|
Feb
(4) |
Mar
(2) |
Apr
|
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
(2) |
Dec
(2) |
|
From: <sub...@co...> - 2007-04-25 15:16:44
|
Author: phd Date: 2007-04-25 09:16:39 -0600 (Wed, 25 Apr 2007) New Revision: 2600 Modified: SQLObject/branches/0.8/docs/News.txt SQLObject/branches/0.8/docs/SQLObject.txt Log: More documentation about orderBy. Modified: SQLObject/branches/0.8/docs/News.txt =================================================================== --- SQLObject/branches/0.8/docs/News.txt 2007-04-25 15:16:26 UTC (rev 2599) +++ SQLObject/branches/0.8/docs/News.txt 2007-04-25 15:16:39 UTC (rev 2600) @@ -162,6 +162,8 @@ * Yet another patch to properly initialize MySQL connection encoding. +* More documentation about orderBy. + SQLObject 0.7.5 =============== Modified: SQLObject/branches/0.8/docs/SQLObject.txt =================================================================== --- SQLObject/branches/0.8/docs/SQLObject.txt 2007-04-25 15:16:26 UTC (rev 2599) +++ SQLObject/branches/0.8/docs/SQLObject.txt 2007-04-25 15:16:39 UTC (rev 2600) @@ -567,11 +567,13 @@ .. _orderBy: -You can use the keyword arguments `orderBy` to create ``ORDER BY`` in -the select statements: `orderBy` takes a string, which should be the -*database* name of the column, or a column in the form -``Person.q.firstName``. You can use ``"-colname"`` to specify -descending order, or call ``MyClass.select().reversed()``. +You can use the keyword arguments `orderBy` to create ``ORDER BY`` in the +select statements: `orderBy` takes a string, which should be the *database* +name of the column, or a column in the form ``Person.q.firstName``. You +can use ``"-colname"`` or ``DESC(Person.q.firstName``) to specify +descending order (this is translated to DESC, so it works on non-numeric +types as well), or call ``MyClass.select().reversed()``. orderBy can also +take a list of columns in the same format: ``["-weight", "name"]``. You can use the special class variable `_defaultOrder` to give a default ordering for all selects. To get an unordered result when |
|
From: <sub...@co...> - 2007-04-25 15:16:30
|
Author: phd Date: 2007-04-25 09:16:26 -0600 (Wed, 25 Apr 2007) New Revision: 2599 Modified: SQLObject/branches/0.7/docs/News.txt SQLObject/branches/0.7/docs/SQLObject.txt Log: More documentation about orderBy. Modified: SQLObject/branches/0.7/docs/News.txt =================================================================== --- SQLObject/branches/0.7/docs/News.txt 2007-04-25 15:01:46 UTC (rev 2598) +++ SQLObject/branches/0.7/docs/News.txt 2007-04-25 15:16:26 UTC (rev 2599) @@ -25,6 +25,8 @@ * Yet another patch to properly initialize MySQL connection encoding. +* More documentation about orderBy. + SQLObject 0.7.5 =============== Modified: SQLObject/branches/0.7/docs/SQLObject.txt =================================================================== --- SQLObject/branches/0.7/docs/SQLObject.txt 2007-04-25 15:01:46 UTC (rev 2598) +++ SQLObject/branches/0.7/docs/SQLObject.txt 2007-04-25 15:16:26 UTC (rev 2599) @@ -566,11 +566,13 @@ .. _orderBy: -You can use the keyword arguments `orderBy` to create ``ORDER BY`` in -the select statements: `orderBy` takes a string, which should be the -*database* name of the column, or a column in the form -``Person.q.firstName``. You can use ``"-colname"`` to specify -descending order, or call ``MyClass.select().reversed()``. +You can use the keyword arguments `orderBy` to create ``ORDER BY`` in the +select statements: `orderBy` takes a string, which should be the *database* +name of the column, or a column in the form ``Person.q.firstName``. You +can use ``"-colname"`` or ``DESC(Person.q.firstName``) to specify +descending order (this is translated to DESC, so it works on non-numeric +types as well), or call ``MyClass.select().reversed()``. orderBy can also +take a list of columns in the same format: ``["-weight", "name"]``. You can use the special class variable `_defaultOrder` to give a default ordering for all selects. To get an unordered result when |
|
From: <sub...@co...> - 2007-04-25 15:01:49
|
Author: phd
Date: 2007-04-25 09:01:46 -0600 (Wed, 25 Apr 2007)
New Revision: 2598
Modified:
home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py
Log:
Merged patches from the revisions 2597:2597 from the trunk
Modified: home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2007-04-25 14:57:02 UTC (rev 2597)
+++ home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2007-04-25 15:01:46 UTC (rev 2598)
@@ -57,6 +57,13 @@
connectionFromURI = classmethod(connectionFromURI)
def makeConnection(self):
+ from MySQLdb.connections import Connection
+ if not hasattr(Connection, 'set_character_set'):
+ # monkeypatch pre MySQLdb 1.2.1
+ encoding = self.dbEncoding
+ def character_set_name(self):
+ return encoding + '_' + encoding
+ Connection.character_set_name = character_set_name
try:
conn = self.module.connect(host=self.host, port=self.port,
db=self.db, user=self.user, passwd=self.password, **self.kw)
@@ -71,6 +78,12 @@
if hasattr(conn, 'autocommit'):
conn.autocommit(bool(self.autoCommit))
+ if hasattr(conn, 'set_character_set'): # MySQLdb 1.2.1 and later
+ conn.set_character_set(self.dbEncoding)
+ else: # pre MySQLdb 1.2.1
+ # works along with monkeypatching code above
+ conn.query("SET NAMES %s" % self.dbEncoding)
+
return conn
def _setAutoCommit(self, conn, auto):
@@ -92,13 +105,11 @@
# done by calling ping(True) on the connection.
for count in range(3):
try:
- if self.need_unicode:
- # For MysqlDB 1.2.1 and later, we go
- # encoding->unicode->charset (in the mysql db)
- myquery = unicode(query, self.encoding)
- return DBAPI._executeRetry(self, conn, cursor, query)
- else:
- return DBAPI._executeRetry(self, conn, cursor, query)
+ # For MySQLdb 1.2.1 and later, we go
+ # encoding->unicode->charset (in the mysql db)
+ if self.need_unicode and not isinstance(query, unicode):
+ query = unicode(query, self.encoding)
+ return DBAPI._executeRetry(self, conn, cursor, query)
except MySQLdb.OperationalError, e:
if e.args[0] in (MySQLdb.constants.CR.SERVER_GONE_ERROR, MySQLdb.constants.CR.SERVER_LOST):
if count == 2:
|
|
From: SourceForge.net <no...@so...> - 2007-04-25 14:57:38
|
Patches item #1653898, was opened at 2007-02-07 10:57 Message generated for change (Comment added) made by phd You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540674&aid=1653898&group_id=74338 Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: None Group: None Status: Open >Resolution: Accepted Priority: 5 Private: No Submitted By: Maxim F. Ischenko (mfi) Assigned to: Oleg Broytmann (phd) Summary: proper init mysql conn encoding Initial Comment: Current implementation of the mysqlconnection.py accepts 'sqlobject_encoding' and 'charset' parameters but doesn't quite properly use them. In particular, MySQLdb does query.encode(charset) call in execute() where charset is taken from conn.get_character_name(). The problem is - SQLObject never initializes it properly. This one-line patch fixes it by adding a call to conn.set_character_set() in makeConnection() helper. Index: sqlobject/mysql/mysqlconnection.py =================================================================== --- sqlobject/mysql/mysqlconnection.py (revision 2269) +++ sqlobject/mysql/mysqlconnection.py (working copy) @@ -62,6 +62,8 @@ if hasattr(conn, 'autocommit'): conn.autocommit(bool(self.autoCommit)) + conn.set_character_set(self.encoding) + return conn def _setAutoCommit(self, conn, auto): ---------------------------------------------------------------------- >Comment By: Oleg Broytmann (phd) Date: 2007-04-25 18:57 Message: Logged In: YES user_id=4799 Originator: NO I applied a pert of the patch, but I didn't apply the UnicodeStringLikeConvertor (I have to think about it a bit more to find problems with the part) and dbEncoding/sqlobject_encoding unification. Committed in the revisions 2593-2597 (0.7, 0.8, 0.9, trunk and docs). Thank you! ---------------------------------------------------------------------- Comment By: Maxim F. Ischenko (mfi) Date: 2007-02-07 17:54 Message: Logged In: YES user_id=113894 Originator: YES Note that I also had to tweak UnicodeStringLikeConvertor so that unicode parameters are encoded into utf8. Without this tweak I got errors like this one when unicode parameters are passed into queries built with sqlbuilder: File "/home/max/oss-projects/SQLObject-0.7/sqlobject/sqlbuilder.py", line 237, in __sqlrepr__ return "(%s %s %s)" % (s1, self.op, s2) UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 19: ordinal not in range(128) The converter trick is controversial but I haven't found a better solution. ;( ---------------------------------------------------------------------- Comment By: Maxim F. Ischenko (mfi) Date: 2007-02-07 17:46 Message: Logged In: YES user_id=113894 Originator: YES It was tested against MySQL 4.1 (5.x should work while 4.0 shouldn't) and MySQLdb driver versions 1.2.0 and 1.2.1. I only tested it with utf8 encoding, the other ones like latin1 should work though I don't know why would you want to use them. ---------------------------------------------------------------------- Comment By: Maxim F. Ischenko (mfi) Date: 2007-02-07 17:44 Message: Logged In: YES user_id=113894 Originator: YES Please ignore that one-line fix; it won't work with MySQLdb 1.2.0 and there are other issues as I have discovered during testing. I attached new patch which is quite more involved. ;) ---------------------------------------------------------------------- Comment By: Maxim F. Ischenko (mfi) Date: 2007-02-07 17:42 Message: Logged In: YES user_id=113894 Originator: YES File Added: mysql_charset.patch ---------------------------------------------------------------------- Comment By: Oleg Broytmann (phd) Date: 2007-02-07 11:34 Message: Logged In: YES user_id=4799 Originator: NO Thank you. Does all MySQLdb versions have the call or have I test "if hasattr(conn, 'set_character_set')"? ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540674&aid=1653898&group_id=74338 |
|
From: <sub...@co...> - 2007-04-25 14:57:07
|
Author: phd
Date: 2007-04-25 08:57:02 -0600 (Wed, 25 Apr 2007)
New Revision: 2597
Modified:
SQLObject/docs/News.txt
Log:
Applied the patch 1653898: properly initialize MySQL connection encoding.
Modified: SQLObject/docs/News.txt
===================================================================
--- SQLObject/docs/News.txt 2007-04-25 14:56:49 UTC (rev 2596)
+++ SQLObject/docs/News.txt 2007-04-25 14:57:02 UTC (rev 2597)
@@ -218,6 +218,8 @@
their parameter must be a string; now you can pass an SQLExpression:
Table.q.name.contains(func.upper('a')), for example.
+* Yet another patch to properly initialize MySQL connection encoding.
+
SQLObject 0.7.5
===============
|
|
From: <sub...@co...> - 2007-04-25 14:56:55
|
Author: phd
Date: 2007-04-25 08:56:49 -0600 (Wed, 25 Apr 2007)
New Revision: 2596
Modified:
SQLObject/trunk/sqlobject/mysql/mysqlconnection.py
Log:
Applied the patch 1653898: properly initialize MySQL connection encoding.
Modified: SQLObject/trunk/sqlobject/mysql/mysqlconnection.py
===================================================================
--- SQLObject/trunk/sqlobject/mysql/mysqlconnection.py 2007-04-25 14:56:28 UTC (rev 2595)
+++ SQLObject/trunk/sqlobject/mysql/mysqlconnection.py 2007-04-25 14:56:49 UTC (rev 2596)
@@ -57,6 +57,13 @@
connectionFromURI = classmethod(connectionFromURI)
def makeConnection(self):
+ from MySQLdb.connections import Connection
+ if not hasattr(Connection, 'set_character_set'):
+ # monkeypatch pre MySQLdb 1.2.1
+ encoding = self.dbEncoding
+ def character_set_name(self):
+ return encoding + '_' + encoding
+ Connection.character_set_name = character_set_name
try:
conn = self.module.connect(host=self.host, port=self.port,
db=self.db, user=self.user, passwd=self.password, **self.kw)
@@ -71,6 +78,12 @@
if hasattr(conn, 'autocommit'):
conn.autocommit(bool(self.autoCommit))
+ if hasattr(conn, 'set_character_set'): # MySQLdb 1.2.1 and later
+ conn.set_character_set(self.dbEncoding)
+ else: # pre MySQLdb 1.2.1
+ # works along with monkeypatching code above
+ conn.query("SET NAMES %s" % self.dbEncoding)
+
return conn
def _setAutoCommit(self, conn, auto):
@@ -92,13 +105,11 @@
# done by calling ping(True) on the connection.
for count in range(3):
try:
- if self.need_unicode:
- # For MysqlDB 1.2.1 and later, we go
- # encoding->unicode->charset (in the mysql db)
- myquery = unicode(query, self.encoding)
- return cursor.execute(myquery)
- else:
- return cursor.execute(query)
+ # For MySQLdb 1.2.1 and later, we go
+ # encoding->unicode->charset (in the mysql db)
+ if self.need_unicode and not isinstance(query, unicode):
+ query = unicode(query, self.encoding)
+ return cursor.execute(query)
except MySQLdb.OperationalError, e:
if e.args[0] in (MySQLdb.constants.CR.SERVER_GONE_ERROR, MySQLdb.constants.CR.SERVER_LOST):
if count == 2:
|
|
From: <sub...@co...> - 2007-04-25 14:56:33
|
Author: phd
Date: 2007-04-25 08:56:28 -0600 (Wed, 25 Apr 2007)
New Revision: 2595
Modified:
SQLObject/branches/0.9/docs/News.txt
SQLObject/branches/0.9/sqlobject/mysql/mysqlconnection.py
Log:
Applied the patch 1653898: properly initialize MySQL connection encoding.
Modified: SQLObject/branches/0.9/docs/News.txt
===================================================================
--- SQLObject/branches/0.9/docs/News.txt 2007-04-25 14:55:51 UTC (rev 2594)
+++ SQLObject/branches/0.9/docs/News.txt 2007-04-25 14:56:28 UTC (rev 2595)
@@ -215,6 +215,8 @@
their parameter must be a string; now you can pass an SQLExpression:
Table.q.name.contains(func.upper('a')), for example.
+* Yet another patch to properly initialize MySQL connection encoding.
+
SQLObject 0.7.5
===============
Modified: SQLObject/branches/0.9/sqlobject/mysql/mysqlconnection.py
===================================================================
--- SQLObject/branches/0.9/sqlobject/mysql/mysqlconnection.py 2007-04-25 14:55:51 UTC (rev 2594)
+++ SQLObject/branches/0.9/sqlobject/mysql/mysqlconnection.py 2007-04-25 14:56:28 UTC (rev 2595)
@@ -57,6 +57,13 @@
connectionFromURI = classmethod(connectionFromURI)
def makeConnection(self):
+ from MySQLdb.connections import Connection
+ if not hasattr(Connection, 'set_character_set'):
+ # monkeypatch pre MySQLdb 1.2.1
+ encoding = self.dbEncoding
+ def character_set_name(self):
+ return encoding + '_' + encoding
+ Connection.character_set_name = character_set_name
try:
conn = self.module.connect(host=self.host, port=self.port,
db=self.db, user=self.user, passwd=self.password, **self.kw)
@@ -71,6 +78,12 @@
if hasattr(conn, 'autocommit'):
conn.autocommit(bool(self.autoCommit))
+ if hasattr(conn, 'set_character_set'): # MySQLdb 1.2.1 and later
+ conn.set_character_set(self.dbEncoding)
+ else: # pre MySQLdb 1.2.1
+ # works along with monkeypatching code above
+ conn.query("SET NAMES %s" % self.dbEncoding)
+
return conn
def _setAutoCommit(self, conn, auto):
@@ -92,13 +105,11 @@
# done by calling ping(True) on the connection.
for count in range(3):
try:
- if self.need_unicode:
- # For MysqlDB 1.2.1 and later, we go
- # encoding->unicode->charset (in the mysql db)
- myquery = unicode(query, self.encoding)
- return cursor.execute(myquery)
- else:
- return cursor.execute(query)
+ # For MySQLdb 1.2.1 and later, we go
+ # encoding->unicode->charset (in the mysql db)
+ if self.need_unicode and not isinstance(query, unicode):
+ query = unicode(query, self.encoding)
+ return cursor.execute(query)
except MySQLdb.OperationalError, e:
if e.args[0] in (MySQLdb.constants.CR.SERVER_GONE_ERROR, MySQLdb.constants.CR.SERVER_LOST):
if count == 2:
|
|
From: <sub...@co...> - 2007-04-25 14:55:55
|
Author: phd
Date: 2007-04-25 08:55:51 -0600 (Wed, 25 Apr 2007)
New Revision: 2594
Modified:
SQLObject/branches/0.8/docs/News.txt
SQLObject/branches/0.8/sqlobject/mysql/mysqlconnection.py
Log:
Applied the patch 1653898: properly initialize MySQL connection encoding.
Modified: SQLObject/branches/0.8/docs/News.txt
===================================================================
--- SQLObject/branches/0.8/docs/News.txt 2007-04-25 14:52:51 UTC (rev 2593)
+++ SQLObject/branches/0.8/docs/News.txt 2007-04-25 14:55:51 UTC (rev 2594)
@@ -160,6 +160,8 @@
their parameter must be a string; now you can pass an SQLExpression:
Table.q.name.contains(func.upper('a')), for example.
+* Yet another patch to properly initialize MySQL connection encoding.
+
SQLObject 0.7.5
===============
Modified: SQLObject/branches/0.8/sqlobject/mysql/mysqlconnection.py
===================================================================
--- SQLObject/branches/0.8/sqlobject/mysql/mysqlconnection.py 2007-04-25 14:52:51 UTC (rev 2593)
+++ SQLObject/branches/0.8/sqlobject/mysql/mysqlconnection.py 2007-04-25 14:55:51 UTC (rev 2594)
@@ -57,6 +57,13 @@
connectionFromURI = classmethod(connectionFromURI)
def makeConnection(self):
+ from MySQLdb.connections import Connection
+ if not hasattr(Connection, 'set_character_set'):
+ # monkeypatch pre MySQLdb 1.2.1
+ encoding = self.dbEncoding
+ def character_set_name(self):
+ return encoding + '_' + encoding
+ Connection.character_set_name = character_set_name
try:
conn = self.module.connect(host=self.host, port=self.port,
db=self.db, user=self.user, passwd=self.password, **self.kw)
@@ -71,6 +78,12 @@
if hasattr(conn, 'autocommit'):
conn.autocommit(bool(self.autoCommit))
+ if hasattr(conn, 'set_character_set'): # MySQLdb 1.2.1 and later
+ conn.set_character_set(self.dbEncoding)
+ else: # pre MySQLdb 1.2.1
+ # works along with monkeypatching code above
+ conn.query("SET NAMES %s" % self.dbEncoding)
+
return conn
def _setAutoCommit(self, conn, auto):
@@ -92,13 +105,11 @@
# done by calling ping(True) on the connection.
for count in range(3):
try:
- if self.need_unicode:
- # For MysqlDB 1.2.1 and later, we go
- # encoding->unicode->charset (in the mysql db)
- myquery = unicode(query, self.encoding)
- return cursor.execute(myquery)
- else:
- return cursor.execute(query)
+ # For MySQLdb 1.2.1 and later, we go
+ # encoding->unicode->charset (in the mysql db)
+ if self.need_unicode and not isinstance(query, unicode):
+ query = unicode(query, self.encoding)
+ return cursor.execute(query)
except MySQLdb.OperationalError, e:
if e.args[0] in (MySQLdb.constants.CR.SERVER_GONE_ERROR, MySQLdb.constants.CR.SERVER_LOST):
if count == 2:
|
|
From: <sub...@co...> - 2007-04-25 14:52:55
|
Author: phd
Date: 2007-04-25 08:52:51 -0600 (Wed, 25 Apr 2007)
New Revision: 2593
Modified:
SQLObject/branches/0.7/docs/News.txt
SQLObject/branches/0.7/sqlobject/mysql/mysqlconnection.py
Log:
Applied the patch 1653898: properly initialize MySQL connection encoding.
Modified: SQLObject/branches/0.7/docs/News.txt
===================================================================
--- SQLObject/branches/0.7/docs/News.txt 2007-04-25 14:17:43 UTC (rev 2592)
+++ SQLObject/branches/0.7/docs/News.txt 2007-04-25 14:52:51 UTC (rev 2593)
@@ -23,6 +23,8 @@
their parameter must be a string; now you can pass an SQLExpression:
Table.q.name.contains(func.upper('a')), for example.
+* Yet another patch to properly initialize MySQL connection encoding.
+
SQLObject 0.7.5
===============
Modified: SQLObject/branches/0.7/sqlobject/mysql/mysqlconnection.py
===================================================================
--- SQLObject/branches/0.7/sqlobject/mysql/mysqlconnection.py 2007-04-25 14:17:43 UTC (rev 2592)
+++ SQLObject/branches/0.7/sqlobject/mysql/mysqlconnection.py 2007-04-25 14:52:51 UTC (rev 2593)
@@ -48,6 +48,13 @@
connectionFromURI = classmethod(connectionFromURI)
def makeConnection(self):
+ from MySQLdb.connections import Connection
+ if not hasattr(Connection, 'set_character_set'):
+ # monkeypatch pre MySQLdb 1.2.1
+ encoding = self.dbEncoding
+ def character_set_name(self):
+ return encoding + '_' + encoding
+ Connection.character_set_name = character_set_name
try:
conn = self.module.connect(host=self.host, port=self.port,
db=self.db, user=self.user, passwd=self.password, **self.kw)
@@ -62,6 +69,12 @@
if hasattr(conn, 'autocommit'):
conn.autocommit(bool(self.autoCommit))
+ if hasattr(conn, 'set_character_set'): # MySQLdb 1.2.1 and later
+ conn.set_character_set(self.dbEncoding)
+ else: # pre MySQLdb 1.2.1
+ # works along with monkeypatching code above
+ conn.query("SET NAMES %s" % self.dbEncoding)
+
return conn
def _setAutoCommit(self, conn, auto):
@@ -71,13 +84,11 @@
def _executeRetry(self, conn, cursor, query):
while 1:
try:
- if self.need_unicode:
- # For MysqlDB 1.2.1 and later, we go
- # encoding->unicode->charset (in the mysql db)
- myquery = unicode(query, self.encoding)
- return cursor.execute(myquery)
- else:
- return cursor.execute(query)
+ # For MySQLdb 1.2.1 and later, we go
+ # encoding->unicode->charset (in the mysql db)
+ if self.need_unicode and not isinstance(query, unicode):
+ query = unicode(query, self.encoding)
+ return cursor.execute(query)
except MySQLdb.OperationalError, e:
if e.args[0] == 2013: # SERVER_LOST error
if self.debug:
|
|
From: <sub...@co...> - 2007-04-25 14:17:49
|
Author: novalis Date: 2007-04-25 08:17:43 -0600 (Wed, 25 Apr 2007) New Revision: 2592 Modified: SQLObject/docs/SQLObject.txt Log: documented orderby multiple columns Modified: SQLObject/docs/SQLObject.txt =================================================================== --- SQLObject/docs/SQLObject.txt 2007-04-24 15:45:32 UTC (rev 2591) +++ SQLObject/docs/SQLObject.txt 2007-04-25 14:17:43 UTC (rev 2592) @@ -572,7 +572,10 @@ the select statements: `orderBy` takes a string, which should be the *database* name of the column, or a column in the form ``Person.q.firstName``. You can use ``"-colname"`` to specify -descending order, or call ``MyClass.select().reversed()``. +descending order (this is translated to DESC, so it works on +non-numeric types as well), or call +``MyClass.select().reversed()``. orderBy can also take a list of +column names in the same format as a single column name. You can use the special class variable `_defaultOrder` to give a default ordering for all selects. To get an unordered result when |
|
From: SourceForge.net <no...@so...> - 2007-04-25 13:50:21
|
Bugs item #1592786, was opened at 2006-11-08 20:20 Message generated for change (Comment added) made by phd You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540672&aid=1592786&group_id=74338 Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: SQLite Group: None Status: Open Resolution: Invalid Priority: 5 Private: No Submitted By: Jayhem (jayhem) Assigned to: Nobody/Anonymous (nobody) Summary: so-sqlite data corruption during updates Initial Comment: I'm hitting a bug when using SO with turbogears 1.1b with an sqlite database. When I do several successive updates to a table (which are very slow btw), data gets corrupted in the interface, select() returns invalid objects, as if objects were pulled from a cache that was out of synch with the db. >From this point, successive select() without any updates in-between can return different values, randomly selecting one of the previsouly set values. I have created a simple test-case (on turbogears) Just launch it and change some values. Usually after 10-20 changes, the corruption appears. I have tried this same testcase with MySQL and do not hit this problem. Note that dev.cfg declares sqlobject.dburi="notrans_sqlite:///..." file: model.py ====================================================== from sqlobject import * from turbogears.database import PackageHub hub = PackageHub("bug") __connection__ = hub class Item(SQLObject): data = UnicodeCol(length=40) def loaddb(): hub.begin() Item.dropTable(ifExists=True, cascade=True) hub.commit() Item.createTable(ifNotExists=True) for i in range(20): Item(data = str(i)) hub.commit() loaddb() file: controllers.py ====================================================== import turbogears from turbogears.controllers import RootController, expose from model import Item class Root(RootController): @expose(template="bug.templates.index") def index(self): items = Item.select() return dict(items = items) @expose(template="bug.templates.index") def change(self, id): item = Item.get(id) item.data += str(id) items = Item.select() return dict(items = items) file: index.kid ====================================================== <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'"> <head> <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/> <title>Items</title> </head> <body> <ul py:for="i in items"> <li>${i.data} <a href="/change/${i.id}">[edit]</a></li> </ul> </body> </html> ---------------------------------------------------------------------- >Comment By: Oleg Broytmann (phd) Date: 2007-04-25 17:50 Message: Logged In: YES user_id=4799 Originator: NO > >> TypeError: _init() takes exactly 2 arguments (4 given) Hector, this is a bug in your program, not in SQLObject. You've declared ventas._init() with the following signature: def _init(self,id): But in SQLObject it is def _init(self, id, connection=None, selectResults=None): You must declare you ._init() the same way, and you must pass all parameters to SQLObject: def _init(self, id, connection=None, selectResults=None): SQLObject._init(self, id, connection=connection, selectResults=selectResults) ###Subrayala por favor Now your program works. ---------------------------------------------------------------------- Comment By: Nobody/Anonymous (nobody) Date: 2007-04-21 00:56 Message: Logged In: NO from: he...@en... Bug: so-sqlite data corruption during updates In relation to this, I am running an aplication using only sqlobject, sqlite and python, currently I am not using TG. I have a similar error. I had created quite a few tables using three versions of sqlobject (0.8.2 0.8.1 and the development version 0.10 fron svn) in the three versions it had come with the following error: Traceback (most recent call last): File "<pyshell#16>", line 1, in -toplevel- ventas.get(3) File "/usr/lib/python2.4/site-packages/SQLObject-0.10dev_r2553-py2.4.egg/sqlobject/main.py", line 919, in get val._init(id, connection, selectResults) TypeError: _init() takes exactly 2 arguments (4 given) Currently I am using Debian testing version and sqlite-3-3-14, I am able to isolate the error to the following I create a small table called "ventas" with 24 records in it then I do in python: for x in range(1,25): print x, ventas.get(x) this print: 1 <ventas 1 producto_idID=1 fecha_idID=1 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=5.0> 2 <ventas 2 producto_idID=1 fecha_idID=2 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=5.0> 3 <ventas 3 producto_idID=1 fecha_idID=3 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=5.0> 4 <ventas 4 producto_idID=1 fecha_idID=4 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=5.0> 5 <ventas 5 producto_idID=2 fecha_idID=1 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=5.0> 6 <ventas 6 producto_idID=2 fecha_idID=2 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=5.0> 7 <ventas 7 producto_idID=2 fecha_idID=3 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=5.0> 8 <ventas 8 producto_idID=2 fecha_idID=4 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=5.0> 9 <ventas 9 producto_idID=3 fecha_idID=1 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=6.0> 10 <ventas 10 producto_idID=3 fecha_idID=2 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=6.0> 11 <ventas 11 producto_idID=3 fecha_idID=3 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=6.0> 12 <ventas 12 producto_idID=3 fecha_idID=4 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=6.0> 13 <ventas 13 producto_idID=4 fecha_idID=1 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=7.0> 14 <ventas 14 producto_idID=4 fecha_idID=2 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=7.0> 15 <ventas 15 producto_idID=4 fecha_idID=3 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=7.0> 16 <ventas 16 producto_idID=4 fecha_idID=4 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=7.0> 17 <ventas 17 producto_idID=5 fecha_idID=1 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=5.0> 18 <ventas 18 producto_idID=5 fecha_idID=2 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=5.0> 19 <ventas 19 producto_idID=5 fecha_idID=3 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=5.0> 20 <ventas 20 producto_idID=5 fecha_idID=4 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=5.0> 21 <ventas 21 producto_idID=6 fecha_idID=1 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=5.5> 22 <ventas 22 producto_idID=6 fecha_idID=2 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=5.5> 23 <ventas 23 producto_idID=6 fecha_idID=3 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=5.5> 24 <ventas 24 producto_idID=6 fecha_idID=4 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=5.5> Then I do: for x in ventas.select(): print x <ventas 1 producto_idID=1 fecha_idID=1 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=5.0> <ventas 2 producto_idID=1 fecha_idID=2 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=5.0> <ventas 3 producto_idID=1 fecha_idID=3 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=5.0> <ventas 4 producto_idID=1 fecha_idID=4 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=5.0> <ventas 5 producto_idID=2 fecha_idID=1 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=5.0> <ventas 6 producto_idID=2 fecha_idID=2 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=5.0> <ventas 7 producto_idID=2 fecha_idID=3 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=5.0> <ventas 8 producto_idID=2 fecha_idID=4 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=5.0> <ventas 9 producto_idID=3 fecha_idID=1 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=6.0> <ventas 10 producto_idID=3 fecha_idID=2 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=6.0> <ventas 11 producto_idID=3 fecha_idID=3 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=6.0> <ventas 12 producto_idID=3 fecha_idID=4 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=6.0> <ventas 13 producto_idID=4 fecha_idID=1 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=7.0> <ventas 14 producto_idID=4 fecha_idID=2 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=7.0> <ventas 15 producto_idID=4 fecha_idID=3 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=7.0> <ventas 16 producto_idID=4 fecha_idID=4 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=7.0> <ventas 17 producto_idID=5 fecha_idID=1 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=5.0> <ventas 18 producto_idID=5 fecha_idID=2 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=5.0> <ventas 19 producto_idID=5 fecha_idID=3 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=5.0> <ventas 20 producto_idID=5 fecha_idID=4 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=5.0> <ventas 21 producto_idID=6 fecha_idID=1 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=5.5> <ventas 22 producto_idID=6 fecha_idID=2 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=5.5> <ventas 23 producto_idID=6 fecha_idID=3 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=5.5> <ventas 24 producto_idID=6 fecha_idID=4 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=5.5> Then I do: for x in range(1,25): print x, ventas.get(x) 1 <ventas 1 producto_idID=1 fecha_idID=1 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=5.0> 2 <ventas 2 producto_idID=1 fecha_idID=2 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=5.0> 3 <ventas 3 producto_idID=1 fecha_idID=3 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=5.0> 4 <ventas 4 producto_idID=1 fecha_idID=4 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=5.0> 5 <ventas 5 producto_idID=2 fecha_idID=1 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=5.0> 6 <ventas 6 producto_idID=2 fecha_idID=2 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=5.0> 7 <ventas 7 producto_idID=2 fecha_idID=3 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=5.0> 8 <ventas 8 producto_idID=2 fecha_idID=4 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=5.0> 9 <ventas 9 producto_idID=3 fecha_idID=1 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=6.0> 10 <ventas 10 producto_idID=3 fecha_idID=2 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=6.0> 11 <ventas 11 producto_idID=3 fecha_idID=3 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=6.0> 12 <ventas 12 producto_idID=3 fecha_idID=4 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=6.0> 13 <ventas 13 producto_idID=4 fecha_idID=1 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=7.0> 14 <ventas 14 producto_idID=4 fecha_idID=2 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=7.0> 15 <ventas 15 producto_idID=4 fecha_idID=3 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=7.0> 16 <ventas 16 producto_idID=4 fecha_idID=4 status_idID=2 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=7.0> 17 <ventas 17 producto_idID=5 fecha_idID=1 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=5.0> 18 <ventas 18 producto_idID=5 fecha_idID=2 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=5.0> 19 <ventas 19 producto_idID=5 fecha_idID=3 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=5.0> 20 <ventas 20 producto_idID=5 fecha_idID=4 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=5.0> 21 <ventas 21 producto_idID=6 fecha_idID=1 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=5.5> 22 <ventas 22 producto_idID=6 fecha_idID=2 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=5000 precio=5.5> 23 <ventas 23 producto_idID=6 fecha_idID=3 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=6000 precio=5.5> 24 <ventas 24 producto_idID=6 fecha_idID=4 status_idID=3 region_idID=1 pais_idID=1 moneda_idID=2 volumen=7000 precio=5.5> The I do: ventas.get(1) <ventas 1 producto_idID=1 fecha_idID=1 status_idID=1 region_idID=1 pais_idID=1 moneda_idID=2 volumen=4000 precio=5.0> Then I do this one: for x in ventas.select(): print x And I obtain this error: Traceback (most recent call last): File "<pyshell#39>", line 1, in -toplevel- for x in ventas.select(): File "/usr/lib/python2.4/site-packages/SQLObject-0.10dev_r2553-py2.4.egg/sqlobject/sresults.py", line 165, in __iter__ return iter(list(self.lazyIter())) File "/usr/lib/python2.4/site-packages/SQLObject-0.10dev_r2553-py2.4.egg/sqlobject/dbconnection.py", line 814, in next obj = self.select.sourceClass.get(result[0], selectResults=result[1:], connection=self.dbconn) File "/usr/lib/python2.4/site-packages/SQLObject-0.10dev_r2553-py2.4.egg/sqlobject/main.py", line 919, in get val._init(id, connection, selectResults) TypeError: _init() takes exactly 2 arguments (4 given) Is important to note that to get the error I had to run the commands in this sequence. Also the database is only corrupted in memory, the file in the hard disk is ok. Also, it is only corrupted in odd registry id record numbers, even records are ok. I am using python2.4.4 I am sorry for the great amount of data posted. ---------------------------------------------------------------------- Comment By: Jayhem (jayhem) Date: 2006-11-14 15:04 Message: Logged In: YES user_id=1640652 You are right. the bug does not seem to cause data corruption in the database (i.e it's not a db related issue), it just causes random results to be returned from queries. Simply switching the database to MySQL solves the problem, which confirms the bug is not in the db. An even more annoying issue, which I think is related, is the extremely slow inserts/updates into sqlite, and frequent error messages telling me the db is locked. I am new to turbogears, sqlobject, sqlite and python, so I'm sorry I won't have time to work on a SqlObject-only testcase. Let me know if I can do anything to help fix this. ---------------------------------------------------------------------- Comment By: Oleg Broytmann (phd) Date: 2006-11-13 19:59 Message: Logged In: YES user_id=4799 Our company has been using SQLObject with SQLite for three rather large commercial programs. Neither of our developers, testers or users ever experienced data loss. Are you sure the problem is not TG-related? Please write an SQLObject-only test. In any case I cannot run your program - I don't have TG and not going to install it. ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540672&aid=1592786&group_id=74338 |
|
From: wei I. <Inz...@an...> - 2007-04-25 11:41:47
|
wont |
|
From: <sub...@co...> - 2007-04-24 15:45:37
|
Author: luke
Date: 2007-04-24 09:45:32 -0600 (Tue, 24 Apr 2007)
New Revision: 2591
Added:
SQLObject/branches/cache-deps-on-views/sqlobject/tests/test_derived_accessors.py
Modified:
SQLObject/branches/cache-deps-on-views/sqlobject/__init__.py
SQLObject/branches/cache-deps-on-views/sqlobject/col.py
SQLObject/branches/cache-deps-on-views/sqlobject/main.py
SQLObject/branches/cache-deps-on-views/sqlobject/sqlbuilder.py
Log:
Derived Columns
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/__init__.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/__init__.py 2007-04-24 15:07:03 UTC (rev 2590)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/__init__.py 2007-04-24 15:45:32 UTC (rev 2591)
@@ -4,6 +4,7 @@
from styles import *
from joins import *
from index import *
+from derived import *
from dbconnection import connectionForURI
import dberrors
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/col.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/col.py 2007-04-24 15:07:03 UTC (rev 2590)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/col.py 2007-04-24 15:45:32 UTC (rev 2591)
@@ -131,6 +131,7 @@
title=None,
tags=[],
origName=None,
+ derived=False,
extra_vars=None):
super(SOCol, self).__init__()
@@ -150,6 +151,7 @@
self.creationOrder = creationOrder
self.immutable = immutable
+ self.derived = derived
# cascade can be one of:
# None: no constraint is generated
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/main.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/main.py 2007-04-24 15:07:03 UTC (rev 2590)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/main.py 2007-04-24 15:45:32 UTC (rev 2591)
@@ -293,6 +293,8 @@
# None of these objects can be shared with superclasses
cls.columns = {}
cls.columnList = []
+ cls.columnsExtended= {}
+ cls.columnListExtended = []
# These, however, can be shared:
cls.columnDefinitions = cls.columnDefinitions.copy()
cls.indexes = []
@@ -339,9 +341,13 @@
"add the column %r"
% (soClass.__module__, soClass.__name__, name, name))
sqlmeta.columnDefinitions[name] = columnDef
- sqlmeta.columns[name] = column
+ sqlmeta.columnsExtended[name] = column
# A stable-ordered version of the list...
- sqlmeta.columnList.append(column)
+ sqlmeta.columnListExtended.append(column)
+
+ if not column.derived:
+ sqlmeta.columns[name] = column
+ sqlmeta.columnList.append(column)
###################################################
# Create the getter function(s). We'll start by
@@ -350,7 +356,9 @@
# we'll alias that to _SO_get_columnName. This
# allows a sort of super call, even though there's
# no superclass that defines the database access.
- if sqlmeta.cacheValues:
+ if column.derived:
+ getter = column.__get__
+ elif sqlmeta.cacheValues:
# We create a method here, which is just a function
# that takes "self" as the first argument.
getter = eval('lambda self: self._SO_loadValue(%s)' % repr(instanceName(name)))
@@ -475,9 +483,12 @@
cls.send(events.DeleteColumnSignal, connection, column.name, column,
post_funcs)
name = column.name
- del sqlmeta.columns[name]
+ del sqlmeta.columnsExtended[name]
del sqlmeta.columnDefinitions[name]
- sqlmeta.columnList.remove(column)
+ sqlmeta.columnListExtended.remove(column)
+ if not column.derived:
+ del sqlmeta.columns[name]
+ sqlmeta.columnList.remove(column)
delattr(soClass, rawGetterName(name))
if sqlmeta._plainGetters.has_key(name):
delattr(soClass, getterName(name))
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/sqlbuilder.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/sqlbuilder.py 2007-04-24 15:07:03 UTC (rev 2590)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/sqlbuilder.py 2007-04-24 15:45:32 UTC (rev 2591)
@@ -1201,9 +1201,10 @@
return True
def __getattr__(self, attr):
- if self.soClass is None:
+ try:
+ return getattr(self.soClass.q, attr)
+ except AttributeError:
return _Delay(self, attr)
- return getattr(self.soClass.q, attr)
class _Delay(SQLExpression):
def __init__(self, proxy, attr):
Added: SQLObject/branches/cache-deps-on-views/sqlobject/tests/test_derived_accessors.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/tests/test_derived_accessors.py (rev 0)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/tests/test_derived_accessors.py 2007-04-24 15:45:32 UTC (rev 2591)
@@ -0,0 +1,71 @@
+from sqlobject import *
+from sqlobject.sqlbuilder import ImportProxy
+from sqlobject.tests.dbtest import *
+
+class DerivePerson(SQLObject):
+ name = StringCol(alternateID=True)
+ city = StringCol()
+ phones = SQLMultipleJoin('DerivePhone', joinColumn='personID')
+
+ primaryPhone = OneFrom('phones', query=ImportProxy('DerivePhone').q.isPrimary==True)
+ secondaryPhones = FilterFrom('phones', query=ImportProxy('DerivePhone').q.isPrimary==False)
+
+ primaryMinutes = ValueFrom('primaryPhone', ImportProxy('DerivePhone').q.totalMinutes)
+ mostMinutes = MaxFrom('phones', ImportProxy('DerivePhone').q.totalMinutes)
+ mostSecondaryMinutes = MaxFrom('secondaryPhones', ImportProxy('DerivePhone').q.totalMinutes)
+# mostUsedPhone = OneFrom('phones', query=ImportProxy('DerivePhone').q.totalMinutes==SelfProxy.q.mostMinutes)
+
+
+class DerivePhone(SQLObject):
+ number = StringCol(alternateID=True)
+ isPrimary = BoolCol()
+
+ city = ValueFrom('person', ImportProxy('Person').q.city)
+ totalMinutes = SumFrom('calls', ImportProxy('DerivePhoneCall').q.minutes)
+# totalLocalMinutes = SumFrom('calls', ImportProxy('DerivedPhoneCall').q.minutes,
+# query=ImportProxy('DerivedPhoneCall').q.city == SelfProxy.q.city)
+
+ person = ForeignKey('DerivePerson')
+ calls = SQLMultipleJoin('DerivePhoneCall', joinColumn='phoneID')
+
+class DerivePhoneCall(SQLObject):
+ #onDate = DateTimeCol(default="now")
+ minutes = IntCol()
+ city = StringCol()
+
+ phone = SQLForeignKey('DerivePhone')
+
+
+def setup_module(mod):
+ setupClass([DerivePerson, DerivePhone, DerivePhoneCall], force=True)
+ ppl = inserts(DerivePerson, [{'name':'Luke', 'city':'Chicago'}])
+ phones = inserts(DerivePhone, [
+ {'number':'1234', 'person':ppl[0], 'isPrimary':True},
+ {'number':'5678', 'person':ppl[0], 'isPrimary':False},
+ {'number':'7890', 'person':ppl[0], 'isPrimary':False}
+ ])
+ calls = inserts(DerivePhoneCall, [
+ {'minutes': 10, 'city':'Chicago', 'phone':phones[0]},
+ {'minutes': 20, 'city':'Detroit', 'phone':phones[0]},
+ {'minutes': 10, 'city':'Chicago', 'phone':phones[1]},
+ {'minutes': 15, 'city':'Chicago', 'phone':phones[1]},
+ ])
+
+
+def test_oneFrom():
+ luke = DerivePerson.byName('Luke')
+ ph = DerivePhone.byNumber('1234')
+ assert luke.primaryPhone == ph
+ assert luke.primaryPhone == luke.phones.filter(DerivePhone.q.isPrimary==True).getOne()
+ #assert luke.secondaryPhones == phones[1]
+
+def test_filterFrom():
+ luke = DerivePerson.byName('Luke')
+ assert list(luke.secondaryPhones) == list(luke.phones.filter(DerivePhone.q.isPrimary==False))
+
+def test_aggregates():
+ ph1 = DerivePhone.byNumber('1234')
+ ph2 = DerivePhone.byNumber('5678')
+ assert ph1.totalMinutes == ph1.calls.sum(DerivePhoneCall.q.minutes)
+ #assert ph1.totalLocalMinutes == ph1.calls.filter(DerivePhone.sum(DerivePhoneCall.q.minutes)
+
|
|
From: <sub...@co...> - 2007-04-24 15:07:08
|
Author: phd
Date: 2007-04-24 09:07:03 -0600 (Tue, 24 Apr 2007)
New Revision: 2590
Modified:
SQLObject/docs/SQLObject.txt
Log:
Added an example on how to configure logging.
Modified: SQLObject/docs/SQLObject.txt
===================================================================
--- SQLObject/docs/SQLObject.txt 2007-04-24 15:05:55 UTC (rev 2589)
+++ SQLObject/docs/SQLObject.txt 2007-04-24 15:07:03 UTC (rev 2590)
@@ -1664,6 +1664,24 @@
uses prints instead of logging; `loglevel` can be "stdout" or "stderr" in
this case; default is "stdout".
+To configure logging one can do something like that::
+
+ import logging
+ logging.basicConfig()
+ for handler in logging.root.handlers[:]:
+ logging.root.removeHandler(handler)
+ handler = logging.FileHandler("test.log")
+ fmt = '[%(asctime)s] %(name)s %(levelname)s: %(message)s'
+ handler.setFormatter(logging.Formatter(fmt))
+ logging.root.addHandler(handler)
+ logging.root.setLevel(logging.DEBUG)
+ log = logging.getLogger("TEST")
+ log.info("Log started")
+
+ __connection__ = "sqlite:/:memory:?debug=1&logger=TEST&loglevel=debug"
+
+The code redirects SQLObject debug messages to the `test.log` file.
+
MySQL
-----
|
|
From: <sub...@co...> - 2007-04-24 15:06:01
|
Author: phd
Date: 2007-04-24 09:05:55 -0600 (Tue, 24 Apr 2007)
New Revision: 2589
Modified:
SQLObject/branches/0.9/docs/SQLObject.txt
Log:
Added an example on how to configure logging.
Modified: SQLObject/branches/0.9/docs/SQLObject.txt
===================================================================
--- SQLObject/branches/0.9/docs/SQLObject.txt 2007-04-24 15:02:56 UTC (rev 2588)
+++ SQLObject/branches/0.9/docs/SQLObject.txt 2007-04-24 15:05:55 UTC (rev 2589)
@@ -1664,6 +1664,24 @@
uses prints instead of logging; `loglevel` can be "stdout" or "stderr" in
this case; default is "stdout".
+To configure logging one can do something like that::
+
+ import logging
+ logging.basicConfig()
+ for handler in logging.root.handlers[:]:
+ logging.root.removeHandler(handler)
+ handler = logging.FileHandler("test.log")
+ fmt = '[%(asctime)s] %(name)s %(levelname)s: %(message)s'
+ handler.setFormatter(logging.Formatter(fmt))
+ logging.root.addHandler(handler)
+ logging.root.setLevel(logging.DEBUG)
+ log = logging.getLogger("TEST")
+ log.info("Log started")
+
+ __connection__ = "sqlite:/:memory:?debug=1&logger=TEST&loglevel=debug"
+
+The code redirects SQLObject debug messages to the `test.log` file.
+
MySQL
-----
|
|
From: SourceForge.net <no...@so...> - 2007-04-24 15:03:30
|
Patches item #1704429, was opened at 2007-04-20 19:37 Message generated for change (Comment added) made by phd You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540674&aid=1704429&group_id=74338 Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: None Group: None >Status: Closed >Resolution: Accepted Priority: 5 Private: No Submitted By: Leandro Lucarella (llucax) >Assigned to: Oleg Broytmann (phd) Summary: Add how to change MySQL engine to FAQ Initial Comment: Just add the proposed way to change MySQL engine submitted by Markus Gritsch to the mailing list[1] to the FAQ. [1] http://permalink.gmane.org/gmane.comp.python.sqlobject/8050 ---------------------------------------------------------------------- >Comment By: Oleg Broytmann (phd) Date: 2007-04-24 19:03 Message: Logged In: YES user_id=4799 Originator: NO Applied and committed in the revisions 2586-2588 (0.8, 0.9 and trunk). Thank you! ---------------------------------------------------------------------- Comment By: Markus Gritsch (markus_gritsch) Date: 2007-04-20 21:19 Message: Logged In: YES user_id=553904 Originator: NO Correction: * The table is not altered just before creation, as stated. The table is created, and the alter statements are executed immediately afterwards. * Multiple statements are specified as a list of strings as the value of the dict. ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=540674&aid=1704429&group_id=74338 |
|
From: <sub...@co...> - 2007-04-24 15:03:00
|
Author: phd
Date: 2007-04-24 09:02:56 -0600 (Tue, 24 Apr 2007)
New Revision: 2588
Modified:
SQLObject/docs/FAQ.txt
Log:
Added an answer and examples to the FAQ on how to use sqlmeta.createSQL.
Modified: SQLObject/docs/FAQ.txt
===================================================================
--- SQLObject/docs/FAQ.txt 2007-04-24 15:01:49 UTC (rev 2587)
+++ SQLObject/docs/FAQ.txt 2007-04-24 15:02:56 UTC (rev 2588)
@@ -506,3 +506,25 @@
cannot return a list of meaningful objects.
You can use a lower-level machinery available in SQLBuilder_.
+
+How can I specify the MySQL engine to use, or tweak other SQL-engine specific features?
+---------------------------------------------------------------------------------------
+
+You can *ALTER* the table just before creation using the ``sqlmeta``
+attribute ``createSQL``, for example::
+
+ class SomeObject(SQLObject):
+ class sqlmeta:
+ createSQL = { 'mysql' : 'ALTER TABLE some_object ENGINE InnoDB' }
+ # your columns here
+
+Maybe you want to specify the charset too? No problem::
+
+ class SomeObject(SQLObject):
+ class sqlmeta:
+ createSQL = { 'mysql' : '''
+ ALTER TABLE some_object ENGINE InnoDB;
+ ALTER TABLE some_object CHARACTER SET utf8
+ COLLATE utf8_estonian_ci''' }
+ # your columns here
+
|
|
From: <sub...@co...> - 2007-04-24 15:01:52
|
Author: phd
Date: 2007-04-24 09:01:49 -0600 (Tue, 24 Apr 2007)
New Revision: 2587
Modified:
SQLObject/branches/0.9/docs/FAQ.txt
Log:
Added an answer and examples to the FAQ on how to use sqlmeta.createSQL.
Modified: SQLObject/branches/0.9/docs/FAQ.txt
===================================================================
--- SQLObject/branches/0.9/docs/FAQ.txt 2007-04-24 15:00:34 UTC (rev 2586)
+++ SQLObject/branches/0.9/docs/FAQ.txt 2007-04-24 15:01:49 UTC (rev 2587)
@@ -506,3 +506,25 @@
cannot return a list of meaningful objects.
You can use a lower-level machinery available in SQLBuilder_.
+
+How can I specify the MySQL engine to use, or tweak other SQL-engine specific features?
+---------------------------------------------------------------------------------------
+
+You can *ALTER* the table just before creation using the ``sqlmeta``
+attribute ``createSQL``, for example::
+
+ class SomeObject(SQLObject):
+ class sqlmeta:
+ createSQL = { 'mysql' : 'ALTER TABLE some_object ENGINE InnoDB' }
+ # your columns here
+
+Maybe you want to specify the charset too? No problem::
+
+ class SomeObject(SQLObject):
+ class sqlmeta:
+ createSQL = { 'mysql' : '''
+ ALTER TABLE some_object ENGINE InnoDB;
+ ALTER TABLE some_object CHARACTER SET utf8
+ COLLATE utf8_estonian_ci''' }
+ # your columns here
+
|
|
From: <sub...@co...> - 2007-04-24 15:00:39
|
Author: phd
Date: 2007-04-24 09:00:34 -0600 (Tue, 24 Apr 2007)
New Revision: 2586
Modified:
SQLObject/branches/0.8/docs/FAQ.txt
Log:
Added an answer and examples to the FAQ on how to use sqlmeta.createSQL.
Modified: SQLObject/branches/0.8/docs/FAQ.txt
===================================================================
--- SQLObject/branches/0.8/docs/FAQ.txt 2007-04-24 11:31:59 UTC (rev 2585)
+++ SQLObject/branches/0.8/docs/FAQ.txt 2007-04-24 15:00:34 UTC (rev 2586)
@@ -506,3 +506,25 @@
cannot return a list of meaningful objects.
You can use a lower-level machinery available in SQLBuilder_.
+
+How can I specify the MySQL engine to use, or tweak other SQL-engine specific features?
+---------------------------------------------------------------------------------------
+
+You can *ALTER* the table just before creation using the ``sqlmeta``
+attribute ``createSQL``, for example::
+
+ class SomeObject(SQLObject):
+ class sqlmeta:
+ createSQL = { 'mysql' : 'ALTER TABLE some_object ENGINE InnoDB' }
+ # your columns here
+
+Maybe you want to specify the charset too? No problem::
+
+ class SomeObject(SQLObject):
+ class sqlmeta:
+ createSQL = { 'mysql' : '''
+ ALTER TABLE some_object ENGINE InnoDB;
+ ALTER TABLE some_object CHARACTER SET utf8
+ COLLATE utf8_estonian_ci''' }
+ # your columns here
+
|
|
From: <sub...@co...> - 2007-04-24 11:32:05
|
Author: phd
Date: 2007-04-24 05:31:59 -0600 (Tue, 24 Apr 2007)
New Revision: 2585
Modified:
home/phd/SQLObject/paramstyles/sqlobject/sqlbuilder.py
home/phd/SQLObject/paramstyles/sqlobject/tests/test_select.py
Log:
Merged patches from the revisions 2582:2584 from the trunk
Modified: home/phd/SQLObject/paramstyles/sqlobject/sqlbuilder.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/sqlbuilder.py 2007-04-24 11:31:07 UTC (rev 2584)
+++ home/phd/SQLObject/paramstyles/sqlobject/sqlbuilder.py 2007-04-24 11:31:59 UTC (rev 2585)
@@ -789,14 +789,14 @@
else:
return NOT(_IN(item, list))
-def STARTSWITH(expr, string):
- return SQLOp("LIKE", expr, _LikeQuoted(string) + '%')
+def STARTSWITH(expr, pattern):
+ return SQLOp("LIKE", expr, _LikeQuoted(pattern) + '%')
-def ENDSWITH(expr, string):
- return SQLOp("LIKE", expr, '%' + _LikeQuoted(string))
+def ENDSWITH(expr, pattern):
+ return SQLOp("LIKE", expr, '%' + _LikeQuoted(pattern))
-def CONTAINSSTRING(expr, string):
- return SQLOp("LIKE", expr, '%' + _LikeQuoted(string) + '%')
+def CONTAINSSTRING(expr, pattern):
+ return SQLOp("LIKE", expr, '%' + _LikeQuoted(pattern) + '%')
def ISNULL(expr):
return SQLOp("IS", expr, None)
@@ -805,6 +805,8 @@
return SQLOp("IS NOT", expr, None)
class _LikeQuoted:
+ # It assumes prefix and postfix are strings; usually just a percent sign.
+
# @@: I'm not sure what the quoting rules really are for all the
# databases
@@ -822,13 +824,30 @@
return self
def __sqlrepr__(self, db):
- s = sqlrepr(self.expr, db)[1:-1] # remove quotes
- if db in ('postgres', 'mysql'):
- s = s.replace('%', '\\%')
- else:
- s = s.replace('%', '%%')
- return "'%s%s%s'" % (self.prefix, s, self.postfix)
+ s = self.expr
+ if isinstance(s, SQLExpression):
+ values = []
+ if self.prefix:
+ values.append("'%s'" % self.prefix)
+ s = _quote_percent(sqlrepr(s, db), db)
+ values.append(s)
+ if self.postfix:
+ values.append("'%s'" % self.postfix)
+ if db == "mysql":
+ return "CONCAT(%s)" % ", ".join(values)
+ else:
+ return " || ".join(values)
+ else: # assuming s is a string
+ s = _quote_percent(s, db)
+ return "'%s%s%s'" % (self.prefix, s, self.postfix)
+def _quote_percent(s, db):
+ if db in ('postgres', 'mysql'):
+ s = s.replace('%', '\\%')
+ else:
+ s = s.replace('%', '%%')
+ return s
+
########################################
## SQL JOINs
########################################
Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/test_select.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/tests/test_select.py 2007-04-24 11:31:07 UTC (rev 2584)
+++ home/phd/SQLObject/paramstyles/sqlobject/tests/test_select.py 2007-04-24 11:31:59 UTC (rev 2585)
@@ -1,5 +1,6 @@
from __future__ import generators # for enumerate
from sqlobject import *
+from sqlobject.sqlbuilder import func
from sqlobject.main import SQLObjectIntegrityError
from dbtest import *
from dbtest import setSQLiteConnectionFactory
@@ -73,6 +74,19 @@
pass
assert count == len(names)
+def test_05_select_limit():
+ setupIter()
+ assert len(list(IterTest.select(limit=2))) == 2
+ raises(AssertionError, IterTest.select(limit=2).distinct)
+ raises(AssertionError, IterTest.select(limit=2).clone, start=1)
+
+def test_06_like():
+ setupIter()
+ assert len(list(IterTest.select(IterTest.q.name.startswith('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.endswith('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.contains('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.contains(func.lower('A'))))) == 1
+
def test_select_getOne():
setupClass(IterTest)
a = IterTest(name='a')
@@ -85,12 +99,6 @@
raises(SQLObjectIntegrityError, 'IterTest.selectBy(name="b").getOne()')
raises(SQLObjectIntegrityError, 'IterTest.selectBy(name="b").getOne(None)')
-def test_05_select_limit():
- setupIter()
- assert len(list(IterTest.select(limit=2))) == 2
- raises(AssertionError, IterTest.select(limit=2).distinct)
- raises(AssertionError, IterTest.select(limit=2).clone, start=1)
-
def test_selectBy():
setupClass(IterTest)
a = IterTest(name='a')
|
|
From: <sub...@co...> - 2007-04-24 11:31:11
|
Author: phd
Date: 2007-04-24 05:31:07 -0600 (Tue, 24 Apr 2007)
New Revision: 2584
Modified:
SQLObject/docs/News.txt
Log:
Fixed sqlbuilder - .startswith(), .endswith() and .contains() assumed
their parameter must be a string; now you can pass an SQLExpression.
Modified: SQLObject/docs/News.txt
===================================================================
--- SQLObject/docs/News.txt 2007-04-24 11:30:44 UTC (rev 2583)
+++ SQLObject/docs/News.txt 2007-04-24 11:31:07 UTC (rev 2584)
@@ -214,6 +214,10 @@
* Fixed a bug with absent comma in JOINs.
+* Fixed sqlbuilder - .startswith(), .endswith() and .contains() assumed
+ their parameter must be a string; now you can pass an SQLExpression:
+ Table.q.name.contains(func.upper('a')), for example.
+
SQLObject 0.7.5
===============
|
|
From: <sub...@co...> - 2007-04-24 11:30:48
|
Author: phd
Date: 2007-04-24 05:30:44 -0600 (Tue, 24 Apr 2007)
New Revision: 2583
Modified:
SQLObject/trunk/sqlobject/sqlbuilder.py
SQLObject/trunk/sqlobject/tests/test_select.py
Log:
Fixed sqlbuilder - .startswith(), .endswith() and .contains() assumed
their parameter must be a string; now you can pass an SQLExpression.
Modified: SQLObject/trunk/sqlobject/sqlbuilder.py
===================================================================
--- SQLObject/trunk/sqlobject/sqlbuilder.py 2007-04-24 11:30:14 UTC (rev 2582)
+++ SQLObject/trunk/sqlobject/sqlbuilder.py 2007-04-24 11:30:44 UTC (rev 2583)
@@ -669,14 +669,14 @@
else:
return NOT(_IN(item, list))
-def STARTSWITH(expr, string):
- return SQLOp("LIKE", expr, _LikeQuoted(string) + '%')
+def STARTSWITH(expr, pattern):
+ return SQLOp("LIKE", expr, _LikeQuoted(pattern) + '%')
-def ENDSWITH(expr, string):
- return SQLOp("LIKE", expr, '%' + _LikeQuoted(string))
+def ENDSWITH(expr, pattern):
+ return SQLOp("LIKE", expr, '%' + _LikeQuoted(pattern))
-def CONTAINSSTRING(expr, string):
- return SQLOp("LIKE", expr, '%' + _LikeQuoted(string) + '%')
+def CONTAINSSTRING(expr, pattern):
+ return SQLOp("LIKE", expr, '%' + _LikeQuoted(pattern) + '%')
def ISNULL(expr):
return SQLOp("IS", expr, None)
@@ -685,6 +685,8 @@
return SQLOp("IS NOT", expr, None)
class _LikeQuoted:
+ # It assumes prefix and postfix are strings; usually just a percent sign.
+
# @@: I'm not sure what the quoting rules really are for all the
# databases
@@ -702,13 +704,30 @@
return self
def __sqlrepr__(self, db):
- s = sqlrepr(self.expr, db)[1:-1] # remove quotes
- if db in ('postgres', 'mysql'):
- s = s.replace('%', '\\%')
- else:
- s = s.replace('%', '%%')
- return "'%s%s%s'" % (self.prefix, s, self.postfix)
+ s = self.expr
+ if isinstance(s, SQLExpression):
+ values = []
+ if self.prefix:
+ values.append("'%s'" % self.prefix)
+ s = _quote_percent(sqlrepr(s, db), db)
+ values.append(s)
+ if self.postfix:
+ values.append("'%s'" % self.postfix)
+ if db == "mysql":
+ return "CONCAT(%s)" % ", ".join(values)
+ else:
+ return " || ".join(values)
+ else: # assuming s is a string
+ s = _quote_percent(s, db)
+ return "'%s%s%s'" % (self.prefix, s, self.postfix)
+def _quote_percent(s, db):
+ if db in ('postgres', 'mysql'):
+ s = s.replace('%', '\\%')
+ else:
+ s = s.replace('%', '%%')
+ return s
+
########################################
## SQL JOINs
########################################
Modified: SQLObject/trunk/sqlobject/tests/test_select.py
===================================================================
--- SQLObject/trunk/sqlobject/tests/test_select.py 2007-04-24 11:30:14 UTC (rev 2582)
+++ SQLObject/trunk/sqlobject/tests/test_select.py 2007-04-24 11:30:44 UTC (rev 2583)
@@ -1,5 +1,6 @@
from __future__ import generators # for enumerate
from sqlobject import *
+from sqlobject.sqlbuilder import func
from sqlobject.main import SQLObjectIntegrityError
from dbtest import *
from dbtest import setSQLiteConnectionFactory
@@ -73,6 +74,19 @@
pass
assert count == len(names)
+def test_05_select_limit():
+ setupIter()
+ assert len(list(IterTest.select(limit=2))) == 2
+ raises(AssertionError, IterTest.select(limit=2).distinct)
+ raises(AssertionError, IterTest.select(limit=2).clone, start=1)
+
+def test_06_like():
+ setupIter()
+ assert len(list(IterTest.select(IterTest.q.name.startswith('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.endswith('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.contains('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.contains(func.lower('A'))))) == 1
+
def test_select_getOne():
setupClass(IterTest)
a = IterTest(name='a')
@@ -85,12 +99,6 @@
raises(SQLObjectIntegrityError, 'IterTest.selectBy(name="b").getOne()')
raises(SQLObjectIntegrityError, 'IterTest.selectBy(name="b").getOne(None)')
-def test_05_select_limit():
- setupIter()
- assert len(list(IterTest.select(limit=2))) == 2
- raises(AssertionError, IterTest.select(limit=2).distinct)
- raises(AssertionError, IterTest.select(limit=2).clone, start=1)
-
def test_selectBy():
setupClass(IterTest)
a = IterTest(name='a')
|
|
From: <sub...@co...> - 2007-04-24 11:30:17
|
Author: phd
Date: 2007-04-24 05:30:14 -0600 (Tue, 24 Apr 2007)
New Revision: 2582
Modified:
SQLObject/branches/0.9/docs/News.txt
SQLObject/branches/0.9/sqlobject/sqlbuilder.py
SQLObject/branches/0.9/sqlobject/tests/test_select.py
Log:
Fixed sqlbuilder - .startswith(), .endswith() and .contains() assumed
their parameter must be a string; now you can pass an SQLExpression.
Modified: SQLObject/branches/0.9/docs/News.txt
===================================================================
--- SQLObject/branches/0.9/docs/News.txt 2007-04-24 11:29:54 UTC (rev 2581)
+++ SQLObject/branches/0.9/docs/News.txt 2007-04-24 11:30:14 UTC (rev 2582)
@@ -211,6 +211,10 @@
* Fixed a bug with absent comma in JOINs.
+* Fixed sqlbuilder - .startswith(), .endswith() and .contains() assumed
+ their parameter must be a string; now you can pass an SQLExpression:
+ Table.q.name.contains(func.upper('a')), for example.
+
SQLObject 0.7.5
===============
Modified: SQLObject/branches/0.9/sqlobject/sqlbuilder.py
===================================================================
--- SQLObject/branches/0.9/sqlobject/sqlbuilder.py 2007-04-24 11:29:54 UTC (rev 2581)
+++ SQLObject/branches/0.9/sqlobject/sqlbuilder.py 2007-04-24 11:30:14 UTC (rev 2582)
@@ -669,14 +669,14 @@
else:
return NOT(_IN(item, list))
-def STARTSWITH(expr, string):
- return SQLOp("LIKE", expr, _LikeQuoted(string) + '%')
+def STARTSWITH(expr, pattern):
+ return SQLOp("LIKE", expr, _LikeQuoted(pattern) + '%')
-def ENDSWITH(expr, string):
- return SQLOp("LIKE", expr, '%' + _LikeQuoted(string))
+def ENDSWITH(expr, pattern):
+ return SQLOp("LIKE", expr, '%' + _LikeQuoted(pattern))
-def CONTAINSSTRING(expr, string):
- return SQLOp("LIKE", expr, '%' + _LikeQuoted(string) + '%')
+def CONTAINSSTRING(expr, pattern):
+ return SQLOp("LIKE", expr, '%' + _LikeQuoted(pattern) + '%')
def ISNULL(expr):
return SQLOp("IS", expr, None)
@@ -685,6 +685,8 @@
return SQLOp("IS NOT", expr, None)
class _LikeQuoted:
+ # It assumes prefix and postfix are strings; usually just a percent sign.
+
# @@: I'm not sure what the quoting rules really are for all the
# databases
@@ -702,13 +704,30 @@
return self
def __sqlrepr__(self, db):
- s = sqlrepr(self.expr, db)[1:-1] # remove quotes
- if db in ('postgres', 'mysql'):
- s = s.replace('%', '\\%')
- else:
- s = s.replace('%', '%%')
- return "'%s%s%s'" % (self.prefix, s, self.postfix)
+ s = self.expr
+ if isinstance(s, SQLExpression):
+ values = []
+ if self.prefix:
+ values.append("'%s'" % self.prefix)
+ s = _quote_percent(sqlrepr(s, db), db)
+ values.append(s)
+ if self.postfix:
+ values.append("'%s'" % self.postfix)
+ if db == "mysql":
+ return "CONCAT(%s)" % ", ".join(values)
+ else:
+ return " || ".join(values)
+ else: # assuming s is a string
+ s = _quote_percent(s, db)
+ return "'%s%s%s'" % (self.prefix, s, self.postfix)
+def _quote_percent(s, db):
+ if db in ('postgres', 'mysql'):
+ s = s.replace('%', '\\%')
+ else:
+ s = s.replace('%', '%%')
+ return s
+
########################################
## SQL JOINs
########################################
Modified: SQLObject/branches/0.9/sqlobject/tests/test_select.py
===================================================================
--- SQLObject/branches/0.9/sqlobject/tests/test_select.py 2007-04-24 11:29:54 UTC (rev 2581)
+++ SQLObject/branches/0.9/sqlobject/tests/test_select.py 2007-04-24 11:30:14 UTC (rev 2582)
@@ -1,5 +1,6 @@
from __future__ import generators # for enumerate
from sqlobject import *
+from sqlobject.sqlbuilder import func
from sqlobject.main import SQLObjectIntegrityError
from dbtest import *
from dbtest import setSQLiteConnectionFactory
@@ -73,6 +74,19 @@
pass
assert count == len(names)
+def test_05_select_limit():
+ setupIter()
+ assert len(list(IterTest.select(limit=2))) == 2
+ raises(AssertionError, IterTest.select(limit=2).distinct)
+ raises(AssertionError, IterTest.select(limit=2).clone, start=1)
+
+def test_06_like():
+ setupIter()
+ assert len(list(IterTest.select(IterTest.q.name.startswith('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.endswith('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.contains('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.contains(func.lower('A'))))) == 1
+
def test_select_getOne():
setupClass(IterTest)
a = IterTest(name='a')
@@ -85,12 +99,6 @@
raises(SQLObjectIntegrityError, 'IterTest.selectBy(name="b").getOne()')
raises(SQLObjectIntegrityError, 'IterTest.selectBy(name="b").getOne(None)')
-def test_05_select_limit():
- setupIter()
- assert len(list(IterTest.select(limit=2))) == 2
- raises(AssertionError, IterTest.select(limit=2).distinct)
- raises(AssertionError, IterTest.select(limit=2).clone, start=1)
-
def test_selectBy():
setupClass(IterTest)
a = IterTest(name='a')
|
|
From: <sub...@co...> - 2007-04-24 11:29:58
|
Author: phd
Date: 2007-04-24 05:29:54 -0600 (Tue, 24 Apr 2007)
New Revision: 2581
Modified:
SQLObject/branches/0.8/docs/News.txt
SQLObject/branches/0.8/sqlobject/sqlbuilder.py
SQLObject/branches/0.8/sqlobject/tests/test_select.py
Log:
Fixed sqlbuilder - .startswith(), .endswith() and .contains() assumed
their parameter must be a string; now you can pass an SQLExpression.
Modified: SQLObject/branches/0.8/docs/News.txt
===================================================================
--- SQLObject/branches/0.8/docs/News.txt 2007-04-24 11:29:22 UTC (rev 2580)
+++ SQLObject/branches/0.8/docs/News.txt 2007-04-24 11:29:54 UTC (rev 2581)
@@ -156,6 +156,10 @@
* Fixed a bug with absent comma in JOINs.
+* Fixed sqlbuilder - .startswith(), .endswith() and .contains() assumed
+ their parameter must be a string; now you can pass an SQLExpression:
+ Table.q.name.contains(func.upper('a')), for example.
+
SQLObject 0.7.5
===============
Modified: SQLObject/branches/0.8/sqlobject/sqlbuilder.py
===================================================================
--- SQLObject/branches/0.8/sqlobject/sqlbuilder.py 2007-04-24 11:29:22 UTC (rev 2580)
+++ SQLObject/branches/0.8/sqlobject/sqlbuilder.py 2007-04-24 11:29:54 UTC (rev 2581)
@@ -667,14 +667,14 @@
else:
return NOT(_IN(item, list))
-def STARTSWITH(expr, string):
- return SQLOp("LIKE", expr, _LikeQuoted(string) + '%')
+def STARTSWITH(expr, pattern):
+ return SQLOp("LIKE", expr, _LikeQuoted(pattern) + '%')
-def ENDSWITH(expr, string):
- return SQLOp("LIKE", expr, '%' + _LikeQuoted(string))
+def ENDSWITH(expr, pattern):
+ return SQLOp("LIKE", expr, '%' + _LikeQuoted(pattern))
-def CONTAINSSTRING(expr, string):
- return SQLOp("LIKE", expr, '%' + _LikeQuoted(string) + '%')
+def CONTAINSSTRING(expr, pattern):
+ return SQLOp("LIKE", expr, '%' + _LikeQuoted(pattern) + '%')
def ISNULL(expr):
return SQLOp("IS", expr, None)
@@ -683,6 +683,8 @@
return SQLOp("IS NOT", expr, None)
class _LikeQuoted:
+ # It assumes prefix and postfix are strings; usually just a percent sign.
+
# @@: I'm not sure what the quoting rules really are for all the
# databases
@@ -700,13 +702,30 @@
return self
def __sqlrepr__(self, db):
- s = sqlrepr(self.expr, db)[1:-1] # remove quotes
- if db in ('postgres', 'mysql'):
- s = s.replace('%', '\\%')
- else:
- s = s.replace('%', '%%')
- return "'%s%s%s'" % (self.prefix, s, self.postfix)
+ s = self.expr
+ if isinstance(s, SQLExpression):
+ values = []
+ if self.prefix:
+ values.append("'%s'" % self.prefix)
+ s = _quote_percent(sqlrepr(s, db), db)
+ values.append(s)
+ if self.postfix:
+ values.append("'%s'" % self.postfix)
+ if db == "mysql":
+ return "CONCAT(%s)" % ", ".join(values)
+ else:
+ return " || ".join(values)
+ else: # assuming s is a string
+ s = _quote_percent(s, db)
+ return "'%s%s%s'" % (self.prefix, s, self.postfix)
+def _quote_percent(s, db):
+ if db in ('postgres', 'mysql'):
+ s = s.replace('%', '\\%')
+ else:
+ s = s.replace('%', '%%')
+ return s
+
########################################
## SQL JOINs
########################################
Modified: SQLObject/branches/0.8/sqlobject/tests/test_select.py
===================================================================
--- SQLObject/branches/0.8/sqlobject/tests/test_select.py 2007-04-24 11:29:22 UTC (rev 2580)
+++ SQLObject/branches/0.8/sqlobject/tests/test_select.py 2007-04-24 11:29:54 UTC (rev 2581)
@@ -1,5 +1,6 @@
from __future__ import generators # for enumerate
from sqlobject import *
+from sqlobject.sqlbuilder import func
from sqlobject.main import SQLObjectIntegrityError
from dbtest import *
from dbtest import setSQLiteConnectionFactory
@@ -73,6 +74,19 @@
pass
assert count == len(names)
+def test_05_select_limit():
+ setupIter()
+ assert len(list(IterTest.select(limit=2))) == 2
+ raises(AssertionError, IterTest.select(limit=2).distinct)
+ raises(AssertionError, IterTest.select(limit=2).clone, start=1)
+
+def test_06_like():
+ setupIter()
+ assert len(list(IterTest.select(IterTest.q.name.startswith('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.endswith('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.contains('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.contains(func.lower('A'))))) == 1
+
def test_select_getOne():
setupClass(IterTest)
a = IterTest(name='a')
@@ -85,12 +99,6 @@
raises(SQLObjectIntegrityError, 'IterTest.selectBy(name="b").getOne()')
raises(SQLObjectIntegrityError, 'IterTest.selectBy(name="b").getOne(None)')
-def test_05_select_limit():
- setupIter()
- assert len(list(IterTest.select(limit=2))) == 2
- raises(AssertionError, IterTest.select(limit=2).distinct)
- raises(AssertionError, IterTest.select(limit=2).clone, start=1)
-
def test_selectBy():
setupClass(IterTest)
a = IterTest(name='a')
|
|
From: <sub...@co...> - 2007-04-24 11:29:28
|
Author: phd
Date: 2007-04-24 05:29:22 -0600 (Tue, 24 Apr 2007)
New Revision: 2580
Modified:
SQLObject/branches/0.7/docs/News.txt
SQLObject/branches/0.7/sqlobject/sqlbuilder.py
SQLObject/branches/0.7/sqlobject/tests/test_select.py
Log:
Fixed sqlbuilder - .startswith(), .endswith() and .contains() assumed
their parameter must be a string; now you can pass an SQLExpression.
Modified: SQLObject/branches/0.7/docs/News.txt
===================================================================
--- SQLObject/branches/0.7/docs/News.txt 2007-04-20 17:47:57 UTC (rev 2579)
+++ SQLObject/branches/0.7/docs/News.txt 2007-04-24 11:29:22 UTC (rev 2580)
@@ -19,6 +19,10 @@
* Fixed a bug with absent comma in JOINs.
+* Fixed sqlbuilder - .startswith(), .endswith() and .contains() assumed
+ their parameter must be a string; now you can pass an SQLExpression:
+ Table.q.name.contains(func.upper('a')), for example.
+
SQLObject 0.7.5
===============
Modified: SQLObject/branches/0.7/sqlobject/sqlbuilder.py
===================================================================
--- SQLObject/branches/0.7/sqlobject/sqlbuilder.py 2007-04-20 17:47:57 UTC (rev 2579)
+++ SQLObject/branches/0.7/sqlobject/sqlbuilder.py 2007-04-24 11:29:22 UTC (rev 2580)
@@ -660,14 +660,14 @@
else:
return NOT(_IN(item, list))
-def STARTSWITH(expr, string):
- return SQLOp("LIKE", expr, _LikeQuoted(string) + '%')
+def STARTSWITH(expr, pattern):
+ return SQLOp("LIKE", expr, _LikeQuoted(pattern) + '%')
-def ENDSWITH(expr, string):
- return SQLOp("LIKE", expr, '%' + _LikeQuoted(string))
+def ENDSWITH(expr, pattern):
+ return SQLOp("LIKE", expr, '%' + _LikeQuoted(pattern))
-def CONTAINSSTRING(expr, string):
- return SQLOp("LIKE", expr, '%' + _LikeQuoted(string) + '%')
+def CONTAINSSTRING(expr, pattern):
+ return SQLOp("LIKE", expr, '%' + _LikeQuoted(pattern) + '%')
def ISNULL(expr):
return SQLOp("IS", expr, None)
@@ -676,6 +676,8 @@
return SQLOp("IS NOT", expr, None)
class _LikeQuoted:
+ # It assumes prefix and postfix are strings; usually just a percent sign.
+
# @@: I'm not sure what the quoting rules really are for all the
# databases
@@ -693,13 +695,30 @@
return self
def __sqlrepr__(self, db):
- s = sqlrepr(self.expr, db)[1:-1] # remove quotes
- if db in ('postgres', 'mysql'):
- s = s.replace('%', '\\%')
- else:
- s = s.replace('%', '%%')
- return "'%s%s%s'" % (self.prefix, s, self.postfix)
+ s = self.expr
+ if isinstance(s, SQLExpression):
+ values = []
+ if self.prefix:
+ values.append("'%s'" % self.prefix)
+ s = _quote_percent(sqlrepr(s, db), db)
+ values.append(s)
+ if self.postfix:
+ values.append("'%s'" % self.postfix)
+ if db == "mysql":
+ return "CONCAT(%s)" % ", ".join(values)
+ else:
+ return " || ".join(values)
+ else: # assuming s is a string
+ s = _quote_percent(s, db)
+ return "'%s%s%s'" % (self.prefix, s, self.postfix)
+def _quote_percent(s, db):
+ if db in ('postgres', 'mysql'):
+ s = s.replace('%', '\\%')
+ else:
+ s = s.replace('%', '%%')
+ return s
+
########################################
## SQL JOINs
########################################
Modified: SQLObject/branches/0.7/sqlobject/tests/test_select.py
===================================================================
--- SQLObject/branches/0.7/sqlobject/tests/test_select.py 2007-04-20 17:47:57 UTC (rev 2579)
+++ SQLObject/branches/0.7/sqlobject/tests/test_select.py 2007-04-24 11:29:22 UTC (rev 2580)
@@ -1,5 +1,6 @@
from __future__ import generators # for enumerate
from sqlobject import *
+from sqlobject.sqlbuilder import func
from dbtest import *
try:
@@ -77,6 +78,13 @@
raises(AssertionError, IterTest.select(limit=2).distinct)
raises(AssertionError, IterTest.select(limit=2).clone, start=1)
+def test_06_like():
+ setupIter()
+ assert len(list(IterTest.select(IterTest.q.name.startswith('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.endswith('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.contains('a')))) == 1
+ assert len(list(IterTest.select(IterTest.q.name.contains(func.lower('A'))))) == 1
+
def test_selectBy():
setupClass(IterTest)
a = IterTest(name='a')
|