From bb54eb83c14597db6fed1eb493e1b52094e5effb Mon Sep 17 00:00:00 2001 From: Guido Fioravantti Date: Mon, 26 Oct 2015 18:01:03 +0100 Subject: [PATCH] Drops CDB_Trim_Octets for CDB_Octet_Truncate --- scripts-available/CDB_Helper.sql | 63 ++++++++++++++++---------------- test/CDB_HelperTest.sql | 52 +++++++++++++++----------- test/CDB_HelperTest_expect | 12 +++++- 3 files changed, 71 insertions(+), 56 deletions(-) diff --git a/scripts-available/CDB_Helper.sql b/scripts-available/CDB_Helper.sql index 5227590..6338b67 100644 --- a/scripts-available/CDB_Helper.sql +++ b/scripts-available/CDB_Helper.sql @@ -5,20 +5,21 @@ CREATE OR REPLACE FUNCTION cartodb._CDB_Unique_Identifier(prefix TEXT, relname T RETURNS TEXT AS $$ DECLARE + maxlen CONSTANT INTEGER := 63; + rec RECORD; usedspace INTEGER; ident TEXT; - i INTEGER; origident TEXT; - maxlen CONSTANT integer := 63; + 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); - relname := _CDB_Trim_Octets(relname, usedspace + octet_length(relname) - maxlen); + relname := _CDB_Octet_Truncate(relname, maxlen - usedspace); IF relname = '' THEN PERFORM _CDB_Error('prefixes are to long to generate a valid identifier', '_CDB_Unique_Identifier'); @@ -57,26 +58,28 @@ BEGIN END; $$ LANGUAGE 'plpgsql'; + -- UTF8 safe and lenght aware. Find a unique identifier for a column with a given prefix -- and/or suffix and withing a realtion. CREATE OR REPLACE FUNCTION cartodb._CDB_Unique_Column_Identifier(prefix TEXT, relname TEXT, suffix TEXT, reloid REGCLASS) RETURNS TEXT AS $$ DECLARE + maxlen CONSTANT INTEGER := 63; + rec RECORD; usedspace INTEGER; ident TEXT; - i INTEGER; origident TEXT; - maxlen CONSTANT integer := 63; + 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); - relname := _CDB_Trim_Octets(relname, usedspace + octet_length(relname) - maxlen); + relname := _CDB_Octet_Truncate(relname, maxlen - usedspace); IF relname = '' THEN PERFORM _CDB_Error('prefixes are to long to generate a valid identifier', '_CDB_Unique_Column_Identifier'); @@ -109,47 +112,43 @@ BEGIN END; $$ LANGUAGE 'plpgsql'; --- Trims the end of a given string by the given number of octets taking care --- not to leave characters in half. If a negative or 0 amount of octects to trim --- is specified, the suplied text is returned unaltered. UTF8 safe. -CREATE OR REPLACE FUNCTION cartodb._CDB_Trim_Octets(totrim TEXT, octets INTEGER) + +-- Truncates a given string to a max_octets octexts 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; - totrimlen INTEGER; - charlen INTEGER; + strlen INTEGER; i INTEGER; - tail TEXT; - - trimmed TEXT; BEGIN - charlen := bit_length('a'); - totrimlen := char_length(totrim); - expected := totrimlen * charlen; - examined := bit_length(totrim); - IF octets <= 0 THEN - RETURN totrim; - ELSIF expected = examined THEN - RETURN SUBSTRING(totrim from 1 for (totrimlen - octets)); - ELSIF (octets * charlen) > examined THEN + IF max_octets <= 0 THEN RETURN ''; + ELSIF max_octets >= octet_length(string) THEN + RETURN string; END IF; - i := totrimlen - ((octets - 1) / 2); - LOOP - tail := SUBSTRING(totrim from i for totrimlen); + strlen := char_length(string); - EXIT WHEN octet_length(tail) >= octets OR i <= 0; + expected := char_length(string); + examined := octet_length(string); - i := i - 1; + IF expected = examined THEN + RETURN SUBSTRING(string from 1 for max_octets); + END IF; + + i := max_octets / extcharlen; + + WHILE octet_length(SUBSTRING(string from 1 for i)) <= max_octets LOOP + i := i + 1; END LOOP; - trimmed := SUBSTRING(totrim from 1 for (totrimlen - char_length(tail))); - RETURN trimmed; + RETURN SUBSTRING(string from 1 for (i - 1)); END; $$ LANGUAGE 'plpgsql'; - diff --git a/test/CDB_HelperTest.sql b/test/CDB_HelperTest.sql index 3f82929..86f1e90 100644 --- a/test/CDB_HelperTest.sql +++ b/test/CDB_HelperTest.sql @@ -54,67 +54,75 @@ CREATE TABLE piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpi_suffix (name t 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); +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); +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'); +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); +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); +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); +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 -SELECT * FROM cartodb._CDB_Unique_Column_Identifier(NULL, 'largolargolargolargolargolargolargolargolargolargolargolargolar', '_suffix'); +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'); +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); +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); +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'); +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); +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); +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); +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 -SELECT * FROM cartodb._CDB_Unique_Column_Identifier(NULL, 'piñaácidpiñaácidpiñaácidpiñaácidpiñaácidpiñaácidpin', '_suffix'); +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'); +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_Trim_Octets simple case -SELECT * FROM cartodb._CDB_Octet_Trim('piraña', 1); +-- Test _CDB_Octet_Truncate simple case +SELECT * FROM cartodb._CDB_Octet_Truncate('piraña', 5); --- Test _CDB_Octet_Trim UTF8 case -SELECT * FROM cartodb._CDB_Octet_Trim('piraña', 2); +-- Test _CDB_Octet_Truncate UTF8 case +SELECT * FROM cartodb._CDB_Octet_Truncate('piraña', 6); --- Test _CDB_Octet_Trim UTF8 case -SELECT * FROM cartodb._CDB_Octet_Trim('piraña', 3); \ No newline at end of file +-- 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 index afb7e12..1c1acf2 100644 --- a/test/CDB_HelperTest_expect +++ b/test/CDB_HelperTest_expect @@ -22,30 +22,38 @@ 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 -pira +piraña