From: Jonathan Ellis Date: Thu, 26 Jul 2007 00:50:07 +0000 (+0000) Subject: "You can also specify a list or set of column names to autoload, if you only want... X-Git-Tag: rel_0_4_6~19 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=58a0341e7c3c6cb2a614a35e6620ded20a1250b4;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git "You can also specify a list or set of column names to autoload, if you only want to load a subset of the columns in the actual database." fixes #561 --- diff --git a/lib/sqlalchemy/databases/firebird.py b/lib/sqlalchemy/databases/firebird.py index 525e4788de..103415b238 100644 --- a/lib/sqlalchemy/databases/firebird.py +++ b/lib/sqlalchemy/databases/firebird.py @@ -172,7 +172,7 @@ class FBDialect(ansisql.ANSIDialect): else: return False - def reflecttable(self, connection, table): + def reflecttable(self, connection, table, desired_columns): #TODO: map these better column_func = { 14 : lambda r: sqltypes.String(r['FLEN']), # TEXT @@ -250,7 +250,10 @@ class FBDialect(ansisql.ANSIDialect): while row: name = row['FNAME'] - args = [lower_if_possible(name)] + python_name = lower_if_possible(name) + if desired_columns and python_name not in desired_columns: + continue + args = [python_name] kw = {} # get the data types and lengths diff --git a/lib/sqlalchemy/databases/information_schema.py b/lib/sqlalchemy/databases/information_schema.py index d8cad42003..d645885dd9 100644 --- a/lib/sqlalchemy/databases/information_schema.py +++ b/lib/sqlalchemy/databases/information_schema.py @@ -98,8 +98,7 @@ class ISchema(object): return self.cache[name] -def reflecttable(connection, table, ischema_names): - +def reflecttable(connection, table, desired_columns, ischema_names): key_constraints = pg_key_constraints if table.schema is not None: @@ -130,7 +129,9 @@ def reflecttable(connection, table, ischema_names): row[columns.c.numeric_scale], row[columns.c.column_default] ) - + if desired_columns and name not in desired_columns: + continue + args = [] for a in (charlen, numericprec, numericscale): if a is not None: diff --git a/lib/sqlalchemy/databases/informix.py b/lib/sqlalchemy/databases/informix.py index 5aad21b433..396cd487c2 100644 --- a/lib/sqlalchemy/databases/informix.py +++ b/lib/sqlalchemy/databases/informix.py @@ -253,7 +253,7 @@ class InfoDialect(ansisql.ANSIDialect): cursor = connection.execute("""select tabname from systables where tabname=?""", table_name.lower() ) return bool( cursor.fetchone() is not None ) - def reflecttable(self, connection, table): + def reflecttable(self, connection, table, desired_columns): c = connection.execute ("select distinct OWNER from systables where tabname=?", table.name.lower() ) rows = c.fetchall() if not rows : @@ -280,6 +280,10 @@ class InfoDialect(ansisql.ANSIDialect): raise exceptions.NoSuchTableError(table.name) for name , colattr , collength , default , colno in rows: + name = name.lower() + if desired_columns and name not in desired_columns: + continue + # in 7.31, coltype = 0x000 # ^^-- column type # ^-- 1 not null , 0 null @@ -307,8 +311,6 @@ class InfoDialect(ansisql.ANSIDialect): if default is not None: colargs.append(schema.PassiveDefault(sql.text(default))) - name = name.lower() - table.append_column(schema.Column(name, coltype, nullable = (nullable == 0), *colargs)) # FK diff --git a/lib/sqlalchemy/databases/mssql.py b/lib/sqlalchemy/databases/mssql.py index c7fd01f439..74103ecdbc 100644 --- a/lib/sqlalchemy/databases/mssql.py +++ b/lib/sqlalchemy/databases/mssql.py @@ -471,7 +471,7 @@ class MSSQLDialect(ansisql.ANSIDialect): row = c.fetchone() return row is not None - def reflecttable(self, connection, table): + def reflecttable(self, connection, table, desired_columns): import sqlalchemy.databases.information_schema as ischema # Get base columns @@ -503,6 +503,8 @@ class MSSQLDialect(ansisql.ANSIDialect): row[columns.c.numeric_scale], row[columns.c.column_default] ) + if desired_columns and name not in desired_columns: + continue args = [] for a in (charlen, numericprec, numericscale): diff --git a/lib/sqlalchemy/databases/mysql.py b/lib/sqlalchemy/databases/mysql.py index f8b6e9bd79..bc0691d397 100644 --- a/lib/sqlalchemy/databases/mysql.py +++ b/lib/sqlalchemy/databases/mysql.py @@ -1124,7 +1124,7 @@ class MySQLDialect(ansisql.ANSIDialect): version.append(n) return tuple(version) - def reflecttable(self, connection, table): + def reflecttable(self, connection, table, desired_columns): """Load column definitions from the server.""" decode_from = self._detect_charset(connection) @@ -1147,6 +1147,9 @@ class MySQLDialect(ansisql.ANSIDialect): # leave column names as unicode name = name.decode(decode_from) + + if desired_columns and name not in desired_columns: + continue match = re.match(r'(\w+)(\(.*?\))?\s*(\w+)?\s*(\w+)?', type) col_type = match.group(1) diff --git a/lib/sqlalchemy/databases/oracle.py b/lib/sqlalchemy/databases/oracle.py index 50432f6147..6d876d9109 100644 --- a/lib/sqlalchemy/databases/oracle.py +++ b/lib/sqlalchemy/databases/oracle.py @@ -336,7 +336,7 @@ class OracleDialect(ansisql.ANSIDialect): return name, owner, dblink raise - def reflecttable(self, connection, table): + def reflecttable(self, connection, table, desired_columns): preparer = self.identifier_preparer if not preparer.should_quote(table): name = table.name.upper() @@ -358,6 +358,13 @@ class OracleDialect(ansisql.ANSIDialect): #print "ROW:" , row (colname, coltype, length, precision, scale, nullable, default) = (row[0], row[1], row[2], row[3], row[4], row[5]=='Y', row[6]) + # if name comes back as all upper, assume its case folded + if (colname.upper() == colname): + colname = colname.lower() + + if desired_columns and colname not in desired_columns: + continue + # INTEGER if the scale is 0 and precision is null # NUMBER if the scale and precision are both null # NUMBER(9,2) if the precision is 9 and the scale is 2 @@ -384,10 +391,6 @@ class OracleDialect(ansisql.ANSIDialect): if default is not None: colargs.append(schema.PassiveDefault(sql.text(default))) - # if name comes back as all upper, assume its case folded - if (colname.upper() == colname): - colname = colname.lower() - table.append_column(schema.Column(colname, coltype, nullable=nullable, *colargs)) if not len(table.columns): diff --git a/lib/sqlalchemy/databases/postgres.py b/lib/sqlalchemy/databases/postgres.py index 0561012797..f97a18ff2a 100644 --- a/lib/sqlalchemy/databases/postgres.py +++ b/lib/sqlalchemy/databases/postgres.py @@ -335,9 +335,9 @@ class PGDialect(ansisql.ANSIDialect): else: return False - def reflecttable(self, connection, table): + def reflecttable(self, connection, table, desired_columns): if self.use_information_schema: - ischema.reflecttable(connection, table, ischema_names) + ischema.reflecttable(connection, table, desired_columns, ischema_names) else: preparer = self.identifier_preparer if table.schema is not None: @@ -377,6 +377,9 @@ class PGDialect(ansisql.ANSIDialect): domains = self._load_domains(connection) for name, format_type, default, notnull, attnum, table_oid in rows: + if desired_columns and name not in desired_columns: + continue + ## strip (30) from character varying(30) attype = re.search('([^\([]+)', format_type).group(1) nullable = not notnull diff --git a/lib/sqlalchemy/databases/sqlite.py b/lib/sqlalchemy/databases/sqlite.py index 531db44758..9cc35a8cc1 100644 --- a/lib/sqlalchemy/databases/sqlite.py +++ b/lib/sqlalchemy/databases/sqlite.py @@ -235,7 +235,7 @@ class SQLiteDialect(ansisql.ANSIDialect): return (row is not None) - def reflecttable(self, connection, table): + def reflecttable(self, connection, table, desired_columns): c = connection.execute("PRAGMA table_info(%s)" % self.preparer().format_table(table), {}) found_table = False while True: @@ -246,6 +246,8 @@ class SQLiteDialect(ansisql.ANSIDialect): found_table = True (name, type, nullable, has_default, primary_key) = (row[1], row[2].upper(), not row[3], row[4] is not None, row[5]) name = re.sub(r'^\"|\"$', '', name) + if desired_columns and name not in desired_columns: + continue match = re.match(r'(\w+)(\(.*?\))?', type) if match: coltype = match.group(1) diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index 5cdb32a662..5b1ebfcd39 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -148,11 +148,12 @@ class Dialect(object): raise NotImplementedError() - def reflecttable(self, connection, table): + def reflecttable(self, connection, table, desired_columns=None): """Load table description from the database. Given a [sqlalchemy.engine#Connection] and a [sqlalchemy.schema#Table] object, reflect its - columns and properties from the database. + columns and properties from the database. If desired_columns (a list or set) is specified, limit the autoload + to the given column names. """ raise NotImplementedError() @@ -802,10 +803,10 @@ class Connection(Connectable): return self.__engine.drop(entity, connection=self, **kwargs) - def reflecttable(self, table, **kwargs): + def reflecttable(self, table, desired_columns=None): """Reflect the columns in the given string table name from the database.""" - return self.__engine.reflecttable(table, connection=self, **kwargs) + return self.__engine.reflecttable(table, self, desired_columns) def default_schema_name(self): return self.__engine.dialect.get_default_schema_name(self) @@ -1022,7 +1023,7 @@ class Engine(Connectable): return Connection(self, close_with_result=close_with_result, **kwargs) - def reflecttable(self, table, connection=None): + def reflecttable(self, table, connection=None, desired_columns=None): """Given a Table object, reflects its columns and properties from the database.""" if connection is None: @@ -1030,7 +1031,7 @@ class Engine(Connectable): else: conn = connection try: - self.dialect.reflecttable(conn, table) + self.dialect.reflecttable(conn, table, desired_columns) finally: if connection is None: conn.close() diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 08c1f6bab0..018a152b44 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -153,11 +153,17 @@ class _TableSingleton(sql._FigureVisitName): # we do it after the table is in the singleton dictionary to support # circular foreign keys if autoload: + try: + iter(autoload) + except: + columns = None + else: + columns = autoload try: if autoload_with: - autoload_with.reflecttable(table) + autoload_with.reflecttable(table, desired_columns=columns) else: - metadata._get_engine(raiseerr=True).reflecttable(table) + metadata._get_engine(raiseerr=True).reflecttable(table, desired_columns=columns) except exceptions.NoSuchTableError: del metadata.tables[key] raise