Bruce Momjian <br...@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);

Reply via email to