Don't barf on Composite passed to execute_values()

Close #794
This commit is contained in:
Daniele Varrazzo 2018-10-23 01:06:24 +01:00
parent 05f9e231a0
commit 8fb0f694f7
3 changed files with 26 additions and 0 deletions

2
NEWS
View File

@ -43,6 +43,8 @@ What's new in psycopg 2.7.6
- Fixed hang trying to :sql:`COPY` via `~cursor.execute()` (:ticket:`#781`). - Fixed hang trying to :sql:`COPY` via `~cursor.execute()` (:ticket:`#781`).
- Fixed segfault accessing the `connection.readonly` and - Fixed segfault accessing the `connection.readonly` and
`connection.deferrable` repeatedly (:ticket:`#790`). `connection.deferrable` repeatedly (:ticket:`#790`).
- `~psycopg2.extras.execute_values()` accepts `~psycopg2.sql.Composable`
objects (#794).
- `~psycopg2.errorcodes` map updated to PostgreSQL 11. - `~psycopg2.errorcodes` map updated to PostgreSQL 11.

View File

@ -1254,6 +1254,10 @@ def execute_values(cur, sql, argslist, template=None, page_size=100):
[(1, 20, 3), (4, 50, 6), (7, 8, 9)]) [(1, 20, 3), (4, 50, 6), (7, 8, 9)])
''' '''
from psycopg2.sql import Composable
if isinstance(sql, Composable):
sql = sql.as_string(cur)
# we can't just use sql % vals because vals is bytes: if sql is bytes # we can't just use sql % vals because vals is bytes: if sql is bytes
# there will be some decoding error because of stupid codec used, and Py3 # there will be some decoding error because of stupid codec used, and Py3
# doesn't implement % on bytes. # doesn't implement % on bytes.

View File

@ -83,6 +83,16 @@ class TestExecuteBatch(FastExecuteTestMixin, testutils.ConnectingTestCase):
cur.execute("select id, val from testfast order by id") cur.execute("select id, val from testfast order by id")
self.assertEqual(cur.fetchall(), [(i, i * 10) for i in range(1000)]) self.assertEqual(cur.fetchall(), [(i, i * 10) for i in range(1000)])
def test_composed(self):
from psycopg2 import sql
cur = self.conn.cursor()
psycopg2.extras.execute_batch(cur,
sql.SQL("insert into {0} (id, val) values (%s, %s)")
.format(sql.Identifier('testfast')),
((i, i * 10) for i in range(1000)))
cur.execute("select id, val from testfast order by id")
self.assertEqual(cur.fetchall(), [(i, i * 10) for i in range(1000)])
def test_pages(self): def test_pages(self):
cur = self.conn.cursor() cur = self.conn.cursor()
psycopg2.extras.execute_batch(cur, psycopg2.extras.execute_batch(cur,
@ -169,6 +179,16 @@ class TestExecuteValues(FastExecuteTestMixin, testutils.ConnectingTestCase):
cur.execute("select id, val from testfast order by id") cur.execute("select id, val from testfast order by id")
self.assertEqual(cur.fetchall(), [(i, i * 10) for i in range(1000)]) self.assertEqual(cur.fetchall(), [(i, i * 10) for i in range(1000)])
def test_composed(self):
from psycopg2 import sql
cur = self.conn.cursor()
psycopg2.extras.execute_values(cur,
sql.SQL("insert into {0} (id, val) values %s")
.format(sql.Identifier('testfast')),
((i, i * 10) for i in range(1000)))
cur.execute("select id, val from testfast order by id")
self.assertEqual(cur.fetchall(), [(i, i * 10) for i in range(1000)])
def test_pages(self): def test_pages(self):
cur = self.conn.cursor() cur = self.conn.cursor()
psycopg2.extras.execute_values(cur, psycopg2.extras.execute_values(cur,