From 5f5cd4cca9130c5dc0891ecdd52ee175cc538aa6 Mon Sep 17 00:00:00 2001 From: Giuseppe Sucameli Date: Thu, 24 Oct 2013 23:26:02 +0200 Subject: [PATCH] dbmanager: be sure to close db cursors (fix #7679) --- .../db_plugins/postgis/connector.py | 207 ++++++++++-------- 1 file changed, 117 insertions(+), 90 deletions(-) diff --git a/python/plugins/db_manager/db_plugins/postgis/connector.py b/python/plugins/db_manager/db_plugins/postgis/connector.py index 86e69f9957c..606b2bffd98 100644 --- a/python/plugins/db_manager/db_plugins/postgis/connector.py +++ b/python/plugins/db_manager/db_plugins/postgis/connector.py @@ -66,22 +66,22 @@ class PostGisDBConnector(DBConnector): def _checkSpatial(self): """ check whether postgis_version is present in catalog """ - c = self._get_cursor() - self._execute(c, u"SELECT COUNT(*) FROM pg_proc WHERE proname = 'postgis_version'") - self.has_spatial = c.fetchone()[0] > 0 + c = self._execute(None, u"SELECT COUNT(*) FROM pg_proc WHERE proname = 'postgis_version'") + self.has_spatial = self._fetchone(c)[0] > 0 + self._close_cursor(c) return self.has_spatial def _checkRaster(self): """ check whether postgis_version is present in catalog """ - c = self._get_cursor() - self._execute(c, u"SELECT COUNT(*) FROM pg_proc WHERE proname = 'postgis_raster_lib_version'") - self.has_raster = c.fetchone()[0] > 0 + c = self._execute(None, u"SELECT COUNT(*) FROM pg_proc WHERE proname = 'postgis_raster_lib_version'") + self.has_raster = self._fetchone(c)[0] > 0 + self._close_cursor(c) return self.has_raster def _checkGeometryColumnsTable(self): - c = self._get_cursor() - self._execute(c, u"SELECT relkind = 'v' FROM pg_class WHERE relname = 'geometry_columns' AND relkind IN ('v', 'r')") - res = c.fetchone() + c = self._execute(None, u"SELECT relkind = 'v' FROM pg_class WHERE relname = 'geometry_columns' AND relkind IN ('v', 'r')") + res = self._fetchone(c) + self._close_cursor(c) self.has_geometry_columns = (res != None and len(res) != 0) if not self.has_geometry_columns: @@ -94,9 +94,9 @@ class PostGisDBConnector(DBConnector): return self.has_geometry_columns def _checkRasterColumnsTable(self): - c = self._get_cursor() - self._execute(c, u"SELECT relkind = 'v' FROM pg_class WHERE relname = 'raster_columns' AND relkind IN ('v', 'r')") - res = c.fetchone() + c = self._execute(None, u"SELECT relkind = 'v' FROM pg_class WHERE relname = 'raster_columns' AND relkind IN ('v', 'r')") + res = self._fetchone(c) + self._close_cursor(c) self.has_raster_columns = (res != None and len(res) != 0) if not self.has_raster_columns: @@ -108,9 +108,10 @@ class PostGisDBConnector(DBConnector): return self.has_raster_columns def getInfo(self): - c = self._get_cursor() - self._execute(c, u"SELECT version()") - return c.fetchone() + c = self._execute(None, u"SELECT version()") + res = self._fetchone(c) + self._close_cursor(c) + return res def getSpatialInfo(self): """ returns tuple about postgis support: @@ -123,13 +124,13 @@ class PostGisDBConnector(DBConnector): if not self.has_spatial: return - c = self._get_cursor() try: - self._execute(c, u"SELECT postgis_lib_version(), postgis_geos_version(), postgis_proj_version(), postgis_scripts_installed(), postgis_scripts_released()") + c = self._execute(None, u"SELECT postgis_lib_version(), postgis_geos_version(), postgis_proj_version(), postgis_scripts_installed(), postgis_scripts_released()") except DbError: return - - return c.fetchone() + res = self._fetchone(c) + self._close_cursor(c) + return res def hasSpatialSupport(self): return self.has_spatial @@ -159,17 +160,19 @@ class PostGisDBConnector(DBConnector): def getDatabasePrivileges(self): """ db privileges: (can create schemas, can create temp. tables) """ sql = u"SELECT has_database_privilege(%(d)s, 'CREATE'), has_database_privilege(%(d)s, 'TEMP')" % { 'd' : self.quoteString(self.dbname) } - c = self._get_cursor() - self._execute(c, sql) - return c.fetchone() + c = self._execute(None, sql) + res = self._fetchone(c) + self._close_cursor(c) + return res def getSchemaPrivileges(self, schema): """ schema privileges: (can create new objects, can access objects in schema) """ schema = 'current_schema()' if schema == None else self.quoteString(schema) sql = u"SELECT has_schema_privilege(%(s)s, 'CREATE'), has_schema_privilege(%(s)s, 'USAGE')" % { 's' : schema } - c = self._get_cursor() - self._execute(c, sql) - return c.fetchone() + c = self._execute(None, sql) + res = self._fetchone(c) + self._close_cursor(c) + return res def getTablePrivileges(self, table): """ table privileges: (select, insert, update, delete) """ @@ -182,17 +185,20 @@ class PostGisDBConnector(DBConnector): t = self.quoteId( table ) sql = u"""SELECT has_table_privilege(%(t)s, 'SELECT'), has_table_privilege(%(t)s, 'INSERT'), has_table_privilege(%(t)s, 'UPDATE'), has_table_privilege(%(t)s, 'DELETE')""" % { 't': self.quoteString(t) } - c = self._get_cursor() - self._execute(c, sql) - return c.fetchone() + c = self._execute(None, sql) + res = self._fetchone(c) + self._close_cursor(c) + return res def getSchemas(self): """ get list of schemas in tuples: (oid, name, owner, perms) """ - c = self._get_cursor() sql = u"SELECT oid, nspname, pg_get_userbyid(nspowner), nspacl, pg_catalog.obj_description(oid) FROM pg_namespace WHERE nspname !~ '^pg_' AND nspname != 'information_schema' ORDER BY nspname" - self._execute(c, sql) - return c.fetchall() + + c = self._execute(None, sql) + res = self._fetchall(c) + self._close_cursor(c) + return res def getTables(self, schema=None): """ get list of tables """ @@ -222,8 +228,6 @@ class PostGisDBConnector(DBConnector): except DbError: pass - c = self._get_cursor() - sys_tables = [ "spatial_ref_sys", "geography_columns", "geometry_columns", "raster_columns", "raster_overviews" ] @@ -242,13 +246,13 @@ class PostGisDBConnector(DBConnector): WHERE cla.relkind IN ('v', 'r') """ + schema_where + """ ORDER BY nsp.nspname, cla.relname""" - self._execute(c, sql) - - for tbl in c.fetchall(): + c = self._execute(None, sql) + for tbl in self._fetchall(c): if tablenames.count( (tbl[1], tbl[0]) ) <= 0: item = list(tbl) item.insert(0, Table.TableType) items.append( item ) + self._close_cursor(c) return sorted( items, cmp=lambda x,y: cmp((x[2],x[1]), (y[2],y[1])) ) @@ -272,8 +276,6 @@ class PostGisDBConnector(DBConnector): if not self.has_spatial: return [] - c = self._get_cursor() - if schema: schema_where = u" AND nspname = %s " % self.quoteString(schema) else: @@ -313,13 +315,14 @@ class PostGisDBConnector(DBConnector): WHERE cla.relkind IN ('v', 'r') """ + schema_where + """ ORDER BY nsp.nspname, cla.relname, att.attname""" - self._execute(c, sql) - items = [] - for i, tbl in enumerate(c.fetchall()): + + c = self._execute(None, sql) + for i, tbl in enumerate(self._fetchall(c)): item = list(tbl) item.insert(0, Table.VectorType) items.append( item ) + self._close_cursor(c) return items @@ -345,8 +348,6 @@ class PostGisDBConnector(DBConnector): if not self.has_raster: return [] - c = self._get_cursor() - if schema: schema_where = u" AND nspname = %s " % self.quoteString(schema) else: @@ -387,25 +388,26 @@ class PostGisDBConnector(DBConnector): WHERE cla.relkind IN ('v', 'r') """ + schema_where + """ ORDER BY nsp.nspname, cla.relname, att.attname""" - self._execute(c, sql) - items = [] - for i, tbl in enumerate(c.fetchall()): + + c = self._execute(None, sql) + for i, tbl in enumerate(self._fetchall(c)): item = list(tbl) item.insert(0, Table.RasterType) items.append( item ) + self._close_cursor(c) return items def getTableRowCount(self, table): - c = self._get_cursor() - self._execute( c, u"SELECT COUNT(*) FROM %s" % self.quoteId(table) ) - return c.fetchone()[0] + c = self._execute(None, u"SELECT COUNT(*) FROM %s" % self.quoteId(table)) + res = self._fetchone(c)[0] + self._close_cursor(c) + return res def getTableFields(self, table): """ return list of columns in table """ - c = self._get_cursor() schema, tablename = self.getSchemaTableName(table) schema_where = u" AND nspname=%s " % self.quoteString(schema) if schema is not None else "" @@ -428,8 +430,10 @@ class PostGisDBConnector(DBConnector): a.attnum > 0 AND c.relname=%s %s ORDER BY a.attnum""" % (self.quoteString(tablename), schema_where) - self._execute(c, sql) - return c.fetchall() + c = self._execute(None, sql) + res = self._fetchall(c) + self._close_cursor(c) + return res def getTableIndexes(self, table): """ get info about table's indexes. ignore primary key constraint index, they get listed in constaints """ @@ -442,13 +446,13 @@ class PostGisDBConnector(DBConnector): JOIN pg_namespace nsp ON pg_class.relnamespace = nsp.oid WHERE pg_class.relname=%s %s AND indisprimary != 't' """ % (self.quoteString(tablename), schema_where) - c = self._get_cursor() - self._execute(c, sql) - return c.fetchall() + c = self._execute(None, sql) + res = self._fetchall(c) + self._close_cursor(c) + return res def getTableConstraints(self, table): - c = self._get_cursor() schema, tablename = self.getSchemaTableName(table) schema_where = u" AND nspname=%s " % self.quoteString(schema) if schema is not None else "" @@ -460,12 +464,13 @@ class PostGisDBConnector(DBConnector): JOIN pg_namespace nsp ON t.relnamespace = nsp.oid WHERE t.relname = %s %s """ % (self.quoteString(tablename), schema_where) - self._execute(c, sql) - return c.fetchall() + c = self._execute(None, sql) + res = self._fetchall(c) + self._close_cursor(c) + return res def getTableTriggers(self, table): - c = self._get_cursor() schema, tablename = self.getSchemaTableName(table) schema_where = u" AND nspname=%s " % self.quoteString(schema) if schema is not None else "" @@ -476,8 +481,10 @@ class PostGisDBConnector(DBConnector): JOIN pg_namespace nsp ON t.relnamespace = nsp.oid WHERE t.relname = %s %s """ % (self.quoteString(tablename), schema_where) - self._execute(c, sql) - return c.fetchall() + c = self._execute(None, sql) + res = self._fetchall(c) + self._close_cursor(c) + return res def enableAllTableTriggers(self, enable, table): """ enable or disable all triggers on table """ @@ -496,7 +503,6 @@ class PostGisDBConnector(DBConnector): def getTableRules(self, table): - c = self._get_cursor() schema, tablename = self.getSchemaTableName(table) schema_where = u" AND schemaname=%s " % self.quoteString(schema) if schema is not None else "" @@ -504,8 +510,10 @@ class PostGisDBConnector(DBConnector): sql = u"""SELECT rulename, definition FROM pg_rules WHERE tablename=%s %s """ % (self.quoteString(tablename), schema_where) - self._execute(c, sql) - return c.fetchall() + c = self._execute(None, sql) + res = self._fetchall(c) + self._close_cursor(c) + return res def deleteTableRule(self, rule, table): """ delete rule on table """ @@ -515,28 +523,33 @@ class PostGisDBConnector(DBConnector): def getTableExtent(self, table, geom): """ find out table extent """ - c = self._get_cursor() subquery = u"SELECT st_extent(%s) AS extent FROM %s" % ( self.quoteId(geom), self.quoteId(table) ) sql = u"SELECT st_xmin(extent), st_ymin(extent), st_xmax(extent), st_ymax(extent) FROM (%s) AS subquery" % subquery - self._execute(c, sql) - return c.fetchone() + + c = self._execute(None, sql) + res = self._fetchone(c) + self._close_cursor(c) + return res def getTableEstimatedExtent(self, table, geom): """ find out estimated extent (from the statistics) """ if self.isRasterTable(table): return - c = self._get_cursor() schema, tablename = self.getSchemaTableName(table) schema_part = u"%s," % self.quoteString(schema) if schema is not None else "" subquery = u"SELECT st_estimated_extent(%s%s,%s) AS extent" % (schema_part, self.quoteString(tablename), self.quoteString(geom)) sql = u"""SELECT st_xmin(extent), st_ymin(extent), st_xmax(extent), st_ymax(extent) FROM (%s) AS subquery """ % subquery + try: - self._execute(c, sql) + c = self._execute(None, sql) except DbError, e: # no statistics for the current table return - return c.fetchone() + res = self._fetchone(c) + self._close_cursor(c) + return res + def getViewDefinition(self, view): """ returns definition of the view """ @@ -547,8 +560,10 @@ class PostGisDBConnector(DBConnector): sql = u"""SELECT pg_get_viewdef(c.oid) FROM pg_class c JOIN pg_namespace nsp ON c.relnamespace = nsp.oid WHERE relname=%s %s AND relkind='v' """ % (self.quoteString(tablename), schema_where) + c = self._execute(None, sql) - res = c.fetchone() + res = self._fetchone(c) + self._close_cursor(c) return res[0] if res is not None else None def getSpatialRefInfo(self, srid): @@ -556,37 +571,44 @@ class PostGisDBConnector(DBConnector): return try: - c = self._get_cursor() - self._execute(c, "SELECT srtext FROM spatial_ref_sys WHERE srid = '%d'" % srid) - sr = c.fetchone() - if sr == None: - return - srtext = sr[0] - # try to extract just SR name (should be quoted in double quotes) - regex = QRegExp( '"([^"]+)"' ) - if regex.indexIn( srtext ) > -1: - srtext = regex.cap(1) - return srtext + c = self._execute(None, "SELECT srtext FROM spatial_ref_sys WHERE srid = '%d'" % srid) except DbError, e: return + sr = self._fetchone(c) + self._close_cursor(c) + if sr == None: + return + + srtext = sr[0] + # try to extract just SR name (should be quoted in double quotes) + regex = QRegExp( '"([^"]+)"' ) + if regex.indexIn( srtext ) > -1: + srtext = regex.cap(1) + return srtext def isVectorTable(self, table): if self.has_geometry_columns and self.has_geometry_columns_access: schema, tablename = self.getSchemaTableName(table) sql = u"SELECT count(*) FROM geometry_columns WHERE f_table_schema = %s AND f_table_name = %s" % (self.quoteString(schema), self.quoteString(tablename)) + c = self._execute(None, sql) - res = c.fetchone() + res = self._fetchone(c) + self._close_cursor(c) return res != None and res[0] > 0 + return False def isRasterTable(self, table): if self.has_raster_columns and self.has_raster_columns_access: schema, tablename = self.getSchemaTableName(table) sql = u"SELECT count(*) FROM raster_columns WHERE r_table_schema = %s AND r_table_name = %s" % (self.quoteString(schema), self.quoteString(tablename)) + c = self._execute(None, sql) - res = c.fetchone() + res = self._fetchone(c) + self._close_cursor(c) return res != None and res[0] > 0 + return False @@ -631,6 +653,7 @@ class PostGisDBConnector(DBConnector): schema, tablename = self.getSchemaTableName(table) if new_table == tablename: return + c = self._get_cursor() sql = u"ALTER TABLE %s RENAME TO %s" % (self.quoteId(table), self.quoteId(new_table)) @@ -648,6 +671,7 @@ class PostGisDBConnector(DBConnector): schema, tablename = self.getSchemaTableName(table) if new_schema == schema: return + c = self._get_cursor() sql = u"ALTER TABLE %s SET SCHEMA %s" % (self.quoteId(table), self.quoteId(new_schema)) @@ -729,9 +753,9 @@ class PostGisDBConnector(DBConnector): """ run vacuum analyze on a table """ # vacuum analyze must be run outside transaction block - we have to change isolation level self.connection.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) - c = self._get_cursor() sql = u"VACUUM ANALYZE %s" % self.quoteId(table) - self._execute(c, sql) + c = self._execute(None, sql) + self._commit() self.connection.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED) @@ -808,14 +832,16 @@ class PostGisDBConnector(DBConnector): def isGeometryColumn(self, table, column): - c = self._get_cursor() schema, tablename = self.getSchemaTableName(table) schema_where = u" f_table_schema=%s AND " % self.quoteString(schema) if schema is not None else "" sql = u"SELECT count(*) > 0 FROM geometry_columns WHERE %s f_table_name=%s AND f_geometry_column=%s" % (schema_where, self.quoteString(tablename), self.quoteString(column)) - self._execute(c, sql) - return c.fetchone()[0] == 't' + + c = self._execute(None, sql) + res = self._fetchone(c)[0] == 't' + self._close_cursor(c) + return res def addGeometryColumn(self, table, geom_column='geom', geom_type='POINT', srid=-1, dim=2): schema, tablename = self.getSchemaTableName(table) @@ -914,8 +940,9 @@ class PostGisDBConnector(DBConnector): UNION SELECT relname FROM pg_class WHERE relkind IN ('v', 'r') UNION SELECT attname FROM pg_attribute WHERE attnum > 0""" c = self._execute(None, sql) - for row in c.fetchall(): + for row in self._fetchall(c): items.append( row[0] ) + self._close_cursor(c) sql_dict["identifier"] = items return sql_dict