From d102c8a6400f26ad33e72a42cbba9fad390e1332 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Wed, 17 Apr 2024 23:11:23 +0800 Subject: [PATCH] Quote attribute names in deparsed index definition Otherwise the emitted CREATE INDEX statement could be invalid. Thanks to Oliver Rice for the report. --- expected/hypo_include.out | 8 ++++---- expected/hypopg.out | 10 +++++----- hypopg_index.c | 14 ++++++++------ test/sql/hypo_include.sql | 2 +- test/sql/hypopg.sql | 4 ++-- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/expected/hypo_include.out b/expected/hypo_include.out index fff33b4..58c7b7c 100644 --- a/expected/hypo_include.out +++ b/expected/hypo_include.out @@ -34,7 +34,7 @@ SELECT hypopg_reset(); -- Create INCLUDE index SELECT COUNT(*) AS NB -FROM hypopg_create_index('CREATE INDEX ON hypo (id) INCLUDE (val)'); +FROM hypopg_create_index('CREATE INDEX ON hypo (id) INCLUDE (val, "Id2")'); nb ---- 1 @@ -50,8 +50,8 @@ WHERE e ~ 'Index Only Scan.*<\d+>btree_hypo.*'; -- Deparse the index DDL SELECT hypopg_get_indexdef(indexrelid) FROM hypopg(); - hypopg_get_indexdef ------------------------------------------------------------- - CREATE INDEX ON public.hypo USING btree (id) INCLUDE (val) + hypopg_get_indexdef +------------------------------------------------------------------- + CREATE INDEX ON public.hypo USING btree (id) INCLUDE (val, "Id2") (1 row) diff --git a/expected/hypopg.out b/expected/hypopg.out index a00648f..90121d0 100644 --- a/expected/hypopg.out +++ b/expected/hypopg.out @@ -12,7 +12,7 @@ END; $_$ LANGUAGE plpgsql; CREATE EXTENSION hypopg; -CREATE TABLE hypo (id integer, val text); +CREATE TABLE hypo (id integer, val text, "Id2" bigint); INSERT INTO hypo SELECT i, 'line ' || i FROM generate_series(1,100000) f(i); ANALYZE hypo; @@ -159,10 +159,10 @@ WHERE e ~ 'Index.*<\d+>btree_hypo.*'; (1 row) -- Deparse an index DDL, with almost every possible pathcode -SELECT hypopg_get_indexdef(indexrelid) FROM hypopg_create_index('create index on hypo using btree(id desc, id desc nulls first, id desc nulls last, cast(md5(val) as bpchar) bpchar_pattern_ops) with (fillfactor = 10) WHERE id < 1000 AND id +1 %2 = 3'); - hypopg_get_indexdef ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - CREATE INDEX ON public.hypo USING btree (id DESC, id DESC, id DESC NULLS LAST, ((md5(val))::bpchar) bpchar_pattern_ops) WITH (fillfactor = 10) WHERE ((id < 1000) AND ((id + (1 % 2)) = 3)) +SELECT hypopg_get_indexdef(indexrelid) FROM hypopg_create_index('create index on hypo using btree(id desc, "Id2" desc nulls first, id desc nulls last, cast(md5(val) as bpchar) bpchar_pattern_ops) with (fillfactor = 10) WHERE id < 1000 AND id +1 %2 = 3'); + hypopg_get_indexdef +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + CREATE INDEX ON public.hypo USING btree (id DESC, "Id2" DESC, id DESC NULLS LAST, ((md5(val))::bpchar) bpchar_pattern_ops) WITH (fillfactor = 10) WHERE ((id < 1000) AND ((id + (1 % 2)) = 3)) (1 row) -- Make sure the old Oid generator still works. Test it while keeping existing diff --git a/hypopg_index.c b/hypopg_index.c index 5ae6ffa..1ad170a 100644 --- a/hypopg_index.c +++ b/hypopg_index.c @@ -1467,13 +1467,13 @@ hypopg_get_indexdef(PG_FUNCTION_ARGS) if (entry->indexkeys[keyno] != 0) { int32 keycoltypmod; + char *attname; #if PG_VERSION_NUM >= 110000 - appendStringInfo(&buf, "%s", get_attname(entry->relid, - entry->indexkeys[keyno], false)); + attname = get_attname(entry->relid, entry->indexkeys[keyno], false); #else - appendStringInfo(&buf, "%s", get_attname(entry->relid, - entry->indexkeys[keyno])); + attname = get_attname(entry->relid, entry->indexkeys[keyno]); #endif + appendStringInfo(&buf, "%s", quote_identifier(attname)); get_atttypetypmodcoll(entry->relid, entry->indexkeys[keyno], &keycoltype, &keycoltypmod, @@ -1541,11 +1541,13 @@ hypopg_get_indexdef(PG_FUNCTION_ARGS) appendStringInfo(&buf, " INCLUDE ("); for (keyno = entry->nkeycolumns; keyno < entry->ncolumns; keyno++) { + char *attname; + if (keyno != entry->nkeycolumns) appendStringInfo(&buf, ", "); - appendStringInfo(&buf, "%s", get_attname(entry->relid, - entry->indexkeys[keyno], false)); + attname = get_attname(entry->relid, entry->indexkeys[keyno], false); + appendStringInfo(&buf, "%s", quote_identifier(attname)); } appendStringInfo(&buf, ")"); } diff --git a/test/sql/hypo_include.sql b/test/sql/hypo_include.sql index 4ee483b..0d3f132 100644 --- a/test/sql/hypo_include.sql +++ b/test/sql/hypo_include.sql @@ -21,7 +21,7 @@ SELECT hypopg_reset(); -- Create INCLUDE index SELECT COUNT(*) AS NB -FROM hypopg_create_index('CREATE INDEX ON hypo (id) INCLUDE (val)'); +FROM hypopg_create_index('CREATE INDEX ON hypo (id) INCLUDE (val, "Id2")'); -- Should use hypothetical index using an Index Only Scan SELECT COUNT(*) FROM do_explain('SELECT val FROM hypo WHERE id = 1') e diff --git a/test/sql/hypopg.sql b/test/sql/hypopg.sql index 64cfcd5..99722b0 100644 --- a/test/sql/hypopg.sql +++ b/test/sql/hypopg.sql @@ -14,7 +14,7 @@ LANGUAGE plpgsql; CREATE EXTENSION hypopg; -CREATE TABLE hypo (id integer, val text); +CREATE TABLE hypo (id integer, val text, "Id2" bigint); INSERT INTO hypo SELECT i, 'line ' || i FROM generate_series(1,100000) f(i); @@ -102,7 +102,7 @@ SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE md5(val) = md5(''line WHERE e ~ 'Index.*<\d+>btree_hypo.*'; -- Deparse an index DDL, with almost every possible pathcode -SELECT hypopg_get_indexdef(indexrelid) FROM hypopg_create_index('create index on hypo using btree(id desc, id desc nulls first, id desc nulls last, cast(md5(val) as bpchar) bpchar_pattern_ops) with (fillfactor = 10) WHERE id < 1000 AND id +1 %2 = 3'); +SELECT hypopg_get_indexdef(indexrelid) FROM hypopg_create_index('create index on hypo using btree(id desc, "Id2" desc nulls first, id desc nulls last, cast(md5(val) as bpchar) bpchar_pattern_ops) with (fillfactor = 10) WHERE id < 1000 AND id +1 %2 = 3'); -- Make sure the old Oid generator still works. Test it while keeping existing -- entries, as both should be able to coexist.