PageRenderTime 54ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/sqlalchemy/dialects/informix/base.py

https://bitbucket.org/stavrossk/maraschino
Python | 593 lines | 562 code | 19 blank | 12 comment | 7 complexity | 429c56706bf8b0dcba09ff914a39d8a2 MD5 | raw file
  1. # informix/base.py
  2. # Copyright (C) 2005-2011 the SQLAlchemy authors and contributors <see AUTHORS file>
  3. # coding: gbk
  4. #
  5. # This module is part of SQLAlchemy and is released under
  6. # the MIT License: http://www.opensource.org/licenses/mit-license.php
  7. """Support for the Informix database.
  8. This dialect is mostly functional as of SQLAlchemy 0.6.5.
  9. """
  10. import datetime
  11. from sqlalchemy import sql, schema, exc, pool, util
  12. from sqlalchemy.sql import compiler, text
  13. from sqlalchemy.engine import default, reflection
  14. from sqlalchemy import types as sqltypes
  15. RESERVED_WORDS = set(
  16. ["abs", "absolute", "access", "access_method", "acos", "active", "add",
  17. "address", "add_months", "admin", "after", "aggregate", "alignment",
  18. "all", "allocate", "all_rows", "altere", "and", "ansi", "any", "append",
  19. "array", "as", "asc", "ascii", "asin", "at", "atan", "atan2", "attach",
  20. "attributes", "audit", "authentication", "authid", "authorization",
  21. "authorized", "auto", "autofree", "auto_reprepare", "auto_stat_mode",
  22. "avg", "avoid_execute", "avoid_fact", "avoid_full", "avoid_hash",
  23. "avoid_index", "avoid_index_sj", "avoid_multi_index", "avoid_nl",
  24. "avoid_star_join", "avoid_subqf", "based", "before", "begin",
  25. "between", "bigint", "bigserial", "binary", "bitand", "bitandnot",
  26. "bitnot", "bitor", "bitxor", "blob", "blobdir", "boolean", "both",
  27. "bound_impl_pdq", "buffered", "builtin", "by", "byte", "cache", "call",
  28. "cannothash", "cardinality", "cascade", "case", "cast", "ceil", "char",
  29. "character", "character_length", "char_length", "check", "class",
  30. "class_origin", "client", "clob", "clobdir", "close", "cluster",
  31. "clustersize", "cobol", "codeset", "collation", "collection",
  32. "column", "columns", "commit", "committed", "commutator", "component",
  33. "components", "concat", "concurrent", "connect", "connection",
  34. "connection_name", "connect_by_iscycle", "connect_by_isleaf",
  35. "connect_by_rootconst", "constraint", "constraints", "constructor",
  36. "context", "continue", "copy", "cos", "costfunc", "count", "crcols",
  37. "create", "cross", "current", "current_role", "currval", "cursor",
  38. "cycle", "database", "datafiles", "dataskip", "date", "datetime",
  39. "day", "dba", "dbdate", "dbinfo", "dbpassword", "dbsecadm",
  40. "dbservername", "deallocate", "debug", "debugmode", "debug_env", "dec",
  41. "decimal", "declare", "decode", "decrypt_binary", "decrypt_char",
  42. "dec_t", "default", "default_role", "deferred", "deferred_prepare",
  43. "define", "delay", "delete", "deleting", "delimited", "delimiter",
  44. "deluxe", "desc", "describe", "descriptor", "detach", "diagnostics",
  45. "directives", "dirty", "disable", "disabled", "disconnect", "disk",
  46. "distinct", "distributebinary", "distributesreferences",
  47. "distributions", "document", "domain", "donotdistribute", "dormant",
  48. "double", "drop", "dtime_t", "each", "elif", "else", "enabled",
  49. "encryption", "encrypt_aes", "encrypt_tdes", "end", "enum",
  50. "environment", "error", "escape", "exception", "exclusive", "exec",
  51. "execute", "executeanywhere", "exemption", "exists", "exit", "exp",
  52. "explain", "explicit", "express", "expression", "extdirectives",
  53. "extend", "extent", "external", "fact", "false", "far", "fetch",
  54. "file", "filetoblob", "filetoclob", "fillfactor", "filtering", "first",
  55. "first_rows", "fixchar", "fixed", "float", "floor", "flush", "for",
  56. "force", "forced", "force_ddl_exec", "foreach", "foreign", "format",
  57. "format_units", "fortran", "found", "fraction", "fragment",
  58. "fragments", "free", "from", "full", "function", "general", "get",
  59. "gethint", "global", "go", "goto", "grant", "greaterthan",
  60. "greaterthanorequal", "group", "handlesnulls", "hash", "having", "hdr",
  61. "hex", "high", "hint", "hold", "home", "hour", "idslbacreadarray",
  62. "idslbacreadset", "idslbacreadtree", "idslbacrules",
  63. "idslbacwritearray", "idslbacwriteset", "idslbacwritetree",
  64. "idssecuritylabel", "if", "ifx_auto_reprepare", "ifx_batchedread_table",
  65. "ifx_int8_t", "ifx_lo_create_spec_t", "ifx_lo_stat_t", "immediate",
  66. "implicit", "implicit_pdq", "in", "inactive", "increment", "index",
  67. "indexes", "index_all", "index_sj", "indicator", "informix", "init",
  68. "initcap", "inline", "inner", "inout", "insert", "inserting", "instead",
  69. "int", "int8", "integ", "integer", "internal", "internallength",
  70. "interval", "into", "intrvl_t", "is", "iscanonical", "isolation",
  71. "item", "iterator", "java", "join", "keep", "key", "label", "labeleq",
  72. "labelge", "labelglb", "labelgt", "labelle", "labellt", "labellub",
  73. "labeltostring", "language", "last", "last_day", "leading", "left",
  74. "length", "lessthan", "lessthanorequal", "let", "level", "like",
  75. "limit", "list", "listing", "load", "local", "locator", "lock", "locks",
  76. "locopy", "loc_t", "log", "log10", "logn", "long", "loop", "lotofile",
  77. "low", "lower", "lpad", "ltrim", "lvarchar", "matched", "matches",
  78. "max", "maxerrors", "maxlen", "maxvalue", "mdy", "median", "medium",
  79. "memory", "memory_resident", "merge", "message_length", "message_text",
  80. "middle", "min", "minute", "minvalue", "mod", "mode", "moderate",
  81. "modify", "module", "money", "month", "months_between", "mounting",
  82. "multiset", "multi_index", "name", "nchar", "negator", "new", "next",
  83. "nextval", "next_day", "no", "nocache", "nocycle", "nomaxvalue",
  84. "nomigrate", "nominvalue", "none", "non_dim", "non_resident", "noorder",
  85. "normal", "not", "notemplatearg", "notequal", "null", "nullif",
  86. "numeric", "numrows", "numtodsinterval", "numtoyminterval", "nvarchar",
  87. "nvl", "octet_length", "of", "off", "old", "on", "online", "only",
  88. "opaque", "opclass", "open", "optcompind", "optical", "optimization",
  89. "option", "or", "order", "ordered", "out", "outer", "output",
  90. "override", "page", "parallelizable", "parameter", "partition",
  91. "pascal", "passedbyvalue", "password", "pdqpriority", "percaltl_cos",
  92. "pipe", "pli", "pload", "policy", "pow", "power", "precision",
  93. "prepare", "previous", "primary", "prior", "private", "privileges",
  94. "procedure", "properties", "public", "put", "raise", "range", "raw",
  95. "read", "real", "recordend", "references", "referencing", "register",
  96. "rejectfile", "relative", "release", "remainder", "rename",
  97. "reoptimization", "repeatable", "replace", "replication", "reserve",
  98. "resolution", "resource", "restart", "restrict", "resume", "retain",
  99. "retainupdatelocks", "return", "returned_sqlstate", "returning",
  100. "returns", "reuse", "revoke", "right", "robin", "role", "rollback",
  101. "rollforward", "root", "round", "routine", "row", "rowid", "rowids",
  102. "rows", "row_count", "rpad", "rtrim", "rule", "sameas", "samples",
  103. "sampling", "save", "savepoint", "schema", "scroll", "seclabel_by_comp",
  104. "seclabel_by_name", "seclabel_to_char", "second", "secondary",
  105. "section", "secured", "security", "selconst", "select", "selecting",
  106. "selfunc", "selfuncargs", "sequence", "serial", "serial8",
  107. "serializable", "serveruuid", "server_name", "session", "set",
  108. "setsessionauth", "share", "short", "siblings", "signed", "sin",
  109. "sitename", "size", "skall", "skinhibit", "skip", "skshow",
  110. "smallfloat", "smallint", "some", "specific", "sql", "sqlcode",
  111. "sqlcontext", "sqlerror", "sqlstate", "sqlwarning", "sqrt",
  112. "stability", "stack", "standard", "start", "star_join", "statchange",
  113. "statement", "static", "statistics", "statlevel", "status", "stdev",
  114. "step", "stop", "storage", "store", "strategies", "string",
  115. "stringtolabel", "struct", "style", "subclass_origin", "substr",
  116. "substring", "sum", "support", "sync", "synonym", "sysdate",
  117. "sysdbclose", "sysdbopen", "system", "sys_connect_by_path", "table",
  118. "tables", "tan", "task", "temp", "template", "test", "text", "then",
  119. "time", "timeout", "to", "today", "to_char", "to_date",
  120. "to_dsinterval", "to_number", "to_yminterval", "trace", "trailing",
  121. "transaction", "transition", "tree", "trigger", "triggers", "trim",
  122. "true", "trunc", "truncate", "trusted", "type", "typedef", "typeid",
  123. "typename", "typeof", "uid", "uncommitted", "under", "union",
  124. "unique", "units", "unknown", "unload", "unlock", "unsigned",
  125. "update", "updating", "upon", "upper", "usage", "use",
  126. "uselastcommitted", "user", "use_hash", "use_nl", "use_subqf",
  127. "using", "value", "values", "var", "varchar", "variable", "variance",
  128. "variant", "varying", "vercols", "view", "violations", "void",
  129. "volatile", "wait", "warning", "weekday", "when", "whenever", "where",
  130. "while", "with", "without", "work", "write", "writedown", "writeup",
  131. "xadatasource", "xid", "xload", "xunload", "year"
  132. ])
  133. class InfoDateTime(sqltypes.DateTime):
  134. def bind_processor(self, dialect):
  135. def process(value):
  136. if value is not None:
  137. if value.microsecond:
  138. value = value.replace(microsecond=0)
  139. return value
  140. return process
  141. class InfoTime(sqltypes.Time):
  142. def bind_processor(self, dialect):
  143. def process(value):
  144. if value is not None:
  145. if value.microsecond:
  146. value = value.replace(microsecond=0)
  147. return value
  148. return process
  149. def result_processor(self, dialect, coltype):
  150. def process(value):
  151. if isinstance(value, datetime.datetime):
  152. return value.time()
  153. else:
  154. return value
  155. return process
  156. colspecs = {
  157. sqltypes.DateTime : InfoDateTime,
  158. sqltypes.TIMESTAMP: InfoDateTime,
  159. sqltypes.Time: InfoTime,
  160. }
  161. ischema_names = {
  162. 0 : sqltypes.CHAR, # CHAR
  163. 1 : sqltypes.SMALLINT, # SMALLINT
  164. 2 : sqltypes.INTEGER, # INT
  165. 3 : sqltypes.FLOAT, # Float
  166. 3 : sqltypes.Float, # SmallFloat
  167. 5 : sqltypes.DECIMAL, # DECIMAL
  168. 6 : sqltypes.Integer, # Serial
  169. 7 : sqltypes.DATE, # DATE
  170. 8 : sqltypes.Numeric, # MONEY
  171. 10 : sqltypes.DATETIME, # DATETIME
  172. 11 : sqltypes.LargeBinary, # BYTE
  173. 12 : sqltypes.TEXT, # TEXT
  174. 13 : sqltypes.VARCHAR, # VARCHAR
  175. 15 : sqltypes.NCHAR, # NCHAR
  176. 16 : sqltypes.NVARCHAR, # NVARCHAR
  177. 17 : sqltypes.Integer, # INT8
  178. 18 : sqltypes.Integer, # Serial8
  179. 43 : sqltypes.String, # LVARCHAR
  180. -1 : sqltypes.BLOB, # BLOB
  181. -1 : sqltypes.CLOB, # CLOB
  182. }
  183. class InfoTypeCompiler(compiler.GenericTypeCompiler):
  184. def visit_DATETIME(self, type_):
  185. return "DATETIME YEAR TO SECOND"
  186. def visit_TIME(self, type_):
  187. return "DATETIME HOUR TO SECOND"
  188. def visit_TIMESTAMP(self, type_):
  189. return "DATETIME YEAR TO SECOND"
  190. def visit_large_binary(self, type_):
  191. return "BYTE"
  192. def visit_boolean(self, type_):
  193. return "SMALLINT"
  194. class InfoSQLCompiler(compiler.SQLCompiler):
  195. def default_from(self):
  196. return " from systables where tabname = 'systables' "
  197. def get_select_precolumns(self, select):
  198. s = ""
  199. if select._offset:
  200. s += "SKIP %s " % select._offset
  201. if select._limit:
  202. s += "FIRST %s " % select._limit
  203. s += select._distinct and "DISTINCT " or ""
  204. return s
  205. def visit_select(self, select, asfrom=False, parens=True, **kw):
  206. text = compiler.SQLCompiler.visit_select(self, select, asfrom, parens, **kw)
  207. if asfrom and parens and self.dialect.server_version_info < (11,):
  208. #assuming that 11 version doesn't need this, not tested
  209. return "table(multiset" + text + ")"
  210. else:
  211. return text
  212. def limit_clause(self, select):
  213. return ""
  214. def visit_function(self, func, **kw):
  215. if func.name.lower() == 'current_date':
  216. return "today"
  217. elif func.name.lower() == 'current_time':
  218. return "CURRENT HOUR TO SECOND"
  219. elif func.name.lower() in ('current_timestamp', 'now'):
  220. return "CURRENT YEAR TO SECOND"
  221. else:
  222. return compiler.SQLCompiler.visit_function(self, func, **kw)
  223. def visit_mod(self, binary, **kw):
  224. return "MOD(%s, %s)" % (self.process(binary.left), self.process(binary.right))
  225. class InfoDDLCompiler(compiler.DDLCompiler):
  226. def visit_add_constraint(self, create):
  227. preparer = self.preparer
  228. return "ALTER TABLE %s ADD CONSTRAINT %s" % (
  229. self.preparer.format_table(create.element.table),
  230. self.process(create.element)
  231. )
  232. def get_column_specification(self, column, **kw):
  233. colspec = self.preparer.format_column(column)
  234. first = None
  235. if column.primary_key and column.autoincrement:
  236. try:
  237. first = [c for c in column.table.primary_key.columns
  238. if (c.autoincrement and
  239. isinstance(c.type, sqltypes.Integer) and
  240. not c.foreign_keys)].pop(0)
  241. except IndexError:
  242. pass
  243. if column is first:
  244. colspec += " SERIAL"
  245. else:
  246. colspec += " " + self.dialect.type_compiler.process(column.type)
  247. default = self.get_column_default_string(column)
  248. if default is not None:
  249. colspec += " DEFAULT " + default
  250. if not column.nullable:
  251. colspec += " NOT NULL"
  252. return colspec
  253. def get_column_default_string(self, column):
  254. if (isinstance(column.server_default, schema.DefaultClause) and
  255. isinstance(column.server_default.arg, basestring)):
  256. if isinstance(column.type, (sqltypes.Integer, sqltypes.Numeric)):
  257. return self.sql_compiler.process(text(column.server_default.arg))
  258. return super(InfoDDLCompiler, self).get_column_default_string(column)
  259. ### Informix wants the constraint name at the end, hence this ist c&p from sql/compiler.py
  260. def visit_primary_key_constraint(self, constraint):
  261. if len(constraint) == 0:
  262. return ''
  263. text = "PRIMARY KEY "
  264. text += "(%s)" % ', '.join(self.preparer.quote(c.name, c.quote)
  265. for c in constraint)
  266. text += self.define_constraint_deferrability(constraint)
  267. if constraint.name is not None:
  268. text += " CONSTRAINT %s" % self.preparer.format_constraint(constraint)
  269. return text
  270. def visit_foreign_key_constraint(self, constraint):
  271. preparer = self.dialect.identifier_preparer
  272. remote_table = list(constraint._elements.values())[0].column.table
  273. text = "FOREIGN KEY (%s) REFERENCES %s (%s)" % (
  274. ', '.join(preparer.quote(f.parent.name, f.parent.quote)
  275. for f in constraint._elements.values()),
  276. preparer.format_table(remote_table),
  277. ', '.join(preparer.quote(f.column.name, f.column.quote)
  278. for f in constraint._elements.values())
  279. )
  280. text += self.define_constraint_cascades(constraint)
  281. text += self.define_constraint_deferrability(constraint)
  282. if constraint.name is not None:
  283. text += " CONSTRAINT %s " % \
  284. preparer.format_constraint(constraint)
  285. return text
  286. def visit_unique_constraint(self, constraint):
  287. text = "UNIQUE (%s)" % (', '.join(self.preparer.quote(c.name, c.quote) for c in constraint))
  288. text += self.define_constraint_deferrability(constraint)
  289. if constraint.name is not None:
  290. text += "CONSTRAINT %s " % self.preparer.format_constraint(constraint)
  291. return text
  292. class InformixIdentifierPreparer(compiler.IdentifierPreparer):
  293. reserved_words = RESERVED_WORDS
  294. class InformixDialect(default.DefaultDialect):
  295. name = 'informix'
  296. max_identifier_length = 128 # adjusts at runtime based on server version
  297. type_compiler = InfoTypeCompiler
  298. statement_compiler = InfoSQLCompiler
  299. ddl_compiler = InfoDDLCompiler
  300. colspecs = colspecs
  301. ischema_names = ischema_names
  302. preparer = InformixIdentifierPreparer
  303. default_paramstyle = 'qmark'
  304. def __init__(self, has_transactions=True, *args, **kwargs):
  305. self.has_transactions = has_transactions
  306. default.DefaultDialect.__init__(self, *args, **kwargs)
  307. def initialize(self, connection):
  308. super(InformixDialect, self).initialize(connection)
  309. # http://www.querix.com/support/knowledge-base/error_number_message/error_200
  310. if self.server_version_info < (9, 2):
  311. self.max_identifier_length = 18
  312. else:
  313. self.max_identifier_length = 128
  314. def do_begin(self, connection):
  315. cu = connection.cursor()
  316. cu.execute('SET LOCK MODE TO WAIT')
  317. if self.has_transactions:
  318. cu.execute('SET ISOLATION TO REPEATABLE READ')
  319. def do_commit(self, connection):
  320. if self.has_transactions:
  321. connection.commit()
  322. def do_rollback(self, connection):
  323. if self.has_transactions:
  324. connection.rollback()
  325. def _get_table_names(self, connection, schema, type, **kw):
  326. schema = schema or self.default_schema_name
  327. s = "select tabname, owner from systables where owner=? and tabtype=?"
  328. return [row[0] for row in connection.execute(s, schema, type)]
  329. @reflection.cache
  330. def get_table_names(self, connection, schema=None, **kw):
  331. return self._get_table_names(connection, schema, 'T', **kw)
  332. @reflection.cache
  333. def get_view_names(self, connection, schema=None, **kw):
  334. return self._get_table_names(connection, schema, 'V', **kw)
  335. @reflection.cache
  336. def get_schema_names(self, connection, **kw):
  337. s = "select owner from systables"
  338. return [row[0] for row in connection.execute(s)]
  339. def has_table(self, connection, table_name, schema=None):
  340. schema = schema or self.default_schema_name
  341. cursor = connection.execute(
  342. """select tabname from systables where tabname=? and owner=?""",
  343. table_name, schema)
  344. return cursor.first() is not None
  345. @reflection.cache
  346. def get_columns(self, connection, table_name, schema=None, **kw):
  347. schema = schema or self.default_schema_name
  348. c = connection.execute(
  349. """select colname, coltype, collength, t3.default, t1.colno from
  350. syscolumns as t1 , systables as t2 , OUTER sysdefaults as t3
  351. where t1.tabid = t2.tabid and t2.tabname=? and t2.owner=?
  352. and t3.tabid = t2.tabid and t3.colno = t1.colno
  353. order by t1.colno""", table_name, schema)
  354. primary_cols = self.get_primary_keys(connection, table_name, schema, **kw)
  355. columns = []
  356. rows = c.fetchall()
  357. for name, colattr, collength, default, colno in rows:
  358. name = name.lower()
  359. autoincrement = False
  360. primary_key = False
  361. if name in primary_cols:
  362. primary_key = True
  363. # in 7.31, coltype = 0x000
  364. # ^^-- column type
  365. # ^-- 1 not null, 0 null
  366. not_nullable, coltype = divmod(colattr, 256)
  367. if coltype not in (0, 13) and default:
  368. default = default.split()[-1]
  369. if coltype == 6: # Serial, mark as autoincrement
  370. autoincrement = True
  371. if coltype == 0 or coltype == 13: # char, varchar
  372. coltype = ischema_names[coltype](collength)
  373. if default:
  374. default = "'%s'" % default
  375. elif coltype == 5: # decimal
  376. precision, scale = (collength & 0xFF00) >> 8, collength & 0xFF
  377. if scale == 255:
  378. scale = 0
  379. coltype = sqltypes.Numeric(precision, scale)
  380. else:
  381. try:
  382. coltype = ischema_names[coltype]
  383. except KeyError:
  384. util.warn("Did not recognize type '%s' of column '%s'" %
  385. (coltype, name))
  386. coltype = sqltypes.NULLTYPE
  387. column_info = dict(name=name, type=coltype, nullable=not not_nullable,
  388. default=default, autoincrement=autoincrement,
  389. primary_key=primary_key)
  390. columns.append(column_info)
  391. return columns
  392. @reflection.cache
  393. def get_foreign_keys(self, connection, table_name, schema=None, **kw):
  394. schema_sel = schema or self.default_schema_name
  395. c = connection.execute(
  396. """select t1.constrname as cons_name,
  397. t4.colname as local_column, t7.tabname as remote_table,
  398. t6.colname as remote_column, t7.owner as remote_owner
  399. from sysconstraints as t1 , systables as t2 ,
  400. sysindexes as t3 , syscolumns as t4 ,
  401. sysreferences as t5 , syscolumns as t6 , systables as t7 ,
  402. sysconstraints as t8 , sysindexes as t9
  403. where t1.tabid = t2.tabid and t2.tabname=? and t2.owner=? and t1.constrtype = 'R'
  404. and t3.tabid = t2.tabid and t3.idxname = t1.idxname
  405. and t4.tabid = t2.tabid and t4.colno in (t3.part1, t3.part2, t3.part3,
  406. t3.part4, t3.part5, t3.part6, t3.part7, t3.part8, t3.part9, t3.part10,
  407. t3.part11, t3.part11, t3.part12, t3.part13, t3.part4, t3.part15, t3.part16)
  408. and t5.constrid = t1.constrid and t8.constrid = t5.primary
  409. and t6.tabid = t5.ptabid and t6.colno in (t9.part1, t9.part2, t9.part3,
  410. t9.part4, t9.part5, t9.part6, t9.part7, t9.part8, t9.part9, t9.part10,
  411. t9.part11, t9.part11, t9.part12, t9.part13, t9.part4, t9.part15, t9.part16) and t9.idxname =
  412. t8.idxname
  413. and t7.tabid = t5.ptabid""", table_name, schema_sel)
  414. def fkey_rec():
  415. return {
  416. 'name' : None,
  417. 'constrained_columns' : [],
  418. 'referred_schema' : None,
  419. 'referred_table' : None,
  420. 'referred_columns' : []
  421. }
  422. fkeys = util.defaultdict(fkey_rec)
  423. rows = c.fetchall()
  424. for cons_name, local_column, \
  425. remote_table, remote_column, remote_owner in rows:
  426. rec = fkeys[cons_name]
  427. rec['name'] = cons_name
  428. local_cols, remote_cols = \
  429. rec['constrained_columns'], rec['referred_columns']
  430. if not rec['referred_table']:
  431. rec['referred_table'] = remote_table
  432. if schema is not None:
  433. rec['referred_schema'] = remote_owner
  434. if local_column not in local_cols:
  435. local_cols.append(local_column)
  436. if remote_column not in remote_cols:
  437. remote_cols.append(remote_column)
  438. return fkeys.values()
  439. @reflection.cache
  440. def get_primary_keys(self, connection, table_name, schema=None, **kw):
  441. schema = schema or self.default_schema_name
  442. # Select the column positions from sysindexes for sysconstraints
  443. data = connection.execute(
  444. """select t2.*
  445. from systables as t1, sysindexes as t2, sysconstraints as t3
  446. where t1.tabid=t2.tabid and t1.tabname=? and t1.owner=?
  447. and t2.idxname=t3.idxname and t3.constrtype='P'""",
  448. table_name, schema
  449. ).fetchall()
  450. colpositions = set()
  451. for row in data:
  452. colpos = set([getattr(row, 'part%d' % x) for x in range(1,16)])
  453. colpositions |= colpos
  454. if not len(colpositions):
  455. return []
  456. # Select the column names using the columnpositions
  457. # TODO: Maybe cache a bit of those col infos (eg select all colnames for one table)
  458. place_holder = ','.join('?'*len(colpositions))
  459. c = connection.execute(
  460. """select t1.colname
  461. from syscolumns as t1, systables as t2
  462. where t2.tabname=? and t1.tabid = t2.tabid and
  463. t1.colno in (%s)""" % place_holder,
  464. table_name, *colpositions
  465. ).fetchall()
  466. return reduce(lambda x,y: list(x)+list(y), c, [])
  467. @reflection.cache
  468. def get_indexes(self, connection, table_name, schema, **kw):
  469. # TODO: schema...
  470. c = connection.execute(
  471. """select t1.*
  472. from sysindexes as t1 , systables as t2
  473. where t1.tabid = t2.tabid and t2.tabname=?""",
  474. table_name)
  475. indexes = []
  476. for row in c.fetchall():
  477. colnames = [getattr(row, 'part%d' % x) for x in range(1,16)]
  478. colnames = [x for x in colnames if x]
  479. place_holder = ','.join('?'*len(colnames))
  480. c = connection.execute(
  481. """select t1.colname
  482. from syscolumns as t1, systables as t2
  483. where t2.tabname=? and t1.tabid = t2.tabid and
  484. t1.colno in (%s)""" % place_holder,
  485. table_name, *colnames
  486. ).fetchall()
  487. c = reduce(lambda x,y: list(x)+list(y), c, [])
  488. indexes.append({
  489. 'name': row.idxname,
  490. 'unique': row.idxtype.lower() == 'u',
  491. 'column_names': c
  492. })
  493. return indexes
  494. @reflection.cache
  495. def get_view_definition(self, connection, view_name, schema=None, **kw):
  496. schema = schema or self.default_schema_name
  497. c = connection.execute(
  498. """select t1.viewtext
  499. from sysviews as t1 , systables as t2
  500. where t1.tabid=t2.tabid and t2.tabname=?
  501. and t2.owner=? order by seqno""",
  502. view_name, schema).fetchall()
  503. return ''.join([row[0] for row in c])
  504. def _get_default_schema_name(self, connection):
  505. return connection.execute('select CURRENT_ROLE from systables').scalar()