On Wed, Sep 6, 2017 at 4:06 PM, <
d...@numetric.com> wrote:
> It happens implicitly when iterating over the cursor to get the results.
> Here's an example using fetchmany:
I noticed that you're using the Postgresql dialect directly, note
there is a Redshift variant of this dialect here:
https://github.com/sqlalchemy-redshift/sqlalchemy-redshift
This dialect doesn't have anything specific going on with the cursor,
so is unlikely to solve this issue. However it might be good to use
this dialect for its other Redshift features anyway (as well as that
it's a more appropriate place if some workaround is needed specific to
Redshift).
As far as the cursor, SQLAlchemy opens absolutely one cursor for the
duration of any statement. Test:
from sqlalchemy import create_engine
engine = create_engine('postgres+psycopg2://scott:tiger@localhost/test')
print "INITIALIZE ENGINE FIRST, DOES A FEW THINGS...."
engine.connect().close()
print "OK, READY TO RUN A SINGLE STATEMENT!!!"
with engine.connect().execution_options(stream_results=True) as conn:
results = conn.execute("SELECT 1 WHERE 1=0")
data = [r for r in results]
assert not data
patch with print statements:
diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py
b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
index 31792a492..af8367018 100644
--- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py
+++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
@@ -429,6 +429,7 @@ _server_side_id = util.counter()
class PGExecutionContext_psycopg2(PGExecutionContext):
def create_server_side_cursor(self):
+ print "CREATE PG SERVER SIDE CURSOR!"
# use server-side cursors:
#
http://lists.initd.org/pipermail/psycopg/2007-January/005251.html
ident = "c_%s_%s" % (hex(id(self))[2:],
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index 8b72c0001..9a0a1e55a 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -945,6 +945,7 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
return use_server_side
def create_cursor(self):
+ print "CREATE CURSOR!!!"
if self._use_server_side_cursor():
self._is_server_side = True
return self.create_server_side_cursor()
output:
INITIALIZE ENGINE FIRST, DOES A FEW THINGS....
CREATE CURSOR!!!
CREATE CURSOR!!!
CREATE CURSOR!!!
OK, READY TO RUN A SINGLE STATEMENT!!!
CREATE CURSOR!!!
CREATE PG SERVER SIDE CURSOR!
it is also the case that this cursor is explicitly closed, provided
you have fully fetched all results on the result. If you are getting a
result set, then not fully fetching or closing the result, then doing
another statement, that will *not* have necessarily closed the
previous cursor; it happens upon garbage collection too but its better
to close explicitly if you aren't fully fetching.
the stack trace you have shows that psycopg2 is referring to a new
cursor at the point of fetchmany() being called. I don't have
insight into why that might be.
It might be nice to check however that Redshift is allowing more than
one server side cursor to be opened for the *whole lifespan* of the
database connection - as the connections here are stored in a
connection pool, it is certainly the case that after one cursor is
closed, if you keep doing things with the engine, another cursor will
be opened on that connection.