Re: attndims, typndims still not enforced, but make the value within a sane threshold - Mailing list pgsql-hackers

From Tom Lane
Subject Re: attndims, typndims still not enforced, but make the value within a sane threshold
Date
Msg-id 2881901.1737330434@sss.pgh.pa.us
Whole thread Raw
In response to Re: attndims, typndims still not enforced, but make the value within a sane threshold  (Bruce Momjian <bruce@momjian.us>)
Responses Re: attndims, typndims still not enforced, but make the value within a sane threshold
List pgsql-hackers
Bruce Momjian <bruce@momjian.us> writes:
> Using the queries in that URL, I see:

>     CREATE TABLE test (data integer, data_array integer[5][5]);
>     CREATE TABLE test2 (LIKE test);
>     CREATE TABLE test3 AS SELECT * FROM test;
>     SELECT relname, attndims
>     FROM pg_class JOIN pg_attribute ON (pg_attribute.attrelid = pg_class.oid)
>     WHERE attname = 'data_array';
>      relname | attndims
>     ---------+----------
>      test    |        2
> -->     test2   |        0
> -->     test3   |        0

Yeah, that's not great.  We don't have the ability to extract a
number-of-dimensions from a result column of a SELECT, but we could
at least take care to make attndims be 1 not 0 for an array type.
And CREATE TABLE LIKE can easily do better.  See attached draft.
(We could simplify it a little bit if we decide to store only 1 or 0
in all cases.)

> Interestingly, if I dump and restore with:
>     $ createdb test2; pg_dump test | sql test2
> and run the query again I get:
>      relname | attndims
>     ---------+----------
>      test    |        1
>      test2   |        1
>      test3   |        1

I looked at getting a better result here and decided that it didn't
look very promising.  pg_dump uses format_type() to build the type
name to put in CREATE TABLE, and that doesn't have access to attndims.

            regards, tom lane

diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index 23cecd99c9..13fb6acfcf 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -183,7 +183,8 @@ create_ctas_nodata(List *tlist, IntoClause *into)
             col = makeColumnDef(colname,
                                 exprType((Node *) tle->expr),
                                 exprTypmod((Node *) tle->expr),
-                                exprCollation((Node *) tle->expr));
+                                exprCollation((Node *) tle->expr),
+                                -1 /* detect array-ness */ );

             /*
              * It's possible that the column is of a collatable type but the
@@ -492,10 +493,17 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
         else
             colname = NameStr(attribute->attname);

+        /*
+         * Note: we pass ndims as -1 not attribute->attndims because (a) the
+         * tupledesc we are given may not have accurate attndims, and (b) it
+         * seems best for this path to give results matching
+         * create_ctas_nodata.
+         */
         col = makeColumnDef(colname,
                             attribute->atttypid,
                             attribute->atttypmod,
-                            attribute->attcollation);
+                            attribute->attcollation,
+                            -1 /* detect array-ness */ );

         /*
          * It's possible that the column is of a collatable type but the
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index b13ee2b745..d5ca4ed5cb 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -178,15 +178,18 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
         switch (i)
         {
             case SEQ_COL_LASTVAL:
-                coldef = makeColumnDef("last_value", INT8OID, -1, InvalidOid);
+                coldef = makeColumnDef("last_value", INT8OID, -1,
+                                       InvalidOid, 0);
                 value[i - 1] = Int64GetDatumFast(seqdataform.last_value);
                 break;
             case SEQ_COL_LOG:
-                coldef = makeColumnDef("log_cnt", INT8OID, -1, InvalidOid);
+                coldef = makeColumnDef("log_cnt", INT8OID, -1,
+                                       InvalidOid, 0);
                 value[i - 1] = Int64GetDatum((int64) 0);
                 break;
             case SEQ_COL_CALLED:
-                coldef = makeColumnDef("is_called", BOOLOID, -1, InvalidOid);
+                coldef = makeColumnDef("is_called", BOOLOID, -1,
+                                       InvalidOid, 0);
                 value[i - 1] = BoolGetDatum(false);
                 break;
         }
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d2420a9558..111d96b896 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -2741,7 +2741,9 @@ MergeAttributes(List *columns, const List *supers, char relpersistence,
              * Create new column definition
              */
             newdef = makeColumnDef(attributeName, attribute->atttypid,
-                                   attribute->atttypmod, attribute->attcollation);
+                                   attribute->atttypmod,
+                                   attribute->attcollation,
+                                   attribute->attndims);
             newdef->storage = attribute->attstorage;
             newdef->generated = attribute->attgenerated;
             if (CompressionMethodIsValid(attribute->attcompression))
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 6f0301555e..cd0919a935 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -64,7 +64,8 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace,
             ColumnDef  *def = makeColumnDef(tle->resname,
                                             exprType((Node *) tle->expr),
                                             exprTypmod((Node *) tle->expr),
-                                            exprCollation((Node *) tle->expr));
+                                            exprCollation((Node *) tle->expr),
+                                            -1 /* detect array-ness */ );

             /*
              * It's possible that the column is of a collatable type but the
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 007612563c..aad0e78e3d 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -512,15 +512,29 @@ makeTypeNameFromOid(Oid typeOid, int32 typmod)
  *    build a ColumnDef node to represent a simple column definition.
  *
  * Type and collation are specified by OID.
+ * Typmod must be given in numeric form.
+ *
+ * ndims can be positive to select that number of array dimensions,
+ * or 0 if it's not an array, or -1 for this function to detect whether
+ * it's an array type.  (In that case we will declare the column as having a
+ * single array dimension.  This might not accurately reproduce the source of,
+ * say, CREATE TABLE AS; but we don't have the information to do better.)
+ *
  * Other properties are all basic to start with.
  */
 ColumnDef *
-makeColumnDef(const char *colname, Oid typeOid, int32 typmod, Oid collOid)
+makeColumnDef(const char *colname, Oid typeOid, int32 typmod,
+              Oid collOid, int ndims)
 {
     ColumnDef  *n = makeNode(ColumnDef);

     n->colname = pstrdup(colname);
     n->typeName = makeTypeNameFromOid(typeOid, typmod);
+    if (ndims < 0)
+        ndims = OidIsValid(get_element_type(typeOid)) ? 1 : 0;
+    while (ndims-- > 0)
+        n->typeName->arrayBounds = lappend(n->typeName->arrayBounds,
+                                           makeInteger(-1));
     n->inhcount = 0;
     n->is_local = true;
     n->is_not_null = false;
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index ca028d2a66..d03bc06f3e 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -1198,7 +1198,8 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
          * Create a new column definition
          */
         def = makeColumnDef(NameStr(attribute->attname), attribute->atttypid,
-                            attribute->atttypmod, attribute->attcollation);
+                            attribute->atttypmod, attribute->attcollation,
+                            attribute->attndims);

         /*
          * Add to column list
@@ -1637,7 +1638,8 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
             continue;

         n = makeColumnDef(NameStr(attr->attname), attr->atttypid,
-                          attr->atttypmod, attr->attcollation);
+                          attr->atttypmod, attr->attcollation,
+                          attr->attndims);
         n->is_from_type = true;

         cxt->columns = lappend(cxt->columns, n);
diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h
index 5473ce9a28..3747805f69 100644
--- a/src/include/nodes/makefuncs.h
+++ b/src/include/nodes/makefuncs.h
@@ -75,7 +75,8 @@ extern TypeName *makeTypeNameFromNameList(List *names);
 extern TypeName *makeTypeNameFromOid(Oid typeOid, int32 typmod);

 extern ColumnDef *makeColumnDef(const char *colname,
-                                Oid typeOid, int32 typmod, Oid collOid);
+                                Oid typeOid, int32 typmod, Oid collOid,
+                                int ndims);

 extern FuncExpr *makeFuncExpr(Oid funcid, Oid rettype, List *args,
                               Oid funccollid, Oid inputcollid, CoercionForm fformat);

pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: stored short varlena in array
Next
From: Tatsuo Ishii
Date:
Subject: Re: Add RESPECT/IGNORE NULLS and FROM FIRST/LAST options