diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 976b4ca..ea934b3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,7 +44,7 @@ the extension into your test database. During development the cartodb extension version doesn't change with every commit, so testing latest change requires cheating with PostgreSQL -so to enforce re-load of the scripts. To help with cheating, "make install" +as to enforce the scripts to reload. To help with cheating, "make install" also installs migration scripts to go from "V" to "V"next and from "V"next to "V". Example to upgrade a 0.2.0dev version: diff --git a/Makefile b/Makefile index 2cb23b9..ccf7986 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # cartodb/Makefile EXTENSION = cartodb -EXTVERSION = 0.11.0 +EXTVERSION = 0.11.3 SED = sed @@ -10,6 +10,7 @@ CDBSCRIPTS = \ scripts-available/CDB_SearchPath.sql \ scripts-available/CDB_ExtensionPost.sql \ scripts-available/CDB_ExtensionUtils.sql \ + scripts-available/CDB_Helper.sql \ $(END) UPGRADABLE = \ @@ -50,6 +51,9 @@ UPGRADABLE = \ 0.10.1 \ 0.10.2 \ 0.11.0 \ + 0.11.1 \ + 0.11.2 \ + 0.11.3 \ $(EXTVERSION)dev \ $(EXTVERSION)next \ $(END) diff --git a/NEWS.md b/NEWS.md index 24e604c..dc3fcc9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,23 @@ next (2015-mm-dd) ----------------- +0.11.3 (2015-10-27) +------------------- +* Added CDB_Helper.sql [#173](https://github.com/CartoDB/cartodb-postgresql/pull/173) +* Added _CDB_Unique_Identifier for creating UTF8 aware unique identifiers +* Added _CDB_Unique_Column_Identifier for creating UTF8 aware unique identifiers for columns +* Added _CDB_Octet_Truncate that truncates text to a certain amount of octets. + +0.11.2 (2015-10-19) +------------------- +* Fix schema not being specified on pg_get_serial_sequence [#170](https://github.com/CartoDB/cartodb-postgresql/pull/170) +* Log invalidation function call duration in seconds [#163](https://github.com/CartoDB/cartodb-postgresql/pull/163) + +0.11.1 (2015-10-06) +------------------- +* Added CDB_DateToNumber(timestamp with time zone) [#169](https://github.com/CartoDB/cartodb-postgresql/pull/169) +* cartodbfy now discards cartodb_id candidates that contain nulls [#148](https://github.com/CartoDB/cartodb-postgresql/issues/148) + 0.11.0 (2015-09-dd) ------------------- * Groups API diff --git a/scripts-available/CDB_CartodbfyTable.sql b/scripts-available/CDB_CartodbfyTable.sql index 2e44e9a..849238e 100644 --- a/scripts-available/CDB_CartodbfyTable.sql +++ b/scripts-available/CDB_CartodbfyTable.sql @@ -1,4 +1,5 @@ -- Depends on: +-- * CDB_Helper.sql -- * CDB_ExtensionUtils.sql -- * CDB_TransformToWebmercator.sql -- * CDB_TableMetadata.sql @@ -362,7 +363,7 @@ $$ LANGUAGE PLPGSQL; -- As before, this drops all the metadata and geom sync triggers -- -- (2) _CDB_Has_Usable_Primary_ID() --- Returns TRUE if it can find a unique integer primary key named +-- Returns TRUE if it can find a unique and not null integer primary key named -- 'cartodb_id' or can rename an existing key. -- Returns FALSE otherwise. -- @@ -427,8 +428,9 @@ END; $$ LANGUAGE 'plpgsql'; --- Find a unique relation name in the given schema, starting from the --- template given. If the template is already unique, just return it; +-- DEPRECATED: Use _CDB_Unique_Identifier since it's UTF8 Safe and length +-- aware. Find a unique relation name in the given schema, starting from the +-- template given. If the template is already unique, just return it; -- otherwise, append an increasing integer until you find a unique variant. CREATE OR REPLACE FUNCTION _CDB_Unique_Relation_Name(schemaname TEXT, relationname TEXT) RETURNS TEXT @@ -439,36 +441,15 @@ DECLARE newrelname TEXT; BEGIN - i := 0; - newrelname := relationname; - LOOP + RAISE EXCEPTION '_CDB_Unique_Relation_Name is DEPRECATED. Use _CDB_Unique_Identifier(prefix TEXT, relname TEXT, suffix TEXT, schema TEXT DEFAULT NULL)'; - SELECT c.relname, n.nspname - INTO rec - FROM pg_class c - JOIN pg_namespace n ON c.relnamespace = n.oid - WHERE c.relname = newrelname - AND n.nspname = schemaname; - - IF NOT FOUND THEN - RETURN newrelname; - END IF; - - i := i + 1; - newrelname := relationname || '_' || i; - - IF i > 100 THEN - PERFORM _CDB_Error('looping too far', '_CDB_Unique_Relation_Name'); - END IF; - - END LOOP; - END; $$ LANGUAGE 'plpgsql'; --- Find a unique column name in the given relation, starting from the --- column name given. If the column name is already unique, just return it; +-- DEPRECATED: Use _CDB_Unique_Column_Identifier since it's UTF8 Safe and length +-- aware. Find a unique column name in the given relation, starting from the +-- column name given. If the column name is already unique, just return it; -- otherwise, append an increasing integer until you find a unique variant. CREATE OR REPLACE FUNCTION _CDB_Unique_Column_Name(reloid REGCLASS, columnname TEXT) RETURNS TEXT @@ -479,32 +460,8 @@ DECLARE newcolname TEXT; BEGIN - i := 0; - newcolname := columnname; - LOOP + RAISE EXCEPTION '_CDB_Unique_Column_Name is DEPRECATED. Use _CDB_Unique_Column_Identifier(prefix TEXT, relname TEXT, suffix TEXT, reloid REGCLASS DEFAULT NULL)'; - SELECT a.attname - INTO rec - FROM pg_class c - JOIN pg_attribute a ON a.attrelid = c.oid - WHERE NOT a.attisdropped - AND a.attnum > 0 - AND c.oid = reloid - AND a.attname = newcolname; - - IF NOT FOUND THEN - RETURN newcolname; - END IF; - - i := i + 1; - newcolname := columnname || '_' || i; - - IF i > 100 THEN - PERFORM _CDB_Error('looping too far', '_CDB_Unique_Column_Name'); - END IF; - - END LOOP; - END; $$ LANGUAGE 'plpgsql'; @@ -551,7 +508,7 @@ BEGIN RAISE DEBUG 'CDB(_CDB_Has_Usable_Primary_ID): %', Format('found good ''%s''', const.pkey); RETURN true; - -- Check and see if the column values are unique, + -- Check and see if the column values are unique and not null, -- if they are, we can use this column... ELSE @@ -559,13 +516,17 @@ BEGIN useable_key := true; BEGIN - sql := Format('ALTER TABLE %s ADD CONSTRAINT %s_unique UNIQUE (%s)', reloid::text, const.pkey, const.pkey); + sql := Format('ALTER TABLE %s ADD CONSTRAINT %s_pk PRIMARY KEY (%s)', reloid::text, const.pkey, const.pkey); RAISE DEBUG 'CDB(_CDB_Has_Usable_Primary_ID): %', sql; EXECUTE sql; EXCEPTION -- Failed unique check... WHEN unique_violation THEN - RAISE NOTICE 'CDB(_CDB_Has_Usable_Primary_ID): %', Format('column %s is not unique', const.pkey); + RAISE DEBUG 'CDB(_CDB_Has_Usable_Primary_ID): %', Format('column %s is not unique', const.pkey); + useable_key := false; + -- Failed not null check... + WHEN not_null_violation THEN + RAISE DEBUG 'CDB(_CDB_Has_Usable_Primary_ID): %', Format('column %s contains nulls', const.pkey); useable_key := false; -- Other fatal error WHEN others THEN @@ -574,7 +535,7 @@ BEGIN -- Clean up test constraint IF useable_key THEN - PERFORM _CDB_SQL(Format('ALTER TABLE %s DROP CONSTRAINT %s_unique', reloid::text, const.pkey)); + PERFORM _CDB_SQL(Format('ALTER TABLE %s DROP CONSTRAINT %s_pk', reloid::text, const.pkey)); -- Move non-unique column out of the way ELSE @@ -585,7 +546,7 @@ BEGIN PERFORM _CDB_SQL( Format('ALTER TABLE %s RENAME COLUMN %s TO %I', reloid::text, rec.attname, - _CDB_Unique_Column_Name(reloid, const.pkey)), + cartodb._CDB_Unique_Column_Identifier(NULL, const.pkey, NULL, reloid)), '_CDB_Has_Usable_Primary_ID'); END IF; @@ -602,7 +563,7 @@ BEGIN PERFORM _CDB_SQL( Format('ALTER TABLE %s RENAME COLUMN %s TO %I', - reloid::text, rec.attname, _CDB_Unique_Column_Name(reloid, const.pkey)), + reloid::text, rec.attname, cartodb._CDB_Unique_Column_Identifier(NULL, const.pkey, NULL, reloid)), '_CDB_Has_Usable_Primary_ID'); END IF; @@ -768,7 +729,7 @@ BEGIN WHEN others THEN IF SQLERRM = 'parse error - invalid geometry' THEN text_geom_column := false; - str := _CDB_Unique_Column_Name(reloid, r1.attname); + str := cartodb._CDB_Unique_Column_Identifier(NULL, r1.attname, NULL, reloid); sql := Format('ALTER TABLE %s RENAME COLUMN %s TO %I', reloid::text, r1.attname, str); PERFORM _CDB_SQL(sql,'_CDB_Has_Usable_Geom'); RAISE DEBUG 'CDB(_CDB_Has_Usable_Geom): %', @@ -780,7 +741,7 @@ BEGIN -- Just change its name so we can write a new column into that name. ELSE - str := _CDB_Unique_Column_Name(reloid, r1.attname); + str := cartodb._CDB_Unique_Column_Identifier(NULL, r1.attname, NULL, reloid); sql := Format('ALTER TABLE %s RENAME COLUMN %s TO %I', reloid::text, r1.attname, str); PERFORM _CDB_SQL(sql,'_CDB_Has_Usable_Geom'); RAISE DEBUG 'CDB(_CDB_Has_Usable_Geom): %', @@ -850,8 +811,7 @@ DECLARE destname TEXT; destseq TEXT; destseqmax INTEGER; - - salt TEXT := md5(random()::text || now()); + copyname TEXT; column_name_sql TEXT; @@ -957,19 +917,18 @@ BEGIN -- Put the primary key sequence in the right schema -- If the new table is not moving, better ensure the sequence name -- is unique - destseq := relname || '_' || const.pkey || '_seq'; - destseq := _CDB_Unique_Relation_Name(destschema, destseq); + destseq := cartodb._CDB_Unique_Identifier(NULL, relname, '_' || const.pkey || '_seq', destschema); destseq := Format('%I.%I', destschema, destseq); PERFORM _CDB_SQL(Format('CREATE SEQUENCE %s', destseq), '_CDB_Rewrite_Table'); - -- Salt a temporary table name if we are re-writing in place + -- Temporary table name if we are re-writing in place -- Note copyname is already escaped and safe to use as identifier IF destschema = relschema THEN - copyname := Format('%I.%I', destschema, Format('%s_%s', destname, salt)); + copyname := Format('%I.%I', destschema, cartodb._CDB_Unique_Identifier(NULL, destname, NULL), destschema); ELSE copyname := Format('%I.%I', destschema, destname); END IF; - + -- Start building the SQL! sql := Format('CREATE TABLE %s AS SELECT ', copyname); diff --git a/scripts-available/CDB_DateToNumber.sql b/scripts-available/CDB_DateToNumber.sql index 1b9a449..651d429 100644 --- a/scripts-available/CDB_DateToNumber.sql +++ b/scripts-available/CDB_DateToNumber.sql @@ -13,3 +13,19 @@ RETURN output; END; $$ LANGUAGE 'plpgsql' STABLE STRICT; + +-- Convert timestamp with time zone to double precision +-- +CREATE OR REPLACE FUNCTION CDB_DateToNumber(input timestamp with time zone) +RETURNS double precision AS $$ +DECLARE output double precision; +BEGIN + BEGIN + SELECT extract (EPOCH FROM input) INTO output; + EXCEPTION WHEN OTHERS THEN + RETURN NULL; + END; +RETURN output; +END; +$$ +LANGUAGE 'plpgsql' STABLE STRICT; diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 826c210..43ba023 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -163,7 +163,7 @@ BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); FOR column_name IN EXECUTE 'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG = current_database() AND TABLE_SCHEMA = $1 AND TABLE_NAME = $2 AND COLUMN_DEFAULT LIKE ''nextval%''' USING username, table_name LOOP - EXECUTE 'SELECT PG_GET_SERIAL_SEQUENCE($1, $2)' USING table_name, column_name INTO sequence_name; + EXECUTE format('SELECT PG_GET_SERIAL_SEQUENCE(''%I.%I'', ''%I'')', username, table_name, column_name) INTO sequence_name; IF sequence_name IS NOT NULL THEN IF do_grant THEN -- Here %s is needed since sequence_name has quotes diff --git a/scripts-available/CDB_Helper.sql b/scripts-available/CDB_Helper.sql new file mode 100644 index 0000000..5540086 --- /dev/null +++ b/scripts-available/CDB_Helper.sql @@ -0,0 +1,156 @@ +-- UTF8 safe and length aware. Find a unique identifier with a given prefix +-- and/or suffix and withing a schema. If a schema is not specified, the identifier +-- is guaranteed to be unique for all schemas. +CREATE OR REPLACE FUNCTION cartodb._CDB_Unique_Identifier(prefix TEXT, relname TEXT, suffix TEXT, schema TEXT DEFAULT NULL) +RETURNS TEXT +AS $$ +DECLARE + maxlen CONSTANT INTEGER := 63; + + rec RECORD; + usedspace INTEGER; + ident TEXT; + origident TEXT; + candrelname TEXT; + + i INTEGER; +BEGIN + -- Accounts for the _XX incremental suffix in case the identifier is taken + usedspace := 3; + usedspace := usedspace + coalesce(octet_length(prefix), 0); + usedspace := usedspace + coalesce(octet_length(suffix), 0); + + candrelname := _CDB_Octet_Truncate(relname, maxlen - usedspace); + + IF candrelname = '' THEN + PERFORM _CDB_Error('prefixes are to long to generate a valid identifier', '_CDB_Unique_Identifier'); + END IF; + + ident := coalesce(prefix, '') || candrelname || coalesce(suffix, ''); + + i := 0; + origident := ident; + + WHILE i < 100 LOOP + IF schema IS NOT NULL THEN + SELECT c.relname, n.nspname + INTO rec + FROM pg_class c + JOIN pg_namespace n ON c.relnamespace = n.oid + WHERE c.relname = ident + AND n.nspname = schema; + ELSE + SELECT c.relname, n.nspname + INTO rec + FROM pg_class c + JOIN pg_namespace n ON c.relnamespace = n.oid + WHERE c.relname = ident; + END IF; + + IF NOT FOUND THEN + RETURN ident; + END IF; + + ident := origident || '_' || i; + i := i + 1; + END LOOP; + + PERFORM _CDB_Error('looping too far', '_CDB_Unique_Identifier'); +END; +$$ LANGUAGE 'plpgsql'; + + +-- UTF8 safe and length aware. Find a unique identifier for a column with a given prefix +-- and/or suffix based on colname and within a relation specified via reloid. +CREATE OR REPLACE FUNCTION cartodb._CDB_Unique_Column_Identifier(prefix TEXT, colname TEXT, suffix TEXT, reloid REGCLASS) +RETURNS TEXT +AS $$ +DECLARE + maxlen CONSTANT INTEGER := 63; + + rec RECORD; + candcolname TEXT; + usedspace INTEGER; + ident TEXT; + origident TEXT; + + i INTEGER; +BEGIN + -- Accounts for the _XX incremental suffix in case the identifier is taken + usedspace := 3; + usedspace := usedspace + coalesce(octet_length(prefix), 0); + usedspace := usedspace + coalesce(octet_length(suffix), 0); + + candcolname := _CDB_Octet_Truncate(colname, maxlen - usedspace); + + IF candcolname = '' THEN + PERFORM _CDB_Error('prefixes are to long to generate a valid identifier', '_CDB_Unique_Column_Identifier'); + END IF; + + ident := coalesce(prefix, '') || candcolname || coalesce(suffix, ''); + + i := 0; + origident := ident; + + WHILE i < 100 LOOP + SELECT a.attname + INTO rec + FROM pg_class c + JOIN pg_attribute a ON a.attrelid = c.oid + WHERE NOT a.attisdropped + AND a.attnum > 0 + AND c.oid = reloid + AND a.attname = ident; + + IF NOT FOUND THEN + RETURN ident; + END IF; + + ident := origident || '_' || i; + i := i + 1; + END LOOP; + + PERFORM _CDB_Error('looping too far', '_CDB_Unique_Column_Identifier'); +END; +$$ LANGUAGE 'plpgsql'; + + +-- Truncates a given string to a max_octets octets taking care +-- not to leave characters in half. UTF8 safe. +CREATE OR REPLACE FUNCTION cartodb._CDB_Octet_Truncate(string TEXT, max_octets INTEGER) +RETURNS TEXT +AS $$ +DECLARE + extcharlen CONSTANT INTEGER := octet_length('ñ'); + + expected INTEGER; + examined INTEGER; + strlen INTEGER; + + i INTEGER; +BEGIN + + IF max_octets <= 0 THEN + RETURN ''; + ELSIF max_octets >= octet_length(string) THEN + RETURN string; + END IF; + + strlen := char_length(string); + + expected := char_length(string); + examined := octet_length(string); + + IF expected = examined THEN + RETURN left(string, max_octets); + END IF; + + i := max_octets / extcharlen; + + WHILE octet_length(left(string, i)) <= max_octets LOOP + i := i + 1; + END LOOP; + + RETURN left(string, (i - 1)); +END; +$$ LANGUAGE 'plpgsql'; diff --git a/scripts-available/CDB_TableMetadata.sql b/scripts-available/CDB_TableMetadata.sql index d91f798..858d36b 100644 --- a/scripts-available/CDB_TableMetadata.sql +++ b/scripts-available/CDB_TableMetadata.sql @@ -64,6 +64,10 @@ DECLARE tabname TEXT; rec RECORD; found BOOL; + function_start timestamptz; + function_end timestamptz; + function_duration float; + log_error_verbosity_value text; BEGIN IF TG_OP = 'UPDATE' or TG_OP = 'INSERT' THEN @@ -72,6 +76,8 @@ BEGIN tabname = OLD.tabname; END IF; + function_start := clock_timestamp(); + -- Notify table data update -- This needs a little bit more of research regarding security issues -- see https://github.com/CartoDB/cartodb/pull/241 @@ -105,7 +111,14 @@ BEGIN EXIT; END LOOP; IF NOT found THEN RAISE WARNING 'Missing cdb_invalidate_varnish()'; END IF; - + + function_end := clock_timestamp(); + SELECT extract(epoch from (function_end - function_start)) INTO function_duration; + SELECT setting INTO log_error_verbosity_value FROM pg_settings WHERE name='log_error_verbosity'; + SET log_error_verbosity=TERSE; + RAISE LOG 'invalidation_duration: %', function_duration::text; + PERFORM 'SET log_error_verbosity= ' || log_error_verbosity_value; + RETURN NULL; END; $$ diff --git a/test/CDB_CartodbfyTableTest.sql b/test/CDB_CartodbfyTableTest.sql index b35540b..fc6bd8a 100644 --- a/test/CDB_CartodbfyTableTest.sql +++ b/test/CDB_CartodbfyTableTest.sql @@ -250,7 +250,7 @@ INSERT INTO existing_cartodb_id (cartodb_id, description) VALUES (20, 'b'), (30, 'c'); SELECT CDB_CartodbfyTableCheck('existing_cartodb_id', 'Existing cartodb_id values are respected #138'); -SELECT * from existing_cartodb_id; +SELECT cartodb_id,the_geom,the_geom_webmercator,description,name from existing_cartodb_id; DROP TABLE existing_cartodb_id; -- Table with both the_geom and wkb_geometry @@ -281,6 +281,44 @@ INSERT INTO many_colliding_columns VALUES ( SELECT CDB_CartodbfyTableCheck('many_colliding_columns', 'Many colliding columns #141'); DROP TABLE many_colliding_columns; +-- Table with null cartodb_id +CREATE TABLE test ( + cartodb_id integer +); +INSERT INTO test VALUES + (1), + (2), + (NULL), + (3); +SELECT CDB_CartodbfyTableCheck('test', 'Table with null cartodb_id #148'); +SELECT cartodb_id, cartodb_id_0 from test; +DROP TABLE test; + +-- Table with non unique cartodb_id +CREATE TABLE test ( + cartodb_id integer +); +INSERT INTO test VALUES + (1), + (2), + (2); +SELECT CDB_CartodbfyTableCheck('test', 'Table with non unique cartodb_id #148'); +SELECT cartodb_id, cartodb_id_0 from test; +DROP TABLE test; + +-- Table with non unique and null cartodb_id +CREATE TABLE test ( + cartodb_id integer +); +INSERT INTO test VALUES + (1), + (2), + (NULL), + (2); +SELECT CDB_CartodbfyTableCheck('test', 'Table with non unique and null cartodb_id #148'); +SELECT cartodb_id, cartodb_id_0 from test; +DROP TABLE test; + -- TODO: table with existing custom-triggered the_geom diff --git a/test/CDB_CartodbfyTableTest_expect b/test/CDB_CartodbfyTableTest_expect index 6287c3f..6103dc8 100644 --- a/test/CDB_CartodbfyTableTest_expect +++ b/test/CDB_CartodbfyTableTest_expect @@ -79,5 +79,28 @@ CREATE TABLE INSERT 0 1 Many colliding columns #141 cartodbfied fine DROP TABLE +CREATE TABLE +INSERT 0 4 +Table with null cartodb_id #148 cartodbfied fine +1|1 +2|2 +3| +4|3 +DROP TABLE +CREATE TABLE +INSERT 0 3 +Table with non unique cartodb_id #148 cartodbfied fine +1|1 +2|2 +3|2 +DROP TABLE +CREATE TABLE +INSERT 0 4 +Table with non unique and null cartodb_id #148 cartodbfied fine +1|1 +2|2 +3| +4|2 +DROP TABLE DROP FUNCTION DROP FUNCTION diff --git a/test/CDB_DateToNumberTest.sql b/test/CDB_DateToNumberTest.sql new file mode 100644 index 0000000..0c1051c --- /dev/null +++ b/test/CDB_DateToNumberTest.sql @@ -0,0 +1,2 @@ +SELECT * FROM CDB_DateToNumber('1999-01-08 00:00:00'::timestamp); +SELECT * FROM CDB_DateToNumber('1999-01-08 00:00:00+05'::timestamp with time zone); diff --git a/test/CDB_DateToNumberTest_expect b/test/CDB_DateToNumberTest_expect new file mode 100644 index 0000000..bd3d3b0 --- /dev/null +++ b/test/CDB_DateToNumberTest_expect @@ -0,0 +1,2 @@ +915753600 +915735600 diff --git a/test/CDB_HelperTest.sql b/test/CDB_HelperTest.sql new file mode 100644 index 0000000..86f1e90 --- /dev/null +++ b/test/CDB_HelperTest.sql @@ -0,0 +1,128 @@ +-- Test unique identifier creation with normal length normal relname +SELECT * FROM cartodb._CDB_Unique_Identifier(NULL, 'relname', NULL); + +-- Test unique identifier creation with prefix with normal length normal relname +SELECT * FROM cartodb._CDB_Unique_Identifier('prefix_', 'relname', NULL); + +-- Test unique identifier creation with suffix with normal length normal relname +SELECT * FROM cartodb._CDB_Unique_Identifier(NULL, 'relname', '_suffix'); + +-- Test unique identifier creation with long length normal relname +SELECT * FROM cartodb._CDB_Unique_Identifier(NULL, 'largolargolargolargolargolargolargolargolargolargolargolargolar', NULL); + +-- Test unique identifier creation with prefix with long length normal relname +SELECT * FROM cartodb._CDB_Unique_Identifier('prefix_', 'largolargolargolargolargolargolargolargolargolargolargolargolar', NULL); + +-- Test new identifier is found when name is taken from previous case +CREATE TABLE prefix_largolargolargolargolargolargolargolargolargolargolar (name text); +SELECT * FROM cartodb._CDB_Unique_Identifier('prefix_', 'largolargolargolargolargolargolargolargolargolargolargolargolar', NULL); +DROP TABLE prefix_largolargolargolargolargolargolargolargolargolargolar; + +-- Test unique identifier creation with suffix with long length normal relname +SELECT * FROM cartodb._CDB_Unique_Identifier(NULL, 'largolargolargolargolargolargolargolargolargolargolargolargolar', '_suffix'); + +-- Test new identifier is found when name is taken from previous case +CREATE TABLE largolargolargolargolargolargolargolargolargolargolar_suffix (name text); +SELECT * FROM cartodb._CDB_Unique_Identifier(NULL, 'largolargolargolargolargolargolargolargolargolargolargolargolar', '_suffix'); +DROP TABLE largolargolargolargolargolargolargolargolargolargolar_suffix; + +-- Test unique identifier creation with normal length UTF8 relname +SELECT * FROM cartodb._CDB_Unique_Identifier(NULL, 'piraña', NULL); + +-- Test unique identifier creation with prefix with normal length UTF8 relname +SELECT * FROM cartodb._CDB_Unique_Identifier('prefix_', 'piraña', NULL); + +-- Test unique identifier creation with suffix with normal length UTF8 relname +SELECT * FROM cartodb._CDB_Unique_Identifier(NULL, 'piraña', '_suffix'); + +-- Test unique identifier creation with long length UTF8 relname +SELECT * FROM cartodb._CDB_Unique_Identifier(NULL, 'piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpiñaácidpin', NULL); + +-- Test unique identifier creation with prefix with long length UTF8 relname +SELECT * FROM cartodb._CDB_Unique_Identifier('prefix_', 'piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpiñaácidpin', NULL); + +-- Test new identifier is found when name is taken from previous case +CREATE TABLE prefix_piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi (name text); +SELECT * FROM cartodb._CDB_Unique_Identifier('prefix_', 'piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpiñaácidpin', NULL); +DROP TABLE prefix_piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi; + +-- Test unique identifier creation with suffix with long length UTF8 relname +SELECT * FROM cartodb._CDB_Unique_Identifier(NULL, 'piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpiñaácidpin', '_suffix'); + +-- Test new identifier is found when name is taken from previous case +CREATE TABLE piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi_suffix (name text); +SELECT * FROM cartodb._CDB_Unique_Identifier(NULL, 'piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpiñaácidpin', '_suffix'); +DROP TABLE piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi_suffix; + +CREATE TABLE test (name text); +-- Test unique identifier creation with normal length normal colname +SELECT * FROM cartodb._CDB_Unique_Column_Identifier(NULL, 'colname', NULL, 'test'::regclass); + +-- Test unique identifier creation with prefix with normal length normal colname +SELECT * FROM cartodb._CDB_Unique_Column_Identifier('prefix_', 'colname', NULL, 'test'::regclass); + +-- Test unique identifier creation with suffix with normal length normal colname +SELECT * FROM cartodb._CDB_Unique_Column_Identifier(NULL, 'colname', '_suffix', 'test'::regclass); + +-- Test unique identifier creation with long length normal colname +SELECT * FROM cartodb._CDB_Unique_Column_Identifier(NULL, 'largolargolargolargolargolargolargolargolargolargolargolargolar', NULL, 'test'::regclass); + +-- Test unique identifier creation with prefix with long length normal colname +SELECT * FROM cartodb._CDB_Unique_Column_Identifier('prefix_', 'largolargolargolargolargolargolargolargolargolargolargolargolar', NULL, 'test'::regclass); +DROP TABLE test; + +-- Test new identifier is found when name is taken from previous case +CREATE TABLE test (prefix_largolargolargolargolargolargolargolargolargolargolar text); +SELECT * FROM cartodb._CDB_Unique_Column_Identifier('prefix_', 'largolargolargolargolargolargolargolargolargolargolargolargolar', NULL, 'test'::regclass); +DROP TABLE test; + +-- Test unique identifier creation with suffix with long length normal colname +CREATE TABLE test (name text); +SELECT * FROM cartodb._CDB_Unique_Column_Identifier(NULL, 'largolargolargolargolargolargolargolargolargolargolargolargolar', '_suffix', 'test'::regclass); +DROP TABLE test; + +-- Test new identifier is found when name is taken from previous case +CREATE TABLE test (largolargolargolargolargolargolargolargolargolargolar_suffix text); +SELECT * FROM cartodb._CDB_Unique_Column_Identifier(NULL, 'largolargolargolargolargolargolargolargolargolargolargolargolar', '_suffix', 'test'::regclass); +DROP TABLE test; + +CREATE TABLE test (name text); +-- Test unique identifier creation with normal length UTF8 colname +SELECT * FROM cartodb._CDB_Unique_Column_Identifier(NULL, 'piraña', NULL, 'test'::regclass); + +-- Test unique identifier creation with prefix with normal length UTF8 colname +SELECT * FROM cartodb._CDB_Unique_Column_Identifier('prefix_', 'piraña', NULL, 'test'::regclass); + +-- Test unique identifier creation with suffix with normal length UTF8 colname +SELECT * FROM cartodb._CDB_Unique_Column_Identifier(NULL, 'piraña', '_suffix', 'test'::regclass); + +-- Test unique identifier creation with long length UTF8 colname +SELECT * FROM cartodb._CDB_Unique_Column_Identifier(NULL, 'piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpiñaácidpin', NULL, 'test'::regclass); + +-- Test unique identifier creation with prefix with long length UTF8 colname +SELECT * FROM cartodb._CDB_Unique_Column_Identifier('prefix_', 'piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpiñaácidpin', NULL, 'test'::regclass); +DROP TABLE test; + +-- Test new identifier is found when name is taken from previous case +CREATE TABLE test (prefix_piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi text); +SELECT * FROM cartodb._CDB_Unique_Column_Identifier('prefix_', 'piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpiñaácidpin', NULL, 'test'::regclass); +DROP TABLE test; + +-- Test unique identifier creation with suffix with long length UTF8 colname +CREATE TABLE test (name text); +SELECT * FROM cartodb._CDB_Unique_Column_Identifier(NULL, 'piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpiñaácidpin', '_suffix', 'test'::regclass); +DROP TABLE test; + +-- Test new identifier is found when name is taken from previous case +CREATE TABLE test (piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi_suffix text); +SELECT * FROM cartodb._CDB_Unique_Column_Identifier(NULL, 'piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpiñaácidpin', '_suffix', 'test'::regclass); +DROP TABLE test; + +-- Test _CDB_Octet_Truncate simple case +SELECT * FROM cartodb._CDB_Octet_Truncate('piraña', 5); + +-- Test _CDB_Octet_Truncate UTF8 case +SELECT * FROM cartodb._CDB_Octet_Truncate('piraña', 6); + +-- Test _CDB_Octet_Truncate UTF8 case +SELECT * FROM cartodb._CDB_Octet_Truncate('piraña', 7); diff --git a/test/CDB_HelperTest_expect b/test/CDB_HelperTest_expect new file mode 100644 index 0000000..1c1acf2 --- /dev/null +++ b/test/CDB_HelperTest_expect @@ -0,0 +1,59 @@ +relname +prefix_relname +relname_suffix +largolargolargolargolargolargolargolargolargolargolargolargo +prefix_largolargolargolargolargolargolargolargolargolargolar +CREATE TABLE +prefix_largolargolargolargolargolargolargolargolargolargolar_0 +DROP TABLE +largolargolargolargolargolargolargolargolargolargolar_suffix +CREATE TABLE +largolargolargolargolargolargolargolargolargolargolar_suffix_0 +DROP TABLE +piraña +prefix_piraña +piraña_suffix +piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpiñaácid +prefix_piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi +CREATE TABLE +prefix_piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi_0 +DROP TABLE +piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi_suffix +CREATE TABLE +piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi_suffix_0 +DROP TABLE +CREATE TABLE +colname +prefix_colname +colname_suffix +largolargolargolargolargolargolargolargolargolargolargolargo +prefix_largolargolargolargolargolargolargolargolargolargolar +DROP TABLE +CREATE TABLE +prefix_largolargolargolargolargolargolargolargolargolargolar_0 +DROP TABLE +CREATE TABLE +largolargolargolargolargolargolargolargolargolargolar_suffix +DROP TABLE +CREATE TABLE +largolargolargolargolargolargolargolargolargolargolar_suffix_0 +DROP TABLE +CREATE TABLE +piraña +prefix_piraña +piraña_suffix +piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpiñaácid +prefix_piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi +DROP TABLE +CREATE TABLE +prefix_piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi_0 +DROP TABLE +CREATE TABLE +piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi_suffix +DROP TABLE +CREATE TABLE +piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi_suffix_0 +DROP TABLE +pira +pirañ +piraña