1.3. 获取表结构的存储过程
1.3.1. 通过存储过程获取建表语句
drop PROCEDURE if exists get_ddl(varchar,varchar,varchar,smallint);
/*******************************************************************
* PROCEDURE: get_ddl(OBJECT_TYPE, OWNER, OBJECT_NAME, DELIMIDENT
* DESCRIPTION: get schema for OBJECT_NAME
* OBJECT_TYPE : table, indexes, view, synonym, procedure
* OWNER not use now.
* USAGE EG : get_dll('table', 'gbasedbt', 'Tab1', 1)
* WRITE BY : liaosnet@gbasedbt.com 2024-10-21
* UPDATE : 2025-04-03 support DELIMIDENT
* UPDATE :2025-06-18 fix indexes oracle mode 201 error
* UPDATE :2025-08-04 syscolcomments my has muti rows.
*******************************************************************/
create PROCEDURE get_ddl(p_type varchar(40), p_user varchar(32), p_name varchar(128), p_del smallint default 0)
returning lvarchar(32000) as ddl;
define v_numtab int;
define v_tabname varchar(128);
define v_ddl lvarchar(32000);
define v_colname varchar(128);
define v_coltype_name varchar(128);
define v_nullable varchar(128);
define v_defvalue varchar(254);
define v_deftype varchar(10);
define v_collength int;
define v_decimal_p int;
define v_decimal_s int;
define v_pk_collist lvarchar(2048);
define v_pk_name varchar(128);
define v_pk_owner varchar(128);
define v_idx_name varchar(128);
define v_idx_sqls lvarchar(2048);
define v_view_text nchar(256);
define v_proc_text nchar(256);
define v_comments nvarchar(2048);
define v_tmpcomments nvarchar(512);
define v_synonym_tabname varchar(128);
define v_tmpsegno varchar(128);
define v_curcolname varchar(128);
define v_tmpcolname varchar(128);
on exception
return null;
end exception;
--set debug file to '/home/gbase/spl.debug';
--trace on;
-- exists table, delimident=y only for tablename
let v_tabname = '';
let v_numtab = 0;
let v_ddl = '';
if p_del = 1 then
let v_tabname = p_name;
else
let v_tabname = lower(p_name);
end if;
case lower(p_type)
when 'table' then
-- table
select count(*) into v_numtab from systables where tabname = v_tabname and tabtype = 'T';
if v_numtab = 0 then
return null;
end if;
let v_ddl = 'CREATE TABLE ' || case when p_del = 1 and regexp_like(v_tabname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_tabname || chr(34) else v_tabname end || '(' || chr(10);
-- colname, coltype, nullable, default_value, default_type_flag
foreach SELECT tmp.colname,tmp.coltype_name,
CASE d.type
WHEN 'L' THEN gbasedbt.get_default_value(tmp.coltype, tmp.extended_id, tmp.collength, d.default::lvarchar(256))::VARCHAR(254)
WHEN 'C' THEN 'current year to second'::VARCHAR(254)
WHEN 'S' THEN 'dbservername'::VARCHAR(254)
WHEN 'U' THEN 'user'::VARCHAR(254)
WHEN 'T' THEN 'today'::VARCHAR(254)
WHEN 'E' THEN de.default::VARCHAR(254)
ELSE NULL::VARCHAR(254)
END AS def_value,
tmp.nullable,
d.type,
tmp.collength
INTO v_colname, v_coltype_name, v_defvalue, v_nullable, v_deftype, v_collength
FROM (
SELECT ce.tabid, ce.colno, ce.colname,ce.coltype,ce.extended_id,ce.collength,ce.coltypename2::varchar(128) AS coltype_name,
CASE WHEN bitand(ce.coltype,256) = 256 THEN 'NOT NULL' ELSE '' END AS nullable
FROM syscolumnsext ce, systables t
WHERE ce.tabid = t.tabid
AND t.tabname = v_tabname
-- order by colno default
ORDER BY ce.colno) tmp LEFT JOIN sysdefaults d ON (tmp.tabid = d.tabid AND tmp.colno = d.colno)
LEFT JOIN sysdefaultsexpr de ON (tmp.tabid = de.tabid AND tmp.colno = de.colno and de.type='T')
-- no column found, return null
if v_colname is null or v_colname = '' then
return null;
end if;
IF v_coltype_name in ('DECIMAL','MONEY') THEN
let v_decimal_p = v_collength / 256;
let v_decimal_s = mod(v_collength,256);
if v_decimal_s = 255 then
let v_coltype_name = v_coltype_name || '(' || v_decimal_p || ')';
else
let v_coltype_name = v_coltype_name || '(' || v_decimal_p || ',' || v_decimal_s || ')';
end if;
END IF;
-- default values with function not do.
if v_deftype = 'E' then
let v_defvalue = 'DEFAULT (' || v_defvalue || ')';
elif v_deftype = 'L' and v_coltype_name[1,4] in ('CHAR','VARC','LVAR','NCHA','NVAR') then
let v_defvalue = 'DEFAULT ''' || v_defvalue || '''';
elif v_defvalue is not null then
let v_defvalue = 'DEFAULT ' || v_defvalue;
end if;
-- column: colname coltype default nullable
let v_ddl = v_ddl || ' ' || case when p_del = 1 and regexp_like(v_colname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_colname || chr(34) else v_colname end || ' ' || v_coltype_name || ' ' || v_defvalue || ' ' || v_nullable || ',' || chr(10);
end foreach;
let v_ddl = rtrim(v_ddl, ',' || chr(10)) || ');' || chr(10);
-- indexes, from proc_idxsql(idxname)
let v_idx_name = '';
foreach select si.idxname
into v_idx_name
from sysindexes si, systables st
where si.tabid = st.tabid
and st.tabname = v_tabname
-- and si.idxname[1,1] != ' '
-- order by default
call proc_idxsql(v_idx_name) returning v_idx_sqls;
let v_ddl = v_ddl || v_idx_sqls || chr(10) ;
end foreach;
-- primary key
-- create UNIQUE index and alter TABNAME add constraint primary key lead to duplicate. 2024-10-21
let v_pk_collist = '';
let v_pk_name = '';
let v_pk_owner = '';
foreach SELECT so.owner,so.constrname,
rtrim((select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part1)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part2)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part3)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part4)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part5)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part6)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part7)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part8)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part9)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part10)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part11)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part12)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part13)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part14)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part15)) || ',' ||
(select sc.colname from syscolumns sc where sc.tabid = st.tabid and sc.colno = ABS(si.part16)), ',') as keys
INTO v_pk_owner, v_pk_name, v_pk_collist
FROM systables st, sysconstraints so, sysindexes si
WHERE st.tabname = v_tabname
AND st.tabid = so.tabid
AND so.constrtype = 'P'
AND so.idxname = si.idxname
end foreach;
if v_pk_collist = '' or v_pk_collist is null then
let v_ddl = v_ddl;
elif v_pk_name[1,1] = 'u' then
let v_ddl = v_ddl || 'ALTER TABLE ' || case when p_del = 1 and regexp_like(v_tabname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_tabname || chr(34) else v_tabname end || ' ADD CONSTRAINT PRIMARY KEY(' || v_pk_collist || ');' || chr(10);
else
let v_ddl = v_ddl || 'ALTER TABLE ' || case when p_del = 1 and regexp_like(v_tabname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_tabname || chr(34) else v_tabname end || ' ADD CONSTRAINT PRIMARY KEY(' || v_pk_collist || ') CONSTRAINT ' || chr(34) || trim(v_pk_owner) || chr(34) || '.' || v_pk_name || ';' || chr(10);
end if;
-- has syscomments table, version 2.0 and older has not comments. 2024-09-13
select t.tabname
into v_tmpcomments
from systables t
where t.tabname = 'syscomments';
if v_tmpcomments = 'syscomments' then
-- table comments
-- v3.6.3 has segno
SELECT c.colname
INTO v_tmpsegno
FROM syscolumns c, systables t
WHERE c.tabid = t.tabid
AND t.tabname = 'syscolcomms'
AND c.colname = 'segno';
let v_comments = '';
if v_tmpsegno = 'segno' then
foreach select replace(c.comments, chr(39),'''''')
into v_tmpcomments
from syscomms c, systables t
where c.tabid = t.tabid
and t.tabname =v_tabname
order by c.segno
let v_comments = v_comments || v_tmpcomments;
end foreach;
else
foreach select replace(c.comments, chr(39),'''''')
into v_tmpcomments
from syscomms c, systables t
where c.tabid = t.tabid
and t.tabname =v_tabname
let v_comments = v_comments || v_tmpcomments;
end foreach;
end if;
if v_comments != '' then
let v_ddl = v_ddl || 'COMMENT ON TABLE ' || case when p_del = 1 and regexp_like(v_tabname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_tabname || chr(34) else v_tabname end || ' IS ''' || rtrim(v_comments) || ''';' || chr(10);
end if;
-- column comments
let v_comments = '';
let v_curcolname = '';
if v_tmpsegno = 'segno' then
foreach select c.colname,replace(cc.comments, chr(39),'''''')
into v_tmpcolname, v_tmpcomments
from syscolcomms cc, syscolumns c, systables t
where cc.tabid = t.tabid
and cc.colno = c.colno
and cc.tabid = c.tabid
and t.tabname = v_tabname
order by cc.colno,cc.segno
if v_curcolname = v_tmpcolname then
let v_comments = v_comments || v_tmpcomments;
else
if v_comments != '' then
let v_ddl = v_ddl || 'COMMENT ON COLUMN ' || case when p_del = 1 and regexp_like(v_tabname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_tabname || chr(34) else v_tabname end || '.' || case when p_del = 1 and regexp_like(v_curcolname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_curcolname || chr(34) else v_curcolname end || ' IS ''' || rtrim(v_comments) || ''';' || chr(10);
end if;
let v_curcolname = v_tmpcolname;
let v_comments = v_tmpcomments;
end if;
end foreach;
let v_ddl = v_ddl || 'COMMENT ON COLUMN ' || case when p_del = 1 and regexp_like(v_tabname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_tabname || chr(34) else v_tabname end || '.' || case when p_del = 1 and regexp_like(v_curcolname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_curcolname || chr(34) else v_curcolname end || ' IS ''' || rtrim(v_comments) || ''';' || chr(10);
else
foreach select c.colname,replace(cc.comments, chr(39),'''''')
into v_tmpcolname, v_tmpcomments
from syscolcomms cc, syscolumns c, systables t
where cc.tabid = t.tabid
and cc.colno = c.colno
and cc.tabid = c.tabid
and t.tabname = v_tabname
order by cc.colno
if v_curcolname = v_tmpcolname then
let v_comments = v_comments || v_tmpcomments;
else
if v_comments != '' then
let v_ddl = v_ddl || 'COMMENT ON COLUMN ' || case when p_del = 1 and regexp_like(v_tabname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_tabname || chr(34) else v_tabname end || '.' || case when p_del = 1 and regexp_like(v_curcolname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_curcolname || chr(34) else v_curcolname end || ' IS ''' || rtrim(v_comments) || ''';' || chr(10);
end if;
let v_curcolname = v_tmpcolname;
let v_comments = v_tmpcomments;
end if;
end foreach;
let v_ddl = v_ddl || 'COMMENT ON COLUMN ' || case when p_del = 1 and regexp_like(v_tabname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_tabname || chr(34) else v_tabname end || '.' || case when p_del = 1 and regexp_like(v_curcolname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_curcolname || chr(34) else v_curcolname end || ' IS ''' || rtrim(v_comments) || ''';' || chr(10);
end if;
end if;
when 'indexes' then
-- indexes, from proc_idxsql(idxname,del)
select count(*) into v_numtab from sysindexes where idxname = v_tabname;
if v_numtab = 0 then
return null;
end if;
call proc_idxsql(v_tabname,p_del) returning v_idx_sqls;
let v_ddl = v_idx_sqls ;
when 'view' then
-- view
select count(*) into v_numtab from systables where tabname = v_tabname and tabtype = 'V';
if v_numtab = 0 then
return null;
end if;
foreach select v.viewtext
into v_view_text
from systables t,sysviews v
where t.tabid = v.tabid
and t.tabtype = 'V'
and t.tabname = v_tabname
order by v.seqno
let v_ddl = v_view_text;
end foreach;
when 'procedure' then
-- procedure / function
select count(*) into v_numtab from sysprocedures where procname = v_tabname;
if v_numtab = 0 then
return null;
end if;
foreach select b.data
into v_proc_text
from sysprocedures p, sysprocbody b
where p.procid = b.procid
and p.procname = v_tabname
and b.datakey = 'T'
order by b.seqno
let v_ddl = v_proc_text;
end foreach;
when 'synonym' then
-- SYNONYM, local OR remote
select count(*) into v_numtab from systables where tabname = v_tabname and tabtype = 'S';
if v_numtab = 0 then
return null;
end if;
foreach select nvl(case when regexp_like(syn.tabname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || syn.tabname || chr(34) else syn.tabname end, s.dbname || '@' || nvl(s.servername,DBSERVERNAME) || ':' || chr(34) || trim(s.owner) || chr(34) || '.' || case when regexp_like(s.tabname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || s.tabname || chr(34) else s.tabname end) AS rtabname
into v_synonym_tabname
from syssyntable s LEFT JOIN systables syn
ON s.btabid = syn.tabid, systables t1
WHERE s.tabid = t1.tabid
AND t1.tabname = v_tabname
let v_ddl = 'CREATE SYNONYM ' || case when p_del = 1 and regexp_like(v_tabname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || v_tabname || chr(34) else v_tabname end || ' FOR ' || v_synonym_tabname || ';';
end foreach;
else
let v_ddl = 'NOT_SUPPORTED';
end case;
return v_ddl;
end PROCEDURE;
/*****************************************************
* PROCEDURE: proc_idxsql(idxname)
* DESCRIPTION: build index sql from idxname
* USAGE: call proc_idxsql(idxname);
* WRITE BY: liaosnet@gbasedbt.com 2023-12-19
* UPDATE : 2025-04-03 support DELIMIDENT
* UPDATE : 2025-06-18 index name filter, skip pk.
*****************************************************/
DROP PROCEDURE IF EXISTS proc_idxsql(varchar,smallint);
CREATE PROCEDURE proc_idxsql(p_idxname varchar(128), p_del smallint default 0) returning lvarchar(1024) as idxsql;
define v_idxsql lvarchar(1024);
define v_idx_typename varchar(20);
define v_tabid int;
define v_tabname varchar(128);
define v_idxtype char(1);
define v_idxcluster char(1);
define v_idxowner varchar(128);
define v_idxkeys varchar(128);
define v_idxkeyarr varchar(128);
define v_funcname varchar(128);
define v_procid varchar(128);
define v_start int;
define v_end int;
define v_colno int;
define v_colname varchar(128);
define curr int;
define tmp varchar(128);
define v_desc varchar(10);
ON EXCEPTION
RETURN NULL;
END EXCEPTION;
--set debug file to '/home/gbase/spl.1';
--trace on;
-- primary key or constraints default name.
IF regexp_like(p_idxname,'^ [0-9]+_[0-9]+$') = 't' then
RETURN '';
END IF;
-- GET INDEXKEYS
SELECT t.tabid, t.tabname, i.owner,i.idxtype,clustered, i.indexkeys::lvarchar
INTO v_tabid, v_tabname, v_idxowner, v_idxtype, v_idxcluster,v_idxkeys
FROM sysindices i,systables t
WHERE i.tabid = t.tabid AND i.idxname = p_idxname;
IF v_tabname is null or v_tabname = '' then
RETURN '';
END IF;
let v_idx_typename = '';
if v_idxtype = 'U' then
let v_idx_typename = 'UNIQUE';
elif v_idxcluster = 'C' then
let v_idx_typename = 'CLUSTER';
end if;
LET v_idxsql = 'CREATE ' || v_idx_typename;
LET v_idxsql = rtrim(v_idxsql) || ' INDEX ' || chr(34) || trim(v_idxowner) || chr(34) || '.' || case when p_del = 1 and regexp_like(p_idxname,'^[a-z_][a-z0-9_]*$') = 'f' then chr(34) || p_idxname || chr(34) else p_idxname end || ' ON ' || v_tabname || ' (' ;
-- process IDXKEYS
let v_funcname = '';
IF substr(v_idxkeys,1,1) = '<' THEN
let v_start = 2;
let v_end = instr(v_idxkeys,'>');
let v_procid = substr(v_idxkeys, v_start, v_end - v_start);
SELECT procname INTO v_funcname
FROM sysprocedures
WHERE procid = v_procid::int;
let v_start = instr(v_idxkeys,'(') + 1;
let v_end = instr(v_idxkeys,')');
-- 1,2,
let v_idxkeys = substr(v_idxkeys, v_start, v_end - v_start) || ',';
let tmp = v_funcname || '(';
while v_idxkeys != ''
let curr = instr(v_idxkeys, ',');
let v_colno = substr(v_idxkeys, 1, curr - 1)::int;
SELECT colname
INTO v_colname
FROM syscolumns
WHERE tabid = v_tabid
AND colno = v_colno;
let tmp = tmp || v_colname || ',';
let v_idxkeys = substr(v_idxkeys, curr + 1);
END while;
let tmp = rtrim(tmp,',') || ')';
ELSE
let v_idxkeys = replace(v_idxkeys, ' [1]') || ',';
let tmp = '';
let v_desc = '';
while v_idxkeys != ''
let curr = instr(v_idxkeys, ',');
let v_colno = substr(v_idxkeys, 1, curr - 1)::int;
IF v_colno < 0 THEN
let v_desc = ' DESC';
END IF;
SELECT colname
INTO v_colname
FROM syscolumns
WHERE tabid = v_tabid
AND colno = abs(v_colno);
let tmp = tmp || v_colname || v_desc || ',';
let v_idxkeys = substr(v_idxkeys, curr + 1);
END while;
let tmp = rtrim(tmp,',');
END IF;
LET v_idxsql = v_idxsql || tmp || ');';
RETURN v_idxsql;
END PROCEDURE;
使用方法:
-- call get_ddl(类型,属主,名称,DELIMIDENT标识);
call get_ddl('table','gbasedbt','Tab1',1);
结果:
ddl |
------------------------------------------------------------------------------------------|
CREATE TABLE tabdec(
col1 INTEGER NOT NULL,
col2 DECIMAL(10,2) ,
col3 DECIMAL(10) NOT NULL);
ALTER TABLE tabdec ADD CONSTRAINT PRIMARY KEY(col1) CONSTRAINT "gbasedbt".u1018_19; |
1.3.2. 通过存储过程获取表结构(类似mysql)
drop PROCEDURE if exists get_tableschema(varchar);
/*******************************************************************
* PROCEDURE: get_tableschema(tabname)
* DESCRIPTION: get table schema
* USAGE EG : get_tableschema('table1')
* WRITE BY : liaosnet@gbasedbt.com 2025-05-27
*******************************************************************/
-- return colname,coltypename,nullable,pk,default,extra
create PROCEDURE get_tableschema(p_name varchar(128))
returning nvarchar(128) as field,varchar(128) as type,varchar(10) as null,varchar(10) as key,varchar(255) as default,varchar(128) as extra;
define v_tabname varchar(128);
define v_numtab int;
define v_tabid int;
define v_colno int;
define v_colname nvarchar(128);
define v_coltype_name varchar(128);
define v_isnullable varchar(10);
define v_isprimarykey varchar(10);
define v_defvalue varchar(254);
define v_collength int;
define v_extra varchar(128);
define v_decimal_p int;
define v_decimal_s int;
on exception
return ;
end exception;
let v_numtab = 0;
let v_tabname = lower(p_name);
select count(*) into v_numtab from systables where tabname = v_tabname and tabtype = 'T';
if v_numtab = 0 then
return ;
end if;
-- colname, coltype_name, nullable, default_value, collength
foreach SELECT tmp.tabid,tmp.colno,tmp.colname,tmp.coltype_name,tmp.nullable,
CASE d.type
WHEN 'L' THEN gbasedbt.get_default_value(tmp.coltype, tmp.extended_id, tmp.collength, d.default::lvarchar(256))::VARCHAR(254)
WHEN 'C' THEN 'current year to second'::VARCHAR(254)
WHEN 'S' THEN 'dbservername'::VARCHAR(254)
WHEN 'U' THEN 'user'::VARCHAR(254)
WHEN 'T' THEN 'today'::VARCHAR(254)
WHEN 'E' THEN de.default::VARCHAR(254)
ELSE NULL::VARCHAR(254)
END AS def_value,
tmp.collength
INTO v_tabid,v_colno,v_colname,v_coltype_name,v_isnullable,v_defvalue,v_collength
FROM (
SELECT ce.tabid, ce.colno, ce.colname,ce.coltype,ce.extended_id,ce.collength,ce.coltypename2::varchar(128) AS coltype_name,
CASE WHEN bitand(ce.coltype,256) = 256 THEN 'NO' ELSE 'YES' END AS nullable
FROM syscolumnsext ce, systables t
WHERE ce.tabid = t.tabid
AND t.tabname = v_tabname
ORDER BY ce.colno
) tmp LEFT JOIN sysdefaults d ON (tmp.tabid = d.tabid AND tmp.colno = d.colno)
LEFT JOIN sysdefaultsexpr de ON (tmp.tabid = de.tabid AND tmp.colno = de.colno and de.type='T')
-- no column found, return null
if v_colname is null or v_colname = '' then
return ;
end if;
-- decimal type
IF v_coltype_name in ('DECIMAL','MONEY') THEN
let v_decimal_p = v_collength / 256;
let v_decimal_s = mod(v_collength,256);
if v_decimal_s = 255 then
let v_coltype_name = v_coltype_name || '(' || v_decimal_p || ')';
else
let v_coltype_name = v_coltype_name || '(' || v_decimal_p || ',' || v_decimal_s || ')';
end if;
END IF;
-- primary key
let v_isprimarykey = NULL;
SELECT 'PRI' INTO v_isprimarykey
FROM sysconstraints so, sysindexes si
WHERE so.tabid = v_tabid
AND so.constrtype = 'P'
AND so.idxname = si.idxname
AND (si.part1 = v_colno OR si.part2 = v_colno OR si.part3 = v_colno OR si.part4 = v_colno
OR si.part5 = v_colno OR si.part6 = v_colno OR si.part7 = v_colno OR si.part7 = v_colno
OR si.part8 = v_colno OR si.part10 = v_colno OR si.part11 = v_colno OR si.part12 = v_colno
OR si.part13 = v_colno OR si.part14 = v_colno OR si.part15 = v_colno OR si.part16 = v_colno
);
-- extra
let v_extra = NULL;
IF v_coltype_name IN ('SERIAL','SERIAL8','BITSERIAL') THEN
let v_extra = 'AUTO_INCREMENT';
END IF;
RETURN v_colname,v_coltype_name,v_isnullable,v_isprimarykey,v_defvalue,v_extra WITH resume;
end foreach;
end PROCEDURE;
使用方法:
-- call get_tableschema(表名);
call get_tableschema('tab1');
结果:
field |type |null |key |default |extra |
------|--------------|-----|----|--------|------|
col1 |INTEGER |NO |PRI | | |
col2 |DECIMAL(10,2) |YES | | | |
col3 |DECIMAL(10) |NO | | | |
1.3.3. 通过SQL获取表结构(类似mysql)
SELECT
tmp.colname AS field,
CASE WHEN tmp.coltype_name IN ('DECIMAL','MONEY') THEN
CASE WHEN mod(tmp.collength,256) = 255 THEN tmp.coltype_name || '(' || (tmp.collength / 256)::int || ')'
ELSE tmp.coltype_name || '(' || (tmp.collength / 256)::int || ',' || mod(tmp.collength,256) || ')'
END
ELSE tmp.coltype_name
END AS type,
tmp.nullable AS null,
(SELECT 'PRI'
FROM sysconstraints so, sysindexes si
WHERE so.tabid = tmp.tabid
AND so.constrtype = 'P'
AND so.idxname = si.idxname
AND ( si.part1 = tmp.colno OR si.part2 = tmp.colno OR si.part3 = tmp.colno OR si.part4 = tmp.colno
OR si.part5 = tmp.colno OR si.part6 = tmp.colno OR si.part7 = tmp.colno OR si.part7 = tmp.colno
OR si.part8 = tmp.colno OR si.part10 = tmp.colno OR si.part11 = tmp.colno OR si.part12 = tmp.colno
OR si.part13 = tmp.colno OR si.part14 = tmp.colno OR si.part15 = tmp.colno OR si.part16 = tmp.colno
)
) AS key,
CASE d.type
WHEN 'L' THEN gbasedbt.get_default_value(tmp.coltype, tmp.extended_id, tmp.collength, d.default::lvarchar(256))::VARCHAR(254)
WHEN 'C' THEN 'current year to second'::VARCHAR(254)
WHEN 'S' THEN 'dbservername'::VARCHAR(254)
WHEN 'U' THEN 'user'::VARCHAR(254)
WHEN 'T' THEN 'today'::VARCHAR(254)
WHEN 'E' THEN de.default::VARCHAR(254)
ELSE NULL::VARCHAR(254)
END AS default,
CASE WHEN tmp.coltype_name IN ('SERIAL','SERIAL8','BITSERIAL') THEN 'AUTO_INCREMENT' ELSE NULL END AS extra
FROM (
SELECT ce.tabid, ce.colno, ce.colname,ce.coltype,ce.extended_id,ce.collength,ce.coltypename2::varchar(128) AS coltype_name,
CASE WHEN bitand(ce.coltype,256) = 256 THEN 'NO' ELSE 'YES' END AS nullable
FROM syscolumnsext ce, systables t
WHERE ce.tabid = t.tabid
AND t.tabname = 'tab1' -- table_name here.
ORDER BY ce.colno
) tmp LEFT JOIN sysdefaults d ON (tmp.tabid = d.tabid AND tmp.colno = d.colno)
LEFT JOIN sysdefaultsexpr de ON (tmp.tabid = de.tabid AND tmp.colno = de.colno and de.type='T');
结果:
field |type |null |key |default |extra |
------|--------------|-----|----|--------|------|
col1 |INTEGER |NO |PRI | | |
col2 |DECIMAL(10,2) |YES | | | |
col3 |DECIMAL(10) |NO | | | |
注意修改表名的位置。
1.3.4. 通过存储过程获取表结构(类似oracle)
drop PROCEDURE if exists get_tableschema(varchar);
/*******************************************************************
* PROCEDURE: get_tablechema(tabname)
* DESCRIPTION: get table schema
* USAGE EG : get_tablechema('tab1')
* WRITE BY : liaosnet@gbasedbt.com 2025-06-17
* UPDATE : sysdefaultsexpr may has muti rows. 2025-06-18
* UPDATE : syscolcomments my has muti rows. 2025-08-04
*******************************************************************/
-- columnName,dataType,dataLength,nullable,datadefault,dataScale,comments,isPrimaryKey
create PROCEDURE get_tableschema(p_name varchar(128))
returning nvarchar(128) as columnName,varchar(128) as dataType,int as dataLength,
char(1) as nullable, varchar(255) as datadefault,int as dataScale,
nvarchar(2048) as comments, varchar(3) as isPrimaryKey, varchar(4000) as virtualcolumn;
define v_tabname varchar(128);
define v_numtab int;
define v_tabid int;
define v_colno int;
define v_colname nvarchar(128);
define v_coltype_name varchar(128);
define v_isnullable char(1);
define v_isprimarykey varchar(3);
define v_defvalue varchar(255);
define v_collength int;
define v_decimal_p int;
define v_decimal_s int;
define v_comments nvarchar(2048);
define v_tmpcomments nvarchar(512);
define v_coltype int;
define v_extended_id int;
define v_isvtcol char(1);
define v_vcolexpr varchar(4000);
define v_tmpcolexpr varchar(4000);
on exception
return ;
end exception;
--set debug file to '/home/gbase/spl.log';
--trace on;
let v_numtab = 0;
let v_tabname = p_name;
select count(*) into v_numtab
from systables
where tabname = v_tabname
and tabtype = 'T';
if v_numtab = 0 then
return ;
end if;
-- columnName, coltype_name, nullable, default_value, collength
foreach SELECT tmp.tabid,tmp.colno,tmp.colname,tmp.coltype_name,tmp.nullable,
tmp.collength,
tmp.coltype,tmp.extended_id,tmp.isvtcol
INTO v_tabid,v_colno,v_colname,v_coltype_name,v_isnullable,v_collength,v_coltype,v_extended_id,v_isvtcol
FROM (
SELECT ce.tabid, t.tabname, ce.colno, ce.colname,ce.coltype,ce.extended_id,ce.collength,ce.coltypename2::varchar(128) AS coltype_name,
CASE WHEN bitand(ce.coltype,256) = 256 THEN 'N' ELSE 'Y' END AS nullable,
CASE WHEN bitand(ce.colattr,768) = 768 THEN 'Y' ELSE 'N' END AS isvtcol
FROM syscolumnsext ce, systables t
WHERE ce.tabid = t.tabid
AND t.tabname = v_tabname
ORDER BY ce.colno
) tmp
-- no column found, return null
if v_colname is null or v_colname = '' then
return ;
end if;
-- comments, has segno or not
SELECT c.colname
INTO v_tmpcomments
FROM syscolumns c, systables t
WHERE c.tabid = t.tabid
AND t.tabname = 'syscolcomms'
AND c.colname = 'segno';
let v_comments = '';
if v_tmpcomments = 'segno' then
foreach SELECT cc.comments
INTO v_tmpcomments
FROM syscolcomms cc
WHERE cc.tabid = v_tabid AND cc.colno = v_colno
ORDER BY cc.segno
let v_comments = v_comments || v_tmpcomments;
end foreach;
else -- no segno
foreach SELECT cc.comments
INTO v_tmpcomments
FROM syscolcomms cc
WHERE cc.tabid = v_tabid AND cc.colno = v_colno
let v_comments = v_comments || v_tmpcomments;
end foreach;
end if;
if v_comments = '' then
let v_comments = null;
end if;
-- default value
SELECT CASE d.type
WHEN 'L' THEN get_default_value(v_coltype, v_extended_id, v_collength, d.default::lvarchar(256))::VARCHAR(254)
WHEN 'C' THEN 'current year to second'::VARCHAR(254)
WHEN 'S' THEN 'dbservername'::VARCHAR(254)
WHEN 'U' THEN 'user'::VARCHAR(254)
WHEN 'T' THEN 'today'::VARCHAR(254)
WHEN 'E' THEN de.default::VARCHAR(254)
ELSE NULL::VARCHAR(254)
END AS def_value
INTO v_defvalue
FROM sysdefaults d
LEFT JOIN sysdefaultsexpr de ON (d.tabid = de.tabid AND d.colno = de.colno AND de.type = 'T')
WHERE de.tabid = v_tabid
AND de.colno = v_colno;
-- virtual column
let v_vcolexpr = '';
if v_isvtcol = 'Y' then
foreach SELECT de.default
INTO v_tmpcolexpr
FROM sysdefaultsexpr de
WHERE de.tabid = v_tabid AND de.colno = v_colno AND de.type = 'T'
let v_vcolexpr = v_vcolexpr || v_tmpcolexpr;
end foreach;
end if;
-- data_type
let v_decimal_p = 0;
let v_decimal_s = 0;
if v_coltype_name like '%CHAR%' then
let v_coltype_name = regexp_substr(v_coltype_name,'[^(]+',1);
let v_decimal_p = mod(v_collength,65536);
let v_decimal_s = v_collength / 65536;
let v_collength = v_decimal_p;
end if;
-- decimal type
IF v_coltype_name in ('DECIMAL','MONEY') THEN
let v_decimal_p = v_collength / 256;
let v_decimal_s = mod(v_collength,256);
if v_decimal_s = 255 then
let v_decimal_s = 0;
end if;
let v_collength = v_decimal_p;
END IF;
-- primary key
let v_isprimarykey = '';
SELECT 'YES' INTO v_isprimarykey
FROM sysconstraints so, sysindexes si
WHERE so.tabid = v_tabid
AND so.constrtype = 'P'
AND so.idxname = si.idxname
AND (si.part1 = v_colno OR si.part2 = v_colno OR si.part3 = v_colno OR si.part4 = v_colno
OR si.part5 = v_colno OR si.part6 = v_colno OR si.part7 = v_colno OR si.part7 = v_colno
OR si.part8 = v_colno OR si.part10 = v_colno OR si.part11 = v_colno OR si.part12 = v_colno
OR si.part13 = v_colno OR si.part14 = v_colno OR si.part15 = v_colno OR si.part16 = v_colno
);
if v_isprimarykey is null or v_isprimarykey = '' then
let v_isprimarykey = 'NO';
end if;
RETURN v_colname,v_coltype_name,v_collength,v_isnullable,v_defvalue,v_decimal_s,v_comments,v_isprimarykey,v_vcolexpr WITH resume;
end foreach;
end PROCEDURE;
使用方法:
-- call get_tableschema(表名);
call get_tableschema('tab1');
结果:
columnname |datatype |datalength |nullable |datadefault |datascale |comments |isprimarykey |virtualcolumn |
-----------|---------|-----------|---------|-------------|----------|---------------|-------------|--------------|
col1 |INTEGER |4 |N | |0 |主键 |YES | |
col2 |DECIMAL |10 |Y |3.14 |2 |字段2含默认值 |NO | |
col3 |DECIMAL |10 |Y | |0 |字段3 |NO | |