def get_table_description(self, cursor, table_name): "Returns a description of the table, with the DB-API cursor.description interface." return [ FieldInfo( info['name'], info['type'], None, info['size'], None, None, info['null_ok'], info['default'], ) for info in self._table_info(cursor, table_name) ]
def get_table_description(self, cursor, table_name): "Returns a description of the table, with the DB-API cursor.description interface." self.cache_bust_counter += 1 cursor.execute("SELECT * FROM {} WHERE ROWNUM < 2 AND {} > 0".format( self.connection.ops.quote_name(table_name), self.cache_bust_counter)) description = [] for desc in cursor.description: name = force_text( desc[0] ) # cx_Oracle always returns a 'str' on both Python 2 and 3 name = name % { } # cx_Oracle, for some reason, doubles percent signs. description.append(FieldInfo(*(name.lower(), ) + desc[1:])) return description
def get_table_description(connection, cursor, table_name): "Returns a description of the table, with the DB-API cursor.description interface." # As cursor.description does not return reliably the nullable property, # we have to query the information_schema (#7783) # cursor.execute(""" # SELECT column_name, is_nullable, column_default # FROM information_schema.columns # WHERE table_name = %s""", [table_name]) # field_map = {line[0]: line[1:] for line in cursor.fetchall()} cursor.execute("SELECT * FROM %s LIMIT 1" % connection.ops.quote_name(table_name)) return [ FieldInfo(*((force_text(line[0]), ) + line[1:6] + (False, None))) for line in cursor.description ]
def get_table_description(self, cursor, table_name): cursor.execute( """ SELECT column_name, is_nullable, NULL AS column_default FROM information_schema.columns WHERE table_name = ? AND table_schema = CURRENT_SCHEMA()""", [table_name]) field_map = {line[0]: line[1:] for line in cursor.fetchall()} cursor.execute('SELECT * FROM {} LIMIT 1'.format( self.connection.ops.quote_name(table_name))) return [ FieldInfo(*((force_text(line[0]), ) + line[1:6] + (field_map[force_text(line[0])][0] == 'YES', field_map[force_text(line[0])][1]))) for line in cursor.description ]
def get_table_description(self, cursor, table_name): """ Returns a description of the table, with the DB-API cursor.description interface." """ # information_schema database gives more accurate results for some figures: # - varchar length returned by cursor.description is an internal length, # not visible length (#5725) # - precision and scale (for decimal fields) (#5014) # - auto_increment is not available in cursor.description # 如何获取cursor呢? # 1. 获取所有的column的信息 cursor.execute(""" SELECT column_name, data_type, character_maximum_length, numeric_precision, numeric_scale, extra, column_default FROM information_schema.columns WHERE table_name = %s AND table_schema = DATABASE()""", [table_name]) # 数据Demo: # col_name data_type max_len num_prec num_scale extra column_default # (u'id', u'int', None, 10L, 0L, u'auto_increment', None), # (u'user_id', u'int', None, 10L, 0L, u'', None), field_info = {line[0]: InfoLine(*line) for line in cursor.fetchall()} # 2. 获取一行数据? cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name)) to_int = lambda i: int(i) if i is not None else i fields = [] for line in cursor.description: # ('id', 3, 1, 11, 11, 0, 0), # ('user_id', 3, 2, 11, 11, 0, 0) col_name = force_text(line[0]) # tuple相加,然后再展开 # name type_code display_size internal_size precision scale null_ok fields.append( FieldInfo(*((col_name,) + line[1:3] + (to_int(field_info[col_name].max_len) or line[3], to_int(field_info[col_name].num_prec) or line[4], to_int(field_info[col_name].num_scale) or line[5]) + (line[6],) + (field_info[col_name].extra,) + (field_info[col_name].column_default,))) ) return fields
def get_table_description(self, cursor, table_name): """ Return a description of the table with the DB-API cursor.description interface." """ # information_schema database gives more accurate results for some figures: # - varchar length returned by cursor.description is an internal length, # not visible length (#5725) # - precision and scale (for decimal fields) (#5014) # - auto_increment is not available in cursor.description cursor.execute(""" SELECT column_name, data_type, character_maximum_length, numeric_precision, numeric_scale, extra, column_default, CASE WHEN column_type LIKE '%% unsigned' THEN 1 ELSE 0 END AS is_unsigned FROM information_schema.columns WHERE table_name = %s AND table_schema = DATABASE()""", [table_name]) field_info = {line[0]: InfoLine(*line) for line in cursor.fetchall()} cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name)) def to_int(i): return int(i) if i is not None else i fields = [] for line in cursor.description: col_name = line[0] fields.append( FieldInfo(*( (col_name,) + line[1:3] + ( to_int(field_info[col_name].max_len) or line[3], to_int(field_info[col_name].num_prec) or line[4], to_int(field_info[col_name].num_scale) or line[5], line[6], field_info[col_name].column_default, field_info[col_name].extra, field_info[col_name].is_unsigned, ) )) ) return fields
def get_table_description(self, cursor, table_name): """ Return a description of the table with the DB-API cursor.description interface. """ # As cursor.description does not return reliably the nullable property, # we have to query the information_schema (#7783) cursor.execute(""" SELECT column_name, is_nullable, column_default FROM information_schema.columns WHERE table_name = %s""", [table_name]) field_map = {line[0]: line[1:] for line in cursor.fetchall()} cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name)) return [ FieldInfo(*line[0:6], field_map[line.name][0] == 'YES', field_map[line.name][1]) for line in cursor.description ]
def get_table_description(self, cursor, table_name): """ Returns a description of the table, with the DB-API cursor.description interface." """ # - information_schema database gives more accurate results for # some figures: # - varchar length returned by cursor.description is an internal # length, not visible length (#5725) # - precision and scale (for decimal fields) (#5014) # - auto_increment is not available in cursor.description InfoLine = namedtuple('InfoLine', 'col_name data_type max_len ' 'num_prec num_scale extra column_default') cursor.execute(""" SELECT column_name, data_type, character_maximum_length, numeric_precision, numeric_scale, extra, column_default FROM information_schema.columns WHERE table_name = %s AND table_schema = DATABASE()""", [table_name]) field_info = dict( (line[0], InfoLine(*line)) for line in cursor.fetchall() ) cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name)) to_int = lambda i: int(i) if i is not None else i fields = [] for line in cursor.description: col_name = force_text(line[0]) fields.append( FieldInfo(*( (col_name,) + line[1:3] + ( to_int(field_info[col_name].max_len) or line[3], to_int(field_info[col_name].num_prec) or line[4], to_int(field_info[col_name].num_scale) or line[5], line[6], field_info[col_name].column_default, field_info[col_name].extra, ) )) ) return fields
def get_table_description(self, cursor, table_name): """ Return a description of the table with the DB-API cursor.description interface. """ return [ FieldInfo( info["name"], info["type"], None, info["size"], None, None, info["null_ok"], info["default"], ) for info in self._table_info(cursor, table_name) ]
def get_table_description(self, cursor, table_name): """ Returns a description of the table, with the DB-API cursor.description interface. Must return a 'FieldInfo' struct 'name type_code display_size internal_size precision scale null_ok' """ cursor.execute(""" select trim(rf.rdb$field_name) , case when (f.rdb$field_type in (7,8,16)) and (f.rdb$field_sub_type > 0) then 160 + f.rdb$field_sub_type when (f.rdb$field_type = 261) then 260 + f.rdb$field_sub_type else f.rdb$field_type end as type_code , case when (f.rdb$field_type in (14,37)) then f.rdb$character_length else f.rdb$field_length end as field_length , f.rdb$field_precision , f.rdb$field_scale * -1 , rf.rdb$null_flag , rf.rdb$default_source , c.rdb$collation_name from rdb$relation_fields rf join rdb$fields f on (rf.rdb$field_source = f.rdb$field_name) join rdb$collations c on (rf.rdb$collation_id = c.rdb$collation_id) where rf.rdb$relation_name = '%s' order by rf.rdb$field_position """ % (table_name.strip().upper(), )) items = [] for r in cursor.fetchall(): # name type_code display_size internal_size precision scale null_ok, default, collation items.append( FieldInfo(self.identifier_converter(r[0]), r[1], r[2], r[2] or 0, r[3], r[4], not (r[5] == 1), r[6], r[7])) return items
def get_table_description(self, cursor, table_name): """ Return a description of the table with the DB-API cursor.description interface. """ # Query the pg_catalog tables as cursor.description does not reliably # return the nullable property and information_schema.columns does not # contain details of materialized views. cursor.execute( """ SELECT a.attname AS column_name, NOT (a.attnotnull OR (t.typtype = 'd' AND t.typnotnull)) AS is_nullable, pg_get_expr(ad.adbin, ad.adrelid) AS column_default, CASE WHEN collname = 'default' THEN NULL ELSE collname END AS collation FROM pg_attribute a LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum LEFT JOIN pg_collation co ON a.attcollation = co.oid JOIN pg_type t ON a.atttypid = t.oid JOIN pg_class c ON a.attrelid = c.oid JOIN pg_namespace n ON c.relnamespace = n.oid WHERE c.relkind IN ('f', 'm', 'p', 'r', 'v') AND c.relname = %s AND n.nspname NOT IN ('pg_catalog', 'pg_toast') AND pg_catalog.pg_table_is_visible(c.oid) """, [table_name], ) field_map = {line[0]: line[1:] for line in cursor.fetchall()} cursor.execute( "SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name) ) return [ FieldInfo( line.name, line.type_code, line.display_size, line.internal_size, line.precision, line.scale, *field_map[line.name], ) for line in cursor.description ]
def get_table_description(self, cursor, table_name): """Return a description of the table with the DB-API cursor.description interface. :type cursor: :class:`~google.cloud.spanner_dbapi.cursor.Cursor` :param cursor: A reference to a Spanner Database cursor. :type table_name: str :param table_name: The name of the table. :rtype: list :returns: A description of the table with the DB-API cursor.description interface. """ cursor.execute( "SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name) ) column_details = cursor.get_table_column_schema(table_name) descriptions = [] for line in cursor.description: column_name, type_code = line[0], line[1] details = column_details[column_name] if details.spanner_type.startswith("STRING"): # Extract the size of the string from, e.g. STRING(#). internal_size = details.spanner_type[7:-1] if internal_size != "MAX": internal_size = int(internal_size) else: internal_size = None descriptions.append( FieldInfo( column_name, type_code, None, # display_size internal_size, None, # precision None, # scale details.null_ok, None, # default ) ) return descriptions
def get_table_description(self, cursor, table_name): """ Returns a description of the table, with the DB-API cursor.description interface. Must return a 'FieldInfo' struct 'name type_code display_size internal_size precision scale null_ok' """ cursor.execute(""" select trim(rf.rdb$field_name) , case when (f.rdb$field_type in (7,8,16)) and (f.rdb$field_sub_type > 0) then 160 + f.rdb$field_sub_type when (f.rdb$field_type = 261) then 260 + f.rdb$field_sub_type else f.rdb$field_type end as type_code , case when (f.rdb$field_type in (14,37)) then f.rdb$character_length else f.rdb$field_length end as field_length , f.rdb$field_precision , f.rdb$field_scale * -1 , rf.rdb$null_flag , rf.rdb$default_source /*RDB$IDENTITY_TYPE stores the value 0 for GENERATED ALWAYS, 1 for GENERATED BY DEFAULT, and NULL for non-identity columns.*/ ,NULL as rdb$identity_type /*ToDo: In Firebird 3.0 or hight, this fields exists as: rf.rdb$identity_type*/ from rdb$relation_fields rf join rdb$fields f on (rf.rdb$field_source = f.rdb$field_name) where rf.rdb$relation_name = '%s' order by rf.rdb$field_position """ % (table_name.strip().upper(), )) items = [] for r in cursor.fetchall(): # name type_code display_size internal_size precision scale null_ok, default, identity_type items.append( FieldInfo(self.identifier_converter(r[0]), r[1], r[2], r[2] or 0, r[3], r[4], not (r[5] == 1), r[6], r[7])) return items
def get_table_description(self, cursor, table_name): "Returns a description of the table, with the DB-API cursor.description interface." query_format = """SELECT c.* FROM syscolumns c JOIN systables t ON c.tabid=t.tabid WHERE t.tabname='{}'""" cursor.execute(query_format.format(table_name)) columns = [[c[0], c[3] % 256, None, c[4], c[4], None, 0 if c[3] > 256 else 1, None] for c in cursor.fetchall()] items = [] for column in columns: if column[1] in [SQL_TYPE_NUMERIC, SQL_TYPE_DECIMAL]: column[4] = int(column[3] / 256) column[5] = column[3] - column[4] * 256 # FieldInfo = namedtuple('FieldInfo', 'name type_code display_size internal_size precision scale null_ok default') # The named tuple above will help decypher the introspection process. # We care alot about the type column items.append(FieldInfo(*column)) return items
def get_table_description(self, cursor, table_name, identity_check=True): """Returns a description of the table, with DB-API cursor.description interface. The 'auto_check' parameter has been added to the function argspec. If set to True, the function will check each of the table's fields for the IDENTITY property (the IDENTITY property is the MSSQL equivalent to an AutoField). When an integer field is found with an IDENTITY property, it is given a custom field number of SQL_AUTOFIELD, which maps to the 'AutoField' value in the DATA_TYPES_REVERSE dict. When a bigint field is found with an IDENTITY property, it is given a custom field number of SQL_BIGAUTOFIELD, which maps to the 'BigAutoField' value in the DATA_TYPES_REVERSE dict. """ # map pyodbc's cursor.columns to db-api cursor description columns = [[c[3], c[4], None, c[6], c[6], c[8], c[10], c[12]] for c in cursor.columns(table=table_name)] items = [] for column in columns: if VERSION >= (3, 2): if self.connection.sql_server_version >= 2019: sql = """SELECT collation_name FROM sys.columns c inner join sys.tables t on c.object_id = t.object_id WHERE t.name = '%s' and c.name = '%s' """ % (table_name, column[0]) cursor.execute(sql) collation_name = cursor.fetchone() column.append(collation_name[0] if collation_name else '') else: column.append('') if identity_check and self._is_auto_field(cursor, table_name, column[0]): if column[1] == Database.SQL_BIGINT: column[1] = SQL_BIGAUTOFIELD else: column[1] = SQL_AUTOFIELD if column[1] == Database.SQL_WVARCHAR and column[3] < 4000: column[1] = Database.SQL_WCHAR items.append(FieldInfo(*column)) return items
def get_table_description(self, cursor, table_name): colspecs = collections.defaultdict(lambda: dict( types=collections.Counter(), specs=collections.defaultdict(int), )) fields = cursor.db_conn['__schema__'].find_one( {'name': table_name}, {'fields': True})['fields'] columns = [] for name, properties in fields.items(): columns.append( FieldInfo(name=name, type_code=properties['type_code'], display_size=None, internal_size=None, precision=None, scale=None, null_ok=None, default=None)) return columns
def get_table_description(self, cursor, table_name): "Returns a description of the table, with the DB-API cursor.description interface." # As cursor.description does not return reliably the nullable property, # we have to query the information_schema (#7783) # HACK: limit on supported schemas, adding table_schema constraint cursor.execute(""" SELECT column_name, is_nullable, column_default FROM information_schema.columns WHERE table_name = %s AND table_schema IN %s""", [table_name, self._supported_schemas]) field_map = {line[0]: line[1:] for line in cursor.fetchall()} cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name)) return [ FieldInfo(*( (force_text(line[0]),) + line[1:6] + (field_map[force_text(line[0])][0] == 'YES', field_map[force_text(line[0])][1]) )) for line in cursor.description ]
def get_table_description(self, cursor, table_name): "Returns a description of the table, with the DB-API cursor.description interface." # As cursor.description does not return reliably the nullable property, # we have to query the information_schema (#7783) cursor.execute( """ SELECT column_name, is_nullable, column_default FROM information_schema.columns WHERE table_schema = %s and table_name = %s""", [self.connection._schema.schema_name, table_name], ) field_map = {line[0]: line[1:] for line in cursor.fetchall()} cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name)) return [ FieldInfo(*((force_str(line[0]), ) + line[1:6] + (field_map[force_str(line[0])][0] == "YES", field_map[force_str(line[0])][1]))) for line in cursor.description ]
def get_table_description(self, cursor, table_name, identity_check=True): """Returns a description of the table, with DB-API cursor.description interface. The 'auto_check' parameter has been added to the function argspec. If set to True, the function will check each of the table's fields for the IDENTITY property (the IDENTITY property is the MSSQL equivalent to an AutoField). When a field is found with an IDENTITY property, it is given a custom field number of SQL_AUTOFIELD, which maps to the 'AutoField' value in the DATA_TYPES_REVERSE dict. """ # map pyodbc's cursor.columns to db-api cursor description columns = [[c[3], c[4], None, c[6], c[6], c[8], c[10], c[12]] for c in cursor.columns(table=table_name)] items = [] for column in columns: if identity_check and self._is_auto_field(cursor, table_name, column[0]): column[1] = SQL_AUTOFIELD if column[1] == Database.SQL_WVARCHAR and column[3] < 4000: column[1] = Database.SQL_WCHAR items.append(FieldInfo(*column)) return items
def get_table_description(self, cursor, table_name): """ Returns a description of the table, with the DB-API cursor.description interface. """ # As cursor.description does not return reliably the nullable property, # we have to query the information_schema (#7783) cursor.execute(self._get_table_description_query, { 'schema': self.connection.schema_name, 'table': table_name }) field_map = {line[0]: line[1:] for line in cursor.fetchall()} cursor.execute('SELECT * FROM %s LIMIT 1' % self.connection.ops.quote_name(table_name)) return [ FieldInfo(*((force_text(line[0]), ) + line[1:6] + (field_map[force_text(line[0])][0] == 'YES', field_map[force_text(line[0])][1]))) for line in cursor.description ]
def get_table_description(self, cursor, table_name): """ Returns a description of the table, with the DB-API cursor.description interface. """ # varchar length returned by cursor.description is an internal # length not visible length (#5725), use information_schema database # to fix this cursor.execute( "SELECT column_name, character_maximum_length " "FROM INFORMATION_SCHEMA.COLUMNS " "WHERE table_name = %s AND table_schema = DATABASE() " "AND character_maximum_length IS NOT NULL", [table_name]) length_map = dict(cursor.fetchall()) # Also getting precision and scale from # information_schema (see #5014) cursor.execute( "SELECT column_name, numeric_precision, numeric_scale FROM " "INFORMATION_SCHEMA.COLUMNS WHERE table_name = %s AND " "table_schema = DATABASE() AND data_type='decimal'", [table_name]) numeric_map = dict((line[0], tuple([int(n) for n in line[1:]])) for line in cursor.fetchall()) cursor.execute("SELECT * FROM {0} LIMIT 1".format( self.connection.ops.quote_name(table_name))) if django.VERSION >= (1, 6): return [ FieldInfo(*((force_text(line[0]), ) + line[1:3] + (length_map.get(line[0], line[3]), ) + numeric_map.get(line[0], line[4:6]) + (line[6], ))) for line in cursor.description ] else: return [ line[:3] + (length_map.get(line[0], line[3]), ) + line[4:] for line in cursor.description ]
def get_table_description(self, cursor, table_name, identity_check=True): """Return a description of the table, with DB-API cursor.description interface. The 'auto_check' parameter has been added to the function argspec. If set to True, the function will check each of the table's fields for the IDENTITY property (the IDENTITY property is the MSSQL equivalent to an AutoField). When a field is found with an IDENTITY property, it is given a custom field number of SQL_AUTOFIELD, which maps to the 'AutoField' value in the DATA_TYPES_REVERSE dict. """ table_field_type_map = self._get_table_field_type_map( cursor, table_name) cursor.execute("SELECT * FROM [%s] where 1=0" % (table_name)) columns = cursor.description items = list() for column in columns: column = list(column) # Convert tuple to list # fix data type data_type, char_length = table_field_type_map.get(column[0]) column[1] = self._datatype_to_ado_type(data_type) if identity_check and self._is_auto_field(cursor, table_name, column[0]): if column[1] == ado_consts.adBigInt: column[1] = BIG_AUTO_FIELD_MARKER else: column[1] = AUTO_FIELD_MARKER if column[1] == MONEY_FIELD_MARKER: # force decimal_places=4 to match data type. Cursor description thinks this column is a string column[5] = 4 elif column[1] == ado_consts.adVarWChar and char_length == -1: # treat varchar(max) as text column[1] = self._datatype_to_ado_type('text') items.append(FieldInfo(*column)) return items
def get_table_description(self, cursor, table_name): """ Return a description of the table with the DB-API cursor.description interface. """ # user_tab_columns gives data default for columns cursor.execute(""" SELECT column_name, data_default, CASE WHEN char_used IS NULL THEN data_length ELSE char_length END as internal_size FROM user_tab_cols WHERE table_name = UPPER(%s)""", [table_name]) field_map = { column: (internal_size, default if default != 'NULL' else None) for column, default, internal_size in cursor.fetchall() } self.cache_bust_counter += 1 cursor.execute("SELECT * FROM {} WHERE ROWNUM < 2 AND {} > 0".format( self.connection.ops.quote_name(table_name), self.cache_bust_counter)) description = [] for desc in cursor.description: name = force_text(desc[0]) # cx_Oracle always returns a 'str' internal_size, default = field_map[name] name = name % {} # cx_Oracle, for some reason, doubles percent signs. description.append(FieldInfo(*( (name.lower(),) + desc[1:3] + (internal_size, desc[4] or 0, desc[5] or 0) + desc[6:] + (default,) ))) return description
def get_table_description(self, cursor, table_name): """ Returns a description of the table, with the DB-API cursor.description interface. Must return a 'FieldInfo' struct 'name type_code display_size internal_size precision scale null_ok' """ tbl_name = "'%s'" % table_name.upper() cursor.execute(""" select lower(trim(rf.rdb$field_name)) , case when (f.rdb$field_type in (7,8,16)) and (f.rdb$field_sub_type > 0) then 160 + f.rdb$field_sub_type when (f.rdb$field_type = 261) then 260 + f.rdb$field_sub_type else f.rdb$field_type end as type_code , f.rdb$field_length , f.rdb$field_precision , f.rdb$field_scale * -1 , rf.rdb$null_flag , rf.rdb$default_source from rdb$relation_fields rf join rdb$fields f on (rf.rdb$field_source = f.rdb$field_name) where upper(rf.rdb$relation_name) = %s order by rf.rdb$field_position """ % (tbl_name, )) items = [] for r in cursor.fetchall(): # name type_code display_size internal_size precision scale null_ok items.append( FieldInfo(r[0], r[1], r[2], r[2] or 0, r[3], r[4], not (r[5] == 1), r[6])) return items
def test_get_table_description(self): """ Tests get table description method. """ db_introspection = DatabaseIntrospection(self.connection) cursor = mock.MagicMock() def description(*args, **kwargs): return [["name", TypeCode.STRING], ["age", TypeCode.INT64]] def get_table_column_schema(*args, **kwargs): column_details = {} column_details["name"] = ColumnDetails(null_ok=False, spanner_type="STRING(10)") column_details["age"] = ColumnDetails(null_ok=True, spanner_type="INT64") return column_details cursor.get_table_column_schema = get_table_column_schema cursor.description = description() table_description = db_introspection.get_table_description( cursor=cursor, table_name="Table_1") if USING_DJANGO_3: self.assertEqual( table_description, [ FieldInfo( name="name", type_code=TypeCode.STRING, display_size=None, internal_size=10, precision=None, scale=None, null_ok=False, default=None, collation=None, ), FieldInfo( name="age", type_code=TypeCode.INT64, display_size=None, internal_size=None, precision=None, scale=None, null_ok=True, default=None, collation=None, ), ], ) else: self.assertEqual( table_description, [ FieldInfo( name="name", type_code=TypeCode.STRING, display_size=None, internal_size=10, precision=None, scale=None, null_ok=False, default=None, ), FieldInfo( name="age", type_code=TypeCode.INT64, display_size=None, internal_size=None, precision=None, scale=None, null_ok=True, default=None, ), ], )
def get_table_description(self, cursor, table_name): colspecs = collections.defaultdict(lambda: dict( types=collections.Counter(), specs=collections.defaultdict(int), )) fields = cursor.db_conn['__schema__'].find_one( {'name': table_name}, {'fields': True})['fields'] columns = [] for name, properties in fields.items(): columns.append( FieldInfo(name=name, type_code=properties['type_code'], display_size=None, internal_size=None, precision=None, scale=None, null_ok=None, default=None)) return columns results = cursor.db_conn[table_name].aggregate([ { '$sample': { 'size': self.SAMPLE_SIZE } }, ]) for result in results: for k, v in result.items(): column = colspecs[k] specs = column['specs'] column['types'][type(v)] += 1 if isinstance(v, str): specs['length'] = max(specs['length'], len(str(v))) if isinstance(v, (int, bson.int64.Int64, float)): specs['max_value'] = max(specs['max_value'], v) if isinstance(v, float): # Convert to string and count the characters after the . precision = len(str(v).split('.')[1]) specs['precision'] = max(specs['precision'], precision) columns = [] for name, column in colspecs.items(): types = column['types'] specs = column['specs'] if type(None) in types: nullable = True del types[type(None)] else: nullable = False for from_, count in list(types.items()): to = self.TYPE_MAPPING.get(from_) if to: types[to] = types.pop(from_) type_ = types.most_common(1)[0][0] if type_ == str and specs['length'] > 200: type_ = 'text' del specs['length'] if len(types) > 1: print('# Found multiple types for %s.%s: %s' % (table_name, name, types)) columns.append( FieldInfo( name, # name type_, # type_code specs.get('length'), # display size specs.get('length'), # internal size specs.get('precision'), # precision None, # scale nullable, # nullable None, # default )) return columns
def get_table_description(self, cursor, table_name): <<<<<<< HEAD "Returns a description of the table, with the DB-API cursor.description interface." ======= """ Return a description of the table with the DB-API cursor.description interface. """ >>>>>>> 37c99181c9a6b95433d60f8c8ef9af5731096435 return [ FieldInfo( info['name'], info['type'], None, info['size'], None, None, info['null_ok'], info['default'], ) for info in self._table_info(cursor, table_name) ] <<<<<<< HEAD ======= def get_sequences(self, cursor, table_name, table_fields=()): pk_col = self.get_primary_key_column(cursor, table_name) return [{'table': table_name, 'column': pk_col}] >>>>>>> 37c99181c9a6b95433d60f8c8ef9af5731096435 def column_name_converter(self, name): """