Checking for resultset in Python DB API
2020-11-06
(Warning: Only tested with psycopg2
)
Sometimes you want to execute an SQL query but don’t know whether it
will return a resultset in advance. An example would be a psql
-like
interface where the user can type arbitrary queries (DQL, DML, or DDL)
or a very generic interface class.
Calling fetchone()
or fetchall()
raises a ProgrammingError
when
there is no resultset. We could catch that, but that’s not elegant.
Parsing the query to determine whether it should return a resultset is not feasible.
However, the description
property describes the resultset and
therefore is not None iff there is one:
if csr.description:
result = csr.fetchall()
Test script:
#!/usr/bin/python3
import pprint
import psycopg2
def q(csr, query):
print(query)
csr.execute(query)
print(csr.rowcount, " rows")
pprint.pprint(csr.description)
if csr.description:
pprint.pprint(csr.fetchall())
print("")
db = psycopg2.connect("")
csr = db.cursor()
q(csr, "select * from t")
q(csr, "insert into t(t, v) values('foo', 23)")
q(csr, "insert into t(t, v) select t, v + 1 from t where v < 1000")
q(csr, "insert into t(t, v) values('foo', 23) returning id")
q(csr, "delete from t")
q(csr, "select * from t")
Output:
select * from t
13 rows
(Column(name='id', type_code=23),
Column(name='t', type_code=25),
Column(name='v', type_code=23))
[(1, 'a', 1000),
(4, 'd', 1000),
(7, 'f', 1000),
(8, 'g', 1000),
(3, 'c', 1100),
(9, '20', 30),
(10, 'a', 1000),
(11, 'd', 1000),
(12, 'f', 1000),
(13, 'g', 1000),
(14, 'c', 1100),
(15, '20', 30),
(16, 'test', 42)]
insert into t(t, v) values('foo', 23)
1 rows
None
insert into t(t, v) select t, v + 1 from t where v < 1000
4 rows
None
insert into t(t, v) values('foo', 23) returning id
1 rows
(Column(name='id', type_code=23),)
[(43,)]
delete from t
19 rows
None
select * from t
0 rows
(Column(name='id', type_code=23),
Column(name='t', type_code=25),
Column(name='v', type_code=23))
[]