CREATE TABLE foo (x,y,z) AS SELECT ... can't apply target column names
to the target list in gram.y; it must wait till after expansion of the target list in analyze.c. Per bug report 4-Nov: lx=# CREATE TABLE abc (a char, b char, c char); CREATE lx=# CREATE TABLE xyz (x, y, z) AS SELECT * FROM abc; ERROR: CREATE TABLE/AS SELECT has mismatched column count
This commit is contained in:
parent
d556920a98
commit
5251e7b3d0
@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.159 2001/10/25 05:49:30 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.160 2001/11/05 05:00:14 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1835,6 +1835,7 @@ _copySelectStmt(SelectStmt *from)
|
|||||||
if (from->into)
|
if (from->into)
|
||||||
newnode->into = pstrdup(from->into);
|
newnode->into = pstrdup(from->into);
|
||||||
newnode->istemp = from->istemp;
|
newnode->istemp = from->istemp;
|
||||||
|
Node_Copy(from, newnode, intoColNames);
|
||||||
Node_Copy(from, newnode, targetList);
|
Node_Copy(from, newnode, targetList);
|
||||||
Node_Copy(from, newnode, fromClause);
|
Node_Copy(from, newnode, fromClause);
|
||||||
Node_Copy(from, newnode, whereClause);
|
Node_Copy(from, newnode, whereClause);
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.107 2001/10/25 05:49:30 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.108 2001/11/05 05:00:14 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -681,6 +681,8 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b)
|
|||||||
return false;
|
return false;
|
||||||
if (a->istemp != b->istemp)
|
if (a->istemp != b->istemp)
|
||||||
return false;
|
return false;
|
||||||
|
if (!equal(a->intoColNames, b->intoColNames))
|
||||||
|
return false;
|
||||||
if (!equal(a->targetList, b->targetList))
|
if (!equal(a->targetList, b->targetList))
|
||||||
return false;
|
return false;
|
||||||
if (!equal(a->fromClause, b->fromClause))
|
if (!equal(a->fromClause, b->fromClause))
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.209 2001/11/04 03:08:11 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.210 2001/11/05 05:00:14 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -88,6 +88,7 @@ static void transformFKConstraints(ParseState *pstate,
|
|||||||
CreateStmtContext *cxt);
|
CreateStmtContext *cxt);
|
||||||
static Node *transformTypeRefs(ParseState *pstate, Node *stmt);
|
static Node *transformTypeRefs(ParseState *pstate, Node *stmt);
|
||||||
|
|
||||||
|
static void applyColumnNames(List *dst, List *src);
|
||||||
static void transformTypeRefsList(ParseState *pstate, List *l);
|
static void transformTypeRefsList(ParseState *pstate, List *l);
|
||||||
static void transformTypeRef(ParseState *pstate, TypeName *tn);
|
static void transformTypeRef(ParseState *pstate, TypeName *tn);
|
||||||
static List *getSetColTypes(ParseState *pstate, Node *node);
|
static List *getSetColTypes(ParseState *pstate, Node *node);
|
||||||
@ -1942,9 +1943,13 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
|
|||||||
/* process the FROM clause */
|
/* process the FROM clause */
|
||||||
transformFromClause(pstate, stmt->fromClause);
|
transformFromClause(pstate, stmt->fromClause);
|
||||||
|
|
||||||
/* transform targetlist and WHERE */
|
/* transform targetlist */
|
||||||
qry->targetList = transformTargetList(pstate, stmt->targetList);
|
qry->targetList = transformTargetList(pstate, stmt->targetList);
|
||||||
|
|
||||||
|
if (stmt->intoColNames)
|
||||||
|
applyColumnNames(qry->targetList, stmt->intoColNames);
|
||||||
|
|
||||||
|
/* transform WHERE */
|
||||||
qual = transformWhereClause(pstate, stmt->whereClause);
|
qual = transformWhereClause(pstate, stmt->whereClause);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2003,6 +2008,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
|||||||
SetOperationStmt *sostmt;
|
SetOperationStmt *sostmt;
|
||||||
char *into;
|
char *into;
|
||||||
bool istemp;
|
bool istemp;
|
||||||
|
List *intoColNames;
|
||||||
char *portalname;
|
char *portalname;
|
||||||
bool binary;
|
bool binary;
|
||||||
List *sortClause;
|
List *sortClause;
|
||||||
@ -2031,12 +2037,14 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
|||||||
leftmostSelect->larg == NULL);
|
leftmostSelect->larg == NULL);
|
||||||
into = leftmostSelect->into;
|
into = leftmostSelect->into;
|
||||||
istemp = leftmostSelect->istemp;
|
istemp = leftmostSelect->istemp;
|
||||||
|
intoColNames = leftmostSelect->intoColNames;
|
||||||
portalname = stmt->portalname;
|
portalname = stmt->portalname;
|
||||||
binary = stmt->binary;
|
binary = stmt->binary;
|
||||||
|
|
||||||
/* clear them to prevent complaints in transformSetOperationTree() */
|
/* clear them to prevent complaints in transformSetOperationTree() */
|
||||||
leftmostSelect->into = NULL;
|
leftmostSelect->into = NULL;
|
||||||
leftmostSelect->istemp = false;
|
leftmostSelect->istemp = false;
|
||||||
|
leftmostSelect->intoColNames = NIL;
|
||||||
stmt->portalname = NULL;
|
stmt->portalname = NULL;
|
||||||
stmt->binary = false;
|
stmt->binary = false;
|
||||||
|
|
||||||
@ -2149,6 +2157,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
|||||||
qry->isBinary = FALSE;
|
qry->isBinary = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (intoColNames)
|
||||||
|
applyColumnNames(qry->targetList, intoColNames);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As a first step towards supporting sort clauses that are
|
* As a first step towards supporting sort clauses that are
|
||||||
* expressions using the output columns, generate a namespace entry
|
* expressions using the output columns, generate a namespace entry
|
||||||
@ -2377,6 +2388,27 @@ getSetColTypes(ParseState *pstate, Node *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Attach column names from a ColumnDef list to a TargetEntry list */
|
||||||
|
static void
|
||||||
|
applyColumnNames(List *dst, List *src)
|
||||||
|
{
|
||||||
|
if (length(src) > length(dst))
|
||||||
|
elog(ERROR,"CREATE TABLE AS specifies too many column names");
|
||||||
|
|
||||||
|
while (src != NIL && dst != NIL)
|
||||||
|
{
|
||||||
|
TargetEntry *d = (TargetEntry *) lfirst(dst);
|
||||||
|
ColumnDef *s = (ColumnDef *) lfirst(src);
|
||||||
|
|
||||||
|
Assert(d->resdom && !d->resdom->resjunk);
|
||||||
|
|
||||||
|
d->resdom->resname = pstrdup(s->colname);
|
||||||
|
|
||||||
|
dst = lnext(dst);
|
||||||
|
src = lnext(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* transformUpdateStmt -
|
* transformUpdateStmt -
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.271 2001/10/31 04:49:43 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.272 2001/11/05 05:00:14 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -86,7 +86,6 @@ static Node *makeTypeCast(Node *arg, TypeName *typename);
|
|||||||
static Node *makeStringConst(char *str, TypeName *typename);
|
static Node *makeStringConst(char *str, TypeName *typename);
|
||||||
static Node *makeFloatConst(char *str);
|
static Node *makeFloatConst(char *str);
|
||||||
static Node *makeRowExpr(char *opr, List *largs, List *rargs);
|
static Node *makeRowExpr(char *opr, List *largs, List *rargs);
|
||||||
static void mapTargetColumns(List *source, List *target);
|
|
||||||
static SelectStmt *findLeftmostSelect(SelectStmt *node);
|
static SelectStmt *findLeftmostSelect(SelectStmt *node);
|
||||||
static void insertSelectOptions(SelectStmt *stmt,
|
static void insertSelectOptions(SelectStmt *stmt,
|
||||||
List *sortClause, List *forUpdate,
|
List *sortClause, List *forUpdate,
|
||||||
@ -1611,11 +1610,10 @@ CreateAsStmt: CREATE OptTemp TABLE relation_name OptCreateAs AS SelectStmt
|
|||||||
*/
|
*/
|
||||||
SelectStmt *n = findLeftmostSelect((SelectStmt *) $7);
|
SelectStmt *n = findLeftmostSelect((SelectStmt *) $7);
|
||||||
if (n->into != NULL)
|
if (n->into != NULL)
|
||||||
elog(ERROR,"CREATE TABLE / AS SELECT may not specify INTO");
|
elog(ERROR,"CREATE TABLE AS may not specify INTO");
|
||||||
n->istemp = $2;
|
n->istemp = $2;
|
||||||
n->into = $4;
|
n->into = $4;
|
||||||
if ($5 != NIL)
|
n->intoColNames = $5;
|
||||||
mapTargetColumns($5, n->targetList);
|
|
||||||
$$ = $7;
|
$$ = $7;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -3552,6 +3550,7 @@ simple_select: SELECT opt_distinct target_list
|
|||||||
n->targetList = $3;
|
n->targetList = $3;
|
||||||
n->istemp = (bool) ((Value *) lfirst($4))->val.ival;
|
n->istemp = (bool) ((Value *) lfirst($4))->val.ival;
|
||||||
n->into = (char *) lnext($4);
|
n->into = (char *) lnext($4);
|
||||||
|
n->intoColNames = NIL;
|
||||||
n->fromClause = $5;
|
n->fromClause = $5;
|
||||||
n->whereClause = $6;
|
n->whereClause = $6;
|
||||||
n->groupClause = $7;
|
n->groupClause = $7;
|
||||||
@ -6106,28 +6105,6 @@ makeRowExpr(char *opr, List *largs, List *rargs)
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
mapTargetColumns(List *src, List *dst)
|
|
||||||
{
|
|
||||||
ColumnDef *s;
|
|
||||||
ResTarget *d;
|
|
||||||
|
|
||||||
if (length(src) != length(dst))
|
|
||||||
elog(ERROR,"CREATE TABLE / AS SELECT has mismatched column count");
|
|
||||||
|
|
||||||
while ((src != NIL) && (dst != NIL))
|
|
||||||
{
|
|
||||||
s = (ColumnDef *)lfirst(src);
|
|
||||||
d = (ResTarget *)lfirst(dst);
|
|
||||||
|
|
||||||
d->name = s->colname;
|
|
||||||
|
|
||||||
src = lnext(src);
|
|
||||||
dst = lnext(dst);
|
|
||||||
}
|
|
||||||
} /* mapTargetColumns() */
|
|
||||||
|
|
||||||
|
|
||||||
/* findLeftmostSelect()
|
/* findLeftmostSelect()
|
||||||
* Find the leftmost component SelectStmt in a set-operation parsetree.
|
* Find the leftmost component SelectStmt in a set-operation parsetree.
|
||||||
*/
|
*/
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parsenodes.h,v 1.149 2001/10/28 06:26:07 momjian Exp $
|
* $Id: parsenodes.h,v 1.150 2001/11/05 05:00:14 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -881,6 +881,7 @@ typedef struct SelectStmt
|
|||||||
* DISTINCT) */
|
* DISTINCT) */
|
||||||
char *into; /* name of table (for select into table) */
|
char *into; /* name of table (for select into table) */
|
||||||
bool istemp; /* into is a temp table? */
|
bool istemp; /* into is a temp table? */
|
||||||
|
List *intoColNames; /* column names for into table */
|
||||||
List *targetList; /* the target list (of ResTarget) */
|
List *targetList; /* the target list (of ResTarget) */
|
||||||
List *fromClause; /* the FROM clause */
|
List *fromClause; /* the FROM clause */
|
||||||
Node *whereClause; /* WHERE qualification */
|
Node *whereClause; /* WHERE qualification */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user