aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_clause.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_clause.c')
-rw-r--r--src/backend/parser/parse_clause.c199
1 files changed, 108 insertions, 91 deletions
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 5fa42d307ac..36a3efff876 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -52,9 +52,9 @@
#include "utils/syscache.h"
-static void extractRemainingColumns(List *common_colnames,
- List *src_colnames, List *src_colvars,
- ParseNamespaceColumn *src_nscolumns,
+static int extractRemainingColumns(ParseNamespaceColumn *src_nscolumns,
+ List *src_colnames,
+ List **src_colnos,
List **res_colnames, List **res_colvars,
ParseNamespaceColumn *res_nscolumns);
static Node *transformJoinUsingClause(ParseState *pstate,
@@ -76,6 +76,7 @@ static ParseNamespaceItem *getNSItemForSpecialRelationTypes(ParseState *pstate,
static Node *transformFromClauseItem(ParseState *pstate, Node *n,
ParseNamespaceItem **top_nsitem,
List **namespace);
+static Var *buildVarFromNSColumn(ParseNamespaceColumn *nscol);
static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype,
Var *l_colvar, Var *r_colvar);
static void setNamespaceColumnVisibility(List *namespace, bool cols_visible);
@@ -237,64 +238,61 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
/*
* Extract all not-in-common columns from column lists of a source table
*
- * We hand back new lists in *res_colnames and *res_colvars. But
- * res_nscolumns points to a caller-allocated array that we fill in
- * the next few entries in.
+ * src_nscolumns and src_colnames describe the source table.
+ *
+ * *src_colnos initially contains the column numbers of the already-merged
+ * columns. We add to it the column number of each additional column.
+ * Also append to *res_colnames the name of each additional column,
+ * append to *res_colvars a Var for each additional column, and copy the
+ * columns' nscolumns data into res_nscolumns[] (which is caller-allocated
+ * space that had better be big enough).
+ *
+ * Returns the number of columns added.
*/
-static void
-extractRemainingColumns(List *common_colnames,
- List *src_colnames, List *src_colvars,
- ParseNamespaceColumn *src_nscolumns,
+static int
+extractRemainingColumns(ParseNamespaceColumn *src_nscolumns,
+ List *src_colnames,
+ List **src_colnos,
List **res_colnames, List **res_colvars,
ParseNamespaceColumn *res_nscolumns)
{
- List *new_colnames = NIL;
- List *new_colvars = NIL;
- ListCell *lnames,
- *lvars;
-
- Assert(list_length(src_colnames) == list_length(src_colvars));
+ int colcount = 0;
+ Bitmapset *prevcols;
+ int attnum;
+ ListCell *lc;
- forboth(lnames, src_colnames, lvars, src_colvars)
+ /*
+ * While we could just test "list_member_int(*src_colnos, attnum)" to
+ * detect already-merged columns in the loop below, that would be O(N^2)
+ * for a wide input table. Instead build a bitmapset of just the merged
+ * USING columns, which we won't add to within the main loop.
+ */
+ prevcols = NULL;
+ foreach(lc, *src_colnos)
{
- char *colname = strVal(lfirst(lnames));
- bool match = false;
- ListCell *cnames;
-
- /*
- * Ignore any dropped columns in the src_nscolumns input. (The list
- * inputs won't contain entries for dropped columns.)
- */
- while (src_nscolumns->p_varno == 0)
- src_nscolumns++;
-
- /* is current src column already accounted for in common_colnames? */
- foreach(cnames, common_colnames)
- {
- char *ccolname = strVal(lfirst(cnames));
+ prevcols = bms_add_member(prevcols, lfirst_int(lc));
+ }
- if (strcmp(colname, ccolname) == 0)
- {
- match = true;
- break;
- }
- }
+ attnum = 0;
+ foreach(lc, src_colnames)
+ {
+ char *colname = strVal(lfirst(lc));
- if (!match)
+ attnum++;
+ /* Non-dropped and not already merged? */
+ if (colname[0] != '\0' && !bms_is_member(attnum, prevcols))
{
- /* Nope, so emit it as next output column */
- new_colnames = lappend(new_colnames, lfirst(lnames));
- new_colvars = lappend(new_colvars, lfirst(lvars));
+ /* Yes, so emit it as next output column */
+ *src_colnos = lappend_int(*src_colnos, attnum);
+ *res_colnames = lappend(*res_colnames, lfirst(lc));
+ *res_colvars = lappend(*res_colvars,
+ buildVarFromNSColumn(src_nscolumns + attnum - 1));
/* Copy the input relation's nscolumn data for this column */
- *res_nscolumns = *src_nscolumns;
- res_nscolumns++;
+ res_nscolumns[colcount] = src_nscolumns[attnum - 1];
+ colcount++;
}
-
- src_nscolumns++;
}
-
- *res_colnames = new_colnames;
- *res_colvars = new_colvars;
+ return colcount;
}
/* transformJoinUsingClause()
@@ -1154,10 +1152,12 @@ transformFromClauseItem(ParseState *pstate, Node *n,
*l_colnames,
*r_colnames,
*res_colnames,
- *l_colvars,
- *r_colvars,
+ *l_colnos,
+ *r_colnos,
*res_colvars;
- ParseNamespaceColumn *res_nscolumns;
+ ParseNamespaceColumn *l_nscolumns,
+ *r_nscolumns,
+ *res_nscolumns;
int res_colindex;
bool lateral_ok;
int sv_namespace_length;
@@ -1211,12 +1211,15 @@ transformFromClauseItem(ParseState *pstate, Node *n,
my_namespace = list_concat(l_namespace, r_namespace);
/*
- * Extract column name and var lists from both subtrees
- *
- * Note: expandNSItemVars returns new lists, safe for me to modify
+ * We'll work from the nscolumns data and eref alias column names for
+ * each of the input nsitems. Note that these include dropped
+ * columns, which is helpful because we can keep track of physical
+ * input column numbers more easily.
*/
- l_colvars = expandNSItemVars(l_nsitem, 0, -1, &l_colnames);
- r_colvars = expandNSItemVars(r_nsitem, 0, -1, &r_colnames);
+ l_nscolumns = l_nsitem->p_nscolumns;
+ l_colnames = l_nsitem->p_rte->eref->colnames;
+ r_nscolumns = r_nsitem->p_nscolumns;
+ r_colnames = r_nsitem->p_rte->eref->colnames;
/*
* Natural join does not explicitly specify columns; must generate
@@ -1240,6 +1243,9 @@ transformFromClauseItem(ParseState *pstate, Node *n,
char *l_colname = strVal(lfirst(lx));
Value *m_name = NULL;
+ if (l_colname[0] == '\0')
+ continue; /* ignore dropped columns */
+
foreach(rx, r_colnames)
{
char *r_colname = strVal(lfirst(rx));
@@ -1262,6 +1268,8 @@ transformFromClauseItem(ParseState *pstate, Node *n,
/*
* Now transform the join qualifications, if any.
*/
+ l_colnos = NIL;
+ r_colnos = NIL;
res_colnames = NIL;
res_colvars = NIL;
@@ -1297,6 +1305,8 @@ transformFromClauseItem(ParseState *pstate, Node *n,
Node *u_colvar;
ParseNamespaceColumn *res_nscolumn;
+ Assert(u_colname[0] != '\0');
+
/* Check for USING(foo,foo) */
foreach(col, res_colnames)
{
@@ -1331,6 +1341,7 @@ transformFromClauseItem(ParseState *pstate, Node *n,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" specified in USING clause does not exist in left table",
u_colname)));
+ l_colnos = lappend_int(l_colnos, l_index + 1);
/* Find it in right input */
ndx = 0;
@@ -1354,10 +1365,11 @@ transformFromClauseItem(ParseState *pstate, Node *n,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" specified in USING clause does not exist in right table",
u_colname)));
+ r_colnos = lappend_int(r_colnos, r_index + 1);
- l_colvar = list_nth(l_colvars, l_index);
+ l_colvar = buildVarFromNSColumn(l_nscolumns + l_index);
l_usingvars = lappend(l_usingvars, l_colvar);
- r_colvar = list_nth(r_colvars, r_index);
+ r_colvar = buildVarFromNSColumn(r_nscolumns + r_index);
r_usingvars = lappend(r_usingvars, r_colvar);
res_colnames = lappend(res_colnames, lfirst(ucol));
@@ -1371,26 +1383,12 @@ transformFromClauseItem(ParseState *pstate, Node *n,
if (u_colvar == (Node *) l_colvar)
{
/* Merged column is equivalent to left input */
- res_nscolumn->p_varno = l_colvar->varno;
- res_nscolumn->p_varattno = l_colvar->varattno;
- res_nscolumn->p_vartype = l_colvar->vartype;
- res_nscolumn->p_vartypmod = l_colvar->vartypmod;
- res_nscolumn->p_varcollid = l_colvar->varcollid;
- /* XXX these are not quite right, but doesn't matter yet */
- res_nscolumn->p_varnosyn = l_colvar->varno;
- res_nscolumn->p_varattnosyn = l_colvar->varattno;
+ *res_nscolumn = l_nscolumns[l_index];
}
else if (u_colvar == (Node *) r_colvar)
{
/* Merged column is equivalent to right input */
- res_nscolumn->p_varno = r_colvar->varno;
- res_nscolumn->p_varattno = r_colvar->varattno;
- res_nscolumn->p_vartype = r_colvar->vartype;
- res_nscolumn->p_vartypmod = r_colvar->vartypmod;
- res_nscolumn->p_varcollid = r_colvar->varcollid;
- /* XXX these are not quite right, but doesn't matter yet */
- res_nscolumn->p_varnosyn = r_colvar->varno;
- res_nscolumn->p_varattnosyn = r_colvar->varattno;
+ *res_nscolumn = r_nscolumns[r_index];
}
else
{
@@ -1427,22 +1425,14 @@ transformFromClauseItem(ParseState *pstate, Node *n,
}
/* Add remaining columns from each side to the output columns */
- extractRemainingColumns(res_colnames,
- l_colnames, l_colvars,
- l_nsitem->p_nscolumns,
- &l_colnames, &l_colvars,
- res_nscolumns + res_colindex);
- res_colindex += list_length(l_colvars);
- extractRemainingColumns(res_colnames,
- r_colnames, r_colvars,
- r_nsitem->p_nscolumns,
- &r_colnames, &r_colvars,
- res_nscolumns + res_colindex);
- res_colindex += list_length(r_colvars);
- res_colnames = list_concat(res_colnames, l_colnames);
- res_colvars = list_concat(res_colvars, l_colvars);
- res_colnames = list_concat(res_colnames, r_colnames);
- res_colvars = list_concat(res_colvars, r_colvars);
+ res_colindex +=
+ extractRemainingColumns(l_nscolumns, l_colnames, &l_colnos,
+ &res_colnames, &res_colvars,
+ res_nscolumns + res_colindex);
+ res_colindex +=
+ extractRemainingColumns(r_nscolumns, r_colnames, &r_colnos,
+ &res_colnames, &res_colvars,
+ res_nscolumns + res_colindex);
/*
* Check alias (AS clause), if any.
@@ -1468,7 +1458,10 @@ transformFromClauseItem(ParseState *pstate, Node *n,
res_colnames,
res_nscolumns,
j->jointype,
+ list_length(j->usingClause),
res_colvars,
+ l_colnos,
+ r_colnos,
j->alias,
true);
@@ -1538,6 +1531,30 @@ transformFromClauseItem(ParseState *pstate, Node *n,
}
/*
+ * buildVarFromNSColumn -
+ * build a Var node using ParseNamespaceColumn data
+ *
+ * We assume varlevelsup should be 0, and no location is specified
+ */
+static Var *
+buildVarFromNSColumn(ParseNamespaceColumn *nscol)
+{
+ Var *var;
+
+ Assert(nscol->p_varno > 0); /* i.e., not deleted column */
+ var = makeVar(nscol->p_varno,
+ nscol->p_varattno,
+ nscol->p_vartype,
+ nscol->p_vartypmod,
+ nscol->p_varcollid,
+ 0);
+ /* makeVar doesn't offer parameters for these, so set by hand: */
+ var->varnosyn = nscol->p_varnosyn;
+ var->varattnosyn = nscol->p_varattnosyn;
+ return var;
+}
+
+/*
* buildMergedJoinVar -
* generate a suitable replacement expression for a merged join column
*/