Skip to content

Commit 0dcb53d

Browse files
author
James William Pye
committed
Remove the automatic re-preparation of statements.
It's actually a representing a different object when it's prepared again, so don't pretend that it isn't. Possible alternatives to this will be API theft from perl: "clone()".
1 parent dd471bd commit 0dcb53d

3 files changed

Lines changed: 44 additions & 45 deletions

File tree

postgresql/api.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -789,18 +789,7 @@ def load(self,
789789
@abstractmethod
790790
def close(self) -> None:
791791
"""
792-
Close the prepraed statement releasing resources associated with it.
793-
"""
794-
795-
@abstractmethod
796-
def prepare(self) -> None:
797-
"""
798-
Prepare the statement for use.
799-
800-
If the query has already been prepared, not self.closed,
801-
the implementation *must* prepare it again.
802-
803-
This can be useful for forcing the update of a plan.
792+
Close the prepared statement releasing resources associated with it.
804793
"""
805794

806795
class StoredProcedure(

postgresql/driver/pq3.py

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,7 @@ def __init__(self, statement_id, database):
10071007
self.database = database
10081008
self._pq_xact = None
10091009
self._pq_statement_id = None
1010-
self.closed = True
1010+
self.closed = None
10111011

10121012
def __repr__(self):
10131013
return '<{mod}.{name}[{ci}] {state}>'.format(
@@ -1030,44 +1030,44 @@ def state(self) -> str:
10301030

10311031
@property
10321032
def column_names(self):
1033-
if self.closed:
1034-
self.prepare()
1033+
if self.closed is None:
1034+
self._fini()
10351035
if self._output is not None:
10361036
return list(self.database.typio.decodes(self._output.keys()))
10371037

10381038
@property
10391039
def parameter_types(self):
1040-
if self.closed:
1041-
self.prepare()
1040+
if self.closed is None:
1041+
self._fini()
10421042
if self._input is not None:
10431043
return [self.database.typio.type_from_oid(x) for x in self._input]
10441044

10451045
@property
10461046
def column_types(self):
1047-
if self.closed:
1048-
self.prepare()
1047+
if self.closed is None:
1048+
self._fini()
10491049
if self._output is not None:
10501050
return [
10511051
self.database.typio.type_from_oid(x[3]) for x in self._output
10521052
]
10531053

10541054
@property
10551055
def pg_parameter_types(self):
1056-
if self.closed:
1057-
self.prepare()
1056+
if self.closed is None:
1057+
self._fini()
10581058
return self._input
10591059

10601060
@property
10611061
def pg_column_types(self):
1062-
if self.closed:
1063-
self.prepare()
1062+
if self.closed is None:
1063+
self._fini()
10641064
if self._output is not None:
10651065
return [x[3] for x in self._output]
10661066

10671067
@property
10681068
def sql_column_types(self):
1069-
if self.closed:
1070-
self.prepare()
1069+
if self.closed is None:
1070+
self._fini()
10711071
if self._output is not None:
10721072
return [
10731073
pg_types.oid_to_sql_name.get(x) or \
@@ -1077,8 +1077,8 @@ def sql_column_types(self):
10771077

10781078
@property
10791079
def sql_parameter_types(self):
1080-
if self.closed:
1081-
self.prepare()
1080+
if self.closed is None:
1081+
self._fini()
10821082
if self._input is not None:
10831083
return [
10841084
pg_types.oid_to_sql_name.get(x) or \
@@ -1087,20 +1087,9 @@ def sql_parameter_types(self):
10871087
]
10881088

10891089
def close(self):
1090-
if not self.closed:
1090+
if not (self.closed is True):
10911091
self.database._closestatements.append(self._pq_statement_id)
10921092
self.closed = True
1093-
self._pq_statement_id = None
1094-
self._pq_xact = None
1095-
1096-
def prepare(self):
1097-
# If there's no _init_xact or the _init_xact is not the current
1098-
# transaction
1099-
if self._pq_xact is None \
1100-
or self._pq_xact is not self.database._pq_xact:
1101-
self._init()
1102-
# Finalize the statement for use. It should be ready.
1103-
self._fini()
11041093

11051094
def ife_snapshot_text(self):
11061095
s = ""
@@ -1202,8 +1191,8 @@ def _fini(self):
12021191
self._pq_xact = None
12031192

12041193
def __call__(self, *parameters, **kw):
1205-
if self.closed:
1206-
self.prepare()
1194+
if self.closed is None:
1195+
self._fini()
12071196
# Tuple output per the results of DescribeStatement.
12081197
##
12091198
cursor = Cursor.from_statement(parameters, self, **kw)
@@ -1213,8 +1202,8 @@ def __call__(self, *parameters, **kw):
12131202
__iter__ = __call__
12141203

12151204
def first(self, *parameters):
1216-
if self.closed:
1217-
self.prepare()
1205+
if self.closed is None:
1206+
self._fini()
12181207
# Parameters? Build em'.
12191208
c = self.database
12201209

@@ -1382,8 +1371,8 @@ def load(self, iterable, tps = None):
13821371
13831372
In cases of ``COPY ... FROM STDIN``, iterable must be an iterable `bytes`.
13841373
"""
1385-
if self.closed:
1386-
self.prepare()
1374+
if self.closed is None:
1375+
self._fini()
13871376
if not self._input:
13881377
return self._copy_data_in(iterable, tps = tps)
13891378
else:

postgresql/test/test_driver.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,27 @@ def raise_exc(l):
295295
raise v
296296
self.failUnlessRaises(pg_exc.QueryCanceledError, raise_exc, rl)
297297

298+
def testItsClosed(self):
299+
ps = self.db.prepare("SELECT 1")
300+
c = ps(scroll = True)
301+
#
302+
c.close()
303+
self.failUnlessRaises(pg_exc.CursorNameError, c.read)
304+
self.failUnlessEqual(ps.first(), 1)
305+
#
306+
ps.close()
307+
self.failUnlessRaises(pg_exc.StatementNameError, ps.first)
308+
#
309+
self.db.close()
310+
self.failUnlessRaises(
311+
pg_exc.ConnectionDoesNotExistError,
312+
self.db.execute, "foo"
313+
)
314+
# No errors, it's already closed.
315+
ps.close()
316+
c.close()
317+
self.db.close()
318+
298319
def testStatementParameters(self):
299320
# too few and takes one
300321
ps = self.db.prepare("select $1::integer")

0 commit comments

Comments
 (0)