PageRenderTime 67ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/SQLAlchemy-0.7.8/lib/sqlalchemy/dialects/informix/base.py

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