📄 pathnode.c
字号:
/*------------------------------------------------------------------------- * * pathnode.c * Routines to manipulate pathlists and create path nodes * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.42.2.1 1999/08/02 06:27:08 scrappy Exp $ * *------------------------------------------------------------------------- */#include <math.h>#include "postgres.h"#include "optimizer/cost.h"#include "optimizer/keys.h"#include "optimizer/ordering.h"#include "optimizer/pathnode.h"#include "optimizer/paths.h"#include "optimizer/plancat.h"#include "optimizer/restrictinfo.h"#include "parser/parsetree.h"static Path *better_path(Path *new_path, List *unique_paths, bool *is_new);/***************************************************************************** * MISC. PATH UTILITIES *****************************************************************************//* * path_is_cheaper * Returns t iff 'path1' is cheaper than 'path2'. * */boolpath_is_cheaper(Path *path1, Path *path2){ Cost cost1 = path1->path_cost; Cost cost2 = path2->path_cost; return (bool) (cost1 < cost2);}/* * set_cheapest * Finds the minimum cost path from among a relation's paths. * * 'parent_rel' is the parent relation * 'pathlist' is a list of path nodes corresponding to 'parent_rel' * * Returns and sets the relation entry field with the pathnode that * is minimum. * */Path *set_cheapest(RelOptInfo *parent_rel, List *pathlist){ List *p; Path *cheapest_so_far; Assert(pathlist != NIL); Assert(IsA(parent_rel, RelOptInfo)); cheapest_so_far = (Path *) lfirst(pathlist); foreach(p, lnext(pathlist)) { Path *path = (Path *) lfirst(p); if (path_is_cheaper(path, cheapest_so_far)) cheapest_so_far = path; } parent_rel->cheapestpath = cheapest_so_far; return cheapest_so_far;}/* * add_pathlist * For each path in the list 'new_paths', add to the list 'unique_paths' * only those paths that are unique (i.e., unique ordering and ordering * keys). Should a conflict arise, the more expensive path is thrown out, * thereby pruning the plan space. But we don't prune if xfunc * told us not to. * * 'parent_rel' is the relation entry to which these paths correspond. * * Returns the list of unique pathnodes. * */List *add_pathlist(RelOptInfo *parent_rel, List *unique_paths, List *new_paths){ List *p1; foreach(p1, new_paths) { Path *new_path = (Path *) lfirst(p1); Path *old_path; bool is_new; /* Is this new path already in unique_paths? */ if (member(new_path, unique_paths)) continue; /* Find best matching path */ old_path = better_path(new_path, unique_paths, &is_new); if (is_new) { /* This is a brand new path. */ new_path->parent = parent_rel; unique_paths = lcons(new_path, unique_paths); } else if (old_path == NULL) { ; /* do nothing if path is not cheaper */ } else if (old_path != NULL) { /* (IsA(old_path,Path)) { */ new_path->parent = parent_rel; if (!parent_rel->pruneable) unique_paths = lcons(new_path, unique_paths); else unique_paths = lcons(new_path, LispRemove(old_path, unique_paths)); } } return unique_paths;}/* * better_path * Determines whether 'new_path' has the same ordering and keys as some * path in the list 'unique_paths'. If there is a redundant path, * eliminate the more expensive path. * * Returns: * The old path - if 'new_path' matches some path in 'unique_paths' and is * cheaper * nil - if 'new_path' matches but isn't cheaper * t - if there is no path in the list with the same ordering and keys * */static Path *better_path(Path *new_path, List *unique_paths, bool *is_new){ Path *path = (Path *) NULL; List *temp = NIL; int better_key; int better_sort;#ifdef OPTDUP_DEBUG printf("better_path entry\n"); printf("new\n"); pprint(new_path); printf("unique_paths\n"); pprint(unique_paths);#endif foreach(temp, unique_paths) { path = (Path *) lfirst(temp);#ifdef OPTDUP_DEBUG if (!pathkeys_match(new_path->pathkeys, path->pathkeys, &better_key) || better_key != 0) { printf("betterkey = %d\n", better_key); printf("newpath\n"); pprint(new_path->pathkeys); printf("oldpath\n"); pprint(path->pathkeys); if (path->pathkeys && new_path->pathkeys && length(lfirst(path->pathkeys)) >= 2 /* && * length(lfirst(path->pa * thkeys)) < * length(lfirst(new_path ->pathkeys)) */ ) sleep(0); /* set breakpoint here */ } if (!pathorder_match(new_path->pathorder, path->pathorder, &better_sort) || better_sort != 0) { printf("neword\n"); pprint(new_path->pathorder); printf("oldord\n"); pprint(path->pathorder); }#endif if (pathkeys_match(new_path->pathkeys, path->pathkeys, &better_key) && pathorder_match(new_path->pathorder, path->pathorder, &better_sort)) { /* * Replace pathkeys that match exactly, {{1,2}}, {{1,2}} * Replace pathkeys {{1,2}} with {{1,2,3}}} if the latter is * not more expensive and replace unordered path with ordered * path if it is not more expensive. Favor sorted keys over * unsorted keys in the same way. */ /* same keys, and new is cheaper, use it */ if ((better_key == 0 && better_sort == 0 && new_path->path_cost < path->path_cost) || /* new is better, and cheaper, use it */ (((better_key == 1 && better_sort != 2) || (better_key != 2 && better_sort == 1)) && new_path->path_cost <= path->path_cost)) {#ifdef OPTDUP_DEBUG printf("replace with new %p old %p better key %d better sort %d\n", &new_path, &path, better_key, better_sort); printf("new\n"); pprint(new_path); printf("old\n"); pprint(path);#endif *is_new = false; return path; } /* same keys, new is more expensive, stop */ if ((better_key == 0 && better_sort == 0 && new_path->path_cost >= path->path_cost) || /* old is better, and less expensive, stop */ (((better_key == 2 && better_sort != 1) || (better_key != 1 && better_sort == 2)) && new_path->path_cost >= path->path_cost)) {#ifdef OPTDUP_DEBUG printf("skip new %p old %p better key %d better sort %d\n", &new_path, &path, better_key, better_sort); printf("new\n"); pprint(new_path); printf("old\n"); pprint(path);#endif *is_new = false; return NULL; } } }#ifdef OPTDUP_DEBUG printf("add new %p old %p better key %d better sort %d\n", &new_path, &path, better_key, better_sort); printf("new\n"); pprint(new_path);#endif *is_new = true; return NULL;}/***************************************************************************** * PATH NODE CREATION ROUTINES *****************************************************************************//* * create_seqscan_path * Creates a path corresponding to a sequential scan, returning the * pathnode. * */Path *create_seqscan_path(RelOptInfo *rel){ int relid = 0; Path *pathnode = makeNode(Path); pathnode->pathtype = T_SeqScan; pathnode->parent = rel; pathnode->path_cost = 0.0; pathnode->pathorder = makeNode(PathOrder); pathnode->pathorder->ordtype = SORTOP_ORDER; pathnode->pathorder->ord.sortop = NULL; pathnode->pathkeys = NIL; /* * copy restrictinfo list into path for expensive function processing * JMH, 7/7/92 */ pathnode->loc_restrictinfo = (List *) copyObject((Node *) rel->restrictinfo); if (rel->relids != NULL) relid = lfirsti(rel->relids); pathnode->path_cost = cost_seqscan(relid, rel->pages, rel->tuples); /* add in expensive functions cost! -- JMH, 7/7/92 */#ifdef NOT_USED if (XfuncMode != XFUNC_OFF) pathnode->path_cost += xfunc_get_path_cost(pathnode);#endif return pathnode;}/* * create_index_path * Creates a single path node for an index scan. * * 'rel' is the parent rel * 'index' is the pathnode for the index on 'rel' * 'restriction_clauses' is a list of restriction clause nodes. * 'is_join_scan' is a flag indicating whether or not the index is being * considered because of its sort order. * * Returns the new path node. * */IndexPath *create_index_path(Query *root,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -