| Line | Hits | Source | Commit |
| 1151 |
- |
transformFromClauseItem(ParseState *pstate, Node *n, |
- |
| 1152 |
- |
ParseNamespaceItem **top_nsitem, |
- |
| 1153 |
- |
List **namespace) |
- |
| 1154 |
- |
{ |
- |
| 1155 |
- |
/* Guard against stack overflow due to overly deep subtree */ |
- |
| 1156 |
- |
check_stack_depth(); |
- |
| 1157 |
- |
|
- |
| 1158 |
- |
if (IsA(n, RangeVar)) |
- |
| 1159 |
- |
{ |
- |
| 1160 |
- |
/* Plain relation reference, or perhaps a CTE reference */ |
- |
| 1161 |
- |
RangeVar *rv = (RangeVar *) n; |
- |
| 1162 |
- |
RangeTblRef *rtr; |
- |
| 1163 |
- |
ParseNamespaceItem *nsitem; |
- |
| 1164 |
- |
|
- |
| 1165 |
- |
/* Check if it's a CTE or tuplestore reference */ |
- |
| 1166 |
- |
nsitem = getNSItemForSpecialRelationTypes(pstate, rv); |
- |
| 1167 |
- |
|
- |
| 1168 |
- |
/* if not found above, must be a table reference */ |
- |
| 1169 |
- |
if (!nsitem) |
- |
| 1170 |
- |
nsitem = transformTableEntry(pstate, rv); |
- |
| 1171 |
- |
|
- |
| 1172 |
- |
*top_nsitem = nsitem; |
- |
| 1173 |
- |
*namespace = list_make1(nsitem); |
- |
| 1174 |
- |
rtr = makeNode(RangeTblRef); |
- |
| 1175 |
- |
rtr->rtindex = nsitem->p_rtindex; |
- |
| 1176 |
- |
return (Node *) rtr; |
- |
| 1177 |
- |
} |
- |
| 1178 |
- |
else if (IsA(n, RangeSubselect)) |
- |
| 1179 |
- |
{ |
- |
| 1180 |
- |
/* sub-SELECT is like a plain relation */ |
- |
| 1181 |
- |
RangeTblRef *rtr; |
- |
| 1182 |
- |
ParseNamespaceItem *nsitem; |
- |
| 1183 |
- |
|
- |
| 1184 |
- |
nsitem = transformRangeSubselect(pstate, (RangeSubselect *) n); |
- |
| 1185 |
- |
*top_nsitem = nsitem; |
- |
| 1186 |
- |
*namespace = list_make1(nsitem); |
- |
| 1187 |
- |
rtr = makeNode(RangeTblRef); |
- |
| 1188 |
- |
rtr->rtindex = nsitem->p_rtindex; |
- |
| 1189 |
- |
return (Node *) rtr; |
- |
| 1190 |
- |
} |
- |
| 1191 |
- |
else if (IsA(n, RangeFunction)) |
- |
| 1192 |
- |
{ |
- |
| 1193 |
- |
/* function is like a plain relation */ |
- |
| 1194 |
- |
RangeTblRef *rtr; |
- |
| 1195 |
- |
ParseNamespaceItem *nsitem; |
- |
| 1196 |
- |
|
- |
| 1197 |
- |
nsitem = transformRangeFunction(pstate, (RangeFunction *) n); |
- |
| 1198 |
- |
*top_nsitem = nsitem; |
- |
| 1199 |
- |
*namespace = list_make1(nsitem); |
- |
| 1200 |
- |
rtr = makeNode(RangeTblRef); |
- |
| 1201 |
- |
rtr->rtindex = nsitem->p_rtindex; |
- |
| 1202 |
- |
return (Node *) rtr; |
- |
| 1203 |
- |
} |
- |
| 1204 |
- |
else if (IsA(n, RangeTableFunc) || IsA(n, JsonTable)) |
- |
| 1205 |
- |
{ |
- |
| 1206 |
- |
/* table function is like a plain relation */ |
- |
| 1207 |
- |
RangeTblRef *rtr; |
- |
| 1208 |
- |
ParseNamespaceItem *nsitem; |
- |
| 1209 |
- |
|
- |
| 1210 |
- |
if (IsA(n, JsonTable)) |
- |
| 1211 |
- |
nsitem = transformJsonTable(pstate, (JsonTable *) n); |
- |
| 1212 |
- |
else |
- |
| 1213 |
- |
nsitem = transformRangeTableFunc(pstate, (RangeTableFunc *) n); |
- |
| 1214 |
- |
|
- |
| 1215 |
- |
*top_nsitem = nsitem; |
- |
| 1216 |
- |
*namespace = list_make1(nsitem); |
- |
| 1217 |
- |
rtr = makeNode(RangeTblRef); |
- |
| 1218 |
- |
rtr->rtindex = nsitem->p_rtindex; |
- |
| 1219 |
- |
return (Node *) rtr; |
- |
| 1220 |
- |
} |
- |
| 1221 |
- |
else if (IsA(n, RangeGraphTable)) |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1222 |
- |
{ |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1223 |
372 |
RangeTblRef *rtr; |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1224 |
372 |
ParseNamespaceItem *nsitem; |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1225 |
- |
|
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1226 |
372 |
nsitem = transformRangeGraphTable(pstate, (RangeGraphTable *) n); |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1227 |
351 |
*top_nsitem = nsitem; |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1228 |
351 |
*namespace = list_make1(nsitem); |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1229 |
351 |
rtr = makeNode(RangeTblRef); |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1230 |
351 |
rtr->rtindex = nsitem->p_rtindex; |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1231 |
351 |
return (Node *) rtr; |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1232 |
- |
} |
86c14eaWIP: SQL Property Graph Queries (SQL/PGQ) |
| 1233 |
- |
else if (IsA(n, RangeTableSample)) |
- |
| 1234 |
- |
{ |
- |
| 1235 |
- |
/* TABLESAMPLE clause (wrapping some other valid FROM node) */ |
- |
| 1236 |
- |
RangeTableSample *rts = (RangeTableSample *) n; |
- |
| 1237 |
- |
Node *rel; |
- |
| 1238 |
- |
RangeTblEntry *rte; |
- |
| 1239 |
- |
|
- |
| 1240 |
- |
/* Recursively transform the contained relation */ |
- |
| 1241 |
- |
rel = transformFromClauseItem(pstate, rts->relation, |
- |
| 1242 |
- |
top_nsitem, namespace); |
- |
| 1243 |
- |
rte = (*top_nsitem)->p_rte; |
- |
| 1244 |
- |
/* We only support this on plain relations and matviews */ |
- |
| 1245 |
- |
if (rte->rtekind != RTE_RELATION || |
- |
| 1246 |
- |
(rte->relkind != RELKIND_RELATION && |
- |
| 1247 |
- |
rte->relkind != RELKIND_MATVIEW && |
- |
| 1248 |
- |
rte->relkind != RELKIND_PARTITIONED_TABLE)) |
- |
| 1249 |
- |
ereport(ERROR, |
- |
| 1250 |
- |
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
- |
| 1251 |
- |
errmsg("TABLESAMPLE clause can only be applied to tables and materialized views"), |
- |
| 1252 |
- |
parser_errposition(pstate, exprLocation(rts->relation)))); |
- |
| 1253 |
- |
|
- |
| 1254 |
- |
/* Transform TABLESAMPLE details and attach to the RTE */ |
- |
| 1255 |
- |
rte->tablesample = transformRangeTableSample(pstate, rts); |
- |
| 1256 |
- |
return rel; |
- |
| 1257 |
- |
} |
- |
| 1258 |
- |
else if (IsA(n, JoinExpr)) |
- |
| 1259 |
- |
{ |
- |
| 1260 |
- |
/* A newfangled join expression */ |
- |
| 1261 |
- |
JoinExpr *j = (JoinExpr *) n; |
- |
| 1262 |
- |
ParseNamespaceItem *nsitem; |
- |
| 1263 |
- |
ParseNamespaceItem *l_nsitem; |
- |
| 1264 |
- |
ParseNamespaceItem *r_nsitem; |
- |
| 1265 |
- |
List *l_namespace, |
- |
| 1266 |
- |
*r_namespace, |
- |
| 1267 |
- |
*my_namespace, |
- |
| 1268 |
- |
*l_colnames, |
- |
| 1269 |
- |
*r_colnames, |
- |
| 1270 |
- |
*res_colnames, |
- |
| 1271 |
- |
*l_colnos, |
- |
| 1272 |
- |
*r_colnos, |
- |
| 1273 |
- |
*res_colvars; |
- |
| 1274 |
- |
ParseNamespaceColumn *l_nscolumns, |
- |
| 1275 |
- |
*r_nscolumns, |
- |
| 1276 |
- |
*res_nscolumns; |
- |
| 1277 |
- |
int res_colindex; |
- |
| 1278 |
- |
bool lateral_ok; |
- |
| 1279 |
- |
int sv_namespace_length; |
- |
| 1280 |
- |
int k; |
- |
| 1281 |
- |
|
- |
| 1282 |
- |
/* |
- |
| 1283 |
- |
* Recursively process the left subtree, then the right. We must do |
- |
| 1284 |
- |
* it in this order for correct visibility of LATERAL references. |
- |
| 1285 |
- |
*/ |
- |
| 1286 |
- |
j->larg = transformFromClauseItem(pstate, j->larg, |
- |
| 1287 |
- |
&l_nsitem, |
- |
| 1288 |
- |
&l_namespace); |
- |
| 1289 |
- |
|
- |
| 1290 |
- |
/* |
- |
| 1291 |
- |
* Make the left-side RTEs available for LATERAL access within the |
- |
| 1292 |
- |
* right side, by temporarily adding them to the pstate's namespace |
- |
| 1293 |
- |
* list. Per SQL:2008, if the join type is not INNER or LEFT then the |
- |
| 1294 |
- |
* left-side names must still be exposed, but it's an error to |
- |
| 1295 |
- |
* reference them. (Stupid design, but that's what it says.) Hence, |
- |
| 1296 |
- |
* we always push them into the namespace, but mark them as not |
- |
| 1297 |
- |
* lateral_ok if the jointype is wrong. |
- |
| 1298 |
- |
* |
- |
| 1299 |
- |
* Notice that we don't require the merged namespace list to be |
- |
| 1300 |
- |
* conflict-free. See the comments for scanNameSpaceForRefname(). |
- |
| 1301 |
- |
*/ |
- |
| 1302 |
- |
lateral_ok = (j->jointype == JOIN_INNER || j->jointype == JOIN_LEFT); |
- |
| 1303 |
- |
setNamespaceLateralState(l_namespace, true, lateral_ok); |
- |
| 1304 |
- |
|
- |
| 1305 |
- |
sv_namespace_length = list_length(pstate->p_namespace); |
- |
| 1306 |
- |
pstate->p_namespace = list_concat(pstate->p_namespace, l_namespace); |
- |
| 1307 |
- |
|
- |
| 1308 |
- |
/* And now we can process the RHS */ |
- |
| 1309 |
- |
j->rarg = transformFromClauseItem(pstate, j->rarg, |
- |
| 1310 |
- |
&r_nsitem, |
- |
| 1311 |
- |
&r_namespace); |
- |
| 1312 |
- |
|
- |
| 1313 |
- |
/* Remove the left-side RTEs from the namespace list again */ |
- |
| 1314 |
- |
pstate->p_namespace = list_truncate(pstate->p_namespace, |
- |
| 1315 |
- |
sv_namespace_length); |
- |
| 1316 |
- |
|
- |
| 1317 |
- |
/* |
- |
| 1318 |
- |
* Check for conflicting refnames in left and right subtrees. Must do |
- |
| 1319 |
- |
* this because higher levels will assume I hand back a self- |
- |
| 1320 |
- |
* consistent namespace list. |
- |
| 1321 |
- |
*/ |
- |
| 1322 |
- |
checkNameSpaceConflicts(pstate, l_namespace, r_namespace); |
- |
| 1323 |
- |
|
- |
| 1324 |
- |
/* |
- |
| 1325 |
- |
* Generate combined namespace info for possible use below. |
- |
| 1326 |
- |
*/ |
- |
| 1327 |
- |
my_namespace = list_concat(l_namespace, r_namespace); |
- |
| 1328 |
- |
|
- |
| 1329 |
- |
/* |
- |
| 1330 |
- |
* We'll work from the nscolumns data and eref alias column names for |
- |
| 1331 |
- |
* each of the input nsitems. Note that these include dropped |
- |
| 1332 |
- |
* columns, which is helpful because we can keep track of physical |
- |
| 1333 |
- |
* input column numbers more easily. |
- |
| 1334 |
- |
*/ |
- |
| 1335 |
- |
l_nscolumns = l_nsitem->p_nscolumns; |
- |
| 1336 |
- |
l_colnames = l_nsitem->p_names->colnames; |
- |
| 1337 |
- |
r_nscolumns = r_nsitem->p_nscolumns; |
- |
| 1338 |
- |
r_colnames = r_nsitem->p_names->colnames; |
- |
| 1339 |
- |
|
- |
| 1340 |
- |
/* |
- |
| 1341 |
- |
* Natural join does not explicitly specify columns; must generate |
- |
| 1342 |
- |
* columns to join. Need to run through the list of columns from each |
- |
| 1343 |
- |
* table or join result and match up the column names. Use the first |
- |
| 1344 |
- |
* table, and check every column in the second table for a match. |
- |
| 1345 |
- |
* (We'll check that the matches were unique later on.) The result of |
- |
| 1346 |
- |
* this step is a list of column names just like an explicitly-written |
- |
| 1347 |
- |
* USING list. |
- |
| 1348 |
- |
*/ |
- |
| 1349 |
- |
if (j->isNatural) |
- |
| 1350 |
- |
{ |
- |
| 1351 |
- |
List *rlist = NIL; |
- |
| 1352 |
- |
ListCell *lx, |
- |
| 1353 |
- |
*rx; |
- |
| 1354 |
- |
|
- |
| 1355 |
- |
Assert(j->usingClause == NIL); /* shouldn't have USING() too */ |
- |
| 1356 |
- |
|
- |
| 1357 |
- |
foreach(lx, l_colnames) |
- |
| 1358 |
- |
{ |
- |
| 1359 |
- |
char *l_colname = strVal(lfirst(lx)); |
- |
| 1360 |
- |
String *m_name = NULL; |
- |
| 1361 |
- |
|
- |
| 1362 |
- |
if (l_colname[0] == '\0') |
- |
| 1363 |
- |
continue; /* ignore dropped columns */ |
- |
| 1364 |
- |
|
- |
| 1365 |
- |
foreach(rx, r_colnames) |
- |
| 1366 |
- |
{ |
- |
| 1367 |
- |
char *r_colname = strVal(lfirst(rx)); |
- |
| 1368 |
- |
|
- |
| 1369 |
- |
if (strcmp(l_colname, r_colname) == 0) |
- |
| 1370 |
- |
{ |
- |
| 1371 |
- |
m_name = makeString(l_colname); |
- |
| 1372 |
- |
break; |
- |
| 1373 |
- |
} |
- |
| 1374 |
- |
} |
- |
| 1375 |
- |
|
- |
| 1376 |
- |
/* matched a right column? then keep as join column... */ |
- |
| 1377 |
- |
if (m_name != NULL) |
- |
| 1378 |
- |
rlist = lappend(rlist, m_name); |
- |
| 1379 |
- |
} |
- |
| 1380 |
- |
|
- |
| 1381 |
- |
j->usingClause = rlist; |
- |
| 1382 |
- |
} |
- |
| 1383 |
- |
|
- |
| 1384 |
- |
/* |
- |
| 1385 |
- |
* If a USING clause alias was specified, save the USING columns as |
- |
| 1386 |
- |
* its column list. |
- |
| 1387 |
- |
*/ |
- |
| 1388 |
- |
if (j->join_using_alias) |
- |
| 1389 |
- |
j->join_using_alias->colnames = j->usingClause; |
- |
| 1390 |
- |
|
- |
| 1391 |
- |
/* |
- |
| 1392 |
- |
* Now transform the join qualifications, if any. |
- |
| 1393 |
- |
*/ |
- |
| 1394 |
- |
l_colnos = NIL; |
- |
| 1395 |
- |
r_colnos = NIL; |
- |
| 1396 |
- |
res_colnames = NIL; |
- |
| 1397 |
- |
res_colvars = NIL; |
- |
| 1398 |
- |
|
- |
| 1399 |
- |
/* this may be larger than needed, but it's not worth being exact */ |
- |
| 1400 |
- |
res_nscolumns = (ParseNamespaceColumn *) |
- |
| 1401 |
- |
palloc0((list_length(l_colnames) + list_length(r_colnames)) * |
- |
| 1402 |
- |
sizeof(ParseNamespaceColumn)); |
- |
| 1403 |
- |
res_colindex = 0; |
- |
| 1404 |
- |
|
- |
| 1405 |
- |
if (j->usingClause) |
- |
| 1406 |
- |
{ |
- |
| 1407 |
- |
/* |
- |
| 1408 |
- |
* JOIN/USING (or NATURAL JOIN, as transformed above). Transform |
- |
| 1409 |
- |
* the list into an explicit ON-condition. |
- |
| 1410 |
- |
*/ |
- |
| 1411 |
- |
List *ucols = j->usingClause; |
- |
| 1412 |
- |
List *l_usingvars = NIL; |
- |
| 1413 |
- |
List *r_usingvars = NIL; |
- |
| 1414 |
- |
ListCell *ucol; |
- |
| 1415 |
- |
|
- |
| 1416 |
- |
Assert(j->quals == NULL); /* shouldn't have ON() too */ |
- |
| 1417 |
- |
|
- |
| 1418 |
- |
foreach(ucol, ucols) |
- |
| 1419 |
- |
{ |
- |
| 1420 |
- |
char *u_colname = strVal(lfirst(ucol)); |
- |
| 1421 |
- |
ListCell *col; |
- |
| 1422 |
- |
int ndx; |
- |
| 1423 |
- |
int l_index = -1; |
- |
| 1424 |
- |
int r_index = -1; |
- |
| 1425 |
- |
Var *l_colvar, |
- |
| 1426 |
- |
*r_colvar; |
- |
| 1427 |
- |
|
- |
| 1428 |
- |
Assert(u_colname[0] != '\0'); |
- |
| 1429 |
- |
|
- |
| 1430 |
- |
/* Check for USING(foo,foo) */ |
- |
| 1431 |
- |
foreach(col, res_colnames) |
- |
| 1432 |
- |
{ |
- |
| 1433 |
- |
char *res_colname = strVal(lfirst(col)); |
- |
| 1434 |
- |
|
- |
| 1435 |
- |
if (strcmp(res_colname, u_colname) == 0) |
- |
| 1436 |
- |
ereport(ERROR, |
- |
| 1437 |
- |
(errcode(ERRCODE_DUPLICATE_COLUMN), |
- |
| 1438 |
- |
errmsg("column name \"%s\" appears more than once in USING clause", |
- |
| 1439 |
- |
u_colname))); |
- |
| 1440 |
- |
} |
- |
| 1441 |
- |
|
- |
| 1442 |
- |
/* Find it in left input */ |
- |
| 1443 |
- |
ndx = 0; |
- |
| 1444 |
- |
foreach(col, l_colnames) |
- |
| 1445 |
- |
{ |
- |
| 1446 |
- |
char *l_colname = strVal(lfirst(col)); |
- |
| 1447 |
- |
|
- |
| 1448 |
- |
if (strcmp(l_colname, u_colname) == 0) |
- |
| 1449 |
- |
{ |
- |
| 1450 |
- |
if (l_index >= 0) |
- |
| 1451 |
- |
ereport(ERROR, |
- |
| 1452 |
- |
(errcode(ERRCODE_AMBIGUOUS_COLUMN), |
- |
| 1453 |
- |
errmsg("common column name \"%s\" appears more than once in left table", |
- |
| 1454 |
- |
u_colname))); |
- |
| 1455 |
- |
l_index = ndx; |
- |
| 1456 |
- |
} |
- |
| 1457 |
- |
ndx++; |
- |
| 1458 |
- |
} |
- |
| 1459 |
- |
if (l_index < 0) |
- |
| 1460 |
- |
ereport(ERROR, |
- |
| 1461 |
- |
(errcode(ERRCODE_UNDEFINED_COLUMN), |
- |
| 1462 |
- |
errmsg("column \"%s\" specified in USING clause does not exist in left table", |
- |
| 1463 |
- |
u_colname))); |
- |
| 1464 |
- |
l_colnos = lappend_int(l_colnos, l_index + 1); |
- |
| 1465 |
- |
|
- |
| 1466 |
- |
/* Find it in right input */ |
- |
| 1467 |
- |
ndx = 0; |
- |
| 1468 |
- |
foreach(col, r_colnames) |
- |
| 1469 |
- |
{ |
- |
| 1470 |
- |
char *r_colname = strVal(lfirst(col)); |
- |
| 1471 |
- |
|
- |
| 1472 |
- |
if (strcmp(r_colname, u_colname) == 0) |
- |
| 1473 |
- |
{ |
- |
| 1474 |
- |
if (r_index >= 0) |
- |
| 1475 |
- |
ereport(ERROR, |
- |
| 1476 |
- |
(errcode(ERRCODE_AMBIGUOUS_COLUMN), |
- |
| 1477 |
- |
errmsg("common column name \"%s\" appears more than once in right table", |
- |
| 1478 |
- |
u_colname))); |
- |
| 1479 |
- |
r_index = ndx; |
- |
| 1480 |
- |
} |
- |
| 1481 |
- |
ndx++; |
- |
| 1482 |
- |
} |
- |
| 1483 |
- |
if (r_index < 0) |
- |
| 1484 |
- |
ereport(ERROR, |
- |
| 1485 |
- |
(errcode(ERRCODE_UNDEFINED_COLUMN), |
- |
| 1486 |
- |
errmsg("column \"%s\" specified in USING clause does not exist in right table", |
- |
| 1487 |
- |
u_colname))); |
- |
| 1488 |
- |
r_colnos = lappend_int(r_colnos, r_index + 1); |
- |
| 1489 |
- |
|
- |
| 1490 |
- |
/* Build Vars to use in the generated JOIN ON clause */ |
- |
| 1491 |
- |
l_colvar = buildVarFromNSColumn(pstate, l_nscolumns + l_index); |
- |
| 1492 |
- |
l_usingvars = lappend(l_usingvars, l_colvar); |
- |
| 1493 |
- |
r_colvar = buildVarFromNSColumn(pstate, r_nscolumns + r_index); |
- |
| 1494 |
- |
r_usingvars = lappend(r_usingvars, r_colvar); |
- |
| 1495 |
- |
|
- |
| 1496 |
- |
/* |
- |
| 1497 |
- |
* While we're here, add column names to the res_colnames |
- |
| 1498 |
- |
* list. It's a bit ugly to do this here while the |
- |
| 1499 |
- |
* corresponding res_colvars entries are not made till later, |
- |
| 1500 |
- |
* but doing this later would require an additional traversal |
- |
| 1501 |
- |
* of the usingClause list. |
- |
| 1502 |
- |
*/ |
- |
| 1503 |
- |
res_colnames = lappend(res_colnames, lfirst(ucol)); |
- |
| 1504 |
- |
} |
- |
| 1505 |
- |
|
- |
| 1506 |
- |
/* Construct the generated JOIN ON clause */ |
- |
| 1507 |
- |
j->quals = transformJoinUsingClause(pstate, |
- |
| 1508 |
- |
l_usingvars, |
- |
| 1509 |
- |
r_usingvars); |
- |
| 1510 |
- |
} |
- |
| 1511 |
- |
else if (j->quals) |
- |
| 1512 |
- |
{ |
- |
| 1513 |
- |
/* User-written ON-condition; transform it */ |
- |
| 1514 |
- |
j->quals = transformJoinOnClause(pstate, j, my_namespace); |
- |
| 1515 |
- |
} |
- |
| 1516 |
- |
else |
- |
| 1517 |
- |
{ |
- |
| 1518 |
- |
/* CROSS JOIN: no quals */ |
- |
| 1519 |
- |
} |
- |
| 1520 |
- |
|
- |
| 1521 |
- |
/* |
- |
| 1522 |
- |
* If this is an outer join, now mark the appropriate child RTEs as |
- |
| 1523 |
- |
* being nulled by this join. We have finished processing the child |
- |
| 1524 |
- |
* join expressions as well as the current join's quals, which deal in |
- |
| 1525 |
- |
* non-nulled input columns. All future references to those RTEs will |
- |
| 1526 |
- |
* see possibly-nulled values, and we should mark generated Vars to |
- |
| 1527 |
- |
* account for that. In particular, the join alias Vars that we're |
- |
| 1528 |
- |
* about to build should reflect the nulling effects of this join. |
- |
| 1529 |
- |
* |
- |
| 1530 |
- |
* A difficulty with doing this is that we need the join's RT index, |
- |
| 1531 |
- |
* which we don't officially have yet. However, no other RTE can get |
- |
| 1532 |
- |
* made between here and the addRangeTableEntryForJoin call, so we can |
- |
| 1533 |
- |
* predict what the assignment will be. (Alternatively, we could call |
- |
| 1534 |
- |
* addRangeTableEntryForJoin before we have all the data computed, but |
- |
| 1535 |
- |
* this seems less ugly.) |
- |
| 1536 |
- |
*/ |
- |
| 1537 |
- |
j->rtindex = list_length(pstate->p_rtable) + 1; |
- |
| 1538 |
- |
|
- |
| 1539 |
- |
switch (j->jointype) |
- |
| 1540 |
- |
{ |
- |
| 1541 |
- |
case JOIN_INNER: |
- |
| 1542 |
- |
break; |
- |
| 1543 |
- |
case JOIN_LEFT: |
- |
| 1544 |
- |
markRelsAsNulledBy(pstate, j->rarg, j->rtindex); |
- |
| 1545 |
- |
break; |
- |
| 1546 |
- |
case JOIN_FULL: |
- |
| 1547 |
- |
markRelsAsNulledBy(pstate, j->larg, j->rtindex); |
- |
| 1548 |
- |
markRelsAsNulledBy(pstate, j->rarg, j->rtindex); |
- |
| 1549 |
- |
break; |
- |
| 1550 |
- |
case JOIN_RIGHT: |
- |
| 1551 |
- |
markRelsAsNulledBy(pstate, j->larg, j->rtindex); |
- |
| 1552 |
- |
break; |
- |
| 1553 |
- |
default: |
- |
| 1554 |
- |
/* shouldn't see any other types here */ |
- |
| 1555 |
- |
elog(ERROR, "unrecognized join type: %d", |
- |
| 1556 |
- |
(int) j->jointype); |
- |
| 1557 |
- |
break; |
- |
| 1558 |
- |
} |
- |
| 1559 |
- |
|
- |
| 1560 |
- |
/* |
- |
| 1561 |
- |
* Now we can construct join alias expressions for the USING columns. |
- |
| 1562 |
- |
*/ |
- |
| 1563 |
- |
if (j->usingClause) |
- |
| 1564 |
- |
{ |
- |
| 1565 |
- |
ListCell *lc1, |
- |
| 1566 |
- |
*lc2; |
- |
| 1567 |
- |
|
- |
| 1568 |
- |
/* Scan the colnos lists to recover info from the previous loop */ |
- |
| 1569 |
- |
forboth(lc1, l_colnos, lc2, r_colnos) |
- |
| 1570 |
- |
{ |
- |
| 1571 |
- |
int l_index = lfirst_int(lc1) - 1; |
- |
| 1572 |
- |
int r_index = lfirst_int(lc2) - 1; |
- |
| 1573 |
- |
Var *l_colvar, |
- |
| 1574 |
- |
*r_colvar; |
- |
| 1575 |
- |
Node *u_colvar; |
- |
| 1576 |
- |
ParseNamespaceColumn *res_nscolumn; |
- |
| 1577 |
- |
|
- |
| 1578 |
- |
/* |
- |
| 1579 |
- |
* Note we re-build these Vars: they might have different |
- |
| 1580 |
- |
* varnullingrels than the ones made in the previous loop. |
- |
| 1581 |
- |
*/ |
- |
| 1582 |
- |
l_colvar = buildVarFromNSColumn(pstate, l_nscolumns + l_index); |
- |
| 1583 |
- |
r_colvar = buildVarFromNSColumn(pstate, r_nscolumns + r_index); |
- |
| 1584 |
- |
|
- |
| 1585 |
- |
/* Construct the join alias Var for this column */ |
- |
| 1586 |
- |
u_colvar = buildMergedJoinVar(pstate, |
- |
| 1587 |
- |
j->jointype, |
- |
| 1588 |
- |
l_colvar, |
- |
| 1589 |
- |
r_colvar); |
- |
| 1590 |
- |
res_colvars = lappend(res_colvars, u_colvar); |
- |
| 1591 |
- |
|
- |
| 1592 |
- |
/* Construct column's res_nscolumns[] entry */ |
- |
| 1593 |
- |
res_nscolumn = res_nscolumns + res_colindex; |
- |
| 1594 |
- |
res_colindex++; |
- |
| 1595 |
- |
if (u_colvar == (Node *) l_colvar) |
- |
| 1596 |
- |
{ |
- |
| 1597 |
- |
/* Merged column is equivalent to left input */ |
- |
| 1598 |
- |
*res_nscolumn = l_nscolumns[l_index]; |
- |
| 1599 |
- |
} |
- |
| 1600 |
- |
else if (u_colvar == (Node *) r_colvar) |
- |
| 1601 |
- |
{ |
- |
| 1602 |
- |
/* Merged column is equivalent to right input */ |
- |
| 1603 |
- |
*res_nscolumn = r_nscolumns[r_index]; |
- |
| 1604 |
- |
} |
- |
| 1605 |
- |
else |
- |
| 1606 |
- |
{ |
- |
| 1607 |
- |
/* |
- |
| 1608 |
- |
* Merged column is not semantically equivalent to either |
- |
| 1609 |
- |
* input, so it needs to be referenced as the join output |
- |
| 1610 |
- |
* column. |
- |
| 1611 |
- |
*/ |
- |
| 1612 |
- |
res_nscolumn->p_varno = j->rtindex; |
- |
| 1613 |
- |
res_nscolumn->p_varattno = res_colindex; |
- |
| 1614 |
- |
res_nscolumn->p_vartype = exprType(u_colvar); |
- |
| 1615 |
- |
res_nscolumn->p_vartypmod = exprTypmod(u_colvar); |
- |
| 1616 |
- |
res_nscolumn->p_varcollid = exprCollation(u_colvar); |
- |
| 1617 |
- |
res_nscolumn->p_varnosyn = j->rtindex; |
- |
| 1618 |
- |
res_nscolumn->p_varattnosyn = res_colindex; |
- |
| 1619 |
- |
} |
- |
| 1620 |
- |
} |
- |
| 1621 |
- |
} |
- |
| 1622 |
- |
|
- |
| 1623 |
- |
/* Add remaining columns from each side to the output columns */ |
- |
| 1624 |
- |
res_colindex += |
- |
| 1625 |
- |
extractRemainingColumns(pstate, |
- |
| 1626 |
- |
l_nscolumns, l_colnames, &l_colnos, |
- |
| 1627 |
- |
&res_colnames, &res_colvars, |
- |
| 1628 |
- |
res_nscolumns + res_colindex); |
- |
| 1629 |
- |
res_colindex += |
- |
| 1630 |
- |
extractRemainingColumns(pstate, |
- |
| 1631 |
- |
r_nscolumns, r_colnames, &r_colnos, |
- |
| 1632 |
- |
&res_colnames, &res_colvars, |
- |
| 1633 |
- |
res_nscolumns + res_colindex); |
- |
| 1634 |
- |
|
- |
| 1635 |
- |
/* If join has an alias, it syntactically hides all inputs */ |
- |
| 1636 |
- |
if (j->alias) |
- |
| 1637 |
- |
{ |
- |
| 1638 |
- |
for (k = 0; k < res_colindex; k++) |
- |
| 1639 |
- |
{ |
- |
| 1640 |
- |
ParseNamespaceColumn *nscol = res_nscolumns + k; |
- |
| 1641 |
- |
|
- |
| 1642 |
- |
nscol->p_varnosyn = j->rtindex; |
- |
| 1643 |
- |
nscol->p_varattnosyn = k + 1; |
- |
| 1644 |
- |
} |
- |
| 1645 |
- |
} |
- |
| 1646 |
- |
|
- |
| 1647 |
- |
/* |
- |
| 1648 |
- |
* Now build an RTE and nsitem for the result of the join. |
- |
| 1649 |
- |
*/ |
- |
| 1650 |
- |
nsitem = addRangeTableEntryForJoin(pstate, |
- |
| 1651 |
- |
res_colnames, |
- |
| 1652 |
- |
res_nscolumns, |
- |
| 1653 |
- |
j->jointype, |
- |
| 1654 |
- |
list_length(j->usingClause), |
- |
| 1655 |
- |
res_colvars, |
- |
| 1656 |
- |
l_colnos, |
- |
| 1657 |
- |
r_colnos, |
- |
| 1658 |
- |
j->join_using_alias, |
- |
| 1659 |
- |
j->alias, |
- |
| 1660 |
- |
true); |
- |
| 1661 |
- |
|
- |
| 1662 |
- |
/* Verify that we correctly predicted the join's RT index */ |
- |
| 1663 |
- |
Assert(j->rtindex == nsitem->p_rtindex); |
- |
| 1664 |
- |
/* Cross-check number of columns, too */ |
- |
| 1665 |
- |
Assert(res_colindex == list_length(nsitem->p_names->colnames)); |
- |
| 1666 |
- |
|
- |
| 1667 |
- |
/* |
- |
| 1668 |
- |
* Save a link to the JoinExpr in the proper element of p_joinexprs. |
- |
| 1669 |
- |
* Since we maintain that list lazily, it may be necessary to fill in |
- |
| 1670 |
- |
* empty entries before we can add the JoinExpr in the right place. |
- |
| 1671 |
- |
*/ |
- |
| 1672 |
- |
for (k = list_length(pstate->p_joinexprs) + 1; k < j->rtindex; k++) |
- |
| 1673 |
- |
pstate->p_joinexprs = lappend(pstate->p_joinexprs, NULL); |
- |
| 1674 |
- |
pstate->p_joinexprs = lappend(pstate->p_joinexprs, j); |
- |
| 1675 |
- |
Assert(list_length(pstate->p_joinexprs) == j->rtindex); |
- |
| 1676 |
- |
|
- |
| 1677 |
- |
/* |
- |
| 1678 |
- |
* If the join has a USING alias, build a ParseNamespaceItem for that |
- |
| 1679 |
- |
* and add it to the list of nsitems in the join's input. |
- |
| 1680 |
- |
*/ |
- |
| 1681 |
- |
if (j->join_using_alias) |
- |
| 1682 |
- |
{ |
- |
| 1683 |
- |
ParseNamespaceItem *jnsitem; |
- |
| 1684 |
- |
|
- |
| 1685 |
- |
jnsitem = palloc_object(ParseNamespaceItem); |
- |
| 1686 |
- |
jnsitem->p_names = j->join_using_alias; |
- |
| 1687 |
- |
jnsitem->p_rte = nsitem->p_rte; |
- |
| 1688 |
- |
jnsitem->p_rtindex = nsitem->p_rtindex; |
- |
| 1689 |
- |
jnsitem->p_perminfo = NULL; |
- |
| 1690 |
- |
/* no need to copy the first N columns, just use res_nscolumns */ |
- |
| 1691 |
- |
jnsitem->p_nscolumns = res_nscolumns; |
- |
| 1692 |
- |
/* set default visibility flags; might get changed later */ |
- |
| 1693 |
- |
jnsitem->p_rel_visible = true; |
- |
| 1694 |
- |
jnsitem->p_cols_visible = true; |
- |
| 1695 |
- |
jnsitem->p_lateral_only = false; |
- |
| 1696 |
- |
jnsitem->p_lateral_ok = true; |
- |
| 1697 |
- |
jnsitem->p_returning_type = VAR_RETURNING_DEFAULT; |
- |
| 1698 |
- |
/* Per SQL, we must check for alias conflicts */ |
- |
| 1699 |
- |
checkNameSpaceConflicts(pstate, list_make1(jnsitem), my_namespace); |
- |
| 1700 |
- |
my_namespace = lappend(my_namespace, jnsitem); |
- |
| 1701 |
- |
} |
- |
| 1702 |
- |
|
- |
| 1703 |
- |
/* |
- |
| 1704 |
- |
* Prepare returned namespace list. If the JOIN has an alias then it |
- |
| 1705 |
- |
* hides the contained RTEs completely; otherwise, the contained RTEs |
- |
| 1706 |
- |
* are still visible as table names, but are not visible for |
- |
| 1707 |
- |
* unqualified column-name access. |
- |
| 1708 |
- |
* |
- |
| 1709 |
- |
* Note: if there are nested alias-less JOINs, the lower-level ones |
- |
| 1710 |
- |
* will remain in the list although they have neither p_rel_visible |
- |
| 1711 |
- |
* nor p_cols_visible set. We could delete such list items, but it's |
- |
| 1712 |
- |
* unclear that it's worth expending cycles to do so. |
- |
| 1713 |
- |
*/ |
- |
| 1714 |
- |
if (j->alias != NULL) |
- |
| 1715 |
- |
my_namespace = NIL; |
- |
| 1716 |
- |
else |
- |
| 1717 |
- |
setNamespaceColumnVisibility(my_namespace, false); |
- |
| 1718 |
- |
|
- |
| 1719 |
- |
/* |
- |
| 1720 |
- |
* The join RTE itself is always made visible for unqualified column |
- |
| 1721 |
- |
* names. It's visible as a relation name only if it has an alias. |
- |
| 1722 |
- |
*/ |
- |
| 1723 |
- |
nsitem->p_rel_visible = (j->alias != NULL); |
- |
| 1724 |
- |
nsitem->p_cols_visible = true; |
- |
| 1725 |
- |
nsitem->p_lateral_only = false; |
- |
| 1726 |
- |
nsitem->p_lateral_ok = true; |
- |
| 1727 |
- |
|
- |
| 1728 |
- |
*top_nsitem = nsitem; |
- |
| 1729 |
- |
*namespace = lappend(my_namespace, nsitem); |
- |
| 1730 |
- |
|
- |
| 1731 |
- |
return (Node *) j; |
- |
| 1732 |
- |
} |
- |
| 1733 |
- |
else |
- |
| 1734 |
- |
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(n)); |
- |
| 1735 |
- |
return NULL; /* can't get here, keep compiler quiet */ |
- |
| 1736 |
- |
} |
- |