better teradata adapter, thanks Andrew Willimott

This commit is contained in:
Massimo Di Pierro
2012-05-11 08:14:57 -05:00
parent 3bd84e3698
commit d777cde5fc
3 changed files with 8 additions and 163 deletions
+1 -1
View File
@@ -1 +1 @@
Version 1.99.7 (2012-05-10 22:35:45) dev
Version 1.99.7 (2012-05-11 08:14:33) dev
+1 -1
View File
@@ -28,7 +28,7 @@
</li><li>Alan Etkin (DAL IMAP adapter)
</li><li>Alvaro Justen (dynamical translations)
</li><li>Anders Roos (file locking)
</li><li>Andrew Willimott (documentation)
</li><li>Andrew Willimott (documentation, TeraData support)
</li><li>Angelo Compagnucci (mobile devices)
</li><li>Anthony Bastardi (book, poweredby site, multiple contributions)
</li><li>Arun K. Rajeevan (plugin_wiki)
+6 -161
View File
@@ -3160,167 +3160,6 @@ class TeradataAdapter(BaseAdapter):
'reference TFK': ' FOREIGN KEY (%(field_name)s) REFERENCES %(foreign_table)s (%(foreign_key)s)',
}
def LEFT_JOIN(self):
return 'LEFT OUTER JOIN'
def create_table(self, table,
migrate=True,
fake_migrate=False,
polymodel=None):
fields = []
sql_fields = {}
sql_fields_aux = {}
TFK = {}
tablename = table._tablename
sortable = 0
for field in table:
sortable += 1
k = field.name
if isinstance(field.type,SQLCustomType):
ftype = field.type.native or field.type.type
elif field.type.startswith('reference'):
referenced = field.type[10:].strip()
constraint_name = self.constraint_name(tablename, field.name)
if hasattr(table,'_primarykey'):
rtablename,rfieldname = referenced.split('.')
rtable = table._db[rtablename]
rfield = rtable[rfieldname]
# must be PK reference or unique
if rfieldname in rtable._primarykey or rfield.unique:
ftype = self.types[rfield.type[:9]] % dict(length=rfield.length)
# multicolumn primary key reference?
if not rfield.unique and len(rtable._primarykey)>1 :
# then it has to be a table level FK
if rtablename not in TFK:
TFK[rtablename] = {}
TFK[rtablename][rfieldname] = field.name
else:
ftype = ftype + \
self.types['reference FK'] %dict(\
constraint_name=constraint_name,
table_name=tablename,
field_name=field.name,
foreign_key='%s (%s)'%(rtablename, rfieldname),
on_delete_action=field.ondelete)
else:
# make a guess here for circular references
id_fieldname = referenced in table._db and table._db[referenced]._id.name or 'id'
ftype = self.types[field.type[:9]]\
% dict(table_name=tablename,
field_name=field.name,
constraint_name=constraint_name,
foreign_key=referenced + ('(%s)' % id_fieldname),
on_delete_action=field.ondelete)
elif field.type.startswith('list:reference'):
ftype = self.types[field.type[:14]]
elif field.type.startswith('decimal'):
precision, scale = map(int,field.type[8:-1].split(','))
ftype = self.types[field.type[:7]] % \
dict(precision=precision,scale=scale)
elif not field.type in self.types:
raise SyntaxError, 'Field: unknown field type: %s for %s' % \
(field.type, field.name)
else:
ftype = self.types[field.type]\
% dict(length=field.length)
if not field.type.startswith('id') and not field.type.startswith('reference'):
if field.notnull:
ftype += ' NOT NULL'
else:
ftype += self.ALLOW_NULL()
if field.unique:
ftype += ' UNIQUE'
# add to list of fields
sql_fields[field.name] = dict(sortable=sortable,
type=str(field.type),
sql=ftype)
if isinstance(field.default,(str,int,float)):
# Caveat: sql_fields and sql_fields_aux differ for default values.
# sql_fields is used to trigger migrations and sql_fields_aux
# is used for create tables.
# The reason is that we do not want to trigger a migration simply
# because a default value changes.
not_null = self.NOT_NULL(field.default, field.type)
ftype = ftype.replace('NOT NULL', not_null)
sql_fields_aux[field.name] = dict(sql=ftype)
fields.append('%s %s' % (field.name, ftype))
other = ';'
fields = ',\n '.join(fields)
for rtablename in TFK:
rfields = TFK[rtablename]
pkeys = table._db[rtablename]._primarykey
fkeys = [ rfields[k] for k in pkeys ]
fields = fields + ',\n ' + \
self.types['reference TFK'] %\
dict(table_name=tablename,
field_name=', '.join(fkeys),
foreign_table=rtablename,
foreign_key=', '.join(pkeys),
on_delete_action=field.ondelete)
if hasattr(table,'_primarykey'):
query = '''CREATE TABLE %s(\n %s,\n %s) %s''' % \
(tablename, fields, self.PRIMARY_KEY(', '.join(table._primarykey)),other)
else:
query = '''CREATE TABLE %s(\n %s\n)%s''' % \
(tablename, fields, other)
if self.uri.startswith('sqlite:///'):
path_encoding = sys.getfilesystemencoding() or locale.getdefaultlocale()[1] or 'utf8'
dbpath = self.uri[9:self.uri.rfind('/')].decode('utf8').encode(path_encoding)
else:
dbpath = self.folder
if not migrate:
return query
elif self.uri.startswith('sqlite:memory'):
table._dbt = None
elif isinstance(migrate, str):
table._dbt = os.path.join(dbpath, migrate)
else:
table._dbt = os.path.join(dbpath, '%s_%s.table' \
% (table._db._uri_hash, tablename))
if table._dbt:
table._loggername = os.path.join(dbpath, 'sql.log')
logfile = self.file_open(table._loggername, 'a')
else:
logfile = None
if not table._dbt or not self.file_exists(table._dbt):
if table._dbt:
logfile.write('timestamp: %s\n'
% datetime.datetime.today().isoformat())
logfile.write(query + '\n')
if not fake_migrate:
self.create_sequence_and_triggers(query,table)
table._db.commit()
if table._dbt:
tfile = self.file_open(table._dbt, 'w')
cPickle.dump(sql_fields, tfile)
self.file_close(tfile)
if fake_migrate:
logfile.write('faked!\n')
else:
logfile.write('success!\n')
else:
tfile = self.file_open(table._dbt, 'r')
try:
sql_fields_old = cPickle.load(tfile)
except EOFError:
self.file_close(tfile)
self.file_close(logfile)
raise RuntimeError, 'File %s appears corrupted' % table._dbt
self.file_close(tfile)
if sql_fields != sql_fields_old:
self.migrate_table(table,
sql_fields, sql_fields_old,
sql_fields_aux, logfile,
fake_migrate=fake_migrate)
self.file_close(logfile)
return query
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
credential_decoder=lambda x:x, driver_args={},
adapter_args={}):
@@ -3339,6 +3178,9 @@ class TeradataAdapter(BaseAdapter):
self.pool_connection(connect)
self.after_connection()
def LEFT_JOIN(self):
return 'LEFT OUTER JOIN'
# Similar to MSSQL, Teradata can't specify a range (for Pageby)
def select_limitby(self, sql_s, sql_f, sql_t, sql_w, sql_o, limitby):
if limitby:
@@ -3346,6 +3188,9 @@ class TeradataAdapter(BaseAdapter):
sql_s += ' TOP %i' % lmax
return 'SELECT %s %s FROM %s%s%s;' % (sql_s, sql_f, sql_t, sql_w, sql_o)
def _truncate(self, table, mode=''):
tablename = table._tablename
return ['DELETE FROM %s ALL;' % (tablename)]
INGRES_SEQNAME='ii***lineitemsequence' # NOTE invalid database object name
# (ANSI-SQL wants this form of name