connector.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 qgis.core import QgsDataSourceUri
  19. from .plugin import DbError, ConnectionError
  20. class DBConnector:
  21. def __init__(self, uri):
  22. """Creates a new DB connector
  23. """
  24. self.connection = None
  25. self._uri = uri
  26. def __del__(self):
  27. pass # print "DBConnector.__del__", self._uri.connectionInfo()
  28. if self.connection is not None:
  29. self.connection.close()
  30. self.connection = None
  31. def uri(self):
  32. return QgsDataSourceUri(self._uri.uri(False))
  33. def cancel(self):
  34. pass
  35. def publicUri(self):
  36. publicUri = QgsDataSourceUri.removePassword(self._uri.uri(False))
  37. return QgsDataSourceUri(publicUri)
  38. def hasSpatialSupport(self):
  39. return False
  40. def canAddGeometryColumn(self, table):
  41. return self.hasSpatialSupport()
  42. def canAddSpatialIndex(self, table):
  43. return self.hasSpatialSupport()
  44. def hasRasterSupport(self):
  45. return False
  46. def hasCustomQuerySupport(self):
  47. return False
  48. def hasTableColumnEditingSupport(self):
  49. return False
  50. def hasCreateSpatialViewSupport(self):
  51. return False
  52. def execution_error_types(self):
  53. raise Exception("DBConnector.execution_error_types() is an abstract method")
  54. def connection_error_types(self):
  55. raise Exception("DBConnector.connection_error_types() is an abstract method")
  56. def error_types(self):
  57. return self.connection_error_types() + self.execution_error_types()
  58. def _execute(self, cursor, sql):
  59. if cursor is None:
  60. cursor = self._get_cursor()
  61. try:
  62. cursor.execute(sql)
  63. except self.connection_error_types() as e:
  64. raise ConnectionError(e)
  65. except self.execution_error_types() as e:
  66. # do the rollback to avoid a "current transaction aborted, commands ignored" errors
  67. self._rollback()
  68. raise DbError(e, sql)
  69. return cursor
  70. def _execute_and_commit(self, sql):
  71. """ tries to execute and commit some action, on error it rolls back the change """
  72. self._execute(None, sql)
  73. self._commit()
  74. def _get_cursor(self, name=None):
  75. try:
  76. if name is not None:
  77. name = str(name).encode('ascii', 'replace').replace('?', "_")
  78. self._last_cursor_named_id = 0 if not hasattr(self,
  79. '_last_cursor_named_id') else self._last_cursor_named_id + 1
  80. return self.connection.cursor("%s_%d" % (name, self._last_cursor_named_id))
  81. return self.connection.cursor()
  82. except self.connection_error_types() as e:
  83. raise ConnectionError(e)
  84. except self.execution_error_types() as e:
  85. # do the rollback to avoid a "current transaction aborted, commands ignored" errors
  86. self._rollback()
  87. raise DbError(e)
  88. def _close_cursor(self, c):
  89. try:
  90. if c and not c.closed:
  91. c.close()
  92. except self.error_types():
  93. pass
  94. return
  95. def _fetchall(self, c):
  96. try:
  97. return c.fetchall()
  98. except self.connection_error_types() as e:
  99. raise ConnectionError(e)
  100. except self.execution_error_types() as e:
  101. # do the rollback to avoid a "current transaction aborted, commands ignored" errors
  102. self._rollback()
  103. raise DbError(e)
  104. def _fetchone(self, c):
  105. try:
  106. return c.fetchone()
  107. except self.connection_error_types() as e:
  108. raise ConnectionError(e)
  109. except self.execution_error_types() as e:
  110. # do the rollback to avoid a "current transaction aborted, commands ignored" errors
  111. self._rollback()
  112. raise DbError(e)
  113. def _commit(self):
  114. try:
  115. self.connection.commit()
  116. except self.connection_error_types() as e:
  117. raise ConnectionError(e)
  118. except self.execution_error_types() as e:
  119. # do the rollback to avoid a "current transaction aborted, commands ignored" errors
  120. self._rollback()
  121. raise DbError(e)
  122. def _rollback(self):
  123. try:
  124. self.connection.rollback()
  125. except self.connection_error_types() as e:
  126. raise ConnectionError(e)
  127. except self.execution_error_types() as e:
  128. raise DbError(e)
  129. def _get_cursor_columns(self, c):
  130. try:
  131. if c.description:
  132. return [x[0] for x in c.description]
  133. except self.connection_error_types() + self.execution_error_types():
  134. return []
  135. @classmethod
  136. def quoteId(self, identifier):
  137. if hasattr(identifier, '__iter__') and not isinstance(identifier, str):
  138. return '.'.join(
  139. self.quoteId(i)
  140. for i in identifier
  141. if i is not None and i != ""
  142. )
  143. identifier = str(
  144. identifier) if identifier is not None else '' # make sure it's python unicode string
  145. return '"%s"' % identifier.replace('"', '""')
  146. @classmethod
  147. def quoteString(self, txt):
  148. """ make the string safe - replace ' with '' """
  149. if hasattr(txt, '__iter__') and not isinstance(txt, str):
  150. return '.'.join(
  151. self.quoteString(i)
  152. for i in txt
  153. if i is not None
  154. )
  155. txt = str(txt) if txt is not None else '' # make sure it's python unicode string
  156. return "'%s'" % txt.replace("'", "''")
  157. @classmethod
  158. def getSchemaTableName(self, table):
  159. if not hasattr(table, '__iter__') and not isinstance(table, str):
  160. return (None, table)
  161. if isinstance(table, str):
  162. table = table.split('.')
  163. if len(table) < 2:
  164. return (None, table[0])
  165. else:
  166. return (table[0], table[1])
  167. @classmethod
  168. def getSqlDictionary(self):
  169. """ return a generic SQL dictionary """
  170. try:
  171. from ..sql_dictionary import getSqlDictionary
  172. return getSqlDictionary()
  173. except ImportError:
  174. return []
  175. def getComment(self, tablename, field):
  176. """Returns the comment for a field"""
  177. return ''
  178. def commentTable(self, schema, tablename, comment=None):
  179. """Comment the table"""
  180. pass
  181. def getQueryBuilderDictionary(self):
  182. return {}