sqlobject 3.13.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sqlobject/__init__.py +15 -0
- sqlobject/__version__.py +8 -0
- sqlobject/boundattributes.py +124 -0
- sqlobject/cache.py +376 -0
- sqlobject/classregistry.py +138 -0
- sqlobject/col.py +2187 -0
- sqlobject/compat.py +59 -0
- sqlobject/conftest.py +64 -0
- sqlobject/constraints.py +77 -0
- sqlobject/converters.py +278 -0
- sqlobject/dbconnection.py +1137 -0
- sqlobject/dberrors.py +54 -0
- sqlobject/declarative.py +211 -0
- sqlobject/events.py +365 -0
- sqlobject/firebird/__init__.py +8 -0
- sqlobject/firebird/firebirdconnection.py +463 -0
- sqlobject/include/__init__.py +1 -0
- sqlobject/include/hashcol.py +109 -0
- sqlobject/include/tests/__init__.py +1 -0
- sqlobject/include/tests/test_hashcol.py +84 -0
- sqlobject/index.py +189 -0
- sqlobject/inheritance/__init__.py +551 -0
- sqlobject/inheritance/iteration.py +106 -0
- sqlobject/inheritance/tests/__init__.py +1 -0
- sqlobject/inheritance/tests/test_aggregates.py +23 -0
- sqlobject/inheritance/tests/test_asdict.py +48 -0
- sqlobject/inheritance/tests/test_deep_inheritance.py +114 -0
- sqlobject/inheritance/tests/test_destroy_cascade.py +23 -0
- sqlobject/inheritance/tests/test_foreignKey.py +94 -0
- sqlobject/inheritance/tests/test_indexes.py +42 -0
- sqlobject/inheritance/tests/test_inheritance.py +164 -0
- sqlobject/inheritance/tests/test_inheritance_tree.py +50 -0
- sqlobject/joins.py +656 -0
- sqlobject/main.py +1880 -0
- sqlobject/manager/__init__.py +1 -0
- sqlobject/manager/command.py +1309 -0
- sqlobject/maxdb/__init__.py +8 -0
- sqlobject/maxdb/maxdbconnection.py +320 -0
- sqlobject/maxdb/readme.txt +27 -0
- sqlobject/mssql/__init__.py +8 -0
- sqlobject/mssql/mssqlconnection.py +417 -0
- sqlobject/mysql/__init__.py +8 -0
- sqlobject/mysql/mysqlconnection.py +562 -0
- sqlobject/postgres/__init__.py +8 -0
- sqlobject/postgres/pgconnection.py +619 -0
- sqlobject/sqlbuilder.py +1655 -0
- sqlobject/sqlite/__init__.py +8 -0
- sqlobject/sqlite/sqliteconnection.py +418 -0
- sqlobject/sresults.py +377 -0
- sqlobject/styles.py +174 -0
- sqlobject/sybase/__init__.py +8 -0
- sqlobject/sybase/sybaseconnection.py +183 -0
- sqlobject/tests/__init__.py +1 -0
- sqlobject/tests/dbtest.py +363 -0
- sqlobject/tests/test_ForeignKey.py +133 -0
- sqlobject/tests/test_ForeignKey_cascade.py +150 -0
- sqlobject/tests/test_NoneValuedResultItem.py +33 -0
- sqlobject/tests/test_SQLMultipleJoin.py +65 -0
- sqlobject/tests/test_SQLRelatedJoin.py +114 -0
- sqlobject/tests/test_SingleJoin.py +30 -0
- sqlobject/tests/test_aggregates.py +75 -0
- sqlobject/tests/test_aliases.py +49 -0
- sqlobject/tests/test_asdict.py +18 -0
- sqlobject/tests/test_auto.py +218 -0
- sqlobject/tests/test_basic.py +359 -0
- sqlobject/tests/test_blob.py +34 -0
- sqlobject/tests/test_boundattributes.py +67 -0
- sqlobject/tests/test_cache.py +57 -0
- sqlobject/tests/test_class_hash.py +22 -0
- sqlobject/tests/test_columns_order.py +18 -0
- sqlobject/tests/test_combining_joins.py +47 -0
- sqlobject/tests/test_comparison.py +24 -0
- sqlobject/tests/test_compat.py +10 -0
- sqlobject/tests/test_complex_sorting.py +77 -0
- sqlobject/tests/test_constraints.py +43 -0
- sqlobject/tests/test_converters.py +276 -0
- sqlobject/tests/test_create_drop.py +29 -0
- sqlobject/tests/test_csvexport.py +101 -0
- sqlobject/tests/test_csvimport.py +21 -0
- sqlobject/tests/test_cyclic_reference.py +55 -0
- sqlobject/tests/test_datetime.py +171 -0
- sqlobject/tests/test_dbconnection.py +17 -0
- sqlobject/tests/test_decimal.py +63 -0
- sqlobject/tests/test_declarative.py +83 -0
- sqlobject/tests/test_default_style.py +65 -0
- sqlobject/tests/test_delete.py +74 -0
- sqlobject/tests/test_distinct.py +36 -0
- sqlobject/tests/test_empty.py +22 -0
- sqlobject/tests/test_enum.py +75 -0
- sqlobject/tests/test_events.py +142 -0
- sqlobject/tests/test_exceptions.py +40 -0
- sqlobject/tests/test_expire.py +29 -0
- sqlobject/tests/test_groupBy.py +45 -0
- sqlobject/tests/test_identity.py +29 -0
- sqlobject/tests/test_indexes.py +100 -0
- sqlobject/tests/test_inheritance.py +35 -0
- sqlobject/tests/test_joins.py +160 -0
- sqlobject/tests/test_joins_conditional.py +143 -0
- sqlobject/tests/test_jsonbcol.py +53 -0
- sqlobject/tests/test_jsoncol.py +56 -0
- sqlobject/tests/test_lazy.py +165 -0
- sqlobject/tests/test_md5.py +13 -0
- sqlobject/tests/test_mysql.py +50 -0
- sqlobject/tests/test_new_joins.py +165 -0
- sqlobject/tests/test_parse_uri.py +147 -0
- sqlobject/tests/test_paste.py +92 -0
- sqlobject/tests/test_perConnection.py +20 -0
- sqlobject/tests/test_pickle.py +42 -0
- sqlobject/tests/test_picklecol.py +44 -0
- sqlobject/tests/test_postgres.py +82 -0
- sqlobject/tests/test_reparent_sqlmeta.py +33 -0
- sqlobject/tests/test_schema.py +30 -0
- sqlobject/tests/test_select.py +218 -0
- sqlobject/tests/test_select_through.py +63 -0
- sqlobject/tests/test_setters.py +23 -0
- sqlobject/tests/test_slice.py +59 -0
- sqlobject/tests/test_sorting.py +80 -0
- sqlobject/tests/test_sqlbuilder.py +134 -0
- sqlobject/tests/test_sqlbuilder_dbspecific.py +66 -0
- sqlobject/tests/test_sqlbuilder_importproxy.py +55 -0
- sqlobject/tests/test_sqlbuilder_joins_instances.py +90 -0
- sqlobject/tests/test_sqlite.py +160 -0
- sqlobject/tests/test_sqlmeta_idName.py +52 -0
- sqlobject/tests/test_sqlobject_admin.py +38 -0
- sqlobject/tests/test_string_id.py +79 -0
- sqlobject/tests/test_style.py +36 -0
- sqlobject/tests/test_subqueries.py +142 -0
- sqlobject/tests/test_transactions.py +122 -0
- sqlobject/tests/test_unicode.py +84 -0
- sqlobject/tests/test_uuidcol.py +40 -0
- sqlobject/tests/test_validation.py +125 -0
- sqlobject/tests/test_views.py +159 -0
- sqlobject/util/__init__.py +1 -0
- sqlobject/util/csvexport.py +210 -0
- sqlobject/util/csvimport.py +366 -0
- sqlobject/util/moduleloader.py +35 -0
- sqlobject/util/threadinglocal.py +6 -0
- sqlobject/versioning/__init__.py +120 -0
- sqlobject/versioning/test/__init__.py +0 -0
- sqlobject/versioning/test/test_version.py +183 -0
- sqlobject/views.py +151 -0
- sqlobject/wsgi_middleware.py +109 -0
- sqlobject-3.13.1.data/scripts/sqlobject-admin +36 -0
- sqlobject-3.13.1.data/scripts/sqlobject-convertOldURI +19 -0
- sqlobject-3.13.1.dist-info/METADATA +177 -0
- sqlobject-3.13.1.dist-info/RECORD +149 -0
- sqlobject-3.13.1.dist-info/WHEEL +6 -0
- sqlobject-3.13.1.dist-info/entry_points.txt +4 -0
- sqlobject-3.13.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from sqlobject import col
|
|
3
|
+
from sqlobject.dbconnection import DBAPI
|
|
4
|
+
from sqlobject.compat import PY2
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MSSQLConnection(DBAPI):
|
|
8
|
+
|
|
9
|
+
supportTransactions = True
|
|
10
|
+
dbName = 'mssql'
|
|
11
|
+
schemes = [dbName]
|
|
12
|
+
|
|
13
|
+
limit_re = re.compile(r'^\s*(select )(.*)', re.IGNORECASE)
|
|
14
|
+
|
|
15
|
+
odbc_keywords = ('Server', 'Port', 'User Id', 'Password', 'Database')
|
|
16
|
+
|
|
17
|
+
def __init__(self, db, user, password='', host='localhost', port=None,
|
|
18
|
+
autoCommit=0, **kw):
|
|
19
|
+
drivers = kw.pop('driver', None) or 'adodb,pymssql'
|
|
20
|
+
for driver in drivers.split(','):
|
|
21
|
+
driver = driver.strip()
|
|
22
|
+
if not driver:
|
|
23
|
+
continue
|
|
24
|
+
try:
|
|
25
|
+
if driver in ('adodb', 'adodbapi'):
|
|
26
|
+
import adodbapi as sqlmodule
|
|
27
|
+
elif driver == 'pymssql':
|
|
28
|
+
import pymssql as sqlmodule
|
|
29
|
+
elif driver == 'pyodbc':
|
|
30
|
+
import pyodbc
|
|
31
|
+
self.module = pyodbc
|
|
32
|
+
elif driver == 'pypyodbc':
|
|
33
|
+
import pypyodbc
|
|
34
|
+
self.module = pypyodbc
|
|
35
|
+
elif driver == 'odbc':
|
|
36
|
+
try:
|
|
37
|
+
import pyodbc
|
|
38
|
+
except ImportError:
|
|
39
|
+
import pypyodbc as pyodbc
|
|
40
|
+
self.module = pyodbc
|
|
41
|
+
else:
|
|
42
|
+
raise ValueError(
|
|
43
|
+
'Unknown MSSQL driver "%s", '
|
|
44
|
+
'expected adodb, pymssql, '
|
|
45
|
+
'odbc, pyodbc or pypyodbc' % driver)
|
|
46
|
+
except ImportError:
|
|
47
|
+
pass
|
|
48
|
+
else:
|
|
49
|
+
break
|
|
50
|
+
else:
|
|
51
|
+
raise ImportError(
|
|
52
|
+
'Cannot find an MSSQL driver, tried %s' % drivers)
|
|
53
|
+
|
|
54
|
+
timeout = kw.pop('timeout', None)
|
|
55
|
+
if timeout:
|
|
56
|
+
timeout = int(timeout)
|
|
57
|
+
self.timeout = timeout
|
|
58
|
+
|
|
59
|
+
if driver in ('odbc', 'pyodbc', 'pypyodbc'):
|
|
60
|
+
self.make_odbc_conn_str(kw.pop('odbcdrv', 'SQL Server'),
|
|
61
|
+
db, host, port, user, password
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
elif driver in ('adodb', 'adodbapi'):
|
|
65
|
+
self.module = sqlmodule
|
|
66
|
+
self.dbconnection = sqlmodule.connect
|
|
67
|
+
# ADO uses unicode only (AFAIK)
|
|
68
|
+
self.usingUnicodeStrings = True
|
|
69
|
+
|
|
70
|
+
# Need to use SQLNCLI provider for SQL Server Express Edition
|
|
71
|
+
if kw.get("ncli"):
|
|
72
|
+
conn_str = "Provider=SQLNCLI;"
|
|
73
|
+
else:
|
|
74
|
+
conn_str = "Provider=SQLOLEDB;"
|
|
75
|
+
|
|
76
|
+
conn_str += "Data Source=%s;Initial Catalog=%s;"
|
|
77
|
+
|
|
78
|
+
# MSDE does not allow SQL server login
|
|
79
|
+
if kw.get("sspi"):
|
|
80
|
+
conn_str += \
|
|
81
|
+
"Integrated Security=SSPI;Persist Security Info=False"
|
|
82
|
+
self.make_conn_str = lambda keys: conn_str % (
|
|
83
|
+
keys.host, keys.db)
|
|
84
|
+
else:
|
|
85
|
+
conn_str += "User Id=%s;Password=%s"
|
|
86
|
+
self.make_conn_str = lambda keys: conn_str % (
|
|
87
|
+
keys.host, keys.db, keys.user, keys.password)
|
|
88
|
+
|
|
89
|
+
kw.pop("ncli", None)
|
|
90
|
+
kw.pop("sspi", None)
|
|
91
|
+
|
|
92
|
+
elif driver == 'pymssql':
|
|
93
|
+
self.module = sqlmodule
|
|
94
|
+
self.dbconnection = sqlmodule.connect
|
|
95
|
+
sqlmodule.Binary = lambda st: str(st)
|
|
96
|
+
# don't know whether pymssql uses unicode
|
|
97
|
+
self.usingUnicodeStrings = False
|
|
98
|
+
|
|
99
|
+
def _make_conn_str(keys):
|
|
100
|
+
keys_dict = {}
|
|
101
|
+
for attr, value in (
|
|
102
|
+
('database', keys.db),
|
|
103
|
+
('user', keys.user),
|
|
104
|
+
('password', keys.password),
|
|
105
|
+
('host', keys.host),
|
|
106
|
+
('port', keys.port),
|
|
107
|
+
('timeout', keys.timeout),
|
|
108
|
+
('charset', keys.charset),
|
|
109
|
+
('tds_version', keys.tds_version),
|
|
110
|
+
):
|
|
111
|
+
if value:
|
|
112
|
+
keys_dict[attr] = value
|
|
113
|
+
return keys_dict
|
|
114
|
+
self.make_conn_str = _make_conn_str
|
|
115
|
+
self.driver = driver
|
|
116
|
+
|
|
117
|
+
self.autoCommit = int(autoCommit)
|
|
118
|
+
self.user = user
|
|
119
|
+
self.password = password
|
|
120
|
+
self.host = host
|
|
121
|
+
self.port = port
|
|
122
|
+
self.db = db
|
|
123
|
+
self.charset = kw.pop("charset", None)
|
|
124
|
+
self.tds_version = kw.pop("tds_version", None)
|
|
125
|
+
self._server_version = None
|
|
126
|
+
self._can_use_max_types = None
|
|
127
|
+
self._can_use_microseconds = None
|
|
128
|
+
DBAPI.__init__(self, **kw)
|
|
129
|
+
|
|
130
|
+
@classmethod
|
|
131
|
+
def _connectionFromParams(cls, user, password, host, port, path, args):
|
|
132
|
+
path = path.strip('/')
|
|
133
|
+
return cls(user=user, password=password,
|
|
134
|
+
host=host or 'localhost', port=port, db=path, **args)
|
|
135
|
+
|
|
136
|
+
def insert_id(self, conn):
|
|
137
|
+
"""
|
|
138
|
+
insert_id method.
|
|
139
|
+
"""
|
|
140
|
+
c = conn.cursor()
|
|
141
|
+
# converting the identity to an int is ugly, but it gets returned
|
|
142
|
+
# as a decimal otherwise :S
|
|
143
|
+
c.execute('SELECT CONVERT(INT, @@IDENTITY)')
|
|
144
|
+
result = c.fetchone()[0]
|
|
145
|
+
c.close()
|
|
146
|
+
return result
|
|
147
|
+
|
|
148
|
+
def makeConnection(self):
|
|
149
|
+
if self.driver in ('odbc', 'pyodbc', 'pypyodbc'):
|
|
150
|
+
self.debugWriter.write(
|
|
151
|
+
"ODBC connect string: " + self.odbc_conn_str)
|
|
152
|
+
timeout = self.timeout
|
|
153
|
+
if timeout:
|
|
154
|
+
kw = dict(timeout=timeout)
|
|
155
|
+
else:
|
|
156
|
+
kw = dict()
|
|
157
|
+
conn = self.module.connect(self.odbc_conn_str, **kw)
|
|
158
|
+
if timeout:
|
|
159
|
+
conn.timeout = timeout
|
|
160
|
+
else:
|
|
161
|
+
conn_descr = self.make_conn_str(self)
|
|
162
|
+
if isinstance(conn_descr, dict):
|
|
163
|
+
conn = self.dbconnection(**conn_descr)
|
|
164
|
+
else:
|
|
165
|
+
conn = self.dbconnection(conn_descr)
|
|
166
|
+
cur = conn.cursor()
|
|
167
|
+
cur.execute('SET ANSI_NULLS ON')
|
|
168
|
+
cur.execute("SELECT CAST('12345.21' AS DECIMAL(10, 2))")
|
|
169
|
+
self.decimalSeparator = str(cur.fetchone()[0])[-3]
|
|
170
|
+
cur.close()
|
|
171
|
+
return conn
|
|
172
|
+
|
|
173
|
+
def _setAutoCommit(self, conn, auto):
|
|
174
|
+
auto = bool(auto)
|
|
175
|
+
if self.driver in ('adodb', 'adodbapi'):
|
|
176
|
+
if auto:
|
|
177
|
+
option = "ON"
|
|
178
|
+
else:
|
|
179
|
+
option = "OFF"
|
|
180
|
+
c = conn.cursor()
|
|
181
|
+
c.execute("SET AUTOCOMMIT " + option)
|
|
182
|
+
elif self.driver == 'pymssql':
|
|
183
|
+
conn.autocommit(auto)
|
|
184
|
+
elif self.driver in ('odbc', 'pyodbc', 'pypyodbc'):
|
|
185
|
+
conn.autocommit = auto
|
|
186
|
+
|
|
187
|
+
HAS_IDENTITY = """
|
|
188
|
+
select 1
|
|
189
|
+
from INFORMATION_SCHEMA.COLUMNS
|
|
190
|
+
where TABLE_NAME = '%s'
|
|
191
|
+
and COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
def _hasIdentity(self, conn, table):
|
|
195
|
+
query = self.HAS_IDENTITY % table
|
|
196
|
+
c = conn.cursor()
|
|
197
|
+
c.execute(query)
|
|
198
|
+
r = c.fetchone()
|
|
199
|
+
c.close()
|
|
200
|
+
return r is not None
|
|
201
|
+
|
|
202
|
+
def _queryInsertID(self, conn, soInstance, id, names, values):
|
|
203
|
+
"""
|
|
204
|
+
Insert the Initial with names and values, using id.
|
|
205
|
+
"""
|
|
206
|
+
table = soInstance.sqlmeta.table
|
|
207
|
+
idName = soInstance.sqlmeta.idName
|
|
208
|
+
c = conn.cursor()
|
|
209
|
+
has_identity = self._hasIdentity(conn, table)
|
|
210
|
+
if id is not None:
|
|
211
|
+
names = [idName] + names
|
|
212
|
+
values = [id] + values
|
|
213
|
+
elif has_identity and idName in names:
|
|
214
|
+
try:
|
|
215
|
+
i = names.index(idName)
|
|
216
|
+
if i:
|
|
217
|
+
del names[i]
|
|
218
|
+
del values[i]
|
|
219
|
+
except ValueError:
|
|
220
|
+
pass
|
|
221
|
+
|
|
222
|
+
if has_identity:
|
|
223
|
+
if id is not None:
|
|
224
|
+
c.execute('SET IDENTITY_INSERT %s ON' % table)
|
|
225
|
+
else:
|
|
226
|
+
c.execute('SET IDENTITY_INSERT %s OFF' % table)
|
|
227
|
+
|
|
228
|
+
if names and values:
|
|
229
|
+
q = self._insertSQL(table, names, values)
|
|
230
|
+
else:
|
|
231
|
+
q = "INSERT INTO %s DEFAULT VALUES" % table
|
|
232
|
+
if self.debug:
|
|
233
|
+
self.printDebug(conn, q, 'QueryIns')
|
|
234
|
+
c.execute(q)
|
|
235
|
+
if has_identity:
|
|
236
|
+
c.execute('SET IDENTITY_INSERT %s OFF' % table)
|
|
237
|
+
c.close()
|
|
238
|
+
|
|
239
|
+
if id is None:
|
|
240
|
+
id = self.insert_id(conn)
|
|
241
|
+
if self.debugOutput:
|
|
242
|
+
self.printDebug(conn, id, 'QueryIns', 'result')
|
|
243
|
+
return id
|
|
244
|
+
|
|
245
|
+
@classmethod
|
|
246
|
+
def _queryAddLimitOffset(cls, query, start, end):
|
|
247
|
+
if end and not start:
|
|
248
|
+
limit_str = "SELECT TOP %i" % end
|
|
249
|
+
|
|
250
|
+
match = cls.limit_re.match(query)
|
|
251
|
+
if match and len(match.groups()) == 2:
|
|
252
|
+
return ' '.join([limit_str, match.group(2)])
|
|
253
|
+
else:
|
|
254
|
+
return query
|
|
255
|
+
|
|
256
|
+
def createReferenceConstraint(self, soClass, col):
|
|
257
|
+
return col.mssqlCreateReferenceConstraint()
|
|
258
|
+
|
|
259
|
+
def createColumn(self, soClass, col):
|
|
260
|
+
return col.mssqlCreateSQL(self)
|
|
261
|
+
|
|
262
|
+
def createIDColumn(self, soClass):
|
|
263
|
+
key_type = {int: "INT", str: "TEXT"}[soClass.sqlmeta.idType]
|
|
264
|
+
return '%s %s IDENTITY UNIQUE' % (soClass.sqlmeta.idName, key_type)
|
|
265
|
+
|
|
266
|
+
def createIndexSQL(self, soClass, index):
|
|
267
|
+
return index.mssqlCreateIndexSQL(soClass)
|
|
268
|
+
|
|
269
|
+
def joinSQLType(self, join):
|
|
270
|
+
return 'INT NOT NULL'
|
|
271
|
+
|
|
272
|
+
SHOW_TABLES = "SELECT name FROM sysobjects WHERE type='U'"
|
|
273
|
+
|
|
274
|
+
def tableExists(self, tableName):
|
|
275
|
+
for (table,) in self.queryAll(self.SHOW_TABLES):
|
|
276
|
+
if table.lower() == tableName.lower():
|
|
277
|
+
return True
|
|
278
|
+
return False
|
|
279
|
+
|
|
280
|
+
def addColumn(self, tableName, column):
|
|
281
|
+
self.query('ALTER TABLE %s ADD %s' %
|
|
282
|
+
(tableName,
|
|
283
|
+
column.mssqlCreateSQL(self)))
|
|
284
|
+
|
|
285
|
+
def delColumn(self, sqlmeta, column):
|
|
286
|
+
self.query('ALTER TABLE %s DROP COLUMN %s' % (sqlmeta.table,
|
|
287
|
+
column.dbName))
|
|
288
|
+
|
|
289
|
+
# Precision and scale is gotten from column table
|
|
290
|
+
# so that we can create decimal columns if needed.
|
|
291
|
+
SHOW_COLUMNS = """
|
|
292
|
+
select
|
|
293
|
+
name,
|
|
294
|
+
length,
|
|
295
|
+
( select name
|
|
296
|
+
from systypes
|
|
297
|
+
where cast(xusertype as int)= cast(sc.xtype as int)
|
|
298
|
+
) datatype,
|
|
299
|
+
prec,
|
|
300
|
+
scale,
|
|
301
|
+
isnullable,
|
|
302
|
+
cdefault,
|
|
303
|
+
m.text default_text,
|
|
304
|
+
isnull(len(autoval),0) is_identity
|
|
305
|
+
from syscolumns sc
|
|
306
|
+
LEFT OUTER JOIN syscomments m on sc.cdefault = m.id
|
|
307
|
+
AND m.colid = 1
|
|
308
|
+
where
|
|
309
|
+
sc.id in (select id
|
|
310
|
+
from sysobjects
|
|
311
|
+
where name = '%s')
|
|
312
|
+
order by
|
|
313
|
+
colorder"""
|
|
314
|
+
|
|
315
|
+
def columnsFromSchema(self, tableName, soClass):
|
|
316
|
+
colData = self.queryAll(self.SHOW_COLUMNS
|
|
317
|
+
% tableName)
|
|
318
|
+
results = []
|
|
319
|
+
for (field, size, t, precision, scale, nullAllowed,
|
|
320
|
+
default, defaultText, is_identity) in colData:
|
|
321
|
+
if field == soClass.sqlmeta.idName:
|
|
322
|
+
continue
|
|
323
|
+
# precision is needed for decimal columns
|
|
324
|
+
colClass, kw = self.guessClass(t, size, precision, scale)
|
|
325
|
+
kw['name'] = str(soClass.sqlmeta.style.dbColumnToPythonAttr(field))
|
|
326
|
+
kw['dbName'] = str(field)
|
|
327
|
+
kw['notNone'] = not nullAllowed
|
|
328
|
+
if (defaultText):
|
|
329
|
+
# Strip ( and )
|
|
330
|
+
defaultText = defaultText[1:-1]
|
|
331
|
+
if defaultText[0] == "'":
|
|
332
|
+
defaultText = defaultText[1:-1]
|
|
333
|
+
else:
|
|
334
|
+
if t in ("int", "float", "numeric") and \
|
|
335
|
+
defaultText[0] == "(":
|
|
336
|
+
defaultText = defaultText[1:-1]
|
|
337
|
+
if t == "int":
|
|
338
|
+
defaultText = int(defaultText)
|
|
339
|
+
if t == "float":
|
|
340
|
+
defaultText = float(defaultText)
|
|
341
|
+
if t == "numeric":
|
|
342
|
+
defaultText = float(defaultText)
|
|
343
|
+
# TODO need to access the "column" to_python method here --
|
|
344
|
+
# but the object doesn't exists yet.
|
|
345
|
+
|
|
346
|
+
# @@ skip key...
|
|
347
|
+
kw['default'] = defaultText
|
|
348
|
+
|
|
349
|
+
results.append(colClass(**kw))
|
|
350
|
+
return results
|
|
351
|
+
|
|
352
|
+
# precision and scale is needed for decimal columns
|
|
353
|
+
def guessClass(self, t, size, precision, scale):
|
|
354
|
+
"""
|
|
355
|
+
Here we take raw values coming out of syscolumns
|
|
356
|
+
and map to SQLObject class types.
|
|
357
|
+
|
|
358
|
+
"""
|
|
359
|
+
if t.startswith('int'):
|
|
360
|
+
return col.IntCol, {}
|
|
361
|
+
elif t.startswith('varchar'):
|
|
362
|
+
if self.usingUnicodeStrings:
|
|
363
|
+
return col.UnicodeCol, {'length': size}
|
|
364
|
+
return col.StringCol, {'length': size}
|
|
365
|
+
elif t.startswith('char'):
|
|
366
|
+
if self.usingUnicodeStrings:
|
|
367
|
+
return col.UnicodeCol, {'length': size,
|
|
368
|
+
'varchar': False}
|
|
369
|
+
return col.StringCol, {'length': size,
|
|
370
|
+
'varchar': False}
|
|
371
|
+
elif t.startswith('datetime'):
|
|
372
|
+
return col.DateTimeCol, {}
|
|
373
|
+
elif t.startswith('decimal'):
|
|
374
|
+
# be careful for awkward naming
|
|
375
|
+
return col.DecimalCol, {'size': precision,
|
|
376
|
+
'precision': scale}
|
|
377
|
+
else:
|
|
378
|
+
return col.Col, {}
|
|
379
|
+
|
|
380
|
+
def server_version(self):
|
|
381
|
+
"""Get server version:
|
|
382
|
+
8 - 2000
|
|
383
|
+
9 - 2005
|
|
384
|
+
10 - 2008
|
|
385
|
+
11 - 2012
|
|
386
|
+
12 - 2014
|
|
387
|
+
13 - 2016
|
|
388
|
+
"""
|
|
389
|
+
if self._server_version is not None:
|
|
390
|
+
return self._server_version
|
|
391
|
+
try:
|
|
392
|
+
server_version = self.queryOne(
|
|
393
|
+
"SELECT SERVERPROPERTY('productversion')")[0]
|
|
394
|
+
if not PY2 and isinstance(server_version, bytes):
|
|
395
|
+
server_version = server_version.decode('ascii')
|
|
396
|
+
server_version = server_version.split('.')[0]
|
|
397
|
+
server_version = int(server_version)
|
|
398
|
+
except Exception:
|
|
399
|
+
server_version = None # unknown
|
|
400
|
+
self._server_version = server_version
|
|
401
|
+
return server_version
|
|
402
|
+
|
|
403
|
+
def can_use_max_types(self):
|
|
404
|
+
if self._can_use_max_types is not None:
|
|
405
|
+
return self._can_use_max_types
|
|
406
|
+
server_version = self.server_version()
|
|
407
|
+
self._can_use_max_types = can_use_max_types = \
|
|
408
|
+
(server_version is not None) and (server_version >= 9)
|
|
409
|
+
return can_use_max_types
|
|
410
|
+
|
|
411
|
+
def can_use_microseconds(self):
|
|
412
|
+
if self._can_use_microseconds is not None:
|
|
413
|
+
return self._can_use_microseconds
|
|
414
|
+
server_version = self.server_version()
|
|
415
|
+
self._can_use_microseconds = can_use_microseconds = \
|
|
416
|
+
(server_version is not None) and (server_version >= 10)
|
|
417
|
+
return can_use_microseconds
|