]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- [feature] Added "no_parameters=True" execution
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 14 Feb 2012 01:07:44 +0000 (20:07 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 14 Feb 2012 01:07:44 +0000 (20:07 -0500)
    option for connections.   If no parameters
    are present, will pass the statement
    as cursor.execute(statement), thereby invoking
    the DBAPIs behavior when no parameter collection
    is present; for psycopg2 and mysql-python, this
    means not interpreting % signs in the string.
    This only occurs with this option, and not
    just if the param list is blank, as otherwise
    this would produce inconsistent behavior
    of SQL expressions that normally escape percent
    signs (and while compiling, can't know ahead of
    time if parameters will be present in
    some cases).  [ticket:2407]

CHANGES
lib/sqlalchemy/engine/base.py
lib/sqlalchemy/engine/default.py
test/engine/test_execute.py

diff --git a/CHANGES b/CHANGES
index 29e8c2ba0f91b3ef3c434178353477b655b86115..a25c5f45a918529baf767abac34f57da84ea9135 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -71,6 +71,21 @@ CHANGES
     with no columns at all.  [ticket:2380]
 
 - engine
+  - [feature] Added "no_parameters=True" execution
+    option for connections.   If no parameters
+    are present, will pass the statement
+    as cursor.execute(statement), thereby invoking
+    the DBAPIs behavior when no parameter collection
+    is present; for psycopg2 and mysql-python, this
+    means not interpreting % signs in the string.
+    This only occurs with this option, and not
+    just if the param list is blank, as otherwise
+    this would produce inconsistent behavior
+    of SQL expressions that normally escape percent
+    signs (and while compiling, can't know ahead of 
+    time if parameters will be present in 
+    some cases).  [ticket:2407]
+
   - [feature] Added pool_reset_on_return argument
     to create_engine, allows control over 
     "connection return" behavior.  Also added
index 0224d084334236c24a20878c810547b0b3ec8606..7cc5522c41d5c683b36b96b03960a024baabcde0 100644 (file)
@@ -491,14 +491,23 @@ class Dialect(object):
         raise NotImplementedError()
 
     def do_executemany(self, cursor, statement, parameters, context=None):
-        """Provide an implementation of *cursor.executemany(statement,
-        parameters)*."""
+        """Provide an implementation of ``cursor.executemany(statement,
+        parameters)``."""
 
         raise NotImplementedError()
 
     def do_execute(self, cursor, statement, parameters, context=None):
-        """Provide an implementation of *cursor.execute(statement,
-        parameters)*."""
+        """Provide an implementation of ``cursor.execute(statement,
+        parameters)``."""
+
+        raise NotImplementedError()
+
+    def do_execute_no_params(self, cursor, statement, parameters, context=None):
+        """Provide an implementation of ``cursor.execute(statement)``.
+
+        The parameter collection should not be sent.
+
+        """
 
         raise NotImplementedError()
 
@@ -976,6 +985,18 @@ class Connection(Connectable):
           is returned to the connection pool, i.e.
           the :meth:`.Connection.close` method is called.
 
+        :param no_parameters: When ``True``, if the final parameter 
+          list or dictionary is totally empty, will invoke the 
+          statement on the cursor as ``cursor.execute(statement)``,
+          not passing the parameter collection at all.
+          Some DBAPIs such as psycopg2 and mysql-python consider
+          percent signs as significant only when parameters are 
+          present; this option allows code to generate SQL
+          containing percent signs (and possibly other characters)
+          that is neutral regarding whether it's executed by the DBAPI
+          or piped into a script that's later invoked by 
+          command line tools.  New in 0.7.6.
+          
         :param stream_results: Available on: Connection, statement.
           Indicate to the dialect that results should be 
           "streamed" and not pre-buffered, if possible.  This is a limitation
@@ -1647,7 +1668,8 @@ class Connection(Connectable):
 
         if self._echo:
             self.engine.logger.info(statement)
-            self.engine.logger.info("%r", sql_util._repr_params(parameters, batches=10))
+            self.engine.logger.info("%r", 
+                    sql_util._repr_params(parameters, batches=10))
         try:
             if context.executemany:
                 self.dialect.do_executemany(
@@ -1655,6 +1677,11 @@ class Connection(Connectable):
                                     statement, 
                                     parameters, 
                                     context)
+            elif not parameters and context.no_parameters:
+                self.dialect.do_execute_no_params(
+                                    cursor, 
+                                    statement, 
+                                    context)
             else:
                 self.dialect.do_execute(
                                     cursor, 
index a1e5a57991e636179145af970f851a91e87093f4..5c2d98146d28da02564266135e80adabe1302ff4 100644 (file)
@@ -334,6 +334,9 @@ class DefaultDialect(base.Dialect):
     def do_execute(self, cursor, statement, parameters, context=None):
         cursor.execute(statement, parameters)
 
+    def do_execute_no_params(self, cursor, statement, context=None):
+        cursor.execute(statement)
+
     def is_disconnect(self, e, connection, cursor):
         return False
 
@@ -537,6 +540,10 @@ class DefaultExecutionContext(base.ExecutionContext):
         self.cursor = self.create_cursor()
         return self
 
+    @util.memoized_property
+    def no_parameters(self):
+        return self.execution_options.get("no_parameters", False)
+
     @util.memoized_property
     def is_crud(self):
         return self.isinsert or self.isupdate or self.isdelete
index f3206e9cccc13cd99b6af7e3abe552f2f360847e..dc3e46aab93cfdd87f2b10dd1c4ba1d94219a0a5 100644 (file)
@@ -41,6 +41,16 @@ class ExecuteTest(fixtures.TestBase):
     def teardown_class(cls):
         metadata.drop_all()
 
+    def test_no_params_option(self):
+        stmt = "SELECT '%'"
+        if testing.against('oracle'):
+            stmt += " FROM DUAL"
+        conn = testing.db.connect()
+        result = conn.\
+                execution_options(no_parameters=True).\
+                scalar(stmt)
+        eq_(result, '%')
+
     @testing.fails_on_everything_except('firebird', 'maxdb',
                                         'sqlite', '+pyodbc',
                                         '+mxodbc', '+zxjdbc', 'mysql+oursql',