How to create shadow table in Informix How to create shadow table in Informix database database

How to create shadow table in Informix


Your query will work, but it might be more idiomatic to use a join:

SELECT *  FROM "informix".systables AS t  JOIN "informix".syscolumns AS c ON t.tabid = c.tabid WHERE t.tabname = 'table_a';

Also, be aware that the system catalog will only contain table_A in mixed case if you created the table while you had DELIMIDENT set in the environment and you created the table with the name enclosed in double quotes. Normally, the table name will be in all lower-case letters in the system catalog; similarly for column names.

However, that's all tangential to your question. Dealing with user-defined types in all their glory is painful. However, if you're dealing with normal databases, you can certainly work like that, though it might be easier to use DB-Schema (dbschema) to generate the schema for a table, and then trap that. You could actually do that through a stored procedure using the SYSTEM statement, but I'd probably do it from outside a stored procedure. It does depend on what else you need to do. The pre-image and post-image for each field could be modestly costly.

If you have IBM Informix Dynamic Server 11.70, you can create your CREATE {audit} TABLE statement dynamically, and then execute the statement. So, you'd build up your query using a FOREACH loop in the stored procedure to add each column in turn, and then execute the statement to create the audit table. You'll have to decode the type, too. You could/should use a procedure for that, too. I'm assuming that tabname is a variable passed to the stored procedure, and c_colno, c_colname, and c_typename are local variables (as is cts, short for 'create table statement', and pad):

LET cts = 'CREATE TABLE ' || tabname || '(';LET pad = '';FOREACH SELECT c.colno, c.colname, type_name(c.coltype, c.collength)          INTO c_colno, c_colname, c_typename          FROM "informix".systables AS t          JOIN "informix".syscolumns AS c            ON t.tabid = c.tabid         WHERE t.tabname = tabname         ORDER BY c.colno    LET cts = cts || pad || 'pre_'  || c_colname || ' ' || c_coltype;    LET cts = cts || ',' || 'post_' || c_colname || ' ' || c_coltype;    LET pad = ',';END FOREACH;LET cts = cts || ');';

You may want to deal with NOT NULL and primary key constraints and all sorts of other things, but this gives you the basics to be going on with.


In addition to JonathanLeffler's answer, there is the type_name procedure:

    CREATE PROCEDURE type_name(coltype INTEGER, colsize INTEGER)            RETURNING VARCHAR(128);            DEFINE toRet                    VARCHAR(128);            DEFINE size_5                   VARCHAR(5);            DEFINE decimal_p, decimal_s     INTEGER;            DEFINE decimal_t                VARCHAR(16);            DEFINE varchar_m, varchar_n     INTEGER;            DEFINE varchar_t                VARCHAR(16);            LET size_5 = '(' || TRIM(CAST(colsize AS CHAR(5))) || ')';             -- Precision            LET decimal_p = TRUNC(colsize/256);            -- Scale            LET decimal_s = colsize - 256 * decimal_p;            -- Decimal total            LET decimal_t = '(' || TRIM(CAST(decimal_p as VARCHAR(8))) || ',' || TRIM(CAST(decimal_s as VARCHAR(8))) || ')';            -- VARCHAR(M,N)            LET varchar_n = decimal_p;            LET varchar_m = decimal_s;            LET varchar_t = '(' || TRIM(CAST(varchar_m as VARCHAR(8))) || ',' || TRIM(CAST(varchar_n as VARCHAR(8))) || ')';            SELECT                CASE coltype                    WHEN 0   THEN 'char' || size_5                     WHEN 1   THEN 'smallint'                    WHEN 2   THEN 'integer'                    WHEN 3   THEN 'float'                    WHEN 4   THEN 'smallfloat'                    WHEN 5   THEN 'decimal' || decimal_t                    WHEN 6   THEN 'serial'                    WHEN 7   THEN 'date'                    WHEN 8   THEN 'money' || decimal_t                    WHEN 9   THEN 'null'                    WHEN 10  THEN 'DATETIME YEAR TO FRACTION(3)'                    WHEN 11  THEN 'byte'                    WHEN 12  THEN 'TEXT'                    WHEN 13  THEN 'VARCHAR' || varchar_t                    WHEN 14  THEN 'INTERVAL'                    WHEN 15  THEN 'NCHAR' || size_5                    WHEN 16  THEN 'NVARCHAR' || varchar_t                    WHEN 17  THEN 'INT8'                    WHEN 18  THEN 'SERIAL8'                    WHEN 19  THEN 'SET'                    WHEN 20  THEN 'MULTISET'                    WHEN 21  THEN 'LIST'                    WHEN 22  THEN 'ROW'                    WHEN 23  THEN 'COLLECTION'                    WHEN 24  THEN 'ROWDEF'                    WHEN 40  THEN 'LVARCHAR'  || size_5                     WHEN 256 THEN 'CHAR' || size_5 || ' NOT NULL'                    WHEN 257 THEN 'SMALLINT NOT NULL'                    WHEN 258 THEN 'INTEGER NOT NULL'                    WHEN 259 THEN 'FLOAT NOT NULL'                    WHEN 260 THEN 'SMALLFLOAT NOT NULL'                    WHEN 261 THEN 'DECIMAL' || decimal_t || ' NOT NULL'                    WHEN 262 THEN 'SERIAL NOT NULL'                    WHEN 263 THEN 'DATE NOT NULL'                    WHEN 264 THEN 'MONEY' || decimal_t || ' NOT NULL'                    WHEN 265 THEN 'null NOT NULL'                    WHEN 266 THEN 'DATETIME YEAR TO FRACTION(3) NOT NULL'                    WHEN 267 THEN 'BYTE NOT NULL'                    WHEN 268 THEN 'TEXT NOT NULL'                    WHEN 269 THEN 'VARCHAR' || varchar_t || ' NOT NULL'                    WHEN 270 THEN 'INTERVAL NOT NULL'                    WHEN 271 THEN 'nchar(' || size_5 || ') NOT NULL'                    WHEN 272 THEN 'nvarchar' || varchar_t || ' NOT NULL'                    WHEN 273 THEN 'int8 NOT NULL'                    WHEN 274 THEN 'serial8 NOT NULL'                    WHEN 275 THEN 'set NOT NULL'                    WHEN 276 THEN 'multiset NOT NULL'                    WHEN 277 THEN 'list NOT NULL'                    WHEN 278 THEN 'row NOT NULL'                    WHEN 279 THEN 'collection NOT NULL'                    WHEN 280 THEN 'rowdef NOT NULL'                    WHEN 296 THEN 'LVARCHAR'  || varchar_t || ' NOT NULL'                    ELSE 'ERROR'                END datatype            INTO toRet            FROM systables            WHERE tabid = 1;            IF toRet = 'ERROR' THEN               RAISE EXCEPTION -746, 0, 'Unknow datatype ' || coltype;            END IF            RETURN toRet;    END PROCEDURE;

Credit to this.