Changeset: ef988c694472 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/ef988c694472 Modified Files: sql/include/sql_catalog.h Branch: dict Log Message:
merged with default diffs (truncated from 383 to 300 lines): diff --git a/sql/ChangeLog b/sql/ChangeLog --- a/sql/ChangeLog +++ b/sql/ChangeLog @@ -1,6 +1,11 @@ # ChangeLog file for sql # This file is updated with Maddlog +* Thu Oct 21 2021 Martin van Dinther <martin.van.dint...@monetdbsolutions.com> +- Extended SQL system catalog with lookup table sys.fkey_actions and + view sys.fkeys to provide user friendly querying of existing foreign + keys and their ON UPDATE and ON DELETE referential action specifications. + * Mon Oct 18 2021 Pedro Ferreira <pedro.ferre...@monetdbsolutions.com> - The COPY INTO command would use the double quote as the default string delimiter to produce output, while COPY FROM would use the empty string. diff --git a/sql/backends/monet5/sql_upgrades.c b/sql/backends/monet5/sql_upgrades.c --- a/sql/backends/monet5/sql_upgrades.c +++ b/sql/backends/monet5/sql_upgrades.c @@ -4227,6 +4227,32 @@ sql_update_default(Client c, mvc *sql, c pos += snprintf(buf + pos, bufsize - pos, "update sys.functions set system = true where system <> true and name in ('vacuum', 'stop_vacuum') and schema_id = 2000 and type = %d;\n", F_PROC); + /* 10_sys_schema_extension.sql */ + pos += snprintf(buf + pos, bufsize - pos, + "CREATE TABLE sys.fkey_actions (\n" + " action_id SMALLINT NOT NULL PRIMARY KEY,\n" + " action_name VARCHAR(15) NOT NULL);\n" + "INSERT INTO sys.fkey_actions (action_id, action_name) VALUES\n" + " (0, 'NO ACTION'),\n" + " (1, 'CASCADE'),\n" + " (2, 'RESTRICT'),\n" + " (3, 'SET NULL'),\n" + " (4, 'SET DEFAULT');\n" + "ALTER TABLE sys.fkey_actions SET READ ONLY;\n" + "GRANT SELECT ON sys.fkey_actions TO PUBLIC;\n" + "CREATE VIEW sys.fkeys AS\n" + "SELECT id, table_id, type, name, rkey, update_action_id, upd.action_name as update_action, delete_action_id, del.action_name as delete_action FROM (\n" + " SELECT id, table_id, type, name, rkey, cast(((\"action\" >> 8) & 255) as smallint) as update_action_id, cast((\"action\" & 255) as smallint) AS delete_action_id FROM sys.keys WHERE type = 2\n" + " UNION ALL\n" + " SELECT id, table_id, type, name, rkey, cast(((\"action\" >> 8) & 255) as smallint) as update_action_id, cast((\"action\" & 255) as smallint) AS delete_action_id FROM tmp.keys WHERE type = 2\n" + ") AS fks\n" + "JOIN sys.fkey_actions upd ON fks.update_action_id = upd.action_id\n" + "JOIN sys.fkey_actions del ON fks.delete_action_id = del.action_id;\n" + "GRANT SELECT ON sys.fkeys TO PUBLIC;\n" + ); + pos += snprintf(buf + pos, bufsize - pos, + "update sys._tables set system = true where name in ('fkey_actions', 'fkeys') AND schema_id = 2000;\n"); + assert(pos < bufsize); printf("Running database upgrade commands:\n%s\n", buf); err = SQLstatementIntern(c, buf, "update", true, false, NULL); diff --git a/sql/include/sql_catalog.h b/sql/include/sql_catalog.h --- a/sql/include/sql_catalog.h +++ b/sql/include/sql_catalog.h @@ -574,7 +574,7 @@ typedef struct sql_ukey { /* pkey, ukey typedef struct sql_fkey { /* fkey */ sql_key k; - /* no action, restrict (default), cascade, set null, set default */ + /* 0=no action, 1=cascade, 2=restrict (default setting), 3=set null, 4=set default */ int on_delete; int on_update; sqlid rkey; diff --git a/sql/scripts/10_sys_schema_extension.sql b/sql/scripts/10_sys_schema_extension.sql --- a/sql/scripts/10_sys_schema_extension.sql +++ b/sql/scripts/10_sys_schema_extension.sql @@ -409,6 +409,35 @@ ALTER TABLE sys.key_types SET READ ONLY; GRANT SELECT ON sys.key_types TO PUBLIC; +CREATE TABLE sys.fkey_actions ( + action_id SMALLINT NOT NULL PRIMARY KEY, + action_name VARCHAR(15) NOT NULL); + +-- Values taken from sql/include/sql_catalog.h see sql_fkey +-- and sql/server/sql_parser.y search for: ref_action: +INSERT INTO sys.fkey_actions (action_id, action_name) VALUES + (0, 'NO ACTION'), + (1, 'CASCADE'), + (2, 'RESTRICT'), + (3, 'SET NULL'), + (4, 'SET DEFAULT'); + +ALTER TABLE sys.fkey_actions SET READ ONLY; +GRANT SELECT ON sys.fkey_actions TO PUBLIC; + + +CREATE VIEW sys.fkeys AS +SELECT id, table_id, type, name, rkey, update_action_id, upd.action_name as update_action, delete_action_id, del.action_name as delete_action FROM ( + SELECT id, table_id, type, name, rkey, cast((("action" >> 8) & 255) as smallint) as update_action_id, cast(("action" & 255) as smallint) AS delete_action_id FROM sys.keys WHERE type = 2 + UNION ALL + SELECT id, table_id, type, name, rkey, cast((("action" >> 8) & 255) as smallint) as update_action_id, cast(("action" & 255) as smallint) AS delete_action_id FROM tmp.keys WHERE type = 2 +) AS fks +JOIN sys.fkey_actions upd ON fks.update_action_id = upd.action_id +JOIN sys.fkey_actions del ON fks.delete_action_id = del.action_id; + +GRANT SELECT ON sys.fkeys TO PUBLIC; + + CREATE TABLE sys.index_types ( index_type_id SMALLINT NOT NULL PRIMARY KEY, index_type_name VARCHAR(25) NOT NULL UNIQUE); diff --git a/sql/server/rel_dump.c b/sql/server/rel_dump.c --- a/sql/server/rel_dump.c +++ b/sql/server/rel_dump.c @@ -986,6 +986,17 @@ function_error_string(mvc *sql, const ch schema ? "'.":"", fname, arg_list ? arg_list : ""); } +static void /* keep updating the label count */ +try_update_label_count(mvc *sql, const char *label) +{ + if (label && label[0] == '%' && isdigit(label[1])) { + char *eptr = NULL; + unsigned int value = (unsigned int) strtol(label + 1, &eptr, 10); + if (eptr && eptr[0] == '\0') + sql->label = MAX(sql->label, value); + } +} + static sql_exp* exp_read(mvc *sql, sql_rel *lrel, sql_rel *rrel, list *top_exps, char *r, int *pos, int grp) { @@ -1036,6 +1047,10 @@ exp_read(mvc *sql, sql_rel *lrel, sql_re } else if (!exp) { exp = exp_column(sql->sa, tname, cname, NULL, CARD_ATOM, 1, 0, cname[0] == '%'); } + if (exp) { + try_update_label_count(sql, tname); + try_update_label_count(sql, cname); + } } break; /* atom */ @@ -1436,8 +1451,7 @@ exp_read(mvc *sql, sql_rel *lrel, sql_re } else { res->digits = 0; } - } else if (!f->func->vararg && !(exps = check_arguments_and_find_largest_any_type(sql, lrel, exps, f, 0))) - return NULL; + } } else if (list_length(exps) > 2) { if (!f->func->vararg && !(exps = check_arguments_and_find_largest_any_type(sql, lrel, exps, f, 0))) return NULL; @@ -1486,6 +1500,8 @@ exp_read(mvc *sql, sql_rel *lrel, sql_re if (!exp && rrel) exp = rel_bind_column(sql, rrel, var_cname, 0, 1); *e = old; + if (exp) + try_update_label_count(sql, var_cname); skipWS(r,pos); } @@ -1553,6 +1569,7 @@ exp_read(mvc *sql, sql_rel *lrel, sql_re (*pos)++; if (r[*pos] != '.') { cname = tname; + tname = NULL; exp_setname(sql->sa, exp, NULL, cname); skipWS(r, pos); } else { @@ -1564,6 +1581,8 @@ exp_read(mvc *sql, sql_rel *lrel, sql_re skipWS(r, pos); exp_setname(sql->sa, exp, tname, cname); } + try_update_label_count(sql, tname); + try_update_label_count(sql, cname); } return exp; } @@ -1892,6 +1911,8 @@ rel_read(mvc *sql, char *r, int *pos, li set_basecol(next); append(outputs, next); m = m->next; + try_update_label_count(sql, nrname); + try_update_label_count(sql, ncname); skipWS(r, pos); } if (r[*pos] != ']') diff --git a/sql/test/Dependencies/Tests/dependency_DBobjects.test b/sql/test/Dependencies/Tests/dependency_DBobjects.test --- a/sql/test/Dependencies/Tests/dependency_DBobjects.test +++ b/sql/test/Dependencies/Tests/dependency_DBobjects.test @@ -233,6 +233,9 @@ DEP_VIEW query TTT rowsort SELECT c.name, k.name, 'DEP_KEY' from sys.columns as c, sys.objects as kc, sys.keys as k where kc."name" = c.name AND kc.id = k.id AND k.table_id = c.table_id AND k.rkey = -1 order by c.name, k.name ---- +action_id +fkey_actions_action_id_pkey +DEP_KEY dependency_type_id dependency_types_dependency_type_id_pkey DEP_KEY diff --git a/sql/test/Dependencies/Tests/dependency_owner_schema_3.test b/sql/test/Dependencies/Tests/dependency_owner_schema_3.test --- a/sql/test/Dependencies/Tests/dependency_owner_schema_3.test +++ b/sql/test/Dependencies/Tests/dependency_owner_schema_3.test @@ -48,7 +48,7 @@ DEP_SCHEMA query TTT rowsort SELECT t.name, v.name, 'DEP_VIEW' from sys.tables as t, sys.tables as v, sys.dependencies as dep where t.id = dep.id AND v.id = dep.depend_id AND dep.depend_type = 5 AND v.type in (1, 11, 21, 31) order by t.name, v.name ---- -636 values hashing to 90e2ee5bb64e32ae6e9d2ac0ab8dae7b +645 values hashing to 6a76e9478e88821358bdbee0f171f520 query TTT rowsort SELECT t.name, i.name, 'DEP_INDEX' from sys.tables as t, sys.idxs as i where i.table_id = t.id and i.name not in (select name from sys.keys) and t.type in (0, 10, 20, 30) order by t.name, i.name @@ -126,11 +126,14 @@ DEP_FUNC query TTT rowsort SELECT c.name, v.name, 'DEP_VIEW' from sys.columns as c, sys.tables as v, sys.dependencies as dep where c.id = dep.id AND v.id = dep.depend_id AND dep.depend_type = 5 AND v.type in (1, 11, 21, 31) order by c.name, v.name ---- -2217 values hashing to 419c161985866d250f6e16deb56ab344 +2259 values hashing to fbfaada25cafb60a05201d2a699ce3e3 query TTT rowsort SELECT c.name, k.name, 'DEP_KEY' from sys.columns as c, sys.objects as kc, sys.keys as k where kc."name" = c.name AND kc.id = k.id AND k.table_id = c.table_id AND k.rkey = -1 order by c.name, k.name ---- +action_id +fkey_actions_action_id_pkey +DEP_KEY dependency_type_id dependency_types_dependency_type_id_pkey DEP_KEY diff --git a/sql/test/DropCascade/Tests/drop_columns_cascade.test b/sql/test/DropCascade/Tests/drop_columns_cascade.test --- a/sql/test/DropCascade/Tests/drop_columns_cascade.test +++ b/sql/test/DropCascade/Tests/drop_columns_cascade.test @@ -80,6 +80,7 @@ select name from sys.keys where name not ---- dependency_types_dependency_type_id_pkey dependency_types_dependency_type_name_unique +fkey_actions_action_id_pkey function_languages_language_id_pkey function_languages_language_name_unique function_types_function_type_id_pkey diff --git a/sql/test/DropCascade/Tests/drop_pkey_cascade.test b/sql/test/DropCascade/Tests/drop_pkey_cascade.test --- a/sql/test/DropCascade/Tests/drop_pkey_cascade.test +++ b/sql/test/DropCascade/Tests/drop_pkey_cascade.test @@ -22,6 +22,7 @@ select name from sys.keys where name not ---- dependency_types_dependency_type_id_pkey dependency_types_dependency_type_name_unique +fkey_actions_action_id_pkey function_languages_language_id_pkey function_languages_language_name_unique function_types_function_type_id_pkey diff --git a/sql/test/SQLancer/Tests/sqlancer19.SQL.py b/sql/test/SQLancer/Tests/sqlancer19.SQL.py --- a/sql/test/SQLancer/Tests/sqlancer19.SQL.py +++ b/sql/test/SQLancer/Tests/sqlancer19.SQL.py @@ -292,6 +292,10 @@ with SQLTestCase() as cli: .assertSucceeded().assertDataResultMatch([(True,),(True,),(True,),(True,),(True,),(True,),(True,),(None,),(None,),(None,),(None,)]) cli.execute("SELECT CAST(2 AS REAL) BETWEEN 2 AND (rt5.c0 / rt5.c0)^5 AS X FROM rt5 ORDER BY x NULLS LAST;") \ .assertSucceeded().assertDataResultMatch([(True,),(True,),(True,),(True,),(True,),(True,),(True,),(None,),(None,),(None,),(None,)]) + cli.execute("SELECT count(*) FROM t3 GROUP BY 1 + least(2, round(0.68, t3.c0));") \ + .assertSucceeded().assertDataResultMatch([(1,), (5,)]) + cli.execute("SELECT count(*) FROM rt3 GROUP BY 1 + least(2, round(0.68, rt3.c0));") \ + .assertSucceeded().assertDataResultMatch([(1,), (5,)]) cli.execute("ROLLBACK;") cli.execute("CREATE FUNCTION mybooludf(a bool) RETURNS BOOL RETURN a;") diff --git a/sql/test/Tests/keys.test b/sql/test/Tests/keys.test --- a/sql/test/Tests/keys.test +++ b/sql/test/Tests/keys.test @@ -44,6 +44,10 @@ dependency_types_dependency_type_name_un 0 dependency_types_dependency_type_name_unique 1 +fkey_actions_action_id_pkey +0 +fkey_actions_action_id_pkey +0 function_languages_language_id_pkey 0 function_languages_language_id_pkey @@ -122,6 +126,10 @@ dependency_types_dependency_type_name_un 0 dependency_types_dependency_type_name_unique 1 +fkey_actions_action_id_pkey +0 +fkey_actions_action_id_pkey +0 function_languages_language_id_pkey 0 function_languages_language_id_pkey diff --git a/sql/test/sys-schema/Tests/All b/sql/test/sys-schema/Tests/All --- a/sql/test/sys-schema/Tests/All +++ b/sql/test/sys-schema/Tests/All @@ -9,6 +9,8 @@ check_MaxStrLength_violations HAVE_GEOM?geom_tables_checks HAVE_NETCDF?netcdf_tables_checks +fkeys + webExamplesLogicalFunctionsOperators webExamplesComparisonFunctionsOperators webExamplesCastFunctionsOperators diff --git a/sql/test/sys-schema/Tests/fkeys.test b/sql/test/sys-schema/Tests/fkeys.test new file mode 100644 --- /dev/null +++ b/sql/test/sys-schema/Tests/fkeys.test @@ -0,0 +1,85 @@ +query IT nosort +select * from sys.fkey_actions order by 1 _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list