2020-11-16 19:25:25 +08:00
|
|
|
--
|
2020-11-16 22:07:58 +08:00
|
|
|
-- Given a table, returns a series of queries that can be used to recreate it
|
|
|
|
-- It does not include data
|
2020-11-16 19:25:25 +08:00
|
|
|
--
|
2020-11-16 22:07:58 +08:00
|
|
|
CREATE OR REPLACE FUNCTION @extschema@.__CDB_RegenerateTable_Get_Commands(tableoid OID)
|
2020-11-16 20:08:41 +08:00
|
|
|
RETURNS text[]
|
2020-11-16 19:25:25 +08:00
|
|
|
AS $$
|
|
|
|
import subprocess
|
2020-11-17 00:31:38 +08:00
|
|
|
import re
|
2020-11-16 19:25:25 +08:00
|
|
|
|
2020-12-02 18:51:51 +08:00
|
|
|
query = "SELECT current_setting('statement_timeout') as t"
|
|
|
|
rv = plpy.execute(query, 1)
|
|
|
|
timeout_string = str(rv[0]['t'])
|
|
|
|
if timeout_string == "0":
|
|
|
|
timeout_string = "1min"
|
|
|
|
|
2020-11-16 19:25:25 +08:00
|
|
|
query = "SELECT current_database()::text as dname"
|
|
|
|
rv = plpy.execute(query, 1)
|
|
|
|
database_name_string = str(rv[0]['dname'])
|
|
|
|
|
|
|
|
query = """SELECT concat(quote_ident(nspname), '.', quote_ident(relname)) as quoted_name
|
|
|
|
FROM pg_catalog.pg_class AS c
|
|
|
|
JOIN pg_catalog.pg_namespace AS ns
|
|
|
|
ON c.relnamespace = ns.oid
|
|
|
|
WHERE c.oid = '%s'""" % (tableoid)
|
|
|
|
rv = plpy.execute(query, 1)
|
|
|
|
full_tablename_string = str(rv[0]['quoted_name'])
|
|
|
|
|
|
|
|
# NOTE: We always use -s so data is never dumped!
|
|
|
|
# That would be a security issue that we would need to deal with (and we currently do not need it)
|
2020-12-02 18:51:51 +08:00
|
|
|
process_parameters = ["pg_dump", "-s", "--lock-wait-timeout", timeout_string, "-t", full_tablename_string, database_name_string]
|
2020-11-16 19:25:25 +08:00
|
|
|
|
|
|
|
proc = subprocess.Popen(process_parameters, stdout=subprocess.PIPE, shell=False)
|
|
|
|
(out, err) = proc.communicate()
|
2020-11-24 18:07:10 +08:00
|
|
|
if (err or not out):
|
|
|
|
plpy.error('Could not get table properties')
|
2020-11-16 19:25:25 +08:00
|
|
|
|
2020-11-16 20:08:41 +08:00
|
|
|
line = out.decode("utf-8")
|
|
|
|
lines = line.rsplit(";\n", -1)
|
|
|
|
clean_lines = []
|
|
|
|
for i in range(0, len(lines)):
|
|
|
|
line = lines[i]
|
|
|
|
sublines = line.splitlines()
|
|
|
|
sublines = [line.rstrip() for line in sublines]
|
|
|
|
sublines = [line for line in sublines if line]
|
|
|
|
sublines = [line for line in sublines if not line.startswith('--')]
|
2020-11-24 18:07:10 +08:00
|
|
|
sublines = [line for line in sublines if not line.lower().startswith('set ')]
|
|
|
|
sublines = [line for line in sublines if line.lower().find('pg_catalog.set_config(') == -1]
|
|
|
|
|
2020-11-16 20:08:41 +08:00
|
|
|
if len(sublines):
|
|
|
|
clean_lines.append("".join(sublines))
|
2020-11-16 22:07:58 +08:00
|
|
|
|
2020-11-16 20:08:41 +08:00
|
|
|
return clean_lines
|
2020-11-16 19:25:25 +08:00
|
|
|
$$
|
2020-11-16 22:07:58 +08:00
|
|
|
LANGUAGE @@plpythonu@@ VOLATILE PARALLEL UNSAFE;
|
|
|
|
|
2020-11-23 23:02:33 +08:00
|
|
|
-- Returns a list of queries that can be used to regenerate the structure of a table
|
2020-11-24 18:07:10 +08:00
|
|
|
-- The query to create the table is not included
|
2020-11-23 23:02:33 +08:00
|
|
|
-- The optional parameter **ignore_cartodbfication** will remove queries related to the cartodbfication of the table
|
|
|
|
CREATE OR REPLACE FUNCTION @extschema@.CDB_GetTableQueries(tableoid OID, ignore_cartodbfication BOOL DEFAULT false)
|
|
|
|
RETURNS text[]
|
|
|
|
AS
|
|
|
|
$$
|
|
|
|
DECLARE
|
|
|
|
children INTEGER;
|
|
|
|
queries TEXT[];
|
|
|
|
BEGIN
|
|
|
|
EXECUTE FORMAT ('SELECT count(*) FROM pg_catalog.pg_inherits WHERE inhparent = %L', tableoid)
|
|
|
|
INTO children;
|
|
|
|
IF children > 0 THEN
|
|
|
|
RAISE EXCEPTION 'CDB_GetTableQueries does not support the parent of partitioned tables';
|
|
|
|
END IF;
|
|
|
|
IF NOT ignore_cartodbfication THEN
|
|
|
|
EXECUTE FORMAT('
|
|
|
|
SELECT array_agg(a)
|
|
|
|
FROM unnest(@extschema@.__CDB_RegenerateTable_Get_Commands(%L)) a
|
2020-11-24 18:07:10 +08:00
|
|
|
WHERE a NOT SIMILAR TO ''CREATE TABLE%%'';', tableoid) INTO queries;
|
2020-11-23 23:02:33 +08:00
|
|
|
ELSE
|
|
|
|
EXECUTE FORMAT('
|
|
|
|
SELECT array_agg(a)
|
|
|
|
FROM unnest(@extschema@.__CDB_RegenerateTable_Get_Commands(%L)) a
|
|
|
|
WHERE a NOT SIMILAR TO ''CREATE TABLE%%'' AND
|
|
|
|
a NOT SIMILAR TO (''%%PRIMARY KEY \(cartodb_id\)%%'') AND
|
|
|
|
a NOT SIMILAR TO (''%%cartodb_id_seq%%'') AND
|
|
|
|
a NOT SIMILAR TO (''%%track_updates%%'') AND
|
|
|
|
a NOT SIMILAR TO (''%%update_the_geom_webmercator_trigger%%'') AND
|
|
|
|
a NOT SIMILAR TO (''%%test_quota%%'') AND
|
|
|
|
a NOT SIMILAR TO (''%%test_quota_per_row%%'') AND
|
|
|
|
a NOT SIMILAR TO (''%%gist \(the_geom\)%%'') AND
|
|
|
|
a NOT SIMILAR TO (''%%gist \(the_geom_webmercator\)%%'');', tableoid) INTO queries;
|
|
|
|
END IF;
|
|
|
|
RETURN queries;
|
|
|
|
END
|
|
|
|
$$
|
|
|
|
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
|
|
|
|
|
2020-11-24 20:21:43 +08:00
|
|
|
-- Helper function to apply the result of CDB_GetTableQueries catching and discarding any exceptions
|
|
|
|
CREATE OR REPLACE FUNCTION @extschema@.CDB_ApplyQueriesSafe(queries TEXT[])
|
|
|
|
RETURNS void
|
|
|
|
AS
|
|
|
|
$$
|
|
|
|
DECLARE
|
|
|
|
i INTEGER;
|
|
|
|
BEGIN
|
|
|
|
IF array_length(queries, 1) > 0 THEN
|
|
|
|
FOR i IN 1 .. array_upper(queries, 1)
|
|
|
|
LOOP
|
|
|
|
BEGIN
|
|
|
|
EXECUTE queries[i];
|
|
|
|
EXCEPTION WHEN OTHERS THEN
|
|
|
|
CONTINUE;
|
|
|
|
END;
|
|
|
|
END LOOP;
|
|
|
|
END IF;
|
|
|
|
END
|
|
|
|
$$
|
|
|
|
LANGUAGE PLPGSQL STRICT VOLATILE PARALLEL UNSAFE;
|
|
|
|
|
2020-11-16 22:07:58 +08:00
|
|
|
-- Regenerates a table
|
|
|
|
CREATE OR REPLACE FUNCTION @extschema@.CDB_RegenerateTable(tableoid OID)
|
|
|
|
RETURNS void
|
|
|
|
AS
|
|
|
|
$$
|
|
|
|
DECLARE
|
|
|
|
temp_name TEXT := 'temp_' || encode(sha224(random()::text::bytea), 'hex');
|
|
|
|
table_name TEXT;
|
|
|
|
queries TEXT[] := @extschema@.__CDB_RegenerateTable_Get_Commands(tableoid);
|
|
|
|
i INTEGER;
|
2020-11-23 19:11:48 +08:00
|
|
|
children INTEGER;
|
2020-11-16 22:07:58 +08:00
|
|
|
BEGIN
|
2020-11-23 19:11:48 +08:00
|
|
|
EXECUTE FORMAT ('SELECT count(*) FROM pg_catalog.pg_inherits WHERE inhparent = %L', tableoid)
|
|
|
|
INTO children;
|
|
|
|
IF children > 0 THEN
|
|
|
|
RAISE EXCEPTION 'CDB_RegenerateTable does not support the parent of partitioned tables';
|
|
|
|
END IF;
|
|
|
|
|
2020-11-16 22:07:58 +08:00
|
|
|
EXECUTE FORMAT('SELECT concat(quote_ident(nspname), ''.'', quote_ident(relname)) as quoted_name
|
|
|
|
FROM pg_catalog.pg_class AS c
|
|
|
|
JOIN pg_catalog.pg_namespace AS ns
|
|
|
|
ON c.relnamespace = ns.oid
|
|
|
|
WHERE c.oid = %L', tableoid) INTO table_name;
|
|
|
|
|
2020-11-23 19:11:48 +08:00
|
|
|
EXECUTE FORMAT('CREATE TEMPORARY TABLE %s ON COMMIT DROP AS SELECT * FROM %s', temp_name, table_name);
|
2020-11-17 00:15:13 +08:00
|
|
|
EXECUTE FORMAT('DROP TABLE %s', table_name);
|
2020-11-16 22:07:58 +08:00
|
|
|
|
|
|
|
FOR i IN 1 .. array_upper(queries, 1)
|
|
|
|
LOOP
|
|
|
|
EXECUTE queries[i];
|
|
|
|
END LOOP;
|
|
|
|
|
|
|
|
EXECUTE FORMAT('INSERT INTO %s SELECT * FROM %I', table_name, temp_name);
|
|
|
|
END
|
|
|
|
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
|