2015-10-22 18:38:00 +08:00
|
|
|
-- UTF8 safe and lenght aware. Find a unique identifier with a given prefix
|
2015-10-26 22:54:08 +08:00
|
|
|
-- and/or suffix and withing a schema. If a schema is not specified, the identifier
|
|
|
|
-- is guaranteed to be unique for all schemas.
|
2015-10-23 01:00:18 +08:00
|
|
|
CREATE OR REPLACE FUNCTION cartodb._CDB_Unique_Identifier(prefix TEXT, relname TEXT, suffix TEXT, schema TEXT DEFAULT NULL)
|
2015-10-22 18:38:00 +08:00
|
|
|
RETURNS TEXT
|
|
|
|
AS $$
|
|
|
|
DECLARE
|
|
|
|
rec RECORD;
|
|
|
|
usedspace INTEGER;
|
|
|
|
ident TEXT;
|
|
|
|
i INTEGER;
|
|
|
|
origident TEXT;
|
|
|
|
|
2015-10-26 23:15:55 +08:00
|
|
|
maxlen CONSTANT integer := 63;
|
|
|
|
BEGIN
|
|
|
|
-- Accounts for the _XX incremental suffix in case the identifier is taken
|
2015-10-22 18:38:00 +08:00
|
|
|
usedspace := 3;
|
|
|
|
usedspace := usedspace + coalesce(octet_length(prefix), 0);
|
|
|
|
usedspace := usedspace + coalesce(octet_length(suffix), 0);
|
|
|
|
|
2015-10-23 01:00:18 +08:00
|
|
|
relname := _CDB_Octet_Trim(relname, usedspace + octet_length(relname) - maxlen);
|
2015-10-22 18:38:00 +08:00
|
|
|
|
|
|
|
IF relname = '' THEN
|
2015-10-23 01:00:18 +08:00
|
|
|
PERFORM _CDB_Error('prefixes are to long to generate a valid identifier', '_CDB_Unique_Identifier');
|
2015-10-22 18:38:00 +08:00
|
|
|
END IF;
|
|
|
|
|
|
|
|
ident := coalesce(prefix, '') || relname || 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;
|
|
|
|
|
2015-10-23 01:00:18 +08:00
|
|
|
PERFORM _CDB_Error('looping too far', '_CDB_Unique_Identifier');
|
2015-10-22 18:38:00 +08:00
|
|
|
END;
|
|
|
|
$$ LANGUAGE 'plpgsql';
|
|
|
|
|
2015-10-22 23:01:47 +08:00
|
|
|
-- UTF8 safe and lenght aware. Find a unique identifier for a column with a given prefix
|
2015-10-26 22:54:08 +08:00
|
|
|
-- and/or suffix and withing a realtion. If no reloid is give, all relations are examined.
|
2015-10-23 01:00:18 +08:00
|
|
|
CREATE OR REPLACE FUNCTION cartodb._CDB_Unique_Column_Identifier(prefix TEXT, relname TEXT, suffix TEXT, reloid REGCLASS DEFAULT NULL)
|
2015-10-22 23:01:47 +08:00
|
|
|
RETURNS TEXT
|
|
|
|
AS $$
|
|
|
|
DECLARE
|
|
|
|
rec RECORD;
|
|
|
|
usedspace INTEGER;
|
|
|
|
ident TEXT;
|
|
|
|
i INTEGER;
|
|
|
|
origident TEXT;
|
|
|
|
|
2015-10-26 23:15:55 +08:00
|
|
|
maxlen CONSTANT integer := 63;
|
|
|
|
BEGIN
|
|
|
|
-- Accounts for the _XX incremental suffix in case the identifier is taken
|
2015-10-22 23:01:47 +08:00
|
|
|
usedspace := 3;
|
|
|
|
usedspace := usedspace + coalesce(octet_length(prefix), 0);
|
|
|
|
usedspace := usedspace + coalesce(octet_length(suffix), 0);
|
|
|
|
|
2015-10-23 01:00:18 +08:00
|
|
|
relname := _CDB_Octet_Trim(relname, usedspace + octet_length(relname) - maxlen);
|
2015-10-22 23:01:47 +08:00
|
|
|
|
|
|
|
IF relname = '' THEN
|
2015-10-23 01:00:18 +08:00
|
|
|
PERFORM _CDB_Error('prefixes are to long to generate a valid identifier', '_CDB_Unique_Column_Identifier');
|
2015-10-22 23:01:47 +08:00
|
|
|
END IF;
|
|
|
|
|
|
|
|
ident := coalesce(prefix, '') || relname || coalesce(suffix, '');
|
|
|
|
|
|
|
|
i := 0;
|
|
|
|
origident := ident;
|
|
|
|
|
|
|
|
WHILE i < 100 LOOP
|
|
|
|
IF reloid IS NOT NULL THEN
|
|
|
|
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;
|
|
|
|
ELSE
|
|
|
|
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 a.attname = ident;
|
|
|
|
END IF;
|
|
|
|
|
|
|
|
IF NOT FOUND THEN
|
|
|
|
RETURN ident;
|
|
|
|
END IF;
|
|
|
|
|
|
|
|
ident := origident || '_' || i;
|
|
|
|
i := i + 1;
|
|
|
|
END LOOP;
|
|
|
|
|
2015-10-23 01:00:18 +08:00
|
|
|
PERFORM _CDB_Error('looping too far', '_CDB_Unique_Column_Identifier');
|
2015-10-22 23:01:47 +08:00
|
|
|
END;
|
|
|
|
$$ LANGUAGE 'plpgsql';
|
2015-10-22 18:38:00 +08:00
|
|
|
|
|
|
|
-- Trims the end of a given string by the given number of octets taking care
|
|
|
|
-- not to leave characters in half. UTF8 safe.
|
2015-10-23 01:00:18 +08:00
|
|
|
CREATE OR REPLACE FUNCTION cartodb._CDB_Octet_Trim(tostrip TEXT, octets INTEGER)
|
2015-10-22 18:38:00 +08:00
|
|
|
RETURNS TEXT
|
|
|
|
AS $$
|
|
|
|
DECLARE
|
|
|
|
expected INTEGER;
|
|
|
|
examined INTEGER;
|
|
|
|
tostriplen INTEGER;
|
|
|
|
charlen INTEGER;
|
|
|
|
|
|
|
|
i INTEGER;
|
|
|
|
tail TEXT;
|
|
|
|
|
|
|
|
trimmed TEXT;
|
|
|
|
BEGIN
|
|
|
|
charlen := bit_length('a');
|
|
|
|
tostriplen := char_length(tostrip);
|
|
|
|
expected := tostriplen * charlen;
|
|
|
|
examined := bit_length(tostrip);
|
|
|
|
|
|
|
|
IF expected = examined OR octets = 0 THEN
|
|
|
|
RETURN SUBSTRING(tostrip from 1 for (tostriplen - octets));
|
|
|
|
ELSIF octets < 0 THEN
|
|
|
|
RETURN tostrip;
|
|
|
|
ELSIF (octets * charlen) > examined THEN
|
|
|
|
RETURN '';
|
|
|
|
END IF;
|
|
|
|
|
|
|
|
i := tostriplen - ((octets - 1) / 2);
|
|
|
|
LOOP
|
|
|
|
tail := SUBSTRING(tostrip from i for tostriplen);
|
|
|
|
|
|
|
|
EXIT WHEN octet_length(tail) >= octets OR i <= 0;
|
|
|
|
|
|
|
|
i := i - 1;
|
|
|
|
END LOOP;
|
|
|
|
|
|
|
|
trimmed := SUBSTRING(tostrip from 1 for (tostriplen - char_length(tail)));
|
|
|
|
RETURN trimmed;
|
|
|
|
END;
|
|
|
|
$$ LANGUAGE 'plpgsql';
|
|
|
|
|