Commits

Anonymous committed 8b3650f

"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

Comments (0)

Files changed (10)

lib/sqlalchemy/databases/firebird.py

         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
 
         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

lib/sqlalchemy/databases/information_schema.py

         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:
             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:

lib/sqlalchemy/databases/informix.py

         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 :
             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 
             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

lib/sqlalchemy/databases/mssql.py

         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
                 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):

lib/sqlalchemy/databases/mysql.py

                 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)
 
             # 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)

lib/sqlalchemy/databases/oracle.py

                 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()
             #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
             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):

lib/sqlalchemy/databases/postgres.py

         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:
             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

lib/sqlalchemy/databases/sqlite.py

 
         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:
             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)

lib/sqlalchemy/engine/base.py

 
         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()
 
         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)
 
         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:
         else:
             conn = connection
         try:
-            self.dialect.reflecttable(conn, table)
+            self.dialect.reflecttable(conn, table, desired_columns)
         finally:
             if connection is None:
                 conn.close()

lib/sqlalchemy/schema.py

             # 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