connector.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. """
  2. /***************************************************************************
  3. Name : DB Manager
  4. Description : Database manager plugin for QGIS
  5. Date : May 23, 2011
  6. copyright : (C) 2011 by Giuseppe Sucameli
  7. email : brush.tyler@gmail.com
  8. ***************************************************************************/
  9. /***************************************************************************
  10. * *
  11. * This program is free software; you can redistribute it and/or modify *
  12. * it under the terms of the GNU General Public License as published by *
  13. * the Free Software Foundation; either version 2 of the License, or *
  14. * (at your option) any later version. *
  15. * *
  16. ***************************************************************************/
  17. """
  18. from functools import cmp_to_key
  19. from qgis.core import Qgis, QgsSqliteUtils
  20. from qgis.PyQt.QtCore import QFile
  21. from qgis.PyQt.QtWidgets import QApplication
  22. from ..connector import DBConnector
  23. from ..plugin import ConnectionError, DbError, Table
  24. from qgis.utils import spatialite_connect
  25. import sqlite3 as sqlite
  26. def classFactory():
  27. return SpatiaLiteDBConnector
  28. class SpatiaLiteDBConnector(DBConnector):
  29. def __init__(self, uri):
  30. DBConnector.__init__(self, uri)
  31. self.dbname = uri.database()
  32. if not QFile.exists(self.dbname):
  33. raise ConnectionError(QApplication.translate("DBManagerPlugin", '"{0}" not found').format(self.dbname))
  34. try:
  35. self.connection = spatialite_connect(self._connectionInfo())
  36. except self.connection_error_types() as e:
  37. raise ConnectionError(e)
  38. self._checkSpatial()
  39. self._checkRaster()
  40. def _connectionInfo(self):
  41. return str(self.dbname)
  42. def cancel(self):
  43. # https://www.sqlite.org/c3ref/interrupt.html
  44. # This function causes any pending database operation to abort and return at its earliest opportunity.
  45. if self.connection:
  46. self.connection.interrupt()
  47. @classmethod
  48. def isValidDatabase(self, path):
  49. if not QFile.exists(path):
  50. return False
  51. try:
  52. conn = spatialite_connect(path)
  53. except self.connection_error_types():
  54. return False
  55. isValid = False
  56. try:
  57. c = conn.cursor()
  58. c.execute("SELECT count(*) FROM sqlite_master")
  59. c.fetchone()
  60. isValid = True
  61. except sqlite.DatabaseError:
  62. pass
  63. conn.close()
  64. return isValid
  65. def _checkSpatial(self):
  66. """ check if it's a valid SpatiaLite db """
  67. self.has_spatial = self._checkGeometryColumnsTable()
  68. return self.has_spatial
  69. def _checkRaster(self):
  70. """ check if it's a rasterite db """
  71. self.has_raster = self._checkRasterTables()
  72. return self.has_raster
  73. def _checkGeometryColumnsTable(self):
  74. try:
  75. c = self._get_cursor()
  76. self._execute(c, "SELECT CheckSpatialMetaData()")
  77. v = c.fetchone()[0]
  78. self.has_geometry_columns = v == 1 or v == 3
  79. self.has_spatialite4 = v == 3
  80. except Exception:
  81. self.has_geometry_columns = False
  82. self.has_spatialite4 = False
  83. self.has_geometry_columns_access = self.has_geometry_columns
  84. return self.has_geometry_columns
  85. def _checkRasterTables(self):
  86. c = self._get_cursor()
  87. sql = "SELECT count(*) = 3 FROM sqlite_master WHERE name IN ('layer_params', 'layer_statistics', 'raster_pyramids')"
  88. self._execute(c, sql)
  89. ret = c.fetchone()
  90. return ret and ret[0]
  91. def getInfo(self):
  92. c = self._get_cursor()
  93. self._execute(c, "SELECT sqlite_version()")
  94. return c.fetchone()
  95. def getSpatialInfo(self):
  96. """ returns tuple about SpatiaLite support:
  97. - lib version
  98. - geos version
  99. - proj version
  100. """
  101. if not self.has_spatial:
  102. return
  103. c = self._get_cursor()
  104. try:
  105. self._execute(c, "SELECT spatialite_version(), geos_version(), proj4_version()")
  106. except DbError:
  107. return
  108. return c.fetchone()
  109. def hasSpatialSupport(self):
  110. return self.has_spatial
  111. def hasRasterSupport(self):
  112. return self.has_raster
  113. def hasCustomQuerySupport(self):
  114. return Qgis.QGIS_VERSION[0:3] >= "1.6"
  115. def hasTableColumnEditingSupport(self):
  116. return False
  117. def hasCreateSpatialViewSupport(self):
  118. return True
  119. def fieldTypes(self):
  120. return [
  121. "integer", "bigint", "smallint", # integers
  122. "real", "double", "float", "numeric", # floats
  123. "varchar", "varchar(255)", "character(20)", "text", # strings
  124. "date", "datetime" # date/time
  125. ]
  126. def getSchemas(self):
  127. return None
  128. def getTables(self, schema=None, add_sys_tables=False):
  129. """ get list of tables """
  130. tablenames = []
  131. items = []
  132. sys_tables = QgsSqliteUtils.systemTables()
  133. try:
  134. vectors = self.getVectorTables(schema)
  135. for tbl in vectors:
  136. if not add_sys_tables and tbl[1] in sys_tables:
  137. continue
  138. tablenames.append(tbl[1])
  139. items.append(tbl)
  140. except DbError:
  141. pass
  142. try:
  143. rasters = self.getRasterTables(schema)
  144. for tbl in rasters:
  145. if not add_sys_tables and tbl[1] in sys_tables:
  146. continue
  147. tablenames.append(tbl[1])
  148. items.append(tbl)
  149. except DbError:
  150. pass
  151. c = self._get_cursor()
  152. if self.has_geometry_columns:
  153. # get the R*Tree tables
  154. sql = "SELECT f_table_name, f_geometry_column FROM geometry_columns WHERE spatial_index_enabled = 1"
  155. self._execute(c, sql)
  156. for idx_item in c.fetchall():
  157. sys_tables.append('idx_%s_%s' % idx_item)
  158. sys_tables.append('idx_%s_%s_node' % idx_item)
  159. sys_tables.append('idx_%s_%s_parent' % idx_item)
  160. sys_tables.append('idx_%s_%s_rowid' % idx_item)
  161. sql = "SELECT name, type = 'view' FROM sqlite_master WHERE type IN ('table', 'view')"
  162. self._execute(c, sql)
  163. for tbl in c.fetchall():
  164. if tablenames.count(tbl[0]) <= 0 and not tbl[0].startswith('idx_'):
  165. if not add_sys_tables and tbl[0] in sys_tables:
  166. continue
  167. item = list(tbl)
  168. item.insert(0, Table.TableType)
  169. items.append(item)
  170. for i, tbl in enumerate(items):
  171. tbl.insert(3, tbl[1] in sys_tables)
  172. return sorted(items, key=cmp_to_key(lambda x, y: (x[1] > y[1]) - (x[1] < y[1])))
  173. def getVectorTables(self, schema=None):
  174. """ get list of table with a geometry column
  175. it returns:
  176. name (table name)
  177. type = 'view' (is a view?)
  178. geometry_column:
  179. f_table_name (the table name in geometry_columns may be in a wrong case, use this to load the layer)
  180. f_geometry_column
  181. type
  182. coord_dimension
  183. srid
  184. """
  185. if self.has_geometry_columns:
  186. if self.has_spatialite4:
  187. cols = """CASE geometry_type % 10
  188. WHEN 1 THEN 'POINT'
  189. WHEN 2 THEN 'LINESTRING'
  190. WHEN 3 THEN 'POLYGON'
  191. WHEN 4 THEN 'MULTIPOINT'
  192. WHEN 5 THEN 'MULTILINESTRING'
  193. WHEN 6 THEN 'MULTIPOLYGON'
  194. WHEN 7 THEN 'GEOMETRYCOLLECTION'
  195. END AS gtype,
  196. CASE geometry_type / 1000
  197. WHEN 0 THEN 'XY'
  198. WHEN 1 THEN 'XYZ'
  199. WHEN 2 THEN 'XYM'
  200. WHEN 3 THEN 'XYZM'
  201. ELSE NULL
  202. END AS coord_dimension"""
  203. else:
  204. cols = "g.type,g.coord_dimension"
  205. # get geometry info from geometry_columns if exists
  206. sql = """SELECT m.name, m.type = 'view', g.f_table_name, g.f_geometry_column, %s, g.srid
  207. FROM sqlite_master AS m JOIN geometry_columns AS g ON upper(m.name) = upper(g.f_table_name)
  208. WHERE m.type in ('table', 'view')
  209. ORDER BY m.name, g.f_geometry_column""" % cols
  210. else:
  211. return []
  212. c = self._get_cursor()
  213. self._execute(c, sql)
  214. items = []
  215. for tbl in c.fetchall():
  216. item = list(tbl)
  217. item.insert(0, Table.VectorType)
  218. items.append(item)
  219. return items
  220. def getRasterTables(self, schema=None):
  221. """ get list of table with a geometry column
  222. it returns:
  223. name (table name)
  224. type = 'view' (is a view?)
  225. geometry_column:
  226. r.table_name (the prefix table name, use this to load the layer)
  227. r.geometry_column
  228. srid
  229. """
  230. if not self.has_geometry_columns:
  231. return []
  232. if not self.has_raster:
  233. return []
  234. c = self._get_cursor()
  235. # get geometry info from geometry_columns if exists
  236. sql = """SELECT r.table_name||'_rasters', m.type = 'view', r.table_name, r.geometry_column, g.srid
  237. FROM sqlite_master AS m JOIN geometry_columns AS g ON upper(m.name) = upper(g.f_table_name)
  238. JOIN layer_params AS r ON upper(REPLACE(m.name, '_metadata', '')) = upper(r.table_name)
  239. WHERE m.type in ('table', 'view') AND upper(m.name) = upper(r.table_name||'_metadata')
  240. ORDER BY r.table_name"""
  241. self._execute(c, sql)
  242. items = []
  243. for i, tbl in enumerate(c.fetchall()):
  244. item = list(tbl)
  245. item.insert(0, Table.RasterType)
  246. items.append(item)
  247. return items
  248. def getTableRowCount(self, table):
  249. c = self._get_cursor()
  250. self._execute(c, "SELECT COUNT(*) FROM %s" % self.quoteId(table))
  251. ret = c.fetchone()
  252. return ret[0] if ret is not None else None
  253. def getTableFields(self, table):
  254. """ return list of columns in table """
  255. c = self._get_cursor()
  256. sql = "PRAGMA table_info(%s)" % (self.quoteId(table))
  257. self._execute(c, sql)
  258. return c.fetchall()
  259. def getTableIndexes(self, table):
  260. """ get info about table's indexes """
  261. c = self._get_cursor()
  262. sql = "PRAGMA index_list(%s)" % (self.quoteId(table))
  263. self._execute(c, sql)
  264. indexes = c.fetchall()
  265. for i, idx in enumerate(indexes):
  266. # sqlite has changed the number of columns returned by index_list since 3.8.9
  267. # I am not using self.getInfo() here because this behavior
  268. # can be changed back without notice as done for index_info, see:
  269. # http://repo.or.cz/sqlite.git/commit/53555d6da78e52a430b1884b5971fef33e9ccca4
  270. if len(idx) == 3:
  271. num, name, unique = idx
  272. if len(idx) == 5:
  273. num, name, unique, createdby, partial = idx
  274. sql = "PRAGMA index_info(%s)" % (self.quoteId(name))
  275. self._execute(c, sql)
  276. idx = [num, name, unique]
  277. cols = [
  278. cid
  279. for seq, cid, cname in c.fetchall()
  280. ]
  281. idx.append(cols)
  282. indexes[i] = idx
  283. return indexes
  284. def getTableConstraints(self, table):
  285. return None
  286. def getTableTriggers(self, table):
  287. c = self._get_cursor()
  288. schema, tablename = self.getSchemaTableName(table)
  289. sql = "SELECT name, sql FROM sqlite_master WHERE tbl_name = %s AND type = 'trigger'" % (
  290. self.quoteString(tablename))
  291. self._execute(c, sql)
  292. return c.fetchall()
  293. def deleteTableTrigger(self, trigger, table=None):
  294. """Deletes trigger """
  295. sql = "DROP TRIGGER %s" % self.quoteId(trigger)
  296. self._execute_and_commit(sql)
  297. def getTableExtent(self, table, geom):
  298. """ find out table extent """
  299. schema, tablename = self.getSchemaTableName(table)
  300. c = self._get_cursor()
  301. if self.isRasterTable(table):
  302. tablename = tablename.replace('_rasters', '_metadata')
  303. geom = 'geometry'
  304. sql = """SELECT Min(MbrMinX(%(geom)s)), Min(MbrMinY(%(geom)s)), Max(MbrMaxX(%(geom)s)), Max(MbrMaxY(%(geom)s))
  305. FROM %(table)s """ % {'geom': self.quoteId(geom),
  306. 'table': self.quoteId(tablename)}
  307. self._execute(c, sql)
  308. return c.fetchone()
  309. def getViewDefinition(self, view):
  310. """ returns definition of the view """
  311. schema, tablename = self.getSchemaTableName(view)
  312. sql = "SELECT sql FROM sqlite_master WHERE type = 'view' AND name = %s" % self.quoteString(tablename)
  313. c = self._execute(None, sql)
  314. ret = c.fetchone()
  315. return ret[0] if ret is not None else None
  316. def getSpatialRefInfo(self, srid):
  317. sql = "SELECT ref_sys_name FROM spatial_ref_sys WHERE srid = %s" % self.quoteString(srid)
  318. c = self._execute(None, sql)
  319. ret = c.fetchone()
  320. return ret[0] if ret is not None else None
  321. def isVectorTable(self, table):
  322. if self.has_geometry_columns:
  323. schema, tablename = self.getSchemaTableName(table)
  324. sql = "SELECT count(*) FROM geometry_columns WHERE upper(f_table_name) = upper(%s)" % self.quoteString(
  325. tablename)
  326. c = self._execute(None, sql)
  327. ret = c.fetchone()
  328. return ret is not None and ret[0] > 0
  329. return True
  330. def isRasterTable(self, table):
  331. if self.has_geometry_columns and self.has_raster:
  332. schema, tablename = self.getSchemaTableName(table)
  333. if not tablename.endswith("_rasters"):
  334. return False
  335. sql = """SELECT count(*)
  336. FROM layer_params AS r JOIN geometry_columns AS g
  337. ON upper(r.table_name||'_metadata') = upper(g.f_table_name)
  338. WHERE upper(r.table_name) = upper(REPLACE(%s, '_rasters', ''))""" % self.quoteString(
  339. tablename)
  340. c = self._execute(None, sql)
  341. ret = c.fetchone()
  342. return ret is not None and ret[0] > 0
  343. return False
  344. def createTable(self, table, field_defs, pkey):
  345. """Creates ordinary table
  346. 'fields' is array containing field definitions
  347. 'pkey' is the primary key name
  348. """
  349. if len(field_defs) == 0:
  350. return False
  351. sql = "CREATE TABLE %s (" % self.quoteId(table)
  352. sql += ", ".join(field_defs)
  353. if pkey is not None and pkey != "":
  354. sql += ", PRIMARY KEY (%s)" % self.quoteId(pkey)
  355. sql += ")"
  356. self._execute_and_commit(sql)
  357. return True
  358. def deleteTable(self, table):
  359. """Deletes table from the database """
  360. if self.isRasterTable(table):
  361. return False
  362. c = self._get_cursor()
  363. sql = "DROP TABLE %s" % self.quoteId(table)
  364. self._execute(c, sql)
  365. schema, tablename = self.getSchemaTableName(table)
  366. sql = "DELETE FROM geometry_columns WHERE upper(f_table_name) = upper(%s)" % self.quoteString(tablename)
  367. self._execute(c, sql)
  368. self._commit()
  369. return True
  370. def emptyTable(self, table):
  371. """Deletes all rows from table """
  372. if self.isRasterTable(table):
  373. return False
  374. sql = "DELETE FROM %s" % self.quoteId(table)
  375. self._execute_and_commit(sql)
  376. def renameTable(self, table, new_table):
  377. """ rename a table """
  378. schema, tablename = self.getSchemaTableName(table)
  379. if new_table == tablename:
  380. return
  381. if self.isRasterTable(table):
  382. return False
  383. c = self._get_cursor()
  384. sql = "ALTER TABLE %s RENAME TO %s" % (self.quoteId(table), self.quoteId(new_table))
  385. self._execute(c, sql)
  386. # update geometry_columns
  387. if self.has_geometry_columns:
  388. sql = "UPDATE geometry_columns SET f_table_name = %s WHERE upper(f_table_name) = upper(%s)" % (
  389. self.quoteString(new_table), self.quoteString(tablename))
  390. self._execute(c, sql)
  391. self._commit()
  392. return True
  393. def moveTable(self, table, new_table, new_schema=None):
  394. return self.renameTable(table, new_table)
  395. def createView(self, view, query):
  396. sql = "CREATE VIEW %s AS %s" % (self.quoteId(view), query)
  397. self._execute_and_commit(sql)
  398. def deleteView(self, view):
  399. c = self._get_cursor()
  400. sql = "DROP VIEW %s" % self.quoteId(view)
  401. self._execute(c, sql)
  402. # update geometry_columns
  403. if self.has_geometry_columns:
  404. sql = "DELETE FROM geometry_columns WHERE f_table_name = %s" % self.quoteString(view)
  405. self._execute(c, sql)
  406. self._commit()
  407. def renameView(self, view, new_name):
  408. """ rename view """
  409. return self.renameTable(view, new_name)
  410. def createSpatialView(self, view, query):
  411. self.createView(view, query)
  412. # get type info about the view
  413. sql = "PRAGMA table_info(%s)" % self.quoteString(view)
  414. c = self._execute(None, sql)
  415. geom_col = None
  416. for r in c.fetchall():
  417. if r[2].upper() in ('POINT', 'LINESTRING', 'POLYGON',
  418. 'MULTIPOINT', 'MULTILINESTRING', 'MULTIPOLYGON'):
  419. geom_col = r[1]
  420. break
  421. if geom_col is None:
  422. return
  423. # get geometry type and srid
  424. sql = "SELECT geometrytype(%s), srid(%s) FROM %s LIMIT 1" % (self.quoteId(geom_col), self.quoteId(geom_col), self.quoteId(view))
  425. c = self._execute(None, sql)
  426. r = c.fetchone()
  427. if r is None:
  428. return
  429. gtype, gsrid = r
  430. gdim = 'XY'
  431. if ' ' in gtype:
  432. zm = gtype.split(' ')[1]
  433. gtype = gtype.split(' ')[0]
  434. gdim += zm
  435. try:
  436. wkbType = ('POINT', 'LINESTRING', 'POLYGON', 'MULTIPOINT', 'MULTILINESTRING', 'MULTIPOLYGON').index(gtype) + 1
  437. except:
  438. wkbType = 0
  439. if 'Z' in gdim:
  440. wkbType += 1000
  441. if 'M' in gdim:
  442. wkbType += 2000
  443. sql = """INSERT INTO geometry_columns (f_table_name, f_geometry_column, geometry_type, coord_dimension, srid, spatial_index_enabled)
  444. VALUES (%s, %s, %s, %s, %s, 0)""" % (self.quoteId(view), self.quoteId(geom_col), wkbType, len(gdim), gsrid)
  445. self._execute_and_commit(sql)
  446. def runVacuum(self):
  447. """ run vacuum on the db """
  448. # Workaround http://bugs.python.org/issue28518
  449. self.connection.isolation_level = None
  450. c = self._get_cursor()
  451. c.execute('VACUUM')
  452. self.connection.isolation_level = '' # reset to default isolation
  453. def addTableColumn(self, table, field_def):
  454. """Adds a column to table """
  455. sql = "ALTER TABLE %s ADD %s" % (self.quoteId(table), field_def)
  456. self._execute(None, sql)
  457. sql = "SELECT InvalidateLayerStatistics(%s)" % (self.quoteId(table))
  458. self._execute(None, sql)
  459. sql = "SELECT UpdateLayerStatistics(%s)" % (self.quoteId(table))
  460. self._execute(None, sql)
  461. self._commit()
  462. return True
  463. def deleteTableColumn(self, table, column):
  464. """Deletes column from a table """
  465. if not self.isGeometryColumn(table, column):
  466. return False # column editing not supported
  467. # delete geometry column correctly
  468. schema, tablename = self.getSchemaTableName(table)
  469. sql = "SELECT DiscardGeometryColumn(%s, %s)" % (self.quoteString(tablename), self.quoteString(column))
  470. self._execute_and_commit(sql)
  471. def updateTableColumn(self, table, column, new_name, new_data_type=None, new_not_null=None, new_default=None, comment=None):
  472. return False # column editing not supported
  473. def renameTableColumn(self, table, column, new_name):
  474. """ rename column in a table """
  475. return False # column editing not supported
  476. def setColumnType(self, table, column, data_type):
  477. """Changes column type """
  478. return False # column editing not supported
  479. def setColumnDefault(self, table, column, default):
  480. """Changes column's default value. If default=None drop default value """
  481. return False # column editing not supported
  482. def setColumnNull(self, table, column, is_null):
  483. """Changes whether column can contain null values """
  484. return False # column editing not supported
  485. def isGeometryColumn(self, table, column):
  486. c = self._get_cursor()
  487. schema, tablename = self.getSchemaTableName(table)
  488. sql = "SELECT count(*) > 0 FROM geometry_columns WHERE upper(f_table_name) = upper(%s) AND upper(f_geometry_column) = upper(%s)" % (
  489. self.quoteString(tablename), self.quoteString(column))
  490. self._execute(c, sql)
  491. return c.fetchone()[0] == 't'
  492. def addGeometryColumn(self, table, geom_column='geometry', geom_type='POINT', srid=-1, dim=2):
  493. schema, tablename = self.getSchemaTableName(table)
  494. sql = "SELECT AddGeometryColumn(%s, %s, %d, %s, %s)" % (
  495. self.quoteString(tablename), self.quoteString(geom_column), srid, self.quoteString(geom_type), dim)
  496. self._execute_and_commit(sql)
  497. def deleteGeometryColumn(self, table, geom_column):
  498. return self.deleteTableColumn(table, geom_column)
  499. def addTableUniqueConstraint(self, table, column):
  500. """Adds a unique constraint to a table """
  501. return False # constraints not supported
  502. def deleteTableConstraint(self, table, constraint):
  503. """Deletes constraint in a table """
  504. return False # constraints not supported
  505. def addTablePrimaryKey(self, table, column):
  506. """Adds a primery key (with one column) to a table """
  507. sql = "ALTER TABLE %s ADD PRIMARY KEY (%s)" % (self.quoteId(table), self.quoteId(column))
  508. self._execute_and_commit(sql)
  509. def createTableIndex(self, table, name, column, unique=False):
  510. """Creates index on one column using default options """
  511. unique_str = "UNIQUE" if unique else ""
  512. sql = "CREATE %s INDEX %s ON %s (%s)" % (
  513. unique_str, self.quoteId(name), self.quoteId(table), self.quoteId(column))
  514. self._execute_and_commit(sql)
  515. def deleteTableIndex(self, table, name):
  516. schema, tablename = self.getSchemaTableName(table)
  517. sql = "DROP INDEX %s" % self.quoteId((schema, name))
  518. self._execute_and_commit(sql)
  519. def createSpatialIndex(self, table, geom_column='geometry'):
  520. if self.isRasterTable(table):
  521. return False
  522. schema, tablename = self.getSchemaTableName(table)
  523. sql = "SELECT CreateSpatialIndex(%s, %s)" % (self.quoteString(tablename), self.quoteString(geom_column))
  524. self._execute_and_commit(sql)
  525. def deleteSpatialIndex(self, table, geom_column='geometry'):
  526. if self.isRasterTable(table):
  527. return False
  528. schema, tablename = self.getSchemaTableName(table)
  529. try:
  530. sql = "SELECT DiscardSpatialIndex(%s, %s)" % (self.quoteString(tablename), self.quoteString(geom_column))
  531. self._execute_and_commit(sql)
  532. except DbError:
  533. sql = "SELECT DeleteSpatialIndex(%s, %s)" % (self.quoteString(tablename), self.quoteString(geom_column))
  534. self._execute_and_commit(sql)
  535. # delete the index table
  536. idx_table_name = "idx_%s_%s" % (tablename, geom_column)
  537. self.deleteTable(idx_table_name)
  538. def hasSpatialIndex(self, table, geom_column='geometry'):
  539. if not self.has_geometry_columns or self.isRasterTable(table):
  540. return False
  541. c = self._get_cursor()
  542. schema, tablename = self.getSchemaTableName(table)
  543. sql = "SELECT spatial_index_enabled FROM geometry_columns WHERE upper(f_table_name) = upper(%s) AND upper(f_geometry_column) = upper(%s)" % (
  544. self.quoteString(tablename), self.quoteString(geom_column))
  545. self._execute(c, sql)
  546. row = c.fetchone()
  547. return row is not None and row[0] == 1
  548. def execution_error_types(self):
  549. return sqlite.Error, sqlite.ProgrammingError, sqlite.Warning
  550. def connection_error_types(self):
  551. return sqlite.InterfaceError, sqlite.OperationalError
  552. # moved into the parent class: DbConnector._execute()
  553. # def _execute(self, cursor, sql):
  554. # pass
  555. # moved into the parent class: DbConnector._execute_and_commit()
  556. # def _execute_and_commit(self, sql):
  557. # pass
  558. # moved into the parent class: DbConnector._get_cursor()
  559. # def _get_cursor(self, name=None):
  560. # pass
  561. # moved into the parent class: DbConnector._fetchall()
  562. # def _fetchall(self, c):
  563. # pass
  564. # moved into the parent class: DbConnector._fetchone()
  565. # def _fetchone(self, c):
  566. # pass
  567. # moved into the parent class: DbConnector._commit()
  568. # def _commit(self):
  569. # pass
  570. # moved into the parent class: DbConnector._rollback()
  571. # def _rollback(self):
  572. # pass
  573. # moved into the parent class: DbConnector._get_cursor_columns()
  574. # def _get_cursor_columns(self, c):
  575. # pass
  576. def getSqlDictionary(self):
  577. from .sql_dictionary import getSqlDictionary
  578. sql_dict = getSqlDictionary()
  579. items = []
  580. for tbl in self.getTables():
  581. items.append(tbl[1]) # table name
  582. for fld in self.getTableFields(tbl[0]):
  583. items.append(fld[1]) # field name
  584. sql_dict["identifier"] = items
  585. return sql_dict
  586. def getQueryBuilderDictionary(self):
  587. from .sql_dictionary import getQueryBuilderDictionary
  588. return getQueryBuilderDictionary()