Commit
181b6185c failed to do anything useful with a whole-row Var,
deeming it "fishy". But it is legal to put such a Var into an
expression index column, so let's expand it as the name of the table.
Another problem reachable via that one is that we could generate an
empty index column name, which isn't really legal although by chance
nothing complained about it. It's not clear whether any other such
cases remain, but as cheap insurance let's use "expr" if the tree walk
fails to generate any text.
Reported-by: Chauhan Dhruv <chauhandhruv351@gmail.com>
Author: Chauhan Dhruv <chauhandhruv351@gmail.com>
Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CANWwWcp_DCJjq8pomeqp6W=fbygvzXXQO028VDJ9_6sLPjQnVA@mail.gmail.com
context.buf = &buf;
/* Walk the tree, stopping when we have enough text */
(void) ChooseIndexExpressionName_walker(indexExpr, &context);
+ /* Fall back to "expr" if the walk found nothing, to avoid an empty name */
+ if (buf.len == 0)
+ appendStringInfoString(&buf, "expr");
/* Ensure generated names are shorter than NAMEDATALEN */
nlen = pg_mbcliplen(buf.data, buf.len, NAMEDATALEN - 1);
buf.data[nlen] = '\0';
{
Var *var = (Var *) node;
TupleDesc tupdesc = RelationGetDescr(context->rel);
- Form_pg_attribute att;
+ const char *varname;
/* Paranoia: ignore the Var if it looks fishy */
if (var->varno != 1 || var->varlevelsup != 0 ||
- var->varattno <= 0 || var->varattno > tupdesc->natts)
+ var->varattno < 0 || var->varattno > tupdesc->natts)
return false;
- att = TupleDescAttr(tupdesc, var->varattno - 1);
- if (att->attisdropped)
- return false; /* even more paranoia; shouldn't happen */
+ if (var->varattno > 0)
+ {
+ Form_pg_attribute att = TupleDescAttr(tupdesc, var->varattno - 1);
+
+ if (att->attisdropped)
+ return false; /* even more paranoia; shouldn't happen */
+ varname = NameStr(att->attname);
+ }
+ else
+ {
+ /* Whole-row Var: use the table's name */
+ varname = RelationGetRelationName(context->rel);
+ }
if (context->buf->len > 0)
appendStringInfoChar(context->buf, '_');
- appendStringInfoString(context->buf, NameStr(att->attname));
+ appendStringInfoString(context->buf, varname);
/* Done if we've already reached NAMEDATALEN */
return (context->buf->len >= NAMEDATALEN);
DETAIL: Key ((f1 || f2))=(ABCDEF) already exists.
-- but this shouldn't:
INSERT INTO func_index_heap VALUES('QWERTY');
+-- this should fail because of unsafe column type (anonymous record)
+create index on func_index_heap ((f1 || f2), (row(f1, f2)));
+ERROR: column "f1_f21" has pseudo-type record
+-- but this is allowed:
+create index on func_index_heap ((func_index_heap.*));
-- while we're here, see that the metadata looks sane
\d func_index_heap
Table "public.func_index_heap"
f1 | text | | |
f2 | text | | |
Indexes:
+ "func_index_heap_func_index_heap_idx" btree ((func_index_heap.*))
"func_index_index" UNIQUE, btree ((f1 || f2))
\d func_index_index
f1_f2 | text | yes | (f1 || f2)
unique, btree, for table "public.func_index_heap"
--- this should fail because of unsafe column type (anonymous record)
-create index on func_index_heap ((f1 || f2), (row(f1, f2)));
-ERROR: column "f1_f21" has pseudo-type record
+\d func_index_heap_func_index_heap_idx
+ Index "public.func_index_heap_func_index_heap_idx"
+ Column | Type | Key? | Definition
+-----------------+-----------------+------+---------------------
+ func_index_heap | func_index_heap | yes | (func_index_heap.*)
+btree, for table "public.func_index_heap"
+
--
-- Test unique index with included columns
--
-- but this shouldn't:
INSERT INTO func_index_heap VALUES('QWERTY');
+-- this should fail because of unsafe column type (anonymous record)
+create index on func_index_heap ((f1 || f2), (row(f1, f2)));
+
+-- but this is allowed:
+create index on func_index_heap ((func_index_heap.*));
+
-- while we're here, see that the metadata looks sane
\d func_index_heap
\d func_index_index
-
--- this should fail because of unsafe column type (anonymous record)
-create index on func_index_heap ((f1 || f2), (row(f1, f2)));
+\d func_index_heap_func_index_heap_idx
--