Project

General

Profile

« Previous | Next » 

Revision 6899

sql.py: DbConn.col_info(): For PostgreSQL, use pg_catalog tables directly instead of their views in information_schema. This allows using ::regclass to look up the table in the search_path, and fixes a bug in imports with an explicit public schema where column types were looked up in public instead of public.<version>. Also don't wrap default using sql_gen.as_Code() when it's None (indicating no default value, aka default=NULL), because this value is interpreted specially by sql_gen.TypedCol.

View differences:

lib/sql.py
469 469
            self.db.commit()
470 470
    
471 471
    def col_info(self, col, cacheable=True):
472
        table = sql_gen.Table('columns', 'information_schema')
473
        cols = [sql_gen.Col('data_type'), sql_gen.Col('udt_name'),
474
            'column_default', sql_gen.Cast('boolean',
475
            sql_gen.Col('is_nullable'))]
472
        module = util.root_module(db.db)
473
        if module == 'psycopg2':
474
            qual_table = sql_gen.Literal(col.table.to_str(db))
475
            col_name_str = sql_gen.Literal(col.name)
476
            try:
477
                type_, type_is_array, default, nullable = row(run_query(db, '''\
478
SELECT
479
format_type(COALESCE(NULLIF(typelem, 0), pg_type.oid), -1) AS type
480
, typcategory = 'A' AS type_is_array
481
, pg_attrdef.adsrc AS default
482
, NOT pg_attribute.attnotnull AS nullable
483
FROM pg_attribute
484
LEFT JOIN pg_type ON pg_type.oid = atttypid
485
LEFT JOIN pg_attrdef ON adrelid = attrelid AND adnum = attnum
486
WHERE
487
attrelid = '''+self.esc_value(qual_table)+'''::regclass
488
AND attname = '''+self.esc_value(col_name_str)+'''
489
'''
490
                    , cacheable=True, log_level=4))
491
            except StopIteration: raise sql_gen.NoUnderlyingTableException(col)
492
            if type_is_array: type_ = sql_gen.ArrayType(type_)
493
        else:
494
            table = sql_gen.Table('columns', 'information_schema')
495
            cols = [sql_gen.Col('data_type'), sql_gen.Col('udt_name'),
496
                'column_default', sql_gen.Cast('boolean',
497
                sql_gen.Col('is_nullable'))]
498
            
499
            conds = [('table_name', col.table.name),
500
                ('column_name', strings.ustr(col.name))]
501
            schema = col.table.schema
502
            if schema != None: conds.append(('table_schema', schema))
503
            
504
            cur = select(self, table, cols, conds, order_by='table_schema',
505
                limit=1, cacheable=cacheable, log_level=4)
506
            try: type_, extra_type, default, nullable = row(cur)
507
            except StopIteration: raise sql_gen.NoUnderlyingTableException(col)
508
            if type_ == 'USER-DEFINED': type_ = extra_type
509
            elif type_ == 'ARRAY':
510
                type_ = sql_gen.ArrayType(strings.remove_prefix('_', extra_type,
511
                    require=True))
476 512
        
477
        conds = [('table_name', col.table.name),
478
            ('column_name', strings.ustr(col.name))]
479
        schema = col.table.schema
480
        if schema != None: conds.append(('table_schema', schema))
481
        
482
        cur = select(self, table, cols, conds, order_by='table_schema', limit=1,
483
            cacheable=cacheable, log_level=4) # TODO: order by search_path order
484
        try: type_, extra_type, default, nullable = row(cur)
485
        except StopIteration: raise sql_gen.NoUnderlyingTableException(col)
486
        default = sql_gen.as_Code(default, self)
487
        if type_ == 'USER-DEFINED': type_ = extra_type
488
        elif type_ == 'ARRAY':
489
            type_ = sql_gen.ArrayType(strings.remove_prefix('_', extra_type,
490
                require=True))
491
        
513
        if default != None: default = sql_gen.as_Code(default, self)
492 514
        return sql_gen.TypedCol(col.name, type_, default, nullable)
493 515
    
494 516
    def TempFunction(self, name):

Also available in: Unified diff