--
-- $Id$
--
-- This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
-- project.
--
-- Copyright (C) 1998-2017 OpenLink Software
--
-- This project is free software; you can redistribute it and/or modify it
-- under the terms of the GNU General Public License as published by the
-- Free Software Foundation; only version 2 of the License, dated June 1991.
--
-- This program is distributed in the hope that it will be useful, but
-- WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along
-- with this program; if not, write to the Free Software Foundation, Inc.,
-- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
--
--
yacutia_exec_no_error ('drop view db.dba.xddl_tables')
;
yacutia_exec_no_error ('drop view db.dba.xddl_columns')
;
yacutia_exec_no_error ('drop view db.dba.xddl_pk')
;
yacutia_exec_no_error ('drop view db.dba.xddl_pk_parts')
;
yacutia_exec_no_error ('drop view db.dba.xddl_fk')
;
yacutia_exec_no_error ('drop view db.dba.xddl_fk_ref')
;
yacutia_exec_no_error ('drop view db.dba.xddl_procedures')
;
yacutia_exec_no_error ('drop view db.dba.xddl_views')
;
yacutia_exec_no_error ('drop view db.dba.xddl_constraints')
;
create procedure sql_type(in type integer, in prec integer , in scale integer) returns varchar {
declare val varchar;
val := 'any';
if (type = 189) {
return 'integer';
} else if (type = 191) {
val := 'double precision';
} else if (type = 219) {
val := 'numeric';
} else if (type = 188) {
val := 'smallint';
} else if (type = 190) {
val := 'real';
} else if (type = 182 or type = 181 or type = 238) {
val := 'varchar';
-- if (prec <> 0) val := sprintf('varchar(%d)',prec);
} else if (type = 125) {
val := 'long varchar';
} else if (type = 222) {
val := 'varbinary';
-- if (prec <> 0) val := sprintf('varbinary(%d)',prec);
} else if (type = 223 or type = 131 ) {
val := 'long varbinary';
-- if (prec <> 0) val := sprintf('long varbinary(%d)',prec);
} else if (type = 225) {
val := 'nvarchar';
} else if (type = 226) {
val := 'long nvarchar';
} else if (type = 230) {
val := 'long xml';
} else if (type = 183) {
val := 'string';
-- if (prec <> 0) val := sprintf('string(%d)',prec);
} else if (type = 192) {
val := 'char';
} else if (type = 125) {
val := 'any';
} else if (type = 128) {
val := 'timestamp';
} else if (type = 210) {
val := 'time';
} else if (type = 129) {
val := 'date';
} else if (type = 211) {
val := 'datetime';
}
return val;
}
;
-- public static final int DV_C_SHORT = 184;
-- public static final int DV_STRING_SESSION = 185;
-- public static final int DV_SHORT_CONT_STRING = 186;
-- public static final int DV_LONG_CONT_STRING = 187;
-- public static final int DV_NUMERIC = 219;
-- public static final int DV_ARRAY_OF_POINTER = 193;
-- public static final int DV_ARRAY_OF_LONG_PACKED = 194;
-- public static final int DV_ARRAY_OF_FLOAT = 202;
-- public static final int DV_ARRAY_OF_DOUBLE = 195;
-- public static final int DV_ARRAY_OF_LONG = 209;
-- public static final int DV_LIST_OF_POINTER = 196;
create procedure is_not_null(in val any) returns varchar {
if (val is null)
return 0; --'xsi:false';
else return 1; --'xsi:true';
}
;
create procedure is_sequence(in _col_check integer) returns varchar {
if (_col_check is not null and isstring (_col_check)) {
--dbg_obj_print (_col_check, length (_col_check));
if (length(_col_check) >= 1 and aref (_col_check, 0) = 73) -- 'I'
return '1';
}
return '0';
}
;
create procedure is_identified(in _col_check varchar) returns varchar {
if (_col_check is not null and isstring (_col_check)) {
--dbg_obj_print (_col_check, length (_col_check));
if (length(_col_check) >= 2 and aref (_col_check, 1) = 85) -- 'U'
return sprintf ('%s', trim (subseq (_col_check, 2)));
}
return '';
}
;
create procedure get_default(in val varchar) returns varchar {
if (val is not null)
return val;
else return 'null';
}
;
create procedure is_collate(in _col_check varchar) returns varchar {
if (_col_check is not null and isstring (_col_check)) {
--dbg_obj_print (_col_check, length (_col_check));
if ( (length(_col_check) >= 1 and aref (_col_check, 0) = 73) or
(length(_col_check) >= 2 and aref (_col_check, 1) = 85) ) -- 'U'
return '';
else return _col_check;
} else
return '';
}
;
create procedure int_to_yesno(in val integer) returns integer {
if (val = 1)
return 1; --'xsi:true';
else
return 0; -- 'xsi:false';
}
;
create procedure int_to_action(in val integer) returns string {
if (val = 1)
return 'set null';
else if (val = 2)
return 'cascade';
else if (val = 3)
return 'set default';
return '';
}
;
create procedure get_parent(in table_name varchar ) returns varchar {
declare id integer;
declare parent, tmp varchar;
parent := '';
tmp := '';
select KEY_ID into id from SYS_KEYS where KEY_TABLE = table_name;
for select SUPER, SUB from SYS_KEY_SUBKEY where SUB = id do {
select KEY_TABLE into tmp from SYS_KEYS where KEY_ID = SUPER;
if (tmp is not null) {
if (length(parent) > 0 )
parent := concat(parent,', ');
parent := concat(parent,tmp);
}
}
if (length(parent) = 0 )
return 'xsi:nil';
else
return parent;
}
;
create view DB.DBA.XDDL_TABLES (T_NAME, T_PARENT,T_IDENT) as select KEY_TABLE, get_parent(KEY_TABLE),KEY_ID from sys_keys where __any_grants(KEY_TABLE) and KEY_IS_MAIN = 1 and KEY_MIGRATE_TO is null and not exists(select 1 from SYS_VIEWS where V_NAME = KEY_TABLE) order by KEY_TABLE
;
create view DB.DBA.XDDL_COLUMNS ( C_TABLE,
C_COL,
C_TYPE,
C_TYPE_TEXT,
C_PREC,
C_SCALE,
C_NOTNULLABLE,
C_IDENTITY,
C_DEFAULT,
C_COLLATION,
C_IDENTIFIED_BY) as select \TABLE, \COLUMN, COL_DTP, sql_type(COL_DTP, COL_PREC, COL_SCALE), COL_PREC, COL_SCALE,
is_not_null(COL_NULLABLE), is_sequence(COL_CHECK), get_default(cast(deserialize(COL_DEFAULT) as varchar )), is_collate(COL_CHECK), is_identified(COL_CHECK) from sys_cols order by COL_ID
;
create view DB.DBA.XDDL_PK (PK_TABLE, PK_KEY_ID, PK_IS_UNIQUE, PK_IS_CLUSTERED, PK_IS_OID) as select KEY_TABLE, KEY_ID, int_to_yesno(KEY_IS_UNIQUE), int_to_yesno(KEY_CLUSTER_ON_ID), int_to_yesno(KEY_IS_OBJECT_ID) from sys_keys where KEY_IS_MAIN = 1 and KEY_MIGRATE_TO is null
;
create view DB.DBA.XDDL_PK_PARTS (PKP_KEY_ID, PKP_COL, PKP_ORD) as select KP_KEY_ID, \COLUMN, KP_NTH from SYS_KEY_PARTS join SYS_COLS on KP_COL = COL_ID join SYS_KEYS on KP_NTH < KEY_N_SIGNIFICANT AND KEY_ID = KP_KEY_ID
;
create view DB.DBA.XDDL_FK (FK_TABLE, FK_REF_TABLE, FK_UPDATE_RULE, FK_DELETE_RULE) as select FK_TABLE, PK_TABLE, cast(int_to_action(UPDATE_RULE) as varchar), cast(int_to_action(DELETE_RULE) as varchar) from SYS_FOREIGN_KEYS group by FK_TABLE, PK_TABLE, UPDATE_RULE,DELETE_RULE
;
create view DB.DBA.XDDL_FK_REF (FK_TABLE, FK_COL, FK_REF_TABLE, FK_REF_COL) as
select FK_TABLE, FKCOLUMN_NAME, PK_TABLE, PKCOLUMN_NAME from SYS_FOREIGN_KEYS
;
create view DB.DBA.XDDL_VIEWS (V_NAME, V_TEXT) as select V_NAME , V_TEXT from SYS_VIEWS where __any_grants(V_NAME)
;
create view DB.DBA.XDDL_PROCEDURES (SP_NAME, SP_TEXT) as select P_NAME , blob_to_string(coalesce( coalesce (P_TEXT, P_MORE),'')) from SYS_PROCEDURES where __any_grants(P_NAME)
;
create view DB.DBA.XDDL_CONSTRAINTS (C_TABLE, C_NAME, C_CODE) as select C_TABLE, C_TEXT, sql_text(deserialize(C_MODE)) from sys_constraints
;
grant select on DB.DBA.XDDL_TABLES to public
;
grant select on DB.DBA.XDDL_VIEWS to public
;
grant select on DB.DBA.XDDL_PROCEDURES to public
;
grant select on DB.DBA.XDDL_CONSTRAINTS to public
;
create function xddl_init(in path varchar) returns varchar {
declare res, tmp varchar;
res :='';
-- tmp := xml_load_mapping_schema_decl ( path, 'xddl.xsd', 'UTF-8', 'x-any' );
-- res := concat(res, tmp);
tmp := xml_load_mapping_schema_decl ( path, 'xddl_tables.xsd', 'UTF-8', 'x-any' );
res := concat(res, tmp);
tmp:= xml_load_mapping_schema_decl ( path, 'xddl_views.xsd', 'UTF-8', 'x-any' );
res := concat(res, tmp);
tmp:= xml_load_mapping_schema_decl ( path, 'xddl_procs.xsd', 'UTF-8', 'x-any' );
return concat(res, tmp);
}
;
--select xml_load_mapping_schema_decl ('', 'file://xddl.xsd', 'UTF-8', 'x-any');
--select xml_load_mapping_schema_decl ('', 'file://xddl_tables.xsd', 'UTF-8', 'x-any');
--select xml_load_mapping_schema_decl ('', 'file://xddl_views.xsd', 'UTF-8', 'x-any');
--select xml_load_mapping_schema_decl ('', 'file://xddl_procs.xsd', 'UTF-8', 'x-any');
create procedure xddl_get (in path varchar) returns xml_tree {
declare stmt varchar;
declare tree xml_tree;
if (path is null)
path := '/*';
stmt := sprintf('{for \044r in xmlview("xddl")%s return \044r}', path);
return xquery_eval(stmt, xtree_doc(''));
}
;
create procedure xddl_get_tables (in path varchar) returns xml_tree {
declare stmt varchar;
declare tree xml_tree;
if (path is null)
path := '/*';
stmt := sprintf('{for \044r in xmlview("xddl_tables")%s return \044r}', path);
return xquery_eval(stmt, xtree_doc(''));
}
;
create procedure xddl_get_views (in path varchar) returns xml_tree {
declare stmt varchar;
declare tree xml_tree;
if (path is null)
path := '/*';
stmt := sprintf('{for \044r in xmlview("xddl_views")%s return \044r}', path);
return xquery_eval(stmt, xtree_doc(''));
}
;
create procedure xddl_get_procedures (in path varchar) returns xml_tree {
declare stmt varchar;
declare tree xml_tree;
if (path is null)
path := '/*';
stmt := sprintf('{for \044r in xmlview("xddl_procs")%s return \044r}', path);
return xquery_eval(stmt, xtree_doc(''));
}
;
create procedure xddl_diff (in base_path varchar, in fragment xml_tree) returns xml_tree {
declare src_xslt,res, path, vspx varchar;
declare pars, xml_tree_doc, xml_tree_doc2 any;
xml_tree_doc := fragment;
xml_tree_doc2 := xpath_eval('/tables',xddl_get_tables(null));
src_xslt := cast ( xml_uri_resolve_like_get(base_path,'xddl_diff.xsl') as varchar);
pars := vector('fragment', xml_tree_doc, 'database', xml_tree_doc2);
res := xslt (src_xslt, xml_tree_doc,pars);
return res;
}
;
create procedure xddl_to_ddl (in base_path varchar,in fragment xml_tree) returns varchar {
declare src_xslt varchar;
declare ses, res any;
ses := string_output();
src_xslt := cast ( xml_uri_resolve_like_get(base_path,'xddl_exec.xsl') as varchar);
res := xslt (src_xslt, fragment);
-- dbg_obj_print('result', res);
http_value(res,0,ses);
return string_output_string(ses);
}
;
create procedure xddl_attach_pk_xml_tree (in primary_key any, in current_table xml_tree, in key_is_unique varchar, in key_is_clustered varchar, in key_is_oid varchar )
returns xml_tree {
declare len, i integer;
declare cols, objs any;
declare path, tmp_pk varchar;
declare pk_tree xml_tree;
len := length(primary_key);
objs := xpath_eval('/table',xml_tree_doc(current_table));
path := '/table/pk/field';
cols:= xpath_eval(path,objs,0);
if (len > 0) { -- update pk
declare field xml_tree;
pk_tree := xml_tree_doc(sprintf('',
key_is_unique, key_is_clustered, key_is_oid ));
pk_tree := xpath_eval('/pk',pk_tree);
i :=0;
while (i < len) {
tmp_pk := aref(primary_key,i);
field := xml_tree_doc(sprintf('',i,tmp_pk));
XMLAppendChildren ( pk_tree, field);
i:= i +1;
}
dbg_obj_print ('Constructed PK ', pk_tree ,'Flag', cols , 'Table ', objs);
if (length( cols) = 0 ) {
XMLAppendChildren (objs, pk_tree);
return objs;
} else {
path := sprintf('/table/pk');
return XMLUpdate(objs,path, pk_tree);
}
} else if (length(cols) > 0 ) { -- remove pk
return XMLUpdate(objs,'/table/pk', NULL);
}
return current_table;
}
;
create procedure xddl_attach_fk_xml_tree (in fk_columns any, in cur_table xml_tree) returns xml_tree {
declare path, table_name, column_name, pk_name, tmp_pk varchar;
declare tmp_array, cols, fk_array, foreign_key_columns any;
declare i, len, i2, len2, is_found integer;
declare current_table xml_tree;
foreign_key_columns := fk_columns;
current_table := cur_table;
fk_array := vector();
len := length( foreign_key_columns);
while (len > 0) {
table_name := null;
i := 0;
tmp_array := vector();
cols := vector();
while ( i < len) {
if (table_name is null) {
table_name := aref(foreign_key_columns, i+2);
cols := vector(aref(foreign_key_columns, i), aref(foreign_key_columns, i+1));
i := i +3;
} else {
if (table_name = aref(foreign_key_columns, i+2)) {
cols := vector_concat(cols , vector(aref(foreign_key_columns, i), aref(foreign_key_columns, i+1)) );
} else
tmp_array := vector_concat(tmp_array , vector( aref(foreign_key_columns,i), aref(foreign_key_columns,i +1), aref(foreign_key_columns,i +2)) );
i := i +3;
}
}
if (table_name is not null and length(cols) > 0) {
fk_array := vector_concat(fk_array , vector( table_name , cols) );
}
foreign_key_columns := tmp_array;
len := length( foreign_key_columns);
}
current_table := XMLUpdate(xml_tree_doc(current_table),'/table/fk', NULL);
len := length(fk_array);
if (len > 0 ) {
i := 0;
while (i < len) {
path := sprintf('', aref(fk_array,i) );
cols := aref(fk_array,i +1);
i2 :=0;
len2 := length(cols);
dbg_obj_print ('VEC', cols, len2);
while (i2 < len2) {
path := concat (path, sprintf('', aref(cols, i2), aref(cols, i2+1) ));
i2 := i2 +2;
}
path := concat (path, '');
XMLAppendChildren(xpath_eval('/table',current_table), xpath_eval('/fk', xml_tree_doc (path) ));
i := i +2;
}
dbg_obj_print ('FK_ARRAY', current_table);
}
return current_table;
}
;
create procedure xddl_execute_statements (in current_table varchar, out statement_out varchar ) returns any {
declare err_sqlstate, err_msg, rel_path, statement varchar;
declare m_dta, exec_errors any;
declare statements varchar;
declare xq_res any;
declare difference xml_tree;
declare pos, flag integer;
difference := xddl_diff(xddl_get_base(), current_table);
dbg_obj_print('Original',current_table, 'Difference', difference);
statements := xddl_to_ddl(xddl_get_base(), xml_tree_doc(difference));
dbg_obj_print('Exec', statements);
statement_out := statements;
err_sqlstate := '00000';
if (statements is not null and length(statements) > 0) {
flag := 1;
exec_errors := vector();
while(flag = 1 and length(statements) > 0) {
pos := locate(';',statements);
dbg_obj_print('POsition is ', pos, length(statements));
if (pos > 0) {
statement := substring(statements, 1, pos -1);
if (locate(';', substring(statements, pos + 1, length(statements) - pos)) = 0 )
flag := 0;
else
statements := substring(statements, pos + 1, length(statements) - pos);
} else {
statement := statements;
flag := 0;
}
declare exit handler for sqlstate '*' {
dbg_obj_print ('Error', __SQL_MESSAGE);
err_msg := sprintf(' Execution Error: %s', __SQL_MESSAGE);
exec_errors := vector_concat( exec_errors, vector(statement, err_msg));
};
exec (statement, err_sqlstate, err_msg, vector(),100, m_dta, xq_res);
if ('00000' <> err_sqlstate) {
err_msg := sprintf(' Execution Error: %s', err_msg);
exec_errors := vector_concat( exec_errors, vector(statement, err_msg));
}
} -- while
return exec_errors;
}
return null;
}
;
create procedure xddl_attach_table_xml_tree( in current_table xml_tree, in kind varchar, in objects xml_tree) returns xml_tree {
declare objs xml_tree;
declare path varchar;
if ( kind ='create' ) {
objs := xpath_eval('/tables',objects);
XMLAppendChildren(objs, current_table);
return objs;
} else if ( kind ='edit' ) {
path := sprintf('/tables/table[@name=\'%s\']',xpath_eval('/table/@name',current_table) );
return XMLUpdate(objects, path, xml_tree_doc(current_table) );
}
return objects;
}
;
create procedure xddl_exec (in stmt varchar, out exec_error varchar) returns integer {
declare m_dta any;
declare err_sqlstate, err_msg varchar;
declare xq_res any;
err_msg := '';
err_sqlstate := '00000';
dbg_obj_print ('---------------------------Execute the following statement', stmt);
declare exit handler for sqlstate '*' {
err_msg := sprintf('Check creation Error: %s', cast(__SQL_MESSAGE as varchar) );
exec_error := err_msg;
return -1;
};
exec (stmt, err_sqlstate, err_msg, vector(),100, m_dta, xq_res);
if ('00000' <> err_sqlstate) {
dbg_obj_print('Creation ============================== Error: %s', err_msg);
exec_error := err_msg;
return -1;
}
return 0;
}
;
create procedure xddl_check_constraints_validation (in current_table xml_tree, in sid varchar, inout errors any) returns integer {
declare objs xml_tree;
declare path, code , err_msg, name, stmt, table_name varchar;
declare cols, err_list any;
declare i, len, result integer;
table_name := sprintf('db.dba.check_consttraint_%s',sid);
stmt := sprintf('create table %s (', table_name);
objs := xpath_eval('/table',xml_tree_doc(current_table));
path := '/table/constraint';
cols:= xpath_eval(path,objs,0);
if (length (cols) = 0 ) {
errors := vector();
return 0;
}
result := xddl_exec(sprintf('drop table %s',table_name), err_msg);
path := '/table/column';
cols:= xpath_eval(path,objs,0);
i := 0;
len := length(cols);
while(i < len) {
name := xpath_eval('@name',aref(cols,i));
code := xpath_eval('@type-text',aref(cols,i));
stmt := concat(stmt, sprintf ('%s %s', name, code) );
i := i + 1;
if (i < len ) {
stmt := concat(stmt, ', ');
}
}
stmt := concat(stmt, ')');
result := xddl_exec(stmt, err_msg);
if (result < 0) {
errors := vector('Cannot create temporary table', err_msg);
return -1;
}
err_list := vector();
path := '/table/constraint';
cols:= xpath_eval(path,objs,0);
i := 0;
len := length(cols);
while(i < len) {
name := xpath_eval('@name',aref(cols,i));
code := cast ( xpath_eval('code/text()',aref(cols,i)) as varchar);
stmt := sprintf('select 1 from %s where %s', table_name, code);
result := xddl_exec(stmt, err_msg);
if (result < 0)
err_list := vector_concat( err_list, vector(code, err_msg));
i := i + 1;
}
errors := err_list;
result := xddl_exec(sprintf('drop table %s',table_name), err_msg);
if (length (err_list) > 0) {
return -1;
}
return 0;
}