Fix error reporting for index expressions of prohibited types.
authorTom Lane
Tue, 17 Dec 2019 22:44:28 +0000 (17:44 -0500)
committerTom Lane
Tue, 17 Dec 2019 22:44:28 +0000 (17:44 -0500)
If CheckAttributeType() threw an error about the datatype of an
index expression column, it would report an empty column name,
which is pretty unhelpful and certainly not the intended behavior.
I (tgl) evidently broke this in commit cfc5008a5, by not noticing
that the column's attname was used above where I'd placed the
assignment of it.

In HEAD and v12, this is trivially fixable by moving up the
assignment of attname.  Before v12 the code is a bit more messy;
to avoid doing substantial refactoring, I took the lazy way out
and just put in two copies of the assignment code.

Report and patch by Amit Langote.  Back-patch to all supported
branches.

Discussion: https://postgr.es/m/CA+HiwqFA+BGyBFimjiYXXMa2Hc3fcL0+OJOyzUNjhU4NCa_XXw@mail.gmail.com

src/backend/catalog/index.c
src/test/regress/expected/create_index.out
src/test/regress/sql/create_index.sql

index 942d43db892ba8c06f84c9097c02856f95ea72c6..f2712b94c5ec20e59bb53dbb33d4391a67612f8a 100644 (file)
@@ -348,6 +348,14 @@ ConstructTupleDescriptor(Relation heapRelation,
             */
            memcpy(to, from, ATTRIBUTE_FIXED_PART_SIZE);
 
+           /*
+            * Set the attribute name as specified by caller.
+            */
+           if (colnames_item == NULL)  /* shouldn't happen */
+               elog(ERROR, "too few entries in colnames list");
+           namestrcpy(&to->attname, (const char *) lfirst(colnames_item));
+           colnames_item = lnext(colnames_item);
+
            /*
             * Fix the stuff that should not be the same as the underlying
             * attr
@@ -370,6 +378,14 @@ ConstructTupleDescriptor(Relation heapRelation,
 
            MemSet(to, 0, ATTRIBUTE_FIXED_PART_SIZE);
 
+           /*
+            * Set the attribute name as specified by caller.
+            */
+           if (colnames_item == NULL)  /* shouldn't happen */
+               elog(ERROR, "too few entries in colnames list");
+           namestrcpy(&to->attname, (const char *) lfirst(colnames_item));
+           colnames_item = lnext(colnames_item);
+
            if (indexpr_item == NULL)   /* shouldn't happen */
                elog(ERROR, "too few entries in indexprs list");
            indexkey = (Node *) lfirst(indexpr_item);
@@ -422,14 +438,6 @@ ConstructTupleDescriptor(Relation heapRelation,
         */
        to->attrelid = InvalidOid;
 
-       /*
-        * Set the attribute name as specified by caller.
-        */
-       if (colnames_item == NULL)  /* shouldn't happen */
-           elog(ERROR, "too few entries in colnames list");
-       namestrcpy(&to->attname, (const char *) lfirst(colnames_item));
-       colnames_item = lnext(colnames_item);
-
        /*
         * Check the opclass and index AM to see if either provides a keytype
         * (overriding the attribute type).  Opclass takes precedence.
index 064adb4640bc3c99b7f73df7ae696192bfc86f8a..3db118177459de8b7b1f4b24d4f32a390e11b7a6 100644 (file)
@@ -2379,6 +2379,23 @@ ERROR:  duplicate key value violates unique constraint "func_index_index"
 DETAIL:  Key (textcat(f1, f2))=(ABCDEF) already exists.
 -- but this shouldn't:
 INSERT INTO func_index_heap VALUES('QWERTY');
+-- while we're here, see that the metadata looks sane
+\d func_index_heap
+         Table "public.func_index_heap"
+ Column | Type | Collation | Nullable | Default 
+--------+------+-----------+----------+---------
+ f1     | text |           |          | 
+ f2     | text |           |          | 
+Indexes:
+    "func_index_index" UNIQUE, btree (textcat(f1, f2))
+
+\d func_index_index
+ Index "public.func_index_index"
+ Column  | Type |   Definition    
+---------+------+-----------------
+ textcat | text | textcat(f1, f2)
+unique, btree, for table "public.func_index_heap"
+
 --
 -- Same test, expressional index
 --
@@ -2394,6 +2411,26 @@ ERROR:  duplicate key value violates unique constraint "func_index_index"
 DETAIL:  Key ((f1 || f2))=(ABCDEF) already exists.
 -- but this shouldn't:
 INSERT INTO func_index_heap VALUES('QWERTY');
+-- while we're here, see that the metadata looks sane
+\d func_index_heap
+         Table "public.func_index_heap"
+ Column | Type | Collation | Nullable | Default 
+--------+------+-----------+----------+---------
+ f1     | text |           |          | 
+ f2     | text |           |          | 
+Indexes:
+    "func_index_index" UNIQUE, btree ((f1 || f2))
+
+\d func_index_index
+Index "public.func_index_index"
+ Column | Type | Definition 
+--------+------+------------
+ expr   | text | (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 "row" has pseudo-type record
 --
 -- Also try building functional, expressional, and partial indexes on
 -- tables that already contain data.
index 67470db918b7bd6884c1363edd48551270106ce7..d906d6c7050c9bd401e4defcbf6e8d9c2d2002ae 100644 (file)
@@ -715,6 +715,10 @@ INSERT INTO func_index_heap VALUES('ABCD', 'EF');
 -- but this shouldn't:
 INSERT INTO func_index_heap VALUES('QWERTY');
 
+-- while we're here, see that the metadata looks sane
+\d func_index_heap
+\d func_index_index
+
 
 --
 -- Same test, expressional index
@@ -731,6 +735,14 @@ INSERT INTO func_index_heap VALUES('ABCD', 'EF');
 -- but this shouldn't:
 INSERT INTO func_index_heap VALUES('QWERTY');
 
+-- 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)));
+
+
 --
 -- Also try building functional, expressional, and partial indexes on
 -- tables that already contain data.