|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.46 2000/04/12 17:15:21 momjian Exp $ |
| 11 | + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.46.2.1 2000/09/23 23:50:47 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
15 | 15 | #include <sys/types.h>
|
16 | 16 |
|
17 | 17 | #include "postgres.h"
|
| 18 | +#include "catalog/pg_operator.h" |
18 | 19 | #include "catalog/pg_type.h"
|
19 | 20 | #include "nodes/makefuncs.h"
|
20 | 21 | #include "optimizer/clauses.h"
|
|
25 | 26 | #include "optimizer/planmain.h"
|
26 | 27 | #include "optimizer/tlist.h"
|
27 | 28 | #include "optimizer/var.h"
|
| 29 | +#include "parser/parse_expr.h" |
| 30 | +#include "parser/parse_oper.h" |
| 31 | +#include "parser/parse_type.h" |
28 | 32 | #include "utils/lsyscache.h"
|
29 | 33 |
|
30 | 34 |
|
@@ -280,6 +284,113 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
|
280 | 284 | }
|
281 | 285 | }
|
282 | 286 |
|
| 287 | +/* |
| 288 | + * process_implied_equality |
| 289 | + * Check to see whether we already have a restrictinfo item that says |
| 290 | + * item1 = item2, and create one if not. This is a consequence of |
| 291 | + * transitivity of mergejoin equality: if we have mergejoinable |
| 292 | + * clauses A = B and B = C, we can deduce A = C (where = is an |
| 293 | + * appropriate mergejoinable operator). |
| 294 | + */ |
| 295 | +void |
| 296 | +process_implied_equality(Query *root, Node *item1, Node *item2, |
| 297 | + Oid sortop1, Oid sortop2) |
| 298 | +{ |
| 299 | + Index irel1; |
| 300 | + Index irel2; |
| 301 | + RelOptInfo *rel1; |
| 302 | + List *restrictlist; |
| 303 | + List *itm; |
| 304 | + Oid ltype, |
| 305 | + rtype; |
| 306 | + Operator eq_operator; |
| 307 | + Form_pg_operator pgopform; |
| 308 | + Expr *clause; |
| 309 | + |
| 310 | + /* |
| 311 | + * Currently, since check_mergejoinable only accepts Var = Var clauses, |
| 312 | + * we should only see Var nodes here. Would have to work a little |
| 313 | + * harder to locate the right rel(s) if more-general mergejoin clauses |
| 314 | + * were accepted. |
| 315 | + */ |
| 316 | + Assert(IsA(item1, Var)); |
| 317 | + irel1 = ((Var *) item1)->varno; |
| 318 | + Assert(IsA(item2, Var)); |
| 319 | + irel2 = ((Var *) item2)->varno; |
| 320 | + /* |
| 321 | + * If both vars belong to same rel, we need to look at that rel's |
| 322 | + * baserestrictinfo list. If different rels, each will have a |
| 323 | + * joininfo node for the other, and we can scan either list. |
| 324 | + */ |
| 325 | + rel1 = get_base_rel(root, irel1); |
| 326 | + if (irel1 == irel2) |
| 327 | + restrictlist = rel1->baserestrictinfo; |
| 328 | + else |
| 329 | + { |
| 330 | + JoinInfo *joininfo = find_joininfo_node(rel1, |
| 331 | + lconsi(irel2, NIL)); |
| 332 | + |
| 333 | + restrictlist = joininfo->jinfo_restrictinfo; |
| 334 | + } |
| 335 | + /* |
| 336 | + * Scan to see if equality is already known. |
| 337 | + */ |
| 338 | + foreach(itm, restrictlist) |
| 339 | + { |
| 340 | + RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(itm); |
| 341 | + Node *left, |
| 342 | + *right; |
| 343 | + |
| 344 | + if (restrictinfo->mergejoinoperator == InvalidOid) |
| 345 | + continue; /* ignore non-mergejoinable clauses */ |
| 346 | + /* We now know the restrictinfo clause is a binary opclause */ |
| 347 | + left = (Node *) get_leftop(restrictinfo->clause); |
| 348 | + right = (Node *) get_rightop(restrictinfo->clause); |
| 349 | + if ((equal(item1, left) && equal(item2, right)) || |
| 350 | + (equal(item2, left) && equal(item1, right))) |
| 351 | + return; /* found a matching clause */ |
| 352 | + } |
| 353 | + /* |
| 354 | + * This equality is new information, so construct a clause |
| 355 | + * representing it to add to the query data structures. |
| 356 | + */ |
| 357 | + ltype = exprType(item1); |
| 358 | + rtype = exprType(item2); |
| 359 | + eq_operator = oper("=", ltype, rtype, true); |
| 360 | + if (!HeapTupleIsValid(eq_operator)) |
| 361 | + { |
| 362 | + /* |
| 363 | + * Would it be safe to just not add the equality to the query if |
| 364 | + * we have no suitable equality operator for the combination of |
| 365 | + * datatypes? NO, because sortkey selection may screw up anyway. |
| 366 | + */ |
| 367 | + elog(ERROR, "Unable to identify an equality operator for types '%s' and '%s'", |
| 368 | + typeidTypeName(ltype), typeidTypeName(rtype)); |
| 369 | + } |
| 370 | + pgopform = (Form_pg_operator) GETSTRUCT(eq_operator); |
| 371 | + /* |
| 372 | + * Let's just make sure this appears to be a compatible operator. |
| 373 | + */ |
| 374 | + if (pgopform->oprlsortop != sortop1 || |
| 375 | + pgopform->oprrsortop != sortop2 || |
| 376 | + pgopform->oprresult != BOOLOID) |
| 377 | + elog(ERROR, "Equality operator for types '%s' and '%s' should be mergejoinable, but isn't", |
| 378 | + typeidTypeName(ltype), typeidTypeName(rtype)); |
| 379 | + |
| 380 | + clause = makeNode(Expr); |
| 381 | + clause->typeOid = BOOLOID; |
| 382 | + clause->opType = OP_EXPR; |
| 383 | + clause->oper = (Node *) makeOper(oprid(eq_operator), /* opno */ |
| 384 | + InvalidOid, /* opid */ |
| 385 | + BOOLOID, /* operator result type */ |
| 386 | + 0, |
| 387 | + NULL); |
| 388 | + clause->args = lcons(item1, lcons(item2, NIL)); |
| 389 | + |
| 390 | + add_restrict_and_join_to_rel(root, (Node *) clause); |
| 391 | +} |
| 392 | + |
| 393 | + |
283 | 394 | /*****************************************************************************
|
284 | 395 | *
|
285 | 396 | * CHECKS FOR MERGEJOINABLE AND HASHJOINABLE CLAUSES
|
|
0 commit comments