11 def for_each_connector(func):
12 @functools.wraps(func)
13 def wrapper_for_each_connector(*args, **kwargs):
14 for connector in db_connectors.values():
16 return func(connector, *args, **kwargs)
20 raise Exception("No database connector found!!")
21 return wrapper_for_each_connector
27 for entry_point in pkg_resources.iter_entry_points('datasette.connectors'):
28 db_connectors[entry_point.name] = entry_point.load()
31 def add_connector(name, connector):
32 db_connectors[name] = connector
34 class DatabaseNotSupported(Exception):
39 for connector in db_connectors.values():
41 return connector.connect(path)
45 raise ConnectorList.DatabaseNotSupported
49 def __init__(self, path, connector):
51 self.connector = connector
53 def execute(self, *args, **kwargs):
55 cursor.execute(*args, **kwargs)
61 def set_progress_handler(self, handler, n):
65 class OperationalError(Exception):
70 class QueryNotSupported(Exception):
73 def __init__(self, conn):
75 self.connector = conn.connector
84 custom_time_limit=None,
96 sql = ' '.join(sql.split())
98 if sql == "select name from sqlite_master where type='table'" or \
99 sql == "select name from sqlite_master where type=\"table\"":
100 results = [{'name': name} for name in self.connector.table_names()]
101 elif sql == "select name from sqlite_master where rootpage = 0 and sql like '%VIRTUAL TABLE%USING FTS%'":
102 results = [{'name': name} for name in self.connector.hidden_table_names()]
103 elif sql == 'select 1 from sqlite_master where tbl_name = "geometry_columns"':
104 if self.connector.detect_spatialite():
105 results = [{'1': '1'}]
106 elif sql == "select name from sqlite_master where type='view'":
107 results = [{'name': name} for name in self.connector.view_names()]
108 elif sql.startswith("select count(*) from ["):
109 match = re.search(r'select count\(\*\) from \[(.*)\]', sql)
110 results = [{'count(*)': self.connector.table_count(match.group(1))}]
111 elif sql.startswith("select count(*) from "):
112 match = re.search(r'select count\(\*\) from (.*)', sql)
113 results = [{'count(*)': self.connector.table_count(match.group(1))}]
114 elif sql.startswith("PRAGMA table_info("):
115 match = re.search(r'PRAGMA table_info\((.*)\)', sql)
116 results = self.connector.table_info(match.group(1))
117 elif sql.startswith("select name from sqlite_master where rootpage = 0 and ( sql like \'%VIRTUAL TABLE%USING FTS%content="):
118 match = re.search(r'select name from sqlite_master where rootpage = 0 and \( sql like \'%VIRTUAL TABLE%USING FTS%content="(.*)"', sql)
119 if self.connector.detect_fts(match.group(1)):
120 results = [{'name': match.group(1)}]
121 elif sql.startswith("PRAGMA foreign_key_list(["):
122 match = re.search(r'PRAGMA foreign_key_list\(\[(.*)\]\)', sql)
123 results = self.connector.foreign_keys(match.group(1))
124 elif sql == "select 1 from sqlite_master where type='table' and name=?":
125 if self.connector.table_exists(params[0]):
126 results = [{'1': '1'}]
127 elif sql == "select sql from sqlite_master where name = :n and type=:t":
128 results = [{'sql': self.connector.table_definition(params['t'], params['n'])}]
129 elif sql == "select sql from sqlite_master where tbl_name = :n and type='index' and sql is not null":
130 results = [{'sql': sql} for sql in self.connector.indices_definition(params['n'])]
133 results, truncated, description = \
134 self.connector.execute(
138 custom_time_limit=custom_time_limit,
140 log_sql_errors=log_sql_errors,
142 except OperationalError as ex:
143 raise sqlite3.OperationalError(*ex.args)
145 self.rows = [Row(result) for result in results]
146 self.description = description
151 def fetchmany(self, max):
152 return self.rows[:max]
154 def __getitem__(self, index):
155 return self.rows[index]
159 connector_type = None
160 connection_class = Connection
162 def connect(self, path):
163 return self.connection_class(path, self)
165 def table_names(self):
167 Return a list of table names
169 raise NotImplementedError
171 def hidden_table_names(self):
172 raise NotImplementedError
174 def detect_spatialite(self):
176 Return boolean indicating if geometry_columns exists
178 raise NotImplementedError
180 def view_names(self):
182 Return a list of view names
184 raise NotImplementedError
186 def table_count(self, table_name):
188 Return an integer with the rows count of the table
190 raise NotImplementedError
192 def table_info(self, table_name):
194 Return a list of dictionaries with columns description, with format:
199 'primary_key': False,
204 raise NotImplementedError
206 def detect_fts(self, table_name):
208 Return boolean indicating if table has a corresponding FTS virtual table
210 raise NotImplementedError
212 def foreign_keys(self, table_name):
214 Return a list of dictionaries with foreign keys description
215 id, seq, table_name, from_, to_, on_update, on_delete, match
217 raise NotImplementedError
219 def table_exists(self, table_name):
221 Return boolean indicating if table exists in the database
223 raise NotImplementedError
225 def table_definition(self, table_type, table_name):
227 Return string with a 'CREATE TABLE' sql definition
229 raise NotImplementedError
231 def indices_definition(self, table_name):
233 Return a list of strings with 'CREATE INDEX' sql definitions
235 raise NotImplementedError
242 custom_time_limit=None,
246 raise NotImplementedError