Oleg Broytmann wrote:
On Thu, Apr 13, 2006 at 05:12:20PM -0500, Charles Duffy wrote:
It would probably have been a good thing if this patch actually fixed the issue it purported to, yes?

   Can you also add a test?

The attached version breaks fewer tests; fixes the ones which it breaks; and adds a few new test cases.

I've also validated that test_subqueries.test_5perform_direct fails with the unpatched SQLObject build, such that this is in fact a valid test.

def test_5perform_direct():
    insert()
select = TestIn1.select(TestIn1.q.col1 == Select(TestIn2.q.col2, where=(TestIn2.q.col2 == "test")))
    assert select.count() == 1
Index: sqlobject/dbconnection.py
===================================================================
--- sqlobject/dbconnection.py	(revision 1695)
+++ sqlobject/dbconnection.py	(working copy)
@@ -604,9 +604,9 @@
     # in the SQLObject class.
 
     def _SO_update(self, so, values):
-        self.query("UPDATE %s SET %s WHERE %s = %s" %
+        self.query("UPDATE %s SET %s WHERE %s = (%s)" %
                    (so.sqlmeta.table,
-                    ", ".join(["%s = %s" % (dbName, self.sqlrepr(value))
+                    ", ".join(["%s = (%s)" % (dbName, self.sqlrepr(value))
                                for dbName, value in values]),
                     so.sqlmeta.idName,
                     self.sqlrepr(so.id)))
@@ -615,14 +615,14 @@
         columns = ", ".join(columnNames)
         if columns:
             return self.queryOne(
-                "SELECT %s FROM %s WHERE %s = %s" %
+                "SELECT %s FROM %s WHERE %s = (%s)" %
                 (columns,
                  so.sqlmeta.table,
                  so.sqlmeta.idName,
                  self.sqlrepr(so.id)))
         else:
             return self.queryOne(
-                "SELECT NULL FROM %s WHERE %s = %s" %
+                "SELECT NULL FROM %s WHERE %s = (%s)" %
                 (so.sqlmeta.table,
                  so.sqlmeta.idName,
                  self.sqlrepr(so.id)))
@@ -635,7 +635,7 @@
             raise ValueError, "'column' and 'value' tuples must be of the same size"
         columns = []
         for i in xrange(len(column)):
-            columns.append("%s = %s" % (column[i], self.sqlrepr(value[i])))
+            columns.append("(%s) = (%s)" % (column[i], self.sqlrepr(value[i])))
         condition = ' AND '.join(columns)
         return self.queryOne("SELECT %s FROM %s WHERE %s" %
                              (", ".join(columnNames),
@@ -643,20 +643,20 @@
                               condition))
 
     def _SO_delete(self, so):
-        self.query("DELETE FROM %s WHERE %s = %s" %
+        self.query("DELETE FROM %s WHERE %s = (%s)" %
                    (so.sqlmeta.table,
                     so.sqlmeta.idName,
                     self.sqlrepr(so.id)))
 
     def _SO_selectJoin(self, soClass, column, value):
-        return self.queryAll("SELECT %s FROM %s WHERE %s = %s" %
+        return self.queryAll("SELECT %s FROM %s WHERE %s = (%s)" %
                              (soClass.sqlmeta.idName,
                               soClass.sqlmeta.table,
                               column,
                               self.sqlrepr(value)))
 
     def _SO_intermediateJoin(self, table, getColumn, joinColumn, value):
-        return self.queryAll("SELECT %s FROM %s WHERE %s = %s" %
+        return self.queryAll("SELECT %s FROM %s WHERE %s = (%s)" %
                              (getColumn,
                               table,
                               joinColumn,
@@ -664,7 +664,7 @@
 
     def _SO_intermediateDelete(self, table, firstColumn, firstValue,
                                secondColumn, secondValue):
-        self.query("DELETE FROM %s WHERE %s = %s AND %s = %s" %
+        self.query("DELETE FROM %s WHERE %s = (%s) AND %s = (%s)" %
                    (table,
                     firstColumn,
                     self.sqlrepr(firstValue),
Index: sqlobject/sqlbuilder.py
===================================================================
--- sqlobject/sqlbuilder.py	(revision 1695)
+++ sqlobject/sqlbuilder.py	(working copy)
@@ -230,7 +230,13 @@
         self.expr1 = expr1
         self.expr2 = expr2
     def __sqlrepr__(self, db):
-        return "(%s %s %s)" % (sqlrepr(self.expr1, db), self.op, sqlrepr(self.expr2, db))
+        s1 = sqlrepr(self.expr1, db)
+        s2 = sqlrepr(self.expr2, db)
+        if s1[0] != '(' and s1 != 'NULL':
+            s1 = '(' + s1 + ')'
+        if s2[0] != '(' and s2 != 'NULL':
+            s2 = '(' + s2 + ')'
+        return "(%s %s %s)" % (s1, self.op, s2)
     def components(self):
         return [self.expr1, self.expr2]
     def execute(self, executor):
@@ -884,7 +890,7 @@
         self.expr = expr
         self.string = string
     def __sqlrepr__(self, db):
-        return "(%s %s %s)" % (sqlrepr(self.expr, db), self.op, sqlrepr(self.string, db))
+        return "(%s %s (%s))" % (sqlrepr(self.expr, db), self.op, sqlrepr(self.string, db))
     def components(self):
         return [self.expr, self.string]
     def execute(self, executor):
@@ -912,7 +918,7 @@
         else:
             return "LIKE"
     def __sqlrepr__(self, db):
-        return "(%s %s %s)" % (
+        return "(%s %s (%s))" % (
             sqlrepr(self.expr, db), self._get_op(db), sqlrepr(self.string, db)
         )
     def execute(self, executor):
Index: sqlobject/tests/test_joins_conditional.py
===================================================================
--- sqlobject/tests/test_joins_conditional.py	(revision 1695)
+++ sqlobject/tests/test_joins_conditional.py	(working copy)
@@ -35,7 +35,7 @@
             on_condition=(TestJoin1.q.col1 == TestJoin2.q.col2))
     )
     assert str(select) == \
-        "SELECT test_join1.id, test_join1.col1 FROM  test_join1 LEFT JOIN test_join2 ON (test_join1.col1 = test_join2.col2) WHERE 1 = 1"
+        "SELECT test_join1.id, test_join1.col1 FROM  test_join1 LEFT JOIN test_join2 ON ((test_join1.col1) = (test_join2.col2)) WHERE 1 = 1"
 
 def test_3perform_join():
     setup()
Index: sqlobject/tests/test_subqueries.py
===================================================================
--- sqlobject/tests/test_subqueries.py	(revision 1695)
+++ sqlobject/tests/test_subqueries.py	(working copy)
@@ -40,9 +40,20 @@
     setup()
     select = TestIn1.select(NOTEXISTS(Select(TestIn2.q.col2, where=(Outer(TestIn1).q.col1 == TestIn2.q.col2))))
     assert str(select) == \
-        "SELECT test_in1.id, test_in1.col1 FROM test_in1 WHERE NOT EXISTS (SELECT test_in2.col2 FROM test_in2 WHERE (test_in1.col1 = test_in2.col2))"
+        "SELECT test_in1.id, test_in1.col1 FROM test_in1 WHERE NOT EXISTS (SELECT test_in2.col2 FROM test_in2 WHERE ((test_in1.col1) = (test_in2.col2)))"
 
 def test_4perform_exists():
     insert()
     select = TestIn1.select(EXISTS(Select(TestIn2.q.col2, where=(Outer(TestIn1).q.col1 == TestIn2.q.col2))))
     assert len(list(select)) == 2
+
+def test_4syntax_direct():
+    setup()
+    select = TestIn1.select(TestIn1.q.col1 == Select(TestIn2.q.col2, where=(TestIn2.q.col2 == "test")))
+    assert str(select) == \
+	"SELECT test_in1.id, test_in1.col1 FROM test_in1 WHERE ((test_in1.col1) = (SELECT test_in2.col2 FROM test_in2 WHERE ((test_in2.col2) = ('test'))))"
+
+def test_4perform_direct():
+    insert()
+    select = TestIn1.select(TestIn1.q.col1 == Select(TestIn2.q.col2, where=(TestIn2.q.col2 == "test")))
+    assert select.count() == 1
Index: sqlobject/tests/test_converters.py
===================================================================
--- sqlobject/tests/test_converters.py	(revision 1695)
+++ sqlobject/tests/test_converters.py	(working copy)
@@ -163,7 +163,7 @@
 
 def test_op():
     instance = SQLOp('and', 'this', 'that')
-    assert sqlrepr(instance, 'mysql') == "('this' AND 'that')"
+    assert sqlrepr(instance, 'mysql') == "(('this') AND ('that'))"
 
 def test_call():
     instance = SQLCall('test', ('test',))
Index: sqlobject/tests/test_aliases.py
===================================================================
--- sqlobject/tests/test_aliases.py	(revision 1695)
+++ sqlobject/tests/test_aliases.py	(working copy)
@@ -15,7 +15,7 @@
     alias = Alias(JoinAlias)
     select = JoinAlias.select(JoinAlias.q.parent == alias.q.name)
     assert str(select) == \
-        "SELECT join_alias.id, join_alias.name, join_alias.parent FROM join_alias AS join_alias_alias1, join_alias WHERE (join_alias.parent = join_alias_alias1.name)"
+        "SELECT join_alias.id, join_alias.name, join_alias.parent FROM join_alias AS join_alias_alias1, join_alias WHERE ((join_alias.parent) = (join_alias_alias1.name))"
 
 def test_2perform_join():
     setupClass(JoinAlias)
Index: sqlobject/main.py
===================================================================
--- sqlobject/main.py	(revision 1695)
+++ sqlobject/main.py	(working copy)
@@ -1483,7 +1483,7 @@
                 if col.cascade == False:
                     # Found a restriction
                     restrict = True
-                query.append("%s = %s" % (col.dbName, self.id))
+                query.append("%s = (%s)" % (col.dbName, self.id))
                 if col.cascade == 'null':
                     setnull = col.name
                 elif col.cascade:

Reply via email to