From dc2ae31bf5a1007324ed51b214595846a31af683 Mon Sep 17 00:00:00 2001 From: mertmit Date: Mon, 10 Oct 2022 03:34:48 +0300 Subject: [PATCH] feat: snowflake improvements Signed-off-by: mertmit --- .../nocodb-sdk/src/lib/sqlUi/SnowflakeUi.ts | 1675 ++++------------- .../lib/snowflake/SnowflakeClient.ts | 287 ++- .../sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 43 +- 3 files changed, 503 insertions(+), 1502 deletions(-) diff --git a/packages/nocodb-sdk/src/lib/sqlUi/SnowflakeUi.ts b/packages/nocodb-sdk/src/lib/sqlUi/SnowflakeUi.ts index ce3fa80b9a..4c8a06776a 100644 --- a/packages/nocodb-sdk/src/lib/sqlUi/SnowflakeUi.ts +++ b/packages/nocodb-sdk/src/lib/sqlUi/SnowflakeUi.ts @@ -2,104 +2,40 @@ import UITypes from '../UITypes'; import { IDType } from './index'; const dbTypes = [ - 'int', - 'integer', - 'bigint', - 'bigserial', - 'char', - 'int2', - 'int4', - 'int8', - 'int4range', - 'int8range', - 'serial', - 'serial2', - 'serial8', - 'character', - 'bit', - 'bool', - 'boolean', - 'date', - 'double precision', - 'event_trigger', - 'fdw_handler', - 'float4', - 'float8', - 'uuid', - 'smallint', - 'smallserial', - 'character varying', - 'text', - 'real', - 'time', - 'time without time zone', - 'timestamp', - 'timestamp without time zone', - 'timestamptz', - 'timestamp with time zone', - 'timetz', - 'time with time zone', - 'daterange', - 'json', - 'jsonb', - 'gtsvector', - 'index_am_handler', - 'anyenum', - 'anynonarray', - 'anyrange', - 'box', - 'bpchar', - 'bytea', - 'cid', - 'cidr', - 'circle', - 'cstring', - 'inet', - 'internal', - 'interval', - 'language_handler', - 'line', - 'lsec', - 'macaddr', - 'money', - 'name', - 'numeric', - 'numrange', - 'oid', - 'opaque', - 'path', - 'pg_ddl_command', - 'pg_lsn', - 'pg_node_tree', - 'point', - 'polygon', - 'record', - 'refcursor', - 'regclass', - 'regconfig', - 'regdictionary', - 'regnamespace', - 'regoper', - 'regoperator', - 'regproc', - 'regpreocedure', - 'regrole', - 'regtype', - 'reltime', - 'smgr', - 'tid', - 'tinterval', - 'trigger', - 'tsm_handler', - 'tsquery', - 'tsrange', - 'tstzrange', - 'tsvector', - 'txid_snapshot', - 'unknown', - 'void', - 'xid', - 'xml', + 'NUMBER', + 'DECIMAL', + 'NUMERIC', + 'INT', + 'INTEGER', + 'BIGINT', + 'SMALLINT', + 'TINYINT', + 'BYTEINT', + 'FLOAT', + 'FLOAT4', + 'FLOAT8', + 'DOUBLE', + 'DOUBLE PRECISION', + 'REAL', + 'VARCHAR', + 'CHAR', + 'CHARACTER', + 'STRING', + 'TEXT', + 'BINARY', + 'VARBINARY', + 'BOOLEAN', + 'DATE', + 'DATETIME', + 'TIME', + 'TIMESTAMP', + 'TIMESTAMP_LTZ', + 'TIMESTAMP_NTZ', + 'TIMESTAMP_TZ', + 'VARIANT', + 'OBJECT', + 'ARRAY', + 'GEOGRAPHY', ]; export class SnowflakeUi { @@ -108,7 +44,7 @@ export class SnowflakeUi { { column_name: 'id', title: 'Id', - dt: 'int4', + dt: 'int', dtx: 'integer', ct: 'int(11)', nrqd: false, @@ -131,7 +67,7 @@ export class SnowflakeUi { { column_name: 'title', title: 'Title', - dt: 'character varying', + dt: 'varchar', dtx: 'specificType', ct: 'varchar(45)', nrqd: true, @@ -163,7 +99,7 @@ export class SnowflakeUi { pk: false, un: false, ai: false, - cdf: 'now()', + cdf: 'current_timestamp()', clen: 45, np: null, ns: null, @@ -187,7 +123,7 @@ export class SnowflakeUi { un: false, ai: false, au: true, - cdf: 'now()', + cdf: 'current_timestamp()', clen: 45, np: null, ns: null, @@ -204,7 +140,7 @@ export class SnowflakeUi { static getNewColumn(suffix) { return { column_name: 'title' + suffix, - dt: 'character varying', + dt: 'varchar', dtx: 'specificType', ct: 'varchar(45)', nrqd: true, @@ -226,842 +162,129 @@ export class SnowflakeUi { }; } - // static getDefaultLengthForDatatype(type) { - // switch (type) { - // case "int": - // return 11; - // break; - // case "tinyint": - // return 1; - // break; - // case "smallint": - // return 5; - // break; - // - // case "mediumint": - // return 9; - // break; - // case "bigint": - // return 20; - // break; - // case "bit": - // return 64; - // break; - // case "boolean": - // return ''; - // break; - // case "float": - // return 12; - // break; - // case "decimal": - // return 10; - // break; - // case "double": - // return 22; - // break; - // case "serial": - // return 20; - // break; - // case "date": - // return ''; - // break; - // case "datetime": - // case "timestamp": - // return 6; - // break; - // case "time": - // return ''; - // break; - // case "year": - // return ''; - // break; - // case "char": - // return 255; - // break; - // case "varchar": - // return 45; - // break; - // case "nchar": - // return 255; - // break; - // case "text": - // return ''; - // break; - // case "tinytext": - // return ''; - // break; - // case "mediumtext": - // return ''; - // break; - // case "longtext": - // return '' - // break; - // case "binary": - // return 255; - // break; - // case "varbinary": - // return 65500; - // break; - // case "blob": - // return ''; - // break; - // case "tinyblob": - // return ''; - // break; - // case "mediumblob": - // return ''; - // break; - // case "longblob": - // return ''; - // break; - // case "enum": - // return '\'a\',\'b\''; - // break; - // case "set": - // return '\'a\',\'b\''; - // break; - // case "geometry": - // return ''; - // case "point": - // return ''; - // case "linestring": - // return ''; - // case "polygon": - // return ''; - // case "multipoint": - // return ''; - // case "multilinestring": - // return ''; - // case "multipolygon": - // return ''; - // case "json": - // return '' - // break; - // - // } - // - // } - static getDefaultLengthForDatatype(type): any { switch (type) { - case 'int': - return ''; - - case 'tinyint': - return ''; - - case 'smallint': - return ''; - - case 'mediumint': - return ''; - - case 'bigint': - return ''; - - case 'bit': - return ''; - - case 'boolean': - return ''; - - case 'float': - return ''; - - case 'decimal': - return ''; - - case 'double': - return ''; - - case 'serial': - return ''; - - case 'date': - return ''; - - case 'datetime': - case 'timestamp': - return ''; - - case 'time': - return ''; - - case 'year': - return ''; - - case 'char': - return ''; - - case 'varchar': - return ''; - - case 'nchar': - return ''; - - case 'text': - return ''; - - case 'tinytext': - return ''; - - case 'mediumtext': - return ''; - - case 'longtext': - return ''; - - case 'binary': - return ''; - - case 'varbinary': - return ''; - - case 'blob': - return ''; - - case 'tinyblob': - return ''; - - case 'mediumblob': - return ''; - - case 'longblob': - return ''; - - case 'enum': - return ''; - - case 'set': - return ''; - - case 'geometry': - return ''; - case 'point': - return ''; - case 'linestring': - return ''; - case 'polygon': - return ''; - case 'multipoint': - return ''; - case 'multilinestring': - return ''; - case 'multipolygon': - return ''; - case 'json': + case 'NUMBER': + case 'DECIMAL': + case 'NUMERIC': + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'SMALLINT': + case 'TINYINT': + case 'BYTEINT': + case 'FLOAT': + case 'FLOAT4': + case 'FLOAT8': + case 'DOUBLE': + case 'DOUBLE PRECISION': + case 'REAL': + case 'VARCHAR': + case 'CHAR': + case 'CHARACTER': + case 'STRING': + case 'TEXT': + case 'BINARY': + case 'VARBINARY': + case 'BOOLEAN': + case 'DATE': + case 'DATETIME': + case 'TIME': + case 'TIMESTAMP': + case 'TIMESTAMP_LTZ': + case 'TIMESTAMP_NTZ': + case 'TIMESTAMP_TZ': + case 'VARIANT': + case 'OBJECT': + case 'ARRAY': + case 'GEOGRAPHY': return ''; } } static getDefaultLengthIsDisabled(type): any { switch (type) { - case 'anyenum': - case 'anynonarray': - case 'anyrange': - case 'bigint': - case 'bigserial': - case 'bit': - case 'bool': - case 'box': - case 'bpchar': - case 'bytea': - case 'char': - case 'character': - case 'cid': - case 'cidr': - case 'circle': - case 'cstring': - case 'date': - case 'daterange': - case 'double precision': - case 'event_trigger': - case 'fdw_handler': - case 'float4': - case 'float8': - case 'gtsvector': - case 'index_am_handler': - case 'inet': - case 'int': - case 'int2': - case 'int4': - case 'int8': - case 'int4range': - case 'int8range': - case 'integer': - case 'internal': - case 'interval': - case 'jsonb': - case 'language_handler': - case 'line': - case 'lsec': - case 'macaddr': - case 'money': - case 'name': - case 'numeric': - case 'numrange': - case 'oid': - case 'opaque': - case 'path': - case 'pg_ddl_command': - case 'pg_lsn': - case 'pg_node_tree': - case 'real': - case 'record': - case 'refcursor': - case 'regclass': - case 'regconfig': - case 'regdictionary': - case 'regnamespace': - case 'regoper': - case 'regoperator': - case 'regproc': - case 'regpreocedure': - case 'regrole': - case 'regtype': - case 'reltime': - case 'serial': - case 'serial2': - case 'serial8': - case 'smallint': - case 'smallserial': - case 'smgr': - case 'text': - case 'tid': - case 'time': - case 'time without time zone': - case 'timestamp': - case 'timestamp without time zone': - case 'timestamptz': - case 'timestamp with time zone': - case 'timetz': - case 'time with time zone': - case 'tinterval': - case 'trigger': - case 'tsm_handler': - case 'tsquery': - case 'tsrange': - case 'tstzrange': - case 'tsvector': - case 'txid_snapshot': - case 'unknown': - case 'void': - case 'xid': - case 'xml': - case 'character varying': - case 'tinyint': - case 'mediumint': - case 'float': - case 'decimal': - case 'double': - case 'boolean': - case 'datetime': - case 'uuid': - case 'year': - case 'varchar': - case 'nchar': - case 'tinytext': - case 'mediumtext': - case 'longtext': - case 'binary': - case 'varbinary': - case 'blob': - case 'tinyblob': - case 'mediumblob': - case 'longblob': - case 'enum': - case 'set': - case 'geometry': - case 'point': - case 'linestring': - case 'polygon': - case 'multipoint': - case 'multilinestring': - case 'multipolygon': - case 'json': + case 'NUMBER': + case 'DECIMAL': + case 'NUMERIC': + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'SMALLINT': + case 'TINYINT': + case 'BYTEINT': + case 'FLOAT': + case 'FLOAT4': + case 'FLOAT8': + case 'DOUBLE': + case 'DOUBLE PRECISION': + case 'REAL': + case 'VARCHAR': + case 'CHAR': + case 'CHARACTER': + case 'STRING': + case 'TEXT': + case 'BINARY': + case 'VARBINARY': + case 'BOOLEAN': + case 'DATE': + case 'DATETIME': + case 'TIME': + case 'TIMESTAMP': + case 'TIMESTAMP_LTZ': + case 'TIMESTAMP_NTZ': + case 'TIMESTAMP_TZ': + case 'VARIANT': + case 'OBJECT': + case 'ARRAY': + case 'GEOGRAPHY': return true; } } static getDefaultValueForDatatype(type): any { switch (type) { - case 'anyenum': - return 'eg: '; - - case 'anynonarray': - return 'eg: '; - - case 'anyrange': - return 'eg: '; - - case 'bigint': - return 'eg: '; - - case 'bigserial': - return 'eg: '; - - case 'bit': - return 'eg: '; - - case 'bool': - return 'eg: '; - - case 'box': - return 'eg: '; - - case 'bpchar': - return 'eg: '; - - case 'bytea': - return 'eg: '; - - case 'char': - return 'eg: '; - - case 'character': - return "eg: 'sample'"; - - case 'cid': - return 'eg: '; - - case 'cidr': - return 'eg: '; - - case 'circle': - return 'eg: '; - - case 'cstring': - return 'eg: '; - - case 'date': - return "eg: '2020-09-09'"; - - case 'daterange': - return 'eg: '; - - case 'double precision': - return 'eg: 1.2'; - - case 'event_trigger': - return 'eg: '; - - case 'fdw_handler': - return 'eg: '; - - case 'float4': - return 'eg: 1.2'; - - case 'float8': - return 'eg: 1.2'; - - case 'gtsvector': - return 'eg: '; - - case 'index_am_handler': - return 'eg: '; - - case 'inet': - return 'eg: '; - - case 'int': - return 'eg: '; - - case 'int2': - return 'eg: '; - - case 'int4': - return 'eg: '; - - case 'int8': - return 'eg: '; - - case 'int4range': - return 'eg: '; - - case 'int8range': - return 'eg: '; - - case 'integer': - return 'eg: '; - - case 'internal': - return 'eg: '; - - case 'interval': - return 'eg: '; - - case 'json': - return 'eg: '; - - case 'jsonb': - return 'eg: '; - - case 'language_handler': - return 'eg: '; - - case 'line': - return 'eg: '; - - case 'lsec': - return 'eg: '; - - case 'macaddr': - return 'eg: '; - - case 'money': - return 'eg: '; - - case 'name': - return 'eg: '; - - case 'numeric': - return 'eg: '; - - case 'numrange': - return 'eg: '; - - case 'oid': - return 'eg: '; - - case 'opaque': - return 'eg: '; - - case 'path': - return 'eg: '; - - case 'pg_ddl_command': - return 'eg: '; - - case 'pg_lsn': - return 'eg: '; - - case 'pg_node_tree': - return 'eg: '; - - case 'point': - return 'eg: '; - - case 'polygon': - return 'eg: '; - - case 'real': - return 'eg: 1.2'; - - case 'record': - return 'eg: '; - - case 'refcursor': - return 'eg: '; - - case 'regclass': - return 'eg: '; - - case 'regconfig': - return 'eg: '; - - case 'regdictionary': - return 'eg: '; - - case 'regnamespace': - return 'eg: '; - - case 'regoper': - return 'eg: '; - - case 'regoperator': - return 'eg: '; - - case 'regproc': - return 'eg: '; - - case 'regpreocedure': - return 'eg: '; - - case 'regrole': - return 'eg: '; - - case 'regtype': - return 'eg: '; - - case 'reltime': - return 'eg: '; - - case 'serial': - return 'eg: '; - - case 'serial2': - return 'eg: '; - - case 'serial8': - return 'eg: '; - - case 'smallint': - return 'eg: '; - - case 'smallserial': - return 'eg: '; - - case 'smgr': - return 'eg: '; - - case 'text': - return "eg: 'sample text'"; - - case 'tid': - return 'eg: '; - - case 'time': - return "eg: now()\n\n'04:05:06.789'"; - - case 'time without time zone': - return "eg: now()\n\n'04:05:06.789'"; - - case 'timestamp': - return "eg: now()\n\n'2016-06-22 19:10:25-07'"; - - case 'timestamp without time zone': - return "eg: now()\n\n'2016-06-22 19:10:25-07'"; - - case 'timestamptz': - return "eg: timezone('America/New_York','2016-06-01 00:00')\n\nnow()\n\n'2016-06-22 19:10:25-07'"; - - case 'timestamp with time zone': - return "eg: now()\n\n'2016-06-22 19:10:25-07'"; - - case 'timetz': - return 'eg: now()'; - - case 'time with time zone': - return 'eg: now()'; - - case 'tinterval': - return 'eg: '; - - case 'trigger': - return 'eg: '; - - case 'tsm_handler': - return 'eg: '; - - case 'tsquery': - return 'eg: '; - - case 'tsrange': - return 'eg: '; - - case 'tstzrange': - return 'eg: '; - - case 'tsvector': - return 'eg: '; - - case 'txid_snapshot': - return 'eg: '; - - case 'unknown': - return 'eg: '; - - case 'void': - return 'eg: '; - - case 'xid': - return 'eg: '; - - case 'xml': - return 'eg: '; - - case 'character varying': - return "eg: 'sample text'"; - - case 'tinyint': - return 'eg: '; - - case 'mediumint': - return 'eg: '; - - case 'float': - return 'eg: '; - - case 'decimal': - return 'eg: '; - - case 'double': - return 'eg: 1.2'; - - case 'boolean': - return 'eg: true\n\nfalse'; - - case 'datetime': - return 'eg: '; - - case 'uuid': - return 'eg: '; - - case 'year': - return 'eg: '; - - case 'varchar': - return 'eg: '; - - case 'nchar': - return 'eg: '; - - case 'tinytext': - return 'eg: '; - - case 'mediumtext': - return 'eg: '; - - case 'longtext': - return 'eg: '; - - case 'binary': - return 'eg: '; - - case 'varbinary': - return 'eg: '; - - case 'blob': - return 'eg: '; - - case 'tinyblob': - return 'eg: '; - - case 'mediumblob': - return 'eg: '; - - case 'longblob': - return 'eg: '; - - case 'enum': - return 'eg: '; - - case 'set': - return 'eg: '; - - case 'geometry': - return 'eg: '; - - case 'linestring': - return 'eg: '; - - case 'multipoint': - return 'eg: '; - - case 'multilinestring': - return 'eg: '; - - case 'multipolygon': + default: return 'eg: '; } } static getDefaultScaleForDatatype(type): any { switch (type) { - case 'int': - return ' '; - - case 'tinyint': - return ' '; - - case 'smallint': - return ' '; - - case 'mediumint': - return ' '; - - case 'bigint': - return ' '; - - case 'bit': - return ' '; - - case 'boolean': - return ' '; - - case 'float': - return '2'; - - case 'decimal': - return '2'; - - case 'double': - return '2'; - - case 'serial': - return ' '; - - case 'date': - case 'datetime': - case 'timestamp': - return ' '; - - case 'time': - return ' '; - - case 'year': - return ' '; - - case 'char': - return ' '; - - case 'varchar': - return ' '; - - case 'nchar': - return ' '; - - case 'text': - return ' '; - - case 'tinytext': - return ' '; - - case 'mediumtext': - return ' '; - - case 'longtext': - return ' '; - - case 'binary': - return ' '; - - case 'varbinary': - return ' '; - - case 'blob': - return ' '; - - case 'tinyblob': - return ' '; - - case 'mediumblob': - return ' '; - - case 'longblob': - return ' '; - - case 'enum': - return ' '; - - case 'set': - return ' '; - - case 'geometry': - return ' '; - case 'point': - return ' '; - case 'linestring': - return ' '; - case 'polygon': - return ' '; - case 'multipoint': - return ' '; - case 'multilinestring': - return ' '; - case 'multipolygon': - return ' '; - case 'json': + case 'NUMBER': + case 'DECIMAL': + case 'NUMERIC': + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'SMALLINT': + case 'TINYINT': + case 'BYTEINT': + case 'FLOAT': + case 'FLOAT4': + case 'FLOAT8': + case 'DOUBLE': + case 'DOUBLE PRECISION': + case 'REAL': + case 'VARCHAR': + case 'CHAR': + case 'CHARACTER': + case 'STRING': + case 'TEXT': + case 'BINARY': + case 'VARBINARY': + case 'BOOLEAN': + case 'DATE': + case 'DATETIME': + case 'TIME': + case 'TIMESTAMP': + case 'TIMESTAMP_LTZ': + case 'TIMESTAMP_NTZ': + case 'TIMESTAMP_TZ': + case 'VARIANT': + case 'OBJECT': + case 'ARRAY': + case 'GEOGRAPHY': return ' '; } } @@ -1069,10 +292,13 @@ export class SnowflakeUi { static colPropAIDisabled(col, columns) { // console.log(col); if ( - col.dt === 'int4' || - col.dt === 'integer' || - col.dt === 'bigint' || - col.dt === 'smallint' + col.dt === 'NUMBER' || + col.dt === 'DECIMAL' || + col.dt === 'NUMERIC' || + col.dt === 'INT' || + col.dt === 'INTEGER' || + col.dt === 'BIGINT' || + col.dt === 'SMALLINT' ) { for (let i = 0; i < columns.length; ++i) { if (columns[i].cn !== col.cn && columns[i].ai) { @@ -1102,10 +328,13 @@ export class SnowflakeUi { static onCheckboxChangeAI(col) { console.log(col); if ( - col.dt === 'int' || - col.dt === 'bigint' || - col.dt === 'smallint' || - col.dt === 'tinyint' + col.dt === 'NUMBER' || + col.dt === 'DECIMAL' || + col.dt === 'NUMERIC' || + col.dt === 'INT' || + col.dt === 'INTEGER' || + col.dt === 'BIGINT' || + col.dt === 'SMALLINT' ) { col.altered = col.altered || 2; } @@ -1123,7 +352,7 @@ export class SnowflakeUi { col.altered = col.altered || 2; // } if (col.au) { - col.cdf = 'now()'; + col.cdf = 'current_timestamp()'; } // if (!col.ai) { @@ -1142,11 +371,10 @@ export class SnowflakeUi { if ( columns[i].altered === 1 && !( - columns[i].dt === 'int' || - columns[i].dt === 'bigint' || - columns[i].dt === 'tinyint' || - columns[i].dt === 'smallint' || - columns[i].dt === 'mediumint' + columns[i].dt === 'INT' || + columns[i].dt === 'BIGINT' || + columns[i].dt === 'SMALLINT' || + columns[i].dt === 'TINYINT' ) ) { columns[i].un = false; @@ -1288,7 +516,7 @@ export class SnowflakeUi { }); } else if (json[keys[i]].length <= 255) { Object.assign(column, { - dt: 'character varying', + dt: 'VARCHAR', np: null, ns: 0, dtxp: null, @@ -1342,15 +570,14 @@ export class SnowflakeUi { return true; } - switch (col.dt) { - case 'time': - case 'time without time zone': - case 'timestamp': - case 'timestamp without time zone': - case 'timestamptz': - case 'timestamp with time zone': - case 'timetz': - case 'time with time zone': + switch (col.dt.toUpperCase()) { + case 'DATE': + case 'DATETIME': + case 'TIME': + case 'TIMESTAMP': + case 'TIMESTAMP_LTZ': + case 'TIMESTAMP_NTZ': + case 'TIMESTAMP_TZ': return false; default: return true; @@ -1358,214 +585,90 @@ export class SnowflakeUi { } static getAbstractType(col): any { - switch ((col.dt || col.dt).toLowerCase()) { - case 'anyenum': - return 'enum'; - case 'anynonarray': - case 'anyrange': - return 'string'; - - case 'bit': - return 'integer'; - case 'bigint': - case 'bigserial': - return 'string'; - - case 'bool': - return 'boolean'; - - case 'box': - case 'bpchar': - case 'bytea': - case 'char': - case 'character': - return 'string'; - - case 'cid': - case 'cidr': - case 'circle': - case 'cstring': - return 'string'; - - case 'date': - return 'date'; - case 'daterange': - return 'string'; - case 'double precision': - return 'string'; - - case 'event_trigger': - case 'fdw_handler': - return 'string'; - - case 'float4': - case 'float8': - return 'float'; - - case 'gtsvector': - case 'index_am_handler': - case 'inet': - return 'string'; - - case 'int': - case 'int2': - case 'int4': - case 'int8': - case 'integer': + switch (col.dt.toUpperCase()) { + case 'NUMBER': + case 'DECIMAL': + case 'NUMERIC': + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'SMALLINT': + case 'TINYINT': + case 'BYTEINT': return 'integer'; - case 'int4range': - case 'int8range': - case 'internal': - case 'interval': - return 'string'; - case 'jsonb': - return 'string'; - - case 'language_handler': - case 'line': - case 'lsec': - case 'macaddr': - case 'money': - case 'name': - case 'numeric': - case 'numrange': - case 'oid': - case 'opaque': - case 'path': - case 'pg_ddl_command': - case 'pg_lsn': - case 'pg_node_tree': - case 'point': - case 'polygon': - return 'string'; - case 'real': + case 'FLOAT': + case 'FLOAT4': + case 'FLOAT8': + case 'DOUBLE': + case 'DOUBLE PRECISION': + case 'REAL': return 'float'; - case 'record': - case 'refcursor': - case 'regclass': - case 'regconfig': - case 'regdictionary': - case 'regnamespace': - case 'regoper': - case 'regoperator': - case 'regproc': - case 'regpreocedure': - case 'regrole': - case 'regtype': - case 'reltime': - return 'string'; - case 'serial': - case 'serial2': - case 'serial8': - case 'smallint': - case 'smallserial': - return 'integer'; - case 'smgr': + case 'VARCHAR': + case 'CHAR': + case 'CHARACTER': + case 'STRING': return 'string'; - case 'text': + case 'TEXT': return 'text'; - case 'tid': + case 'BINARY': + case 'VARBINARY': return 'string'; - case 'time': - case 'time without time zone': - return 'time'; - case 'timestamp': - case 'timestamp without time zone': - case 'timestamptz': - case 'timestamp with time zone': - return 'datetime'; - case 'timetz': - case 'time with time zone': - return 'time'; - - case 'tinterval': - case 'trigger': - case 'tsm_handler': - case 'tsquery': - case 'tsrange': - case 'tstzrange': - case 'tsvector': - case 'txid_snapshot': - case 'unknown': - case 'void': - case 'xid': - case 'character varying': - case 'xml': - return 'string'; - - case 'tinyint': - case 'mediumint': - return 'integer'; - - case 'float': - case 'decimal': - case 'double': - return 'float'; - case 'boolean': + case 'BOOLEAN': return 'boolean'; - case 'datetime': - return 'datetime'; - - case 'uuid': - case 'year': - case 'varchar': - case 'nchar': + case 'DATE': + return 'date'; + case 'DATETIME': + case 'TIME': + case 'TIMESTAMP': + case 'TIMESTAMP_LTZ': + case 'TIMESTAMP_NTZ': + case 'TIMESTAMP_TZ': return 'string'; - case 'tinytext': - case 'mediumtext': - case 'longtext': - return 'text'; - case 'binary': - case 'varbinary': + case 'VARIANT': return 'string'; - case 'blob': - case 'tinyblob': - case 'mediumblob': - case 'longblob': - return 'blob'; - case 'enum': + case 'OBJECT': + return 'json'; + case 'ARRAY': return 'enum'; - case 'set': - return 'set'; - case 'geometry': - case 'linestring': - case 'multipoint': - case 'multilinestring': - case 'multipolygon': + case 'GEOGRAPHY': + return 'string'; + default: return 'string'; - case 'json': - return 'json'; } } static getUIType(col): any { switch (this.getAbstractType(col)) { - case 'integer': + case 'NUMBER': + case 'DECIMAL': + case 'NUMERIC': + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'SMALLINT': + case 'TINYINT': + case 'BYTEINT': return 'Number'; - case 'boolean': - return 'Checkbox'; - case 'float': + case 'FLOAT': + case 'FLOAT4': + case 'FLOAT8': + case 'DOUBLE': + case 'DOUBLE PRECISION': + case 'REAL': return 'Decimal'; - case 'date': - return 'Date'; - case 'datetime': - return 'CreateTime'; - case 'time': - return 'Time'; - case 'year': - return 'Year'; - case 'string': + case 'VARCHAR': + case 'CHAR': + case 'CHARACTER': + case 'STRING': return 'SingleLineText'; - case 'text': - return 'LongText'; - case 'blob': - return 'Attachment'; - case 'enum': - return 'SingleSelect'; - case 'set': - return 'MultiSelect'; - case 'json': + case 'TEXT': return 'LongText'; + case 'BOOLEAN': + return 'Checkbox'; + case 'DATE': + return 'Date'; + case 'DATETIME': + return 'DateTime'; } } @@ -1576,7 +679,7 @@ export class SnowflakeUi { { const isAutoIncId = idType === 'AI'; const isAutoGenId = idType === 'AG'; - colProp.dt = isAutoGenId ? 'character varying' : 'int4'; + colProp.dt = isAutoGenId ? 'VARCHAR' : 'int4'; colProp.pk = true; colProp.un = isAutoIncId; colProp.ai = isAutoIncId; @@ -1585,41 +688,41 @@ export class SnowflakeUi { } break; case 'ForeignKey': - colProp.dt = 'character varying'; + colProp.dt = 'VARCHAR'; break; case 'SingleLineText': - colProp.dt = 'character varying'; + colProp.dt = 'VARCHAR'; break; case 'LongText': - colProp.dt = 'text'; + colProp.dt = 'TEXT'; break; case 'Attachment': - colProp.dt = 'text'; + colProp.dt = 'TEXT'; break; case 'Checkbox': - colProp.dt = 'bool'; + colProp.dt = 'BOOLEAN'; break; case 'MultiSelect': - colProp.dt = 'text'; + colProp.dt = 'TEXT'; break; case 'SingleSelect': - colProp.dt = 'text'; + colProp.dt = 'TEXT'; break; case 'Collaborator': - colProp.dt = 'character varying'; + colProp.dt = 'VARCHAR'; break; case 'Date': - colProp.dt = 'date'; + colProp.dt = 'DATE'; break; case 'Year': - colProp.dt = 'int'; + colProp.dt = 'INT'; break; case 'Time': - colProp.dt = 'time'; + colProp.dt = 'VARCHAR'; break; case 'PhoneNumber': - colProp.dt = 'character varying'; + colProp.dt = 'VARCHAR'; colProp.validate = { func: ['isMobilePhone'], args: [''], @@ -1627,7 +730,7 @@ export class SnowflakeUi { }; break; case 'Email': - colProp.dt = 'character varying'; + colProp.dt = 'VARCHAR'; colProp.validate = { func: ['isEmail'], args: [''], @@ -1635,7 +738,7 @@ export class SnowflakeUi { }; break; case 'URL': - colProp.dt = 'character varying'; + colProp.dt = 'VARCHAR'; colProp.validate = { func: ['isURL'], args: [''], @@ -1643,13 +746,13 @@ export class SnowflakeUi { }; break; case 'Number': - colProp.dt = 'bigint'; + colProp.dt = 'BIGINT'; break; case 'Decimal': - colProp.dt = 'decimal'; + colProp.dt = 'DECIMAL'; break; case 'Currency': - colProp.dt = 'decimal'; + colProp.dt = 'DECIMAL'; colProp.validate = { func: ['isCurrency'], args: [''], @@ -1657,49 +760,49 @@ export class SnowflakeUi { }; break; case 'Percent': - colProp.dt = 'double precision'; + colProp.dt = 'DOUBLE PRECISION'; break; case 'Duration': - colProp.dt = 'decimal'; + colProp.dt = 'DECIMAL'; break; case 'Rating': - colProp.dt = 'smallint'; + colProp.dt = 'SMALLINT'; break; case 'Formula': - colProp.dt = 'character varying'; + colProp.dt = 'VARCHAR'; break; case 'Rollup': - colProp.dt = 'character varying'; + colProp.dt = 'VARCHAR'; break; case 'Count': - colProp.dt = 'int8'; + colProp.dt = 'INT'; break; case 'Lookup': - colProp.dt = 'character varying'; + colProp.dt = 'VARCHAR'; break; case 'DateTime': - colProp.dt = 'timestamp'; + colProp.dt = 'TIMESTAMP'; break; case 'CreateTime': - colProp.dt = 'timestamp'; + colProp.dt = 'TIMESTAMP'; break; case 'LastModifiedTime': - colProp.dt = 'timestamp'; + colProp.dt = 'TIMESTAMP'; break; case 'AutoNumber': - colProp.dt = 'int'; + colProp.dt = 'INT'; break; case 'Barcode': - colProp.dt = 'character varying'; + colProp.dt = 'VARCHAR'; break; case 'Button': - colProp.dt = 'character varying'; + colProp.dt = 'VARCHAR'; break; case 'JSON': - colProp.dt = 'json'; + colProp.dt = 'TEXT'; break; default: - colProp.dt = 'character varying'; + colProp.dt = 'VARCHAR'; break; } return colProp; @@ -1709,21 +812,10 @@ export class SnowflakeUi { switch (col.uidt) { case 'ID': if (idType === 'AG') { - return ['char', 'character', 'character varying']; + return ['char', 'character', 'VARCHAR']; } else if (idType === 'AI') { return [ - 'int', - 'integer', - 'bigint', - 'bigserial', - 'int2', - 'int4', - 'int8', - 'serial', - 'serial2', - 'serial8', - 'smallint', - 'smallserial', + 'NUMBER' ]; } else { return dbTypes; @@ -1734,215 +826,170 @@ export class SnowflakeUi { case 'SingleLineText': case 'LongText': case 'Collaborator': - return ['char', 'character', 'character varying', 'text']; + return ['CHAR', 'CHARACTER', 'VARCHAR', 'TEXT']; case 'Attachment': - return ['json', 'char', 'character', 'character varying', 'text']; + return ['TEXT', 'CHAR', 'CHARACTER', 'VARCHAR', 'text']; case 'JSON': - return ['json', 'jsonb', 'text']; + return ['TEXT']; case 'Checkbox': return [ - 'bit', - 'bool', - 'int2', - 'int4', - 'int8', - 'boolean', - 'smallint', - 'int', - 'integer', - 'bigint', - 'char', - 'int4range', - 'int8range', + 'BIT', + 'BOOLEAN', + 'TINYINT', + 'INT', + 'BIGINT', ]; case 'MultiSelect': - return ['text']; + return ['TEXT']; case 'SingleSelect': - return ['text']; + return ['TEXT']; case 'Year': - return ['int']; + return ['INT']; case 'Time': return [ - 'time', - 'time without time zone', - 'timestamp', - 'timestamp without time zone', - 'timestamptz', - 'timestamp with time zone', - 'timetz', - 'time with time zone', + 'TIMESTAMP', + 'VARCHAR', ]; case 'PhoneNumber': case 'Email': - return ['character varying']; + return ['VARCHAR']; case 'URL': - return ['character varying', 'text']; + return ['VARCHAR', 'TEXT']; case 'Number': return [ - 'int', - 'integer', - 'bigint', - 'int2', - 'int4', - 'int8', - 'double precision', - 'float4', - 'float8', - 'smallint', - 'numeric', + 'NUMBER', + 'DECIMAL', + 'NUMERIC', + 'INT', + 'INTEGER', + 'BIGINT', + 'SMALLINT', + 'TINYINT', + 'BYTEINT', + 'FLOAT', + 'FLOAT4', + 'FLOAT8', + 'DOUBLE', + 'DOUBLE PRECISION', + 'REAL', ]; case 'Decimal': - return ['double precision', 'float4', 'float8', 'numeric']; + return ['DOUBLE', 'DOUBLE PRECISION', 'FLOAT', 'FLOAT4', 'FLOAT8', 'NUMERIC']; case 'Currency': return [ - 'int', - 'integer', - 'bigint', - 'int2', - 'int4', - 'int8', - 'double precision', - 'money', - 'float4', - 'float8', - 'numeric', + 'NUMBER', + 'DECIMAL', + 'NUMERIC', + 'INT', + 'INTEGER', + 'BIGINT', + 'FLOAT', + 'FLOAT4', + 'FLOAT8', + 'DOUBLE', + 'DOUBLE PRECISION', ]; case 'Percent': return [ - 'int', - 'integer', - 'bigint', - 'int2', - 'int4', - 'int8', - 'double precision', - 'float4', - 'float8', - 'smallint', - 'numeric', + 'NUMBER', + 'DECIMAL', + 'NUMERIC', + 'INT', + 'INTEGER', + 'BIGINT', + 'FLOAT', + 'FLOAT4', + 'FLOAT8', + 'DOUBLE', + 'DOUBLE PRECISION', ]; case 'Duration': return [ - 'int', - 'integer', - 'bigint', - 'int2', - 'int4', - 'int8', - 'double precision', - 'float4', - 'float8', - 'smallint', - 'smallserial', - 'numeric', + 'NUMBER', + 'DECIMAL', + 'NUMERIC', + 'INT', + 'INTEGER', + 'BIGINT', + 'FLOAT', + 'FLOAT4', + 'FLOAT8', + 'DOUBLE', + 'DOUBLE PRECISION', ]; case 'Rating': return [ - 'int', - 'integer', - 'bigint', - 'bigserial', - 'int2', - 'int4', - 'int8', - 'serial', - 'serial2', - 'serial8', - 'double precision', - 'float4', - 'float8', - 'smallint', - 'smallserial', - 'numeric', + 'NUMBER', + 'DECIMAL', + 'NUMERIC', + 'INT', + 'INTEGER', + 'BIGINT', + 'FLOAT', + 'FLOAT4', + 'FLOAT8', + 'DOUBLE', + 'DOUBLE PRECISION', ]; case 'Formula': - return ['text', 'character varying']; + return ['TEXT', 'VARCHAR']; case 'Rollup': - return ['character varying']; + return ['VARCHAR']; case 'Count': return [ - 'int', - 'integer', - 'bigint', - 'bigserial', - 'int2', - 'int4', - 'int8', - 'serial', - 'serial2', - 'serial8', - 'smallint', - 'smallserial', + 'NUMBER', + 'INT', + 'INTEGER', + 'BIGINT', ]; case 'Lookup': - return ['character varying']; + return ['VARCHAR']; case 'Date': return [ - 'date', - 'timestamp', - 'timestamp without time zone', - 'timestamptz', - 'timestamp with time zone', + 'DATE', + 'TIMESTAMP', ]; case 'DateTime': case 'CreateTime': case 'LastModifiedTime': return [ - 'timestamp', - 'timestamp without time zone', - 'timestamptz', - 'timestamp with time zone', + 'TIMESTAMP', ]; case 'AutoNumber': return [ - 'int', - 'integer', - 'bigint', - 'bigserial', - 'int2', - 'int4', - 'int8', - 'serial', - 'serial2', - 'serial8', - 'smallint', - 'smallserial', + 'NUMBER', + 'INT', + 'INTEGER', + 'BIGINT', ]; case 'Barcode': - return ['character varying']; + return ['VARCHAR']; case 'Geometry': return [ - 'polygon', - 'point', - 'circle', - 'box', - 'line', - 'lseg', - 'path', - 'circle', + 'TEXT', ]; case 'Button': diff --git a/packages/nocodb/src/lib/db/sql-client/lib/snowflake/SnowflakeClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/snowflake/SnowflakeClient.ts index b47c50f62c..737fa7b995 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/snowflake/SnowflakeClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/snowflake/SnowflakeClient.ts @@ -131,9 +131,9 @@ class SnowflakeClient extends KnexClient { const result = new Result(); log.api(`${_func}:args:`, args); try { - args.databaseName = this.connectionConfig.connection.database; + args.databaseName = this.database; const { rows } = await this.raw(`select * - from INFORMATION_SCHEMA.sequences;`); + from "${this.database}".information_schema.sequences;`); result.data.list = rowsToLower(rows).map((seq) => { return { @@ -352,7 +352,7 @@ class SnowflakeClient extends KnexClient { log.debug('checking if db exists'); rows = ( await this.sqlClient.raw( - `SELECT DATABASE_NAME as database FROM information_schema.DATABASES WHERE DATABASE_NAME = '${args.database}'` + `SELECT DATABASE_NAME as database FROM SNOWFLAKE.information_schema.DATABASES WHERE DATABASE_NAME = '${args.database}'` ) ).rows; } catch (e) { @@ -361,7 +361,7 @@ class SnowflakeClient extends KnexClient { if (rows.length === 0) { log.debug('creating database:', args); await this.sqlClient.raw(`CREATE DATABASE ??`, [args.database]); - await this.sqlClient.raw(`USE ??`, [args.database]); + await this.sqlClient.raw(`USE "${this.database}";`); } await this.sqlClient.raw(`CREATE SCHEMA IF NOT EXISTS ??`,[this.schema]); @@ -409,7 +409,7 @@ class SnowflakeClient extends KnexClient { /** ************** START : create _evolution table if not exists *************** */ const exists = await this.sqlClient.raw( `SELECT table_schema,table_name as "tn", table_catalog - FROM information_schema.tables + FROM "${this.database}".information_schema.tables where table_schema=? and table_name = ?`, [this.schema, args.tn] ); @@ -451,8 +451,8 @@ class SnowflakeClient extends KnexClient { try { const { rows } = await this.sqlClient.raw( - `SELECT table_schema,table_name as "tn", table_catalog FROM information_schema.tables where table_schema = ? and table_name = ? and table_catalog = ?`, - [this.schema, args.tn, this.connectionConfig.connection.database] + `SELECT table_schema,table_name as "tn", table_catalog FROM "${this.database}".information_schema.tables where table_schema = ? and table_name = ? and table_catalog = ?`, + [this.schema, args.tn, this.database] ); result.data.value = rows.length > 0; } catch (e) { @@ -472,7 +472,7 @@ class SnowflakeClient extends KnexClient { try { const { rows } = await this.sqlClient.raw( - `SELECT DATABASE_NAME as database FROM information_schema.DATABASES WHERE DATABASE_NAME = ?`, + `SELECT DATABASE_NAME as database FROM SNOWFLAKE.information_schema.DATABASES WHERE DATABASE_NAME = ?`, [args.databaseName] ); result.data.value = rows.length > 0; @@ -499,7 +499,7 @@ class SnowflakeClient extends KnexClient { try { const { rows } = await this.sqlClient.raw( - `SELECT DATABASE_NAME as database_name FROM information_schema.DATABASES;` + `SELECT DATABASE_NAME as database_name FROM SNOWFLAKE.information_schema.DATABASES;` ); result.data.list = rows; } catch (e) { @@ -525,7 +525,7 @@ class SnowflakeClient extends KnexClient { try { const { rows } = await this.raw( `SELECT table_schema as "ts", table_name as "tn", table_type as "table_type" - FROM information_schema.tables + FROM "${this.database}".information_schema.tables where table_schema = ? ORDER BY table_schema, table_name`, [this.schema] @@ -551,7 +551,7 @@ class SnowflakeClient extends KnexClient { try { const { rows } = await this - .raw(`SELECT SCHEMA_NAME as "schema_name" FROM information_schema.SCHEMATA order by schema_name;`); + .raw(`SELECT SCHEMA_NAME as "schema_name" FROM "${this.database}".information_schema.SCHEMATA order by schema_name;`); result.data.list = rows; } catch (e) { @@ -595,22 +595,25 @@ class SnowflakeClient extends KnexClient { const result = new Result(); log.api(`${_func}:args:`, args); try { - args.databaseName = this.connectionConfig.connection.database; - await this.sqlClient.raw(`SHOW PRIMARY KEYS IN SCHEMA ${this.connectionConfig.connection.database}.${this.schema};`); - await this.sqlClient.raw(`SHOW UNIQUE KEYS IN SCHEMA ${this.connectionConfig.connection.database}.${this.schema};`); + args.databaseName = this.database; + await this.sqlClient.raw(`USE "${this.database}";`); + await this.sqlClient.raw(`SHOW PRIMARY KEYS IN SCHEMA "${this.database}"."${this.schema}";`); + await this.sqlClient.raw(`SHOW UNIQUE KEYS IN SCHEMA "${this.database}"."${this.schema}";`); + + const lastQueries = await this.sqlClient.raw(` select * from table(information_schema.query_history()) WHERE query_text like 'SHOW%' ORDER BY start_time DESC - LIMIT 200` + LIMIT 200;` ); let pk_query_id, uq_query_id; for (const r of lastQueries.rows) { - if (r.QUERY_TEXT === `SHOW PRIMARY KEYS IN SCHEMA ${this.connectionConfig.connection.database}.${this.schema};`) { + if (r.QUERY_TEXT === `SHOW PRIMARY KEYS IN SCHEMA "${this.database}"."${this.schema}";`) { pk_query_id = r.QUERY_ID; - } else if (r.QUERY_TEXT === `SHOW UNIQUE KEYS IN SCHEMA ${this.connectionConfig.connection.database}.${this.schema};`) { + } else if (r.QUERY_TEXT === `SHOW UNIQUE KEYS IN SCHEMA "${this.database}"."${this.schema}";`) { uq_query_id = r.QUERY_ID; } if (pk_query_id && uq_query_id) { @@ -637,12 +640,12 @@ class SnowflakeClient extends KnexClient { "PK"."key_sequence" as "pk_ordinal_position", "PK"."constraint_name" as "pk_constraint_name", udt_name - FROM information_schema.COLUMNS cl + FROM "${this.database}".information_schema.COLUMNS cl LEFT JOIN (select * from table(result_scan('${pk_query_id}')) UNION select * from table(result_scan('${uq_query_id}'))) pk - LEFT JOIN information_schema.table_constraints tc ON tc.constraint_name = "PK"."constraint_name" + LEFT JOIN "${this.database}".information_schema.table_constraints tc ON tc.constraint_name = "PK"."constraint_name" ON "PK"."schema_name" = cl.table_schema and "PK"."table_name" = cl.table_name and pk."column_name" = cl.column_name WHERE cl.table_catalog = ? and cl.table_schema = ? and cl.table_name = ?;`, - [this.connectionConfig.connection.database, this.schema, args.tn] + [this.database, this.schema, args.tn] ); const columns = []; @@ -674,8 +677,8 @@ class SnowflakeClient extends KnexClient { column.un = response.rows[i].ct.indexOf('unsigned') !== -1; column.ai = false; - if (response.rows[i].cdf) { - column.ai = response.rows[i].cdf.indexOf('nextval') !== -1; + if (response.rows[i].au) { + column.ai = response.rows[i].au === 'YES'; } // todo : need to find if column is unique or not @@ -766,21 +769,22 @@ class SnowflakeClient extends KnexClient { const result = new Result(); log.api(`${_func}:args:`, args); try { - await this.sqlClient.raw(`SHOW PRIMARY KEYS IN SCHEMA ${this.connectionConfig.connection.database}.${this.schema};`); - await this.sqlClient.raw(`SHOW UNIQUE KEYS IN SCHEMA ${this.connectionConfig.connection.database}.${this.schema};`); + await this.sqlClient.raw(`USE "${this.database}";`); + await this.sqlClient.raw(`SHOW PRIMARY KEYS IN SCHEMA "${this.database}"."${this.schema}";`); + await this.sqlClient.raw(`SHOW UNIQUE KEYS IN SCHEMA "${this.database}"."${this.schema}";`); const lastQueries = await this.sqlClient.raw(` - select * from table(information_schema.query_history()) + select * from table(INFORMATION_SCHEMA.query_history()) WHERE query_text like 'SHOW%' ORDER BY start_time DESC - LIMIT 200` + LIMIT 200;` ); let pk_query_id, uq_query_id; for (const r of lastQueries.rows) { - if (r.QUERY_TEXT === `SHOW PRIMARY KEYS IN SCHEMA ${this.connectionConfig.connection.database}.${this.schema};`) { + if (r.QUERY_TEXT === `SHOW PRIMARY KEYS IN SCHEMA "${this.database}"."${this.schema}";`) { pk_query_id = r.QUERY_ID; - } else if (r.QUERY_TEXT === `SHOW UNIQUE KEYS IN SCHEMA ${this.connectionConfig.connection.database}.${this.schema};`) { + } else if (r.QUERY_TEXT === `SHOW UNIQUE KEYS IN SCHEMA "${this.database}"."${this.schema}";`) { uq_query_id = r.QUERY_ID; } if (pk_query_id && uq_query_id) { @@ -793,11 +797,11 @@ class SnowflakeClient extends KnexClient { constraint_name as "cstn", "PK"."column_name" as "cn", constraint_type as "cst" - FROM information_schema.table_constraints tc + FROM "${this.database}".information_schema.table_constraints tc LEFT JOIN (select * from table(result_scan('${pk_query_id}')) UNION select * from table(result_scan('${uq_query_id}'))) pk ON "PK"."constraint_name" = tc.constraint_name WHERE tc.table_catalog = ? and tc.table_schema = ? and tc.table_name = ?;`, - [this.connectionConfig.connection.database, this.schema, args.tn]); + [this.database, this.schema, args.tn]); result.data.list = rows; } catch (e) { @@ -991,7 +995,7 @@ class SnowflakeClient extends KnexClient { log.api(`${_func}:args:`, args); try { const { rows } = await this.sqlClient.raw( - `select * from INFORMATION_SCHEMA.views WHERE table_schema = ?;`, + `select * from "${this.database}".INFORMATION_SCHEMA.views WHERE table_schema = ?;`, [this.schema] ); @@ -1074,10 +1078,10 @@ class SnowflakeClient extends KnexClient { const result = new Result(); log.api(`${_func}:args:`, args); try { - args.databaseName = this.connectionConfig.connection.database; + args.databaseName = this.database; const { rows } = await this.sqlClient.raw( - `select * from INFORMATION_SCHEMA.views WHERE table_name='${args.view_name}' and table_schema = ${this.schema};` + `select * from "${this.database}".INFORMATION_SCHEMA.views WHERE table_name='${args.view_name}' and table_schema = '${this.schema}';` ); for (let i = 0; i < rows.length; ++i) { @@ -1366,7 +1370,7 @@ class SnowflakeClient extends KnexClient { throw new Error('Function not supported for Snowflake yet'); const upQuery = this.querySeparator() + - `CREATE TRIGGER \`${args.procedure_name}\` \n${args.timing} ${args.event}\nON "${args.tn}" FOR EACH ROW\n${args.statement}`; + `CREATE TRIGGER \`${args.procedure_name}\` \n${args.timing} ${args.event}\nON ${this.getTnPath(args.tn)} FOR EACH ROW\n${args.statement}`; await this.sqlClient.raw(upQuery); const downQuery = this.querySeparator() + @@ -1404,7 +1408,7 @@ class SnowflakeClient extends KnexClient { this.querySeparator() + `DROP TRIGGER ${args.procedure_name}`; const upQuery = this.querySeparator() + - `CREATE TRIGGER \`${args.procedure_name}\` \n${args.timing} ${args.event}\nON "${args.tn}" FOR EACH ROW\n${args.statement}`; + `CREATE TRIGGER \`${args.procedure_name}\` \n${args.timing} ${args.event}\nON ${this.getTnPath(args.tn)} FOR EACH ROW\n${args.statement}`; await this.sqlClient.raw(query); await this.sqlClient.raw(upQuery); @@ -1439,7 +1443,7 @@ class SnowflakeClient extends KnexClient { throw new Error('Function not supported for Snowflake yet'); const upQuery = this.querySeparator() + - `CREATE TRIGGER ${args.trigger_name} \n${args.timing} ${args.event}\nON "${args.tn}" FOR EACH ROW\n${args.statement}`; + `CREATE TRIGGER ${args.trigger_name} \n${args.timing} ${args.event}\nON ${this.getTnPath(args.tn)} FOR EACH ROW\n${args.statement}`; await this.sqlClient.raw(upQuery); result.data.object = { upStatement: [{ sql: upQuery }], @@ -1476,7 +1480,7 @@ class SnowflakeClient extends KnexClient { `DROP TRIGGER ${args.trigger_name} ON ${args.tn}` ); await this.sqlClient.raw( - `CREATE TRIGGER ${args.trigger_name} \n${args.timing} ${args.event}\nON "${args.tn}" FOR EACH ROW\n${args.statement}` + `CREATE TRIGGER ${args.trigger_name} \n${args.timing} ${args.event}\nON ${this.getTnPath(args.tn)} FOR EACH ROW\n${args.statement}` ); result.data.object = { @@ -1486,10 +1490,10 @@ class SnowflakeClient extends KnexClient { args.tn };${this.querySeparator()}CREATE TRIGGER ${args.trigger_name} \n${ args.timing - } ${args.event}\nON "${args.tn}" FOR EACH ROW\n${args.statement}`, + } ${args.event}\nON ${this.getTnPath(args.tn)} FOR EACH ROW\n${args.statement}`, downStatement: this.querySeparator() + - `CREATE TRIGGER ${args.trigger_name} \n${args.timing} ${args.event}\nON "${args.tn}" FOR EACH ROW\n${args.oldStatement}`, + `CREATE TRIGGER ${args.trigger_name} \n${args.timing} ${args.event}\nON ${this.getTnPath(args.tn)} FOR EACH ROW\n${args.oldStatement}`, }; } catch (e) { log.ppe(e, func); @@ -1640,11 +1644,11 @@ class SnowflakeClient extends KnexClient { /**************** create table ****************/ const upQuery = this.querySeparator() + this.createTable(args.tn, args); - await this.sqlClient.raw(upQuery); + await this.sqlClient.schema.raw(upQuery); const downStatement = this.querySeparator() + - this.sqlClient.schema.dropTable(args.table).toString(); + this.sqlClient.raw(`DROP TABLE ${this.getTnPath(args.table)};`).toString(); this.emit(`Success : ${upQuery}`); @@ -1666,107 +1670,13 @@ class SnowflakeClient extends KnexClient { return result; } - async afterTableCreate(args) { + async afterTableCreate(_args) { const result = { upStatement: [], downStatement: [] }; - let upQuery = ''; - let downQuery = ''; - - // TODO handle - for (let i = 0; i < 0; i++) { - const column = args.columns[i]; - if (column.au) { - const triggerFnName = `xc_au_${args.tn}_${column.cn}`; - const triggerName = `xc_trigger_${args.tn}_${column.cn}`; - - const triggerFnQuery = this.genQuery( - `CREATE OR REPLACE FUNCTION ??() - RETURNS TRIGGER AS $$ - BEGIN - NEW.?? = NOW(); - RETURN NEW; - END; - $$ LANGUAGE plpgsql;`, - [triggerFnName, column.cn] - ); - - upQuery += - this.querySeparator() + - triggerFnQuery + - this.querySeparator() + - this.genQuery( - `CREATE TRIGGER ?? - BEFORE UPDATE ON ?? - FOR EACH ROW - EXECUTE PROCEDURE ??();`, - [triggerName, args.tn, triggerFnName] - ); - - downQuery += - this.querySeparator() + - this.genQuery(`DROP TRIGGER IF EXISTS ?? ON ??;`, [ - triggerName, - args.tn, - ]) + - this.querySeparator() + - this.genQuery(`DROP FUNCTION IF EXISTS ??()`, [triggerFnName]); - } - } - await this.sqlClient.raw(upQuery); - result.upStatement[0] = { sql: upQuery }; - result.downStatement[0] = { sql: downQuery }; - return result; } - async afterTableUpdate(args) { + async afterTableUpdate(_args) { const result = { upStatement: [], downStatement: [] }; - let upQuery = ''; - let downQuery = ''; - - // TODO handle - for (let i = 0; i < 0; i++) { - const column = args.columns[i]; - if (column.au && column.altered === 1) { - const triggerFnName = `xc_au_${args.tn}_${column.cn}`; - const triggerName = `xc_trigger_${args.tn}_${column.cn}`; - - const triggerFnQuery = this.genQuery( - `CREATE OR REPLACE FUNCTION ??() - RETURNS TRIGGER AS $$ - BEGIN - NEW.?? = NOW(); - RETURN NEW; - END; - $$ LANGUAGE plpgsql;`, - [triggerFnName, column.cn] - ); - - upQuery += - this.querySeparator() + - triggerFnQuery + - this.querySeparator() + - this.genQuery( - `CREATE TRIGGER ?? - BEFORE UPDATE ON ?? - FOR EACH ROW - EXECUTE PROCEDURE ??();`, - [triggerName, args.tn, triggerFnName] - ); - - downQuery += - this.querySeparator() + - this.genQuery(`DROP TRIGGER IF EXISTS ?? ON ??;`, [ - triggerName, - args.tn, - ]) + - this.querySeparator() + - this.genQuery(`DROP FUNCTION IF EXISTS ??()`, [triggerFnName]); - } - } - await this.sqlClient.raw(upQuery); - result.upStatement[0] = { sql: upQuery }; - result.downStatement[0] = { sql: downQuery }; - return result; } @@ -1883,7 +1793,11 @@ class SnowflakeClient extends KnexClient { //downQuery = `ALTER TABLE "${args.columns[0].tn}" ${downQuery};`; } - await this.sqlClient.raw(upQuery); + for(const q of upQuery.split(';')) { + if (q && q.trim() !== '') { + await this.sqlClient.raw(q); + } + } // console.log(upQuery); @@ -1924,7 +1838,7 @@ class SnowflakeClient extends KnexClient { /** ************** create up & down statements *************** */ const upStatement = this.querySeparator() + - this.sqlClient.schema.dropTable(args.tn).toString(); + this.sqlClient.raw(`DROP TABLE ${this.getTnPath(args.tn)};`).toString(); let downQuery = this.createTable(args.tn, args); /** @@ -2005,7 +1919,7 @@ class SnowflakeClient extends KnexClient { this.emit(`Success : ${upStatement}`); /** ************** drop tn *************** */ - await this.sqlClient.schema.dropTable(args.tn); + await this.sqlClient.raw(`DROP TABLE ${this.getTnPath(args.tn)};`); /** ************** return files *************** */ result.data.object = { @@ -2058,7 +1972,7 @@ class SnowflakeClient extends KnexClient { const result = new Result(); log.api(`${_func}:args:`, args); try { - result.data = `INSERT INTO \`${args.tn}\` (`; + result.data = `INSERT INTO ${this.getTnPath(args.tn)} (`; let values = ' VALUES ('; const response = await this.columnList(args); if (response.data && response.data.list) { @@ -2097,7 +2011,7 @@ class SnowflakeClient extends KnexClient { log.api(`${_func}:args:`, args); try { - result.data = `UPDATE "${args.tn}" \nSET\n`; + result.data = `UPDATE ${this.getTnPath(args.tn)} \nSET\n`; const response = await this.columnList(args); if (response.data && response.data.list) { for (let i = 0; i < response.data.list.length; ++i) { @@ -2130,7 +2044,7 @@ class SnowflakeClient extends KnexClient { const result = new Result(); log.api(`${_func}:args:`, args); try { - result.data = `DELETE FROM "${args.tn}" where ;`; + result.data = `DELETE FROM ${this.getTnPath(args.tn)} where ;`; } catch (e) { log.ppe(e, _func); throw e; @@ -2151,7 +2065,7 @@ class SnowflakeClient extends KnexClient { const result = new Result(); log.api(`${_func}:args:`, args); try { - result.data = `TRUNCATE TABLE "${args.tn}";`; + result.data = `TRUNCATE TABLE ${this.getTnPath(args.tn)};`; } catch (e) { log.ppe(e, _func); throw e; @@ -2185,7 +2099,7 @@ class SnowflakeClient extends KnexClient { } } - result.data += ` FROM "${args.tn}";`; + result.data += ` FROM ${this.getTnPath(args.tn)};`; } catch (e) { log.ppe(e, _func); throw e; @@ -2227,18 +2141,13 @@ class SnowflakeClient extends KnexClient { // do nothing } else if (pksChanged) { query += numOfPksInOriginal.length - ? this.genQuery(`alter TABLE ?? drop constraint IF EXISTS ??;`, [ - t, - `${t}_pkey`, - ]) + ? this.genQuery(`alter TABLE ${this.getTnPath(t)} drop constraint IF EXISTS ??;`, [`${t}_pkey`]) : ''; if (numOfPksInNew.length) { - if (createTable) { - query += this.genQuery(`, PRIMARY KEY(??)`, [numOfPksInNew]); - } else { + if (!createTable) { query += this.genQuery( - `alter TABLE ?? add constraint ?? PRIMARY KEY(??);`, - [t, `${t}_pkey`, numOfPksInNew] + `alter TABLE ${this.getTnPath(t)} add constraint ?? PRIMARY KEY(??);`, + [`${t}_pkey`, numOfPksInNew] ); } } @@ -2251,8 +2160,8 @@ class SnowflakeClient extends KnexClient { const shouldSanitize = true; let query = existingQuery ? ',' : ''; query += this.genQuery( - `ALTER TABLE ?? DROP COLUMN ??`, - [t, n.cn], + `ALTER TABLE ${this.getTnPath(t)} DROP COLUMN ??`, + [n.cn], shouldSanitize ); return query; @@ -2274,12 +2183,12 @@ class SnowflakeClient extends KnexClient { let query = ''; for (let i = 0; i < args.columns.length; ++i) { - query += this.createTableColumn(table, args.columns[i], null, query); + query += this.createTableColumn(this.getTnPath(table), args.columns[i], null, query); } - query += this.alterTablePK(table, args.columns, [], query, true); + query += this.alterTablePK(this.getTnPath(table), args.columns, [], query, true); - query = this.genQuery(`CREATE TABLE ?? (${query});`, [args.tn]); + query = this.genQuery(`CREATE TABLE ${this.getTnPath(args.tn)} (${query});`); return query; } @@ -2293,13 +2202,7 @@ class SnowflakeClient extends KnexClient { if (change === 0) { query = existingQuery ? ',' : ''; if (n.ai) { - if (n.dt === 'int8' || n.dt.indexOf('bigint') > -1) { - query += this.genQuery(` ?? bigserial`, [n.cn], shouldSanitize); - } else if (n.dt === 'int2' || n.dt.indexOf('smallint') > -1) { - query += this.genQuery(` ?? smallserial`, [n.cn], shouldSanitize); - } else { - query += this.genQuery(` ?? serial`, [n.cn], shouldSanitize); - } + query += this.genQuery(` ?? NUMBER(38,0) NOT NULL autoincrement PRIMARY KEY UNIQUE`, [n.cn], shouldSanitize); } else { query += this.genQuery(` ?? ${n.dt}`, [n.cn], shouldSanitize); query += n.rqd ? ' NOT NULL' : ' NULL'; @@ -2309,28 +2212,28 @@ class SnowflakeClient extends KnexClient { query += this.genQuery(` ADD ?? ${n.dt}`, [n.cn], shouldSanitize); query += n.rqd ? ' NOT NULL' : ' NULL'; query += defaultValue ? ` DEFAULT ${defaultValue}` : ''; - query = this.genQuery(`ALTER TABLE ?? ${query};`, [t], shouldSanitize); + query = this.genQuery(`ALTER TABLE ${this.getTnPath(t)} ${query};`, [], shouldSanitize); } else { if (n.cn !== o.cn) { query += this.genQuery( - `\nALTER TABLE ?? RENAME COLUMN ?? TO ?? ;\n`, - [t, o.cn, n.cn], + `\nALTER TABLE ${this.getTnPath(t)} RENAME COLUMN ?? TO ?? ;\n`, + [o.cn, n.cn], shouldSanitize ); } if (n.dt !== o.dt) { query += this.genQuery( - `\nALTER TABLE ?? ALTER COLUMN ?? TYPE ${n.dt} USING ??::${n.dt};\n`, - [t, n.cn, n.cn], + `\nALTER TABLE ${this.getTnPath(t)} ALTER COLUMN ?? SET DATA TYPE ${n.dt};\n`, + [n.cn], shouldSanitize ); } if (n.rqd !== o.rqd) { query += this.genQuery( - `\nALTER TABLE ?? ALTER COLUMN ?? `, - [t, n.cn], + `\nALTER TABLE ${this.getTnPath(t)} ALTER COLUMN ?? `, + [n.cn], shouldSanitize ); query += n.rqd ? ` SET NOT NULL;\n` : ` DROP NOT NULL;\n`; @@ -2338,8 +2241,8 @@ class SnowflakeClient extends KnexClient { if (n.cdf !== o.cdf) { query += this.genQuery( - `\nALTER TABLE ?? ALTER COLUMN ?? `, - [t, n.cn], + `\nALTER TABLE ${this.getTnPath(t)} ALTER COLUMN ?? `, + [n.cn], shouldSanitize ); query += n.cdf ? ` SET DEFAULT ${n.cdf};\n` : ` DROP DEFAULT;\n`; @@ -2355,6 +2258,17 @@ class SnowflakeClient extends KnexClient { ); } + get database() { + return ( + (this.connectionConfig && + this.connectionConfig.connection.database) + ); + } + + getTnPath(t) { + return `"${this.database}"."${this.schema}"."${t}"`; + } + /** * * @param {Object} args @@ -2371,7 +2285,7 @@ class SnowflakeClient extends KnexClient { const data = await this.sqlClient.raw( `SELECT SUM(record_count) as "TotalRecords" FROM (SELECT t.table_schema || '.' || t.table_name as "table_name",t.row_count as record_count - FROM information_schema.tables t + FROM "${this.database}".information_schema.tables t WHERE t.table_type = 'BASE TABLE and table_schema = ?' )`, [this.schema] @@ -2386,6 +2300,27 @@ class SnowflakeClient extends KnexClient { } return result; } + + // Todo: error handling + async insert(args) { + const { tn, data } = args; + const res = await this.sqlClient(this.getTnPath(tn)).insert(data); + log.debug(res); + return res; + } + + async update(args) { + const { tn, data, whereConditions } = args; + const res = await this.sqlClient(this.getTnPath(tn)).where(whereConditions).update(data); + return res; + } + + async delete(args) { + const { tn, whereConditions } = args; + const res = await this.sqlClient(this.getTnPath(tn)).where(whereConditions).del(); + log.debug(res); + return res; + } } function getDefaultValue(n) { diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 12265b76c0..9d32105b5e 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -1557,6 +1557,11 @@ class BaseModelSqlv2 { .select(ai.column_name) .max(ai.column_name, { as: 'id' }) )[0].id; + } else if (this.isSnowflake) { + id = (( + await this.dbDriver(this.tnPath) + .max(ai.column_name, { as: 'id' }) + ) as any).rows[0].id; } response = await this.readByPk(id); } else { @@ -1670,9 +1675,11 @@ class BaseModelSqlv2 { private getTnPath(tb: Model) { const schema = (this.dbDriver as any).searchPath?.(); const table = - this.isMssql && schema - ? this.dbDriver.raw('??.??', [schema, tb.table_name]) - : tb.table_name; + this.isMssql && schema + ? this.dbDriver.raw('??.??', [schema, tb.table_name]) + : this.isSnowflake + ? this.dbDriver.raw(`"${this.dbDriver.client.config.connection.database}"."${this.dbDriver.client.config.connection.schema}"."${tb.table_name}"`) + : tb.table_name; return table; } @@ -1802,7 +1809,19 @@ class BaseModelSqlv2 { } if (ai) { - // response = await this.readByPk(id) + if (this.isSqlite) { + // sqlite doesnt return id after insert + id = ( + await this.dbDriver(this.tnPath) + .select(ai.column_name) + .max(ai.column_name, { as: 'id' }) + )[0].id; + } else if (this.isSnowflake) { + id = (( + await this.dbDriver(this.tnPath) + .max(ai.column_name, { as: 'id' }) + ) as any).rows[0].id; + } response = await this.readByPk(id); } else { response = data; @@ -1875,10 +1894,10 @@ class BaseModelSqlv2 { const response = this.isPg || this.isMssql ? await this.dbDriver - .batchInsert(this.model.table_name, insertDatas, chunkSize) + .batchInsert(this.tnPath, insertDatas, chunkSize) .returning(this.model.primaryKey?.column_name) : await this.dbDriver.batchInsert( - this.model.table_name, + this.tnPath, insertDatas, chunkSize ); @@ -1911,7 +1930,7 @@ class BaseModelSqlv2 { continue; } const wherePk = await this._wherePk(pkValues); - const response = await transaction(this.model.table_name) + const response = await transaction(this.tnPath) .update(d) .where(wherePk); res.push(response); @@ -1991,7 +2010,7 @@ class BaseModelSqlv2 { const res = []; for (const d of deleteIds) { if (Object.keys(d).length) { - const response = await transaction(this.model.table_name) + const response = await transaction(this.tnPath) .del() .where(d); res.push(response); @@ -2240,7 +2259,7 @@ class BaseModelSqlv2 { subject: 'NocoDB Form', html: ejs.render(formSubmissionEmailTemplate, { data: transformedData, - tn: this.model.table_name, + tn: this.tnPath, _tn: this.model.title, }), }); @@ -2559,7 +2578,7 @@ class BaseModelSqlv2 { } else { groupingValues = new Set( ( - await this.dbDriver(this.model.table_name) + await this.dbDriver(this.tnPath) .select(column.column_name) .distinct() ).map((row) => row[column.column_name]) @@ -2567,7 +2586,7 @@ class BaseModelSqlv2 { groupingValues.add(null); } - const qb = this.dbDriver(this.model.table_name); + const qb = this.dbDriver(this.tnPath); qb.limit(+rest?.limit || 25); qb.offset(+rest?.offset || 0); @@ -2705,7 +2724,7 @@ class BaseModelSqlv2 { if (isVirtualCol(column)) NcError.notImplemented('Grouping for virtual columns not implemented'); - const qb = this.dbDriver(this.model.table_name) + const qb = this.dbDriver(this.tnPath) .count('*', { as: 'count' }) .groupBy(column.column_name);