aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_relation.c
diff options
context:
space:
mode:
authorJoe Conway <mail@joeconway.com>2006-08-02 01:59:48 +0000
committerJoe Conway <mail@joeconway.com>2006-08-02 01:59:48 +0000
commit9caafda579f699b43fa4c89bf13a2331ef00611e (patch)
tree330423c4be56ffaacb2d028153706f0c213c0aec /src/backend/parser/parse_relation.c
parentd307c428cbb7c426e40163d234d993e644bbcc6b (diff)
downloadpostgresql-9caafda579f699b43fa4c89bf13a2331ef00611e.tar.gz
postgresql-9caafda579f699b43fa4c89bf13a2331ef00611e.zip
Add support for multi-row VALUES clauses as part of INSERT statements
(e.g. "INSERT ... VALUES (...), (...), ...") and elsewhere as allowed by the spec. (e.g. similar to a FROM clause subselect). initdb required. Joe Conway and Tom Lane.
Diffstat (limited to 'src/backend/parser/parse_relation.c')
-rw-r--r--src/backend/parser/parse_relation.c123
1 files changed, 121 insertions, 2 deletions
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 10f71712ff6..e9896be6349 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.123 2006/04/30 18:30:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.124 2006/08/02 01:59:47 joe Exp $
*
*-------------------------------------------------------------------------
*/
@@ -941,6 +941,75 @@ addRangeTableEntryForFunction(ParseState *pstate,
}
/*
+ * Add an entry for a VALUES list to the pstate's range table (p_rtable).
+ *
+ * This is much like addRangeTableEntry() except that it makes a values RTE.
+ */
+RangeTblEntry *
+addRangeTableEntryForValues(ParseState *pstate,
+ List *exprs,
+ Alias *alias,
+ bool inFromCl)
+{
+ RangeTblEntry *rte = makeNode(RangeTblEntry);
+ char *refname = alias ? alias->aliasname : pstrdup("*VALUES*");
+ Alias *eref;
+ int numaliases;
+ int numcolumns;
+
+ rte->rtekind = RTE_VALUES;
+ rte->relid = InvalidOid;
+ rte->subquery = NULL;
+ rte->values_lists = exprs;
+ rte->alias = alias;
+
+ eref = alias ? copyObject(alias) : makeAlias(refname, NIL);
+
+ /* fill in any unspecified alias columns */
+ numcolumns = list_length((List *) linitial(exprs));
+ numaliases = list_length(eref->colnames);
+ while (numaliases < numcolumns)
+ {
+ char attrname[64];
+
+ numaliases++;
+ snprintf(attrname, sizeof(attrname), "column%d", numaliases);
+ eref->colnames = lappend(eref->colnames,
+ makeString(pstrdup(attrname)));
+ }
+ if (numcolumns < numaliases)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
+ errmsg("VALUES lists \"%s\" have %d columns available but %d columns specified",
+ refname, numcolumns, numaliases)));
+
+ rte->eref = eref;
+
+ /*----------
+ * Flags:
+ * - this RTE should be expanded to include descendant tables,
+ * - this RTE is in the FROM clause,
+ * - this RTE should be checked for appropriate access rights.
+ *
+ * Subqueries are never checked for access rights.
+ *----------
+ */
+ rte->inh = false; /* never true for values RTEs */
+ rte->inFromCl = inFromCl;
+ rte->requiredPerms = 0;
+ rte->checkAsUser = InvalidOid;
+
+ /*
+ * Add completed RTE to pstate's range table list, but not to join list
+ * nor namespace --- caller must do that if appropriate.
+ */
+ if (pstate != NULL)
+ pstate->p_rtable = lappend(pstate->p_rtable, rte);
+
+ return rte;
+}
+
+/*
* Add an entry for a join to the pstate's range table (p_rtable).
*
* This is much like addRangeTableEntry() except that it makes a join RTE.
@@ -1233,6 +1302,41 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
}
}
break;
+ case RTE_VALUES:
+ {
+ /* Values RTE */
+ ListCell *aliasp_item = list_head(rte->eref->colnames);
+ ListCell *lc;
+
+ varattno = 0;
+ foreach(lc, (List *) linitial(rte->values_lists))
+ {
+ Node *col = (Node *) lfirst(lc);
+
+ varattno++;
+ if (colnames)
+ {
+ /* Assume there is one alias per column */
+ char *label = strVal(lfirst(aliasp_item));
+
+ *colnames = lappend(*colnames,
+ makeString(pstrdup(label)));
+ aliasp_item = lnext(aliasp_item);
+ }
+
+ if (colvars)
+ {
+ Var *varnode;
+
+ varnode = makeVar(rtindex, varattno,
+ exprType(col),
+ exprTypmod(col),
+ sublevels_up);
+ *colvars = lappend(*colvars, varnode);
+ }
+ }
+ }
+ break;
case RTE_JOIN:
{
/* Join RTE */
@@ -1569,6 +1673,20 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
}
}
break;
+ case RTE_VALUES:
+ {
+ /* Values RTE --- get type info from first sublist */
+ List *collist = (List *) linitial(rte->values_lists);
+ Node *col;
+
+ if (attnum < 1 || attnum > list_length(collist))
+ elog(ERROR, "values list %s does not have attribute %d",
+ rte->eref->aliasname, attnum);
+ col = (Node *) list_nth(collist, attnum-1);
+ *vartype = exprType(col);
+ *vartypmod = exprTypmod(col);
+ }
+ break;
case RTE_JOIN:
{
/*
@@ -1619,7 +1737,8 @@ get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
}
break;
case RTE_SUBQUERY:
- /* Subselect RTEs never have dropped columns */
+ case RTE_VALUES:
+ /* Subselect and Values RTEs never have dropped columns */
result = false;
break;
case RTE_JOIN: