Title: [961] trunk: Revert to name of prepared query as positional arg
Revision
961
Author
cito
Date
2019-01-04 14:43:23 -0500 (Fri, 04 Jan 2019)

Log Message

Revert to name of prepared query as positional arg

Unnamed prepared queries are not really useful due to their limited
lifetime. To discourage usage of unnamed statements and have a more
consistent API, we switched back from keyword-only to positional arg.

Modified Paths

Diff

Modified: trunk/docs/contents/pg/db_wrapper.rst (960 => 961)


--- trunk/docs/contents/pg/db_wrapper.rst	2019-01-04 17:49:21 UTC (rev 960)
+++ trunk/docs/contents/pg/db_wrapper.rst	2019-01-04 19:43:23 UTC (rev 961)
@@ -508,7 +508,7 @@
 query_prepared -- execute a prepared statement
 ----------------------------------------------
 
-.. method:: DB.query_prepared([arg1, [arg2, ...]], [name=...])
+.. method:: DB.query_prepared(name, [arg1, [arg2, ...]])
 
     Execute a prepared statement
 
@@ -524,9 +524,8 @@
     :raises pg.OperationalError: prepared statement does not exist
 
 This methods works like the :meth:`DB.query` method, except that instead of
-passing the SQL command, you pass the name of a prepared statement via the
-keyword-only argument *name*.  If you don't pass a name, the unnamed
-statement will be executed, if you created one before.
+passing the SQL command, you pass the name of a prepared statement.  If you
+pass an empty name, the unnamed statement will be executed.
 
 You must have created the corresponding named or unnamed statement with
 the :meth:`DB.prepare` method before, otherwise an :exc:`pg.OperationalError`
@@ -537,7 +536,7 @@
 prepare -- create a prepared statement
 --------------------------------------
 
-.. method:: DB.prepare(command, [name])
+.. method:: DB.prepare(name, command)
 
     Create a prepared statement
 
@@ -550,10 +549,10 @@
 
 This method creates a prepared statement for the given command with the
 given name for later execution with the :meth:`DB.query_prepared` method.
-The name can be empty or left out to create an unnamed statement, in which
-case any pre-existing unnamed statement is automatically replaced;
-otherwise a :exc:`pg.ProgrammingError` is raised if the statement name is
-already defined in the current database session.
+The name can be empty to create an unnamed statement, in which case any
+pre-existing unnamed statement is automatically replaced; otherwise a
+:exc:`pg.ProgrammingError` is raised if the statement name is already
+defined in the current database session.
 
 The SQL command may optionally contain positional parameters of the form
 ``$1``, ``$2``, etc instead of literal data.  The corresponding values
@@ -562,21 +561,20 @@
 
 Example::
 
-    db.prepare("update employees set phone=$2 where ein=$1",
-        name='update employees')
+    db.prepare('change phone',
+        "update employees set phone=$2 where ein=$1",
     while True:
         ein = input("Employee ID? ")
         if not ein:
             break
         phone = input("Phone? ")
-        rows = db.query_prepared(ein, phone,
-            name='update employees).getresult()[0][0]
+        db.query_prepared('change phone', ein, phone)
 
 .. note::
 
-    The DB wrapper sometimes issues parameterized queries behind the scenes
-    (for instance to find unknown database types) which could replace the
-    unnamed statement. So we advice to always name prepared statements.
+     We recommend always using named queries, since unnamed queries have a
+     limited lifetime and can be automatically replaced or destroyed by
+     various operations on the database.
 
 .. versionadded:: 5.1
 

Modified: trunk/pg.py (960 => 961)


--- trunk/pg.py	2019-01-04 17:49:21 UTC (rev 960)
+++ trunk/pg.py	2019-01-04 19:43:23 UTC (rev 961)
@@ -1869,18 +1869,15 @@
         return self.query(*self.adapter.format_query(
             command, parameters, types, inline))
 
-    def query_prepared(self, *args, **kwargs):
+    def query_prepared(self, name, *args):
         """Execute a prepared SQL statement.
 
         This works like the query() method, except that instead of passing
-        the SQL command, you pass the name of a prepared statement via
-        the keyword-only argument `name`.  If you don't pass a name, the
-        unnamed statement will be executed, if you created one before.
+        the SQL command, you pass the name of a prepared statement.  If you
+        pass an empty name, the unnamed statement will be executed.
         """
         if not self.db:
             raise _int_error('Connection is not valid')
-        # use kwargs because Python 2 does not support keyword-only arguments
-        name = kwargs.get('name')
         if name is None:
             name = ''
         if args:
@@ -1889,18 +1886,18 @@
         self._do_debug('EXECUTE', name)
         return self.db.query_prepared(name)
 
-    def prepare(self, command, name=None):
+    def prepare(self, name, command):
         """Create a prepared SQL statement.
 
         This creates a prepared statement for the given command with the
         the given name for later execution with the query_prepared() method.
-        The name can be empty or left out to create an unnamed statement,
-        in which case any pre-existing unnamed statement is automatically
-        replaced; otherwise it is an error if the statement name is already
-        defined in the current database session.
 
-        If any parameters are used, they can be referred to in the query as
-        numbered parameters of the form $1.
+        The name can be empty to create an unnamed statement, in which case
+        any pre-existing unnamed statement is automatically replaced;
+        otherwise it is an error if the statement name is already
+        defined in the current database session. We recommend always using
+        named queries, since unnamed queries have a limited lifetime and
+        can be automatically replaced or destroyed by various operations.
         """
         if not self.db:
             raise _int_error('Connection is not valid')

Modified: trunk/tests/test_classic_dbwrapper.py (960 => 961)


--- trunk/tests/test_classic_dbwrapper.py	2019-01-04 17:49:21 UTC (rev 960)
+++ trunk/tests/test_classic_dbwrapper.py	2019-01-04 19:43:23 UTC (rev 961)
@@ -971,73 +971,78 @@
 
     def testPrepare(self):
         p = self.db.prepare
-        self.assertIsNone(p("select 'hello'", 'my query'))
-        self.assertIsNone(p("select 'world'", 'my other query'))
+        self.assertIsNone(p('my query', "select 'hello'"))
+        self.assertIsNone(p('my other query', "select 'world'"))
         self.assertRaises(pg.ProgrammingError,
             p, 'my query', "select 'hello, too'")
 
     def testPrepareUnnamed(self):
         p = self.db.prepare
-        self.assertIsNone(p("select null"))
-        self.assertIsNone(p("select null", None))
-        self.assertIsNone(p("select null", ''))
-        self.assertIsNone(p("select null", name=None))
-        self.assertIsNone(p("select null", name=''))
+        self.assertIsNone(p('', "select null"))
+        self.assertIsNone(p(None, "select null"))
 
     def testQueryPreparedWithoutParams(self):
         f = self.db.query_prepared
         self.assertRaises(pg.OperationalError, f, 'q')
         p = self.db.prepare
-        p("select 17", name='q1')
-        p("select 42", name='q2')
-        r = f(name='q1').getresult()[0][0]
+        p('q1', "select 17")
+        p('q2', "select 42")
+        r = f('q1').getresult()[0][0]
         self.assertEqual(r, 17)
-        r = f(name='q2').getresult()[0][0]
+        r = f('q2').getresult()[0][0]
         self.assertEqual(r, 42)
 
     def testQueryPreparedWithParams(self):
         p = self.db.prepare
-        p("select 1 + $1 + $2 + $3", name='sum')
-        p("select initcap($1) || ', ' || $2 || '!'", name='cat')
+        p('sum', "select 1 + $1 + $2 + $3")
+        p('cat', "select initcap($1) || ', ' || $2 || '!'")
         f = self.db.query_prepared
-        r = f(2, 3, 5, name='sum').getresult()[0][0]
+        r = f('sum', 2, 3, 5).getresult()[0][0]
         self.assertEqual(r, 11)
-        r = f('hello', 'world', name='cat').getresult()[0][0]
+        r = f('cat', 'hello', 'world').getresult()[0][0]
         self.assertEqual(r, 'Hello, world!')
 
     def testQueryPreparedUnnamedWithOutParams(self):
         f = self.db.query_prepared
-        self.assertRaises(pg.OperationalError, f)
+        self.assertRaises(pg.OperationalError, f, None)
+        self.assertRaises(pg.OperationalError, f, '')
         p = self.db.prepare
         # make sure all types are known so that we will not
         # generate other anonymous queries in the background
-        p("select 'no name'::varchar")
-        r = f().getresult()[0][0]
-        self.assertEqual(r, 'no name')
-        r = f(name=None).getresult()[0][0]
-        self.assertEqual(r, 'no name')
-        r = f(name='').getresult()[0][0]
-        self.assertEqual(r, 'no name')
+        p('', "select 'empty'::varchar")
+        r = f(None).getresult()[0][0]
+        self.assertEqual(r, 'empty')
+        r = f('').getresult()[0][0]
+        self.assertEqual(r, 'empty')
+        p(None, "select 'none'::varchar")
+        r = f(None).getresult()[0][0]
+        self.assertEqual(r, 'none')
+        r = f('').getresult()[0][0]
+        self.assertEqual(r, 'none')
 
     def testQueryPreparedUnnamedWithParams(self):
         p = self.db.prepare
-        p("select 1 + $1 + $2")
+        p('', "select 1 + $1 + $2")
         f = self.db.query_prepared
-        r = f(2, 3).getresult()[0][0]
+        r = f('', 2, 3).getresult()[0][0]
         self.assertEqual(r, 6)
-        r = f(2, 3, name=None).getresult()[0][0]
+        r = f(None, 2, 3).getresult()[0][0]
         self.assertEqual(r, 6)
-        r = f(2, 3, name='').getresult()[0][0]
-        self.assertEqual(r, 6)
+        p(None, "select 2 + $1 + $2")
+        f = self.db.query_prepared
+        r = f('', 3, 4).getresult()[0][0]
+        self.assertEqual(r, 9)
+        r = f(None, 3, 4).getresult()[0][0]
+        self.assertEqual(r, 9)
 
     def testDescribePrepared(self):
-        self.db.prepare("select 1 as first, 2 as second", 'count')
+        self.db.prepare('count', "select 1 as first, 2 as second")
         f = self.db.describe_prepared
         r = f('count').listfields()
         self.assertEqual(r, ('first', 'second'))
 
     def testDescribePreparedUnnamed(self):
-        self.db.prepare("select null as anon")
+        self.db.prepare('', "select null as anon")
         f = self.db.describe_prepared
         r = f().listfields()
         self.assertEqual(r, ('anon',))
@@ -1052,14 +1057,14 @@
         e = pg.OperationalError
         self.assertRaises(e, f, 'myquery')
         p = self.db.prepare
-        p("select 1", 'q1')
-        p("select 2", 'q2')
+        p('q1', "select 1")
+        p('q2', "select 2")
         f('q1')
         f('q2')
         self.assertRaises(e, f, 'q1')
         self.assertRaises(e, f, 'q2')
-        p("select 1", 'q1')
-        p("select 2", 'q2')
+        p('q1', "select 1")
+        p('q2', "select 2")
         f()
         self.assertRaises(e, f, 'q1')
         self.assertRaises(e, f, 'q2')
_______________________________________________
PyGreSQL mailing list
[email protected]
https://mail.vex.net/mailman/listinfo/pygresql

Reply via email to