Bruce Momjian <[email protected]> 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);