PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Lib/site-packages/django/db/backends/sqlite3/introspection.py

https://gitlab.com/suyesh/Djangotest
Python | 260 lines | 209 code | 20 blank | 31 comment | 27 complexity | a9516971ee05426afae00a0911f3ba3b MD5 | raw file
  1. import re
  2. from django.db.backends.base.introspection import (
  3. BaseDatabaseIntrospection, FieldInfo, TableInfo,
  4. )
  5. field_size_re = re.compile(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$')
  6. def get_field_size(name):
  7. """ Extract the size number from a "varchar(11)" type name """
  8. m = field_size_re.search(name)
  9. return int(m.group(1)) if m else None
  10. # This light wrapper "fakes" a dictionary interface, because some SQLite data
  11. # types include variables in them -- e.g. "varchar(30)" -- and can't be matched
  12. # as a simple dictionary lookup.
  13. class FlexibleFieldLookupDict(object):
  14. # Maps SQL types to Django Field types. Some of the SQL types have multiple
  15. # entries here because SQLite allows for anything and doesn't normalize the
  16. # field type; it uses whatever was given.
  17. base_data_types_reverse = {
  18. 'bool': 'BooleanField',
  19. 'boolean': 'BooleanField',
  20. 'smallint': 'SmallIntegerField',
  21. 'smallint unsigned': 'PositiveSmallIntegerField',
  22. 'smallinteger': 'SmallIntegerField',
  23. 'int': 'IntegerField',
  24. 'integer': 'IntegerField',
  25. 'bigint': 'BigIntegerField',
  26. 'integer unsigned': 'PositiveIntegerField',
  27. 'decimal': 'DecimalField',
  28. 'real': 'FloatField',
  29. 'text': 'TextField',
  30. 'char': 'CharField',
  31. 'blob': 'BinaryField',
  32. 'date': 'DateField',
  33. 'datetime': 'DateTimeField',
  34. 'time': 'TimeField',
  35. }
  36. def __getitem__(self, key):
  37. key = key.lower()
  38. try:
  39. return self.base_data_types_reverse[key]
  40. except KeyError:
  41. size = get_field_size(key)
  42. if size is not None:
  43. return ('CharField', {'max_length': size})
  44. raise KeyError
  45. class DatabaseIntrospection(BaseDatabaseIntrospection):
  46. data_types_reverse = FlexibleFieldLookupDict()
  47. def get_table_list(self, cursor):
  48. """
  49. Returns a list of table and view names in the current database.
  50. """
  51. # Skip the sqlite_sequence system table used for autoincrement key
  52. # generation.
  53. cursor.execute("""
  54. SELECT name, type FROM sqlite_master
  55. WHERE type in ('table', 'view') AND NOT name='sqlite_sequence'
  56. ORDER BY name""")
  57. return [TableInfo(row[0], row[1][0]) for row in cursor.fetchall()]
  58. def get_table_description(self, cursor, table_name):
  59. "Returns a description of the table, with the DB-API cursor.description interface."
  60. return [FieldInfo(info['name'], info['type'], None, info['size'], None, None,
  61. info['null_ok']) for info in self._table_info(cursor, table_name)]
  62. def column_name_converter(self, name):
  63. """
  64. SQLite will in some cases, e.g. when returning columns from views and
  65. subselects, return column names in 'alias."column"' format instead of
  66. simply 'column'.
  67. Affects SQLite < 3.7.15, fixed by http://www.sqlite.org/src/info/5526e0aa3c
  68. """
  69. # TODO: remove when SQLite < 3.7.15 is sufficiently old.
  70. # 3.7.13 ships in Debian stable as of 2014-03-21.
  71. if self.connection.Database.sqlite_version_info < (3, 7, 15):
  72. return name.split('.')[-1].strip('"')
  73. else:
  74. return name
  75. def get_relations(self, cursor, table_name):
  76. """
  77. Returns a dictionary of {field_index: (field_index_other_table, other_table)}
  78. representing all relationships to the given table. Indexes are 0-based.
  79. """
  80. # Dictionary of relations to return
  81. relations = {}
  82. # Schema for this table
  83. cursor.execute("SELECT sql FROM sqlite_master WHERE tbl_name = %s AND type = %s", [table_name, "table"])
  84. try:
  85. results = cursor.fetchone()[0].strip()
  86. except TypeError:
  87. # It might be a view, then no results will be returned
  88. return relations
  89. results = results[results.index('(') + 1:results.rindex(')')]
  90. # Walk through and look for references to other tables. SQLite doesn't
  91. # really have enforced references, but since it echoes out the SQL used
  92. # to create the table we can look for REFERENCES statements used there.
  93. for field_desc in results.split(','):
  94. field_desc = field_desc.strip()
  95. if field_desc.startswith("UNIQUE"):
  96. continue
  97. m = re.search('references (\S*) ?\(["|]?(.*)["|]?\)', field_desc, re.I)
  98. if not m:
  99. continue
  100. table, column = [s.strip('"') for s in m.groups()]
  101. if field_desc.startswith("FOREIGN KEY"):
  102. # Find name of the target FK field
  103. m = re.match('FOREIGN KEY\(([^\)]*)\).*', field_desc, re.I)
  104. field_name = m.groups()[0].strip('"')
  105. else:
  106. field_name = field_desc.split()[0].strip('"')
  107. cursor.execute("SELECT sql FROM sqlite_master WHERE tbl_name = %s", [table])
  108. result = cursor.fetchall()[0]
  109. other_table_results = result[0].strip()
  110. li, ri = other_table_results.index('('), other_table_results.rindex(')')
  111. other_table_results = other_table_results[li + 1:ri]
  112. for other_desc in other_table_results.split(','):
  113. other_desc = other_desc.strip()
  114. if other_desc.startswith('UNIQUE'):
  115. continue
  116. other_name = other_desc.split(' ', 1)[0].strip('"')
  117. if other_name == column:
  118. relations[field_name] = (other_name, table)
  119. break
  120. return relations
  121. def get_key_columns(self, cursor, table_name):
  122. """
  123. Returns a list of (column_name, referenced_table_name, referenced_column_name) for all
  124. key columns in given table.
  125. """
  126. key_columns = []
  127. # Schema for this table
  128. cursor.execute("SELECT sql FROM sqlite_master WHERE tbl_name = %s AND type = %s", [table_name, "table"])
  129. results = cursor.fetchone()[0].strip()
  130. results = results[results.index('(') + 1:results.rindex(')')]
  131. # Walk through and look for references to other tables. SQLite doesn't
  132. # really have enforced references, but since it echoes out the SQL used
  133. # to create the table we can look for REFERENCES statements used there.
  134. for field_index, field_desc in enumerate(results.split(',')):
  135. field_desc = field_desc.strip()
  136. if field_desc.startswith("UNIQUE"):
  137. continue
  138. m = re.search('"(.*)".*references (.*) \(["|](.*)["|]\)', field_desc, re.I)
  139. if not m:
  140. continue
  141. # This will append (column_name, referenced_table_name, referenced_column_name) to key_columns
  142. key_columns.append(tuple(s.strip('"') for s in m.groups()))
  143. return key_columns
  144. def get_indexes(self, cursor, table_name):
  145. indexes = {}
  146. for info in self._table_info(cursor, table_name):
  147. if info['pk'] != 0:
  148. indexes[info['name']] = {'primary_key': True,
  149. 'unique': False}
  150. cursor.execute('PRAGMA index_list(%s)' % self.connection.ops.quote_name(table_name))
  151. # seq, name, unique
  152. for index, unique in [(field[1], field[2]) for field in cursor.fetchall()]:
  153. cursor.execute('PRAGMA index_info(%s)' % self.connection.ops.quote_name(index))
  154. info = cursor.fetchall()
  155. # Skip indexes across multiple fields
  156. if len(info) != 1:
  157. continue
  158. name = info[0][2] # seqno, cid, name
  159. indexes[name] = {'primary_key': indexes.get(name, {}).get("primary_key", False),
  160. 'unique': unique}
  161. return indexes
  162. def get_primary_key_column(self, cursor, table_name):
  163. """
  164. Get the column name of the primary key for the given table.
  165. """
  166. # Don't use PRAGMA because that causes issues with some transactions
  167. cursor.execute("SELECT sql FROM sqlite_master WHERE tbl_name = %s AND type = %s", [table_name, "table"])
  168. row = cursor.fetchone()
  169. if row is None:
  170. raise ValueError("Table %s does not exist" % table_name)
  171. results = row[0].strip()
  172. results = results[results.index('(') + 1:results.rindex(')')]
  173. for field_desc in results.split(','):
  174. field_desc = field_desc.strip()
  175. m = re.search('"(.*)".*PRIMARY KEY( AUTOINCREMENT)?$', field_desc)
  176. if m:
  177. return m.groups()[0]
  178. return None
  179. def _table_info(self, cursor, name):
  180. cursor.execute('PRAGMA table_info(%s)' % self.connection.ops.quote_name(name))
  181. # cid, name, type, notnull, dflt_value, pk
  182. return [{'name': field[1],
  183. 'type': field[2],
  184. 'size': get_field_size(field[2]),
  185. 'null_ok': not field[3],
  186. 'pk': field[5] # undocumented
  187. } for field in cursor.fetchall()]
  188. def get_constraints(self, cursor, table_name):
  189. """
  190. Retrieves any constraints or keys (unique, pk, fk, check, index) across one or more columns.
  191. """
  192. constraints = {}
  193. # Get the index info
  194. cursor.execute("PRAGMA index_list(%s)" % self.connection.ops.quote_name(table_name))
  195. for row in cursor.fetchall():
  196. # Sqlite3 3.8.9+ has 5 columns, however older versions only give 3
  197. # columns. Discard last 2 columns if there.
  198. number, index, unique = row[:3]
  199. # Get the index info for that index
  200. cursor.execute('PRAGMA index_info(%s)' % self.connection.ops.quote_name(index))
  201. for index_rank, column_rank, column in cursor.fetchall():
  202. if index not in constraints:
  203. constraints[index] = {
  204. "columns": [],
  205. "primary_key": False,
  206. "unique": bool(unique),
  207. "foreign_key": False,
  208. "check": False,
  209. "index": True,
  210. }
  211. constraints[index]['columns'].append(column)
  212. # Get the PK
  213. pk_column = self.get_primary_key_column(cursor, table_name)
  214. if pk_column:
  215. # SQLite doesn't actually give a name to the PK constraint,
  216. # so we invent one. This is fine, as the SQLite backend never
  217. # deletes PK constraints by name, as you can't delete constraints
  218. # in SQLite; we remake the table with a new PK instead.
  219. constraints["__primary__"] = {
  220. "columns": [pk_column],
  221. "primary_key": True,
  222. "unique": False, # It's not actually a unique constraint.
  223. "foreign_key": False,
  224. "check": False,
  225. "index": False,
  226. }
  227. return constraints