diff options
author | Bruce Momjian <bruce@momjian.us> | 1997-09-07 05:04:48 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 1997-09-07 05:04:48 +0000 |
commit | 1ccd423235a48739d6f7a4d7889705b5f9ecc69b (patch) | |
tree | 8001c4e839dfad8f29ceda7f8c5f5dbb8759b564 /src/backend/optimizer | |
parent | 8fecd4febf8357f3cc20383ed29ced484877d5ac (diff) |
Massive commit to run PGINDENT on all *.c and *.h files.
Diffstat (limited to 'src/backend/optimizer')
51 files changed, 14668 insertions, 13185 deletions
diff --git a/src/backend/optimizer/geqo/geqo_copy.c b/src/backend/optimizer/geqo/geqo_copy.c index 3356f8d5475..4c35f99f9f5 100644 --- a/src/backend/optimizer/geqo/geqo_copy.c +++ b/src/backend/optimizer/geqo/geqo_copy.c @@ -4,32 +4,32 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: geqo_copy.c,v 1.1 1997/02/19 12:56:40 scrappy Exp $ + * $Id: geqo_copy.c,v 1.2 1997/09/07 04:43:01 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ /* this is adopted from D. Whitley's Genitor algorithm */ /*************************************************************/ -/* */ -/* Copyright (c) 1990 */ -/* Darrell L. Whitley */ -/* Computer Science Department */ -/* Colorado State University */ -/* */ -/* Permission is hereby granted to copy all or any part of */ -/* this program for free distribution. The author's name */ -/* and this copyright notice must be included in any copy. */ -/* */ +/* */ +/* Copyright (c) 1990 */ +/* Darrell L. Whitley */ +/* Computer Science Department */ +/* Colorado State University */ +/* */ +/* Permission is hereby granted to copy all or any part of */ +/* this program for free distribution. The author's name */ +/* and this copyright notice must be included in any copy. */ +/* */ /*************************************************************/ #include "postgres.h" @@ -52,16 +52,16 @@ /* geqo_copy-- * - * copies one gene to another + * copies one gene to another * */ void -geqo_copy (Chromosome *chromo1, Chromosome *chromo2, int string_length) +geqo_copy(Chromosome * chromo1, Chromosome * chromo2, int string_length) { - int i; + int i; - for (i=0; i<string_length; i++) - chromo1->string[i] = chromo2->string[i]; + for (i = 0; i < string_length; i++) + chromo1->string[i] = chromo2->string[i]; - chromo1->worth = chromo2->worth; + chromo1->worth = chromo2->worth; } diff --git a/src/backend/optimizer/geqo/geqo_cx.c b/src/backend/optimizer/geqo/geqo_cx.c index a3aa6fce4f4..dfde1bdc530 100644 --- a/src/backend/optimizer/geqo/geqo_cx.c +++ b/src/backend/optimizer/geqo/geqo_cx.c @@ -2,35 +2,35 @@ * * geqo_cx.c-- * -* cycle crossover [CX] routines; -* CX operator according to Oliver et al -* (Proc 2nd Int'l Conf on GA's) +* cycle crossover [CX] routines; +* CX operator according to Oliver et al +* (Proc 2nd Int'l Conf on GA's) * -* $Id: geqo_cx.c,v 1.1 1997/02/19 12:56:48 scrappy Exp $ +* $Id: geqo_cx.c,v 1.2 1997/09/07 04:43:02 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ /* the cx algorithm is adopted from Genitor : */ /*************************************************************/ -/* */ -/* Copyright (c) 1990 */ -/* Darrell L. Whitley */ -/* Computer Science Department */ -/* Colorado State University */ -/* */ -/* Permission is hereby granted to copy all or any part of */ -/* this program for free distribution. The author's name */ -/* and this copyright notice must be included in any copy. */ -/* */ +/* */ +/* Copyright (c) 1990 */ +/* Darrell L. Whitley */ +/* Computer Science Department */ +/* Colorado State University */ +/* */ +/* Permission is hereby granted to copy all or any part of */ +/* this program for free distribution. The author's name */ +/* and this copyright notice must be included in any copy. */ +/* */ /*************************************************************/ @@ -57,73 +57,81 @@ /* cx-- * - * cycle crossover + * cycle crossover */ int -cx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table) +cx(Gene * tour1, Gene * tour2, Gene * offspring, int num_gene, City * city_table) { - int i, start_pos, curr_pos; - int count = 0; - int num_diffs = 0; + int i, + start_pos, + curr_pos; + int count = 0; + int num_diffs = 0; - /* initialize city table */ - for (i=1; i<=num_gene; i++) { - city_table[i].used = 0; - city_table[tour2[i-1]].tour2_position = i-1; - city_table[tour1[i-1]].tour1_position = i-1; - } + /* initialize city table */ + for (i = 1; i <= num_gene; i++) + { + city_table[i].used = 0; + city_table[tour2[i - 1]].tour2_position = i - 1; + city_table[tour1[i - 1]].tour1_position = i - 1; + } - /* choose random cycle starting position */ - start_pos = geqo_randint(num_gene - 1, 0); + /* choose random cycle starting position */ + start_pos = geqo_randint(num_gene - 1, 0); - /* child inherits first city */ - offspring[start_pos] = tour1[start_pos]; + /* child inherits first city */ + offspring[start_pos] = tour1[start_pos]; - /* begin cycle with tour1 */ - curr_pos = start_pos; - city_table[(int) tour1[start_pos]].used = 1; + /* begin cycle with tour1 */ + curr_pos = start_pos; + city_table[(int) tour1[start_pos]].used = 1; - count++; + count++; - /* cx main part */ + /* cx main part */ /* STEP 1 */ - while (tour2[curr_pos] != tour1[start_pos]) { - city_table[(int) tour2[curr_pos]].used = 1; - curr_pos = city_table[(int) tour2[curr_pos]].tour1_position; - offspring[curr_pos] = tour1[curr_pos]; - count++; - } + while (tour2[curr_pos] != tour1[start_pos]) + { + city_table[(int) tour2[curr_pos]].used = 1; + curr_pos = city_table[(int) tour2[curr_pos]].tour1_position; + offspring[curr_pos] = tour1[curr_pos]; + count++; + } /* STEP 2 */ - /* failed to create a complete tour */ - if (count < num_gene) { - for (i=1; i<=num_gene; i++) { - if (!city_table[i].used) { - offspring[city_table[i].tour2_position] = - tour2[(int) city_table[i].tour2_position]; - count++; - } - } - } + /* failed to create a complete tour */ + if (count < num_gene) + { + for (i = 1; i <= num_gene; i++) + { + if (!city_table[i].used) + { + offspring[city_table[i].tour2_position] = + tour2[(int) city_table[i].tour2_position]; + count++; + } + } + } /* STEP 3 */ - /* still failed to create a complete tour */ - if (count < num_gene) { + /* still failed to create a complete tour */ + if (count < num_gene) + { - /* count the number of differences between mom and offspring */ - for (i=0; i<num_gene; i++) - if (tour1[i] != offspring[i]) num_diffs++; + /* count the number of differences between mom and offspring */ + for (i = 0; i < num_gene; i++) + if (tour1[i] != offspring[i]) + num_diffs++; - } - - return(num_diffs); - } + } + return (num_diffs); +} diff --git a/src/backend/optimizer/geqo/geqo_erx.c b/src/backend/optimizer/geqo/geqo_erx.c index 8c3c63d755c..9d0f93efe8c 100644 --- a/src/backend/optimizer/geqo/geqo_erx.c +++ b/src/backend/optimizer/geqo/geqo_erx.c @@ -1,33 +1,33 @@ /*------------------------------------------------------------------------ * * geqo_erx.c-- -* edge recombination crossover [ER] +* edge recombination crossover [ER] * -* $Id: geqo_erx.c,v 1.2 1997/06/06 00:37:23 scrappy Exp $ +* $Id: geqo_erx.c,v 1.3 1997/09/07 04:43:04 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ /* the edge recombination algorithm is adopted from Genitor : */ /*************************************************************/ -/* */ -/* Copyright (c) 1990 */ -/* Darrell L. Whitley */ -/* Computer Science Department */ -/* Colorado State University */ -/* */ -/* Permission is hereby granted to copy all or any part of */ -/* this program for free distribution. The author's name */ -/* and this copyright notice must be included in any copy. */ -/* */ +/* */ +/* Copyright (c) 1990 */ +/* Darrell L. Whitley */ +/* Computer Science Department */ +/* Colorado State University */ +/* */ +/* Permission is hereby granted to copy all or any part of */ +/* this program for free distribution. The author's name */ +/* and this copyright notice must be included in any copy. */ +/* */ /*************************************************************/ @@ -52,384 +52,441 @@ #include "optimizer/geqo_random.h" -static int gimme_edge (Gene gene1, Gene gene2, Edge *edge_table); -static void remove_gene(Gene gene, Edge edge, Edge *edge_table); -static Gene gimme_gene(Edge edge, Edge *edge_table); +static int gimme_edge(Gene gene1, Gene gene2, Edge * edge_table); +static void remove_gene(Gene gene, Edge edge, Edge * edge_table); +static Gene gimme_gene(Edge edge, Edge * edge_table); -static Gene edge_failure(Gene *gene, int index, Edge *edge_table, int num_gene); +static Gene edge_failure(Gene * gene, int index, Edge * edge_table, int num_gene); /* alloc_edge_table-- * - * allocate memory for edge table + * allocate memory for edge table * */ -Edge * +Edge * alloc_edge_table(int num_gene) { - Edge *edge_table; + Edge *edge_table; - /* palloc one extra location so that nodes numbered - 1..n can be indexed directly; 0 will not be used */ + /* + * palloc one extra location so that nodes numbered 1..n can be + * indexed directly; 0 will not be used + */ - edge_table = (Edge *) palloc ((num_gene+1)*sizeof(Edge)); + edge_table = (Edge *) palloc((num_gene + 1) * sizeof(Edge)); - return (edge_table); - } + return (edge_table); +} /* free_edge_table-- * - * deallocate memory of edge table + * deallocate memory of edge table * */ - void - free_edge_table(Edge *edge_table) - { - pfree(edge_table); - } +void +free_edge_table(Edge * edge_table) +{ + pfree(edge_table); +} /* gimme_edge_table-- * - * fills a data structure which represents the set of explicit - * edges between points in the (2) input genes + * fills a data structure which represents the set of explicit + * edges between points in the (2) input genes + * + * assumes circular tours and bidirectional edges * - * assumes circular tours and bidirectional edges - * - * gimme_edge() will set "shared" edges to negative values + * gimme_edge() will set "shared" edges to negative values * - * returns average number edges/city in range 2.0 - 4.0 - * where 2.0=homogeneous; 4.0=diverse + * returns average number edges/city in range 2.0 - 4.0 + * where 2.0=homogeneous; 4.0=diverse * */ float -gimme_edge_table (Gene *tour1, Gene *tour2, int num_gene, Edge *edge_table) +gimme_edge_table(Gene * tour1, Gene * tour2, int num_gene, Edge * edge_table) { - int i, index1, index2; - int edge_total; /* total number of unique edges in two genes */ - - /* at first clear the edge table's old data */ - for (i = 1; i <= num_gene; i++) { - edge_table[i].total_edges = 0; - edge_table[i].unused_edges = 0; + int i, + index1, + index2; + int edge_total; /* total number of unique edges in two + * genes */ + + /* at first clear the edge table's old data */ + for (i = 1; i <= num_gene; i++) + { + edge_table[i].total_edges = 0; + edge_table[i].unused_edges = 0; } - /* fill edge table with new data */ + /* fill edge table with new data */ - edge_total = 0; + edge_total = 0; - for (index1 = 0; index1 < num_gene; index1++) { + for (index1 = 0; index1 < num_gene; index1++) + { - /* presume the tour is circular, i.e. 1->2, 2->3, 3->1 - this operaton maps n back to 1 */ + /* + * presume the tour is circular, i.e. 1->2, 2->3, 3->1 this + * operaton maps n back to 1 + */ - index2 = (index1 + 1) % num_gene; + index2 = (index1 + 1) % num_gene; - /* edges are bidirectional, i.e. 1->2 is same as 2->1 - call gimme_edge twice per edge */ + /* + * edges are bidirectional, i.e. 1->2 is same as 2->1 call + * gimme_edge twice per edge + */ - edge_total += gimme_edge(tour1[index1], tour1[index2], edge_table); - gimme_edge(tour1[index2], tour1[index1], edge_table); + edge_total += gimme_edge(tour1[index1], tour1[index2], edge_table); + gimme_edge(tour1[index2], tour1[index1], edge_table); - edge_total += gimme_edge(tour2[index1], tour2[index2], edge_table); - gimme_edge(tour2[index2], tour2[index1], edge_table); - } + edge_total += gimme_edge(tour2[index1], tour2[index2], edge_table); + gimme_edge(tour2[index2], tour2[index1], edge_table); + } - /* return average number of edges per index */ - return (((float) (edge_total * 2)/ (float) num_gene)); + /* return average number of edges per index */ + return (((float) (edge_total * 2) / (float) num_gene)); } /* gimme_edge-- * - * registers edge from city1 to city2 in input edge table + * registers edge from city1 to city2 in input edge table * - * no assumptions about directionality are made; - * therefor it is up to the calling routine to - * call gimme_edge twice to make a bi-directional edge - * between city1 and city2; - * uni-directional edges are possible as well (just call gimme_edge - * once with the direction from city1 to city2) + * no assumptions about directionality are made; + * therefor it is up to the calling routine to + * call gimme_edge twice to make a bi-directional edge + * between city1 and city2; + * uni-directional edges are possible as well (just call gimme_edge + * once with the direction from city1 to city2) * - * returns 1 if edge was not already registered and was just added; - * 0 if edge was already registered and edge_table is unchanged + * returns 1 if edge was not already registered and was just added; + * 0 if edge was already registered and edge_table is unchanged */ static int -gimme_edge (Gene gene1, Gene gene2, Edge *edge_table) +gimme_edge(Gene gene1, Gene gene2, Edge * edge_table) { - int i; - int edges; - int city1 = (int) gene1; - int city2 = (int) gene2; + int i; + int edges; + int city1 = (int) gene1; + int city2 = (int) gene2; - /* check whether edge city1->city2 already exists */ - edges = edge_table[city1].total_edges; + /* check whether edge city1->city2 already exists */ + edges = edge_table[city1].total_edges; - for (i=0; i<edges; i++) { - if ((Gene) Abs(edge_table[city1].edge_list[i]) == city2) { + for (i = 0; i < edges; i++) + { + if ((Gene) Abs(edge_table[city1].edge_list[i]) == city2) + { - /* mark shared edges as negative */ - edge_table[city1].edge_list[i] = 0-city2; + /* mark shared edges as negative */ + edge_table[city1].edge_list[i] = 0 - city2; - return (0); - } - } + return (0); + } + } - /* add city1->city2; */ - edge_table[city1].edge_list[edges] = city2; + /* add city1->city2; */ + edge_table[city1].edge_list[edges] = city2; - /* increment the number of edges from city1 */ - edge_table[city1].total_edges++; - edge_table[city1].unused_edges++; + /* increment the number of edges from city1 */ + edge_table[city1].total_edges++; + edge_table[city1].unused_edges++; - return (1); + return (1); } /* gimme_tour-- * - * creates a new tour using edges from the edge table. - * priority is given to "shared" edges (i.e. edges which - * all parent genes possess and are marked as negative - * in the edge table.) + * creates a new tour using edges from the edge table. + * priority is given to "shared" edges (i.e. edges which + * all parent genes possess and are marked as negative + * in the edge table.) * */ int -gimme_tour (Edge *edge_table, Gene *new_gene, int num_gene) +gimme_tour(Edge * edge_table, Gene * new_gene, int num_gene) { - int i; - int edge_failures=0; + int i; + int edge_failures = 0; - new_gene[0] = (Gene) geqo_randint(num_gene, 1); /* choose int between 1 and num_gene */ + new_gene[0] = (Gene) geqo_randint(num_gene, 1); /* choose int between 1 + * and num_gene */ - for (i=1; i<num_gene; i++) { - - /* as each point is entered into the tour, - remove it from the edge table */ + for (i = 1; i < num_gene; i++) + { - remove_gene(new_gene[i-1], edge_table[(int) new_gene[i-1]], edge_table); - - /* find destination for the newly entered point */ + /* + * as each point is entered into the tour, remove it from the edge + * table + */ - if (edge_table[new_gene[i-1]].unused_edges > 0) { - new_gene[i] = gimme_gene(edge_table[(int) new_gene[i-1]], edge_table); - } + remove_gene(new_gene[i - 1], edge_table[(int) new_gene[i - 1]], edge_table); - else { /* cope with fault */ - edge_failures++; + /* find destination for the newly entered point */ - new_gene[i] = edge_failure(new_gene, i-1, edge_table, num_gene); - } + if (edge_table[new_gene[i - 1]].unused_edges > 0) + { + new_gene[i] = gimme_gene(edge_table[(int) new_gene[i - 1]], edge_table); + } - /* mark this node as incorporated */ - edge_table[(int) new_gene[i-1]].unused_edges = -1; + else + { /* cope with fault */ + edge_failures++; - } /* for (i=1; i<num_gene; i++) */ + new_gene[i] = edge_failure(new_gene, i - 1, edge_table, num_gene); + } -return(edge_failures); + /* mark this node as incorporated */ + edge_table[(int) new_gene[i - 1]].unused_edges = -1; + + } /* for (i=1; i<num_gene; i++) */ + + return (edge_failures); } /* remove_gene-- * - * removes input gene from edge_table. - * input edge is used - * to identify deletion locations within edge table. + * removes input gene from edge_table. + * input edge is used + * to identify deletion locations within edge table. * */ static void -remove_gene (Gene gene, Edge edge, Edge *edge_table) +remove_gene(Gene gene, Edge edge, Edge * edge_table) { - int i,j; - int possess_edge; - int genes_remaining; + int i, + j; + int possess_edge; + int genes_remaining; - /* do for every gene known to have an edge to input gene - (i.e. in edge_list for input edge) */ + /* + * do for every gene known to have an edge to input gene (i.e. in + * edge_list for input edge) + */ - for (i=0; i<edge.unused_edges; i++) { - possess_edge = (int) Abs(edge.edge_list[i]); - genes_remaining = edge_table[possess_edge].unused_edges; + for (i = 0; i < edge.unused_edges; i++) + { + possess_edge = (int) Abs(edge.edge_list[i]); + genes_remaining = edge_table[possess_edge].unused_edges; - /* find the input gene in all edge_lists and delete it */ - for (j=0; j<genes_remaining; j++) { + /* find the input gene in all edge_lists and delete it */ + for (j = 0; j < genes_remaining; j++) + { - if ( (Gene) Abs(edge_table[possess_edge].edge_list[j]) == gene) { + if ((Gene) Abs(edge_table[possess_edge].edge_list[j]) == gene) + { - edge_table[possess_edge].unused_edges--; + edge_table[possess_edge].unused_edges--; - edge_table[possess_edge].edge_list[j] = - edge_table[possess_edge].edge_list[genes_remaining-1]; + edge_table[possess_edge].edge_list[j] = + edge_table[possess_edge].edge_list[genes_remaining - 1]; - break; - } + break; + } } - } + } } /* gimme_gene-- * - * priority is given to "shared" edges - * (i.e. edges which both genes possess) + * priority is given to "shared" edges + * (i.e. edges which both genes possess) * */ -static Gene -gimme_gene (Edge edge, Edge *edge_table) +static Gene +gimme_gene(Edge edge, Edge * edge_table) { - int i; - Gene friend; - int minimum_edges; - int minimum_count = -1; - int rand_decision; - - /* no point has edges to more than 4 other points - thus, this contrived minimum will be replaced */ - - minimum_edges = 5; - - /* consider candidate destination points in edge list */ - - for (i=0; i<edge.unused_edges; i++) { - friend = (Gene) edge.edge_list[i]; - - /* give priority to shared edges that are negative; - so return 'em */ - - /* negative values are caught here - so we need not worry about converting to absolute values */ - if (friend < 0) return ( (Gene) Abs(friend)); - - - /* give priority to candidates with fewest remaining unused edges; - find out what the minimum number of unused edges is (minimum_edges); - if there is more than one cadidate with the minimum number - of unused edges keep count of this number (minimum_count); */ - - /* The test for minimum_count can probably be removed at some - point but comments should probably indicate exactly why it - is guaranteed that the test will always succeed the first - time around. If it can fail then the code is in error */ - - - if (edge_table[(int) friend].unused_edges < minimum_edges) { - minimum_edges = edge_table[(int) friend].unused_edges; - minimum_count = 1; + int i; + Gene friend; + int minimum_edges; + int minimum_count = -1; + int rand_decision; + + /* + * no point has edges to more than 4 other points thus, this contrived + * minimum will be replaced + */ + + minimum_edges = 5; + + /* consider candidate destination points in edge list */ + + for (i = 0; i < edge.unused_edges; i++) + { + friend = (Gene) edge.edge_list[i]; + + /* + * give priority to shared edges that are negative; so return 'em + */ + + /* + * negative values are caught here so we need not worry about + * converting to absolute values + */ + if (friend < 0) + return ((Gene) Abs(friend)); + + + /* + * give priority to candidates with fewest remaining unused edges; + * find out what the minimum number of unused edges is + * (minimum_edges); if there is more than one cadidate with the + * minimum number of unused edges keep count of this number + * (minimum_count); + */ + + /* + * The test for minimum_count can probably be removed at some + * point but comments should probably indicate exactly why it is + * guaranteed that the test will always succeed the first time + * around. If it can fail then the code is in error + */ + + + if (edge_table[(int) friend].unused_edges < minimum_edges) + { + minimum_edges = edge_table[(int) friend].unused_edges; + minimum_count = 1; } - else - if (minimum_count == -1) - elog(WARN, "gimme_gene: Internal error - minimum_count not set"); - else - if (edge_table[(int) friend].unused_edges == minimum_edges) - minimum_count++; + else if (minimum_count == -1) + elog(WARN, "gimme_gene: Internal error - minimum_count not set"); + else if (edge_table[(int) friend].unused_edges == minimum_edges) + minimum_count++; + + } /* for (i=0; i<edge.unused_edges; i++) */ - } /* for (i=0; i<edge.unused_edges; i++) */ - - /* random decision of the possible candidates to use */ - rand_decision = (int) geqo_randint(minimum_count-1, 0); + /* random decision of the possible candidates to use */ + rand_decision = (int) geqo_randint(minimum_count - 1, 0); - - for (i=0; i<edge.unused_edges; i++) { - friend = (Gene) edge.edge_list[i]; - /* return the chosen candidate point */ - if (edge_table[(int) friend].unused_edges == minimum_edges) { - minimum_count--; + for (i = 0; i < edge.unused_edges; i++) + { + friend = (Gene) edge.edge_list[i]; - if ( minimum_count == rand_decision ) return (friend); + /* return the chosen candidate point */ + if (edge_table[(int) friend].unused_edges == minimum_edges) + { + minimum_count--; + + if (minimum_count == rand_decision) + return (friend); } } - /* ... should never be reached */ - elog(WARN,"gimme_gene: neither shared nor minimum number nor random edge found"); - return 0; /* to keep the compiler quiet */ + /* ... should never be reached */ + elog(WARN, "gimme_gene: neither shared nor minimum number nor random edge found"); + return 0; /* to keep the compiler quiet */ } /* edge_failure-- * - * routine for handling edge failure + * routine for handling edge failure * */ -static Gene -edge_failure (Gene *gene, int index, Edge *edge_table, int num_gene) +static Gene +edge_failure(Gene * gene, int index, Edge * edge_table, int num_gene) { - int i; - Gene fail_gene = gene[index]; - int remaining_edges = 0; - int four_count = 0; - int rand_decision; - - - /* how many edges remain? - how many gene with four total (initial) edges remain? */ - - for (i=1; i<=num_gene; i++) { - if ( (edge_table[i].unused_edges != -1) && (i != (int) fail_gene) ) { - remaining_edges++; - - if (edge_table[i].total_edges == 4) four_count++; - } - } + int i; + Gene fail_gene = gene[index]; + int remaining_edges = 0; + int four_count = 0; + int rand_decision; + + + /* + * how many edges remain? how many gene with four total (initial) + * edges remain? + */ + + for (i = 1; i <= num_gene; i++) + { + if ((edge_table[i].unused_edges != -1) && (i != (int) fail_gene)) + { + remaining_edges++; + + if (edge_table[i].total_edges == 4) + four_count++; + } + } - /* random decision of the gene - with remaining edges and whose total_edges == 4 */ + /* + * random decision of the gene with remaining edges and whose + * total_edges == 4 + */ - if (four_count != 0 ) { + if (four_count != 0) + { - rand_decision = (int) geqo_randint(four_count-1, 0); + rand_decision = (int) geqo_randint(four_count - 1, 0); - for (i=1; i<=num_gene; i++) { + for (i = 1; i <= num_gene; i++) + { - if ((Gene) i != fail_gene && + if ((Gene) i != fail_gene && edge_table[i].unused_edges != -1 && - edge_table[i].total_edges==4) { + edge_table[i].total_edges == 4) + { four_count--; - if (rand_decision == four_count) return ((Gene) i); - } + if (rand_decision == four_count) + return ((Gene) i); } + } - elog(DEBUG,"edge_failure(1): no edge found via random decision and total_edges == 4"); + elog(DEBUG, "edge_failure(1): no edge found via random decision and total_edges == 4"); } - else /* random decision of the gene with remaining edges */ + else +/* random decision of the gene with remaining edges */ - if (remaining_edges != 0) { + if (remaining_edges != 0) + { - rand_decision = (int) geqo_randint(remaining_edges-1, 0); + rand_decision = (int) geqo_randint(remaining_edges - 1, 0); - for (i=1; i<=num_gene; i++) { + for (i = 1; i <= num_gene; i++) + { - if ((Gene) i != fail_gene && - edge_table[i].unused_edges != -1) { + if ((Gene) i != fail_gene && + edge_table[i].unused_edges != -1) + { remaining_edges--; - if (rand_decision == remaining_edges) return (i); - } + if (rand_decision == remaining_edges) + return (i); } - - elog(DEBUG,"edge_failure(2): no edge found via random decision and remainig edges"); } - /* edge table seems to be empty; this happens sometimes on - the last point due to the fact that the first point is - removed from the table even though only one of its edges - has been determined */ + elog(DEBUG, "edge_failure(2): no edge found via random decision and remainig edges"); + } - else { /* occurs only at the last point in the tour; - simply look for the point which is not yet used */ + /* + * edge table seems to be empty; this happens sometimes on the last + * point due to the fact that the first point is removed from the + * table even though only one of its edges has been determined + */ - for (i=1; i<=num_gene; i++) - if (edge_table[i].unused_edges >= 0) - return ((Gene) i); - - elog(DEBUG,"edge_failure(3): no edge found via looking for the last ununsed point"); + else + { /* occurs only at the last point in the + * tour; simply look for the point which + * is not yet used */ + + for (i = 1; i <= num_gene; i++) + if (edge_table[i].unused_edges >= 0) + return ((Gene) i); + + elog(DEBUG, "edge_failure(3): no edge found via looking for the last ununsed point"); } /* ... should never be reached */ - elog(WARN,"edge_failure: no edge detected"); - return 0; /* to keep the compiler quiet */ + elog(WARN, "edge_failure: no edge detected"); + return 0; /* to keep the compiler quiet */ } - diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c index 7ec449f2e94..ba34d8f3e02 100644 --- a/src/backend/optimizer/geqo/geqo_eval.c +++ b/src/backend/optimizer/geqo/geqo_eval.c @@ -1,20 +1,20 @@ /*------------------------------------------------------------------------ * * geqo_eval.c-- - * Routines to evaluate query trees + * Routines to evaluate query trees * * Copyright (c) 1994, Regents of the University of California * - * $Id: geqo_eval.c,v 1.12 1997/08/12 22:53:07 momjian Exp $ + * $Id: geqo_eval.c,v 1.13 1997/09/07 04:43:06 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ @@ -22,13 +22,13 @@ #include <math.h> #ifdef HAVE_LIMITS_H -# include <limits.h> -# ifndef MAXINT -# define MAXINT INT_MAX -# endif +#include <limits.h> +#ifndef MAXINT +#define MAXINT INT_MAX +#endif #else -# include <values.h> -#endif +#include <values.h> +#endif #include "nodes/pg_list.h" #include "nodes/relation.h" @@ -50,548 +50,598 @@ #include "optimizer/geqo_paths.h" -static List *gimme_clause_joins(Query *root, Rel *outer_rel, Rel *inner_rel); -static Rel *gimme_clauseless_join(Rel *outer_rel, Rel *inner_rel); -static Rel *init_join_rel(Rel *outer_rel, Rel *inner_rel, JInfo *joininfo); -static List *new_join_tlist(List *tlist, List *other_relids, int first_resdomno); -static List *new_joininfo_list(List *joininfo_list, List *join_relids); -static void geqo_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel); -static Rel *geqo_nth(int stop, List *rels); +static List *gimme_clause_joins(Query * root, Rel * outer_rel, Rel * inner_rel); +static Rel *gimme_clauseless_join(Rel * outer_rel, Rel * inner_rel); +static Rel *init_join_rel(Rel * outer_rel, Rel * inner_rel, JInfo * joininfo); +static List *new_join_tlist(List * tlist, List * other_relids, int first_resdomno); +static List *new_joininfo_list(List * joininfo_list, List * join_relids); +static void geqo_joinrel_size(Rel * joinrel, Rel * outer_rel, Rel * inner_rel); +static Rel *geqo_nth(int stop, List * rels); -/* +/* * geqo_eval-- - * + * * Returns cost of a query tree as an individual of the population. */ Cost -geqo_eval (Query *root, Gene *tour, int num_gene) +geqo_eval(Query * root, Gene * tour, int num_gene) { - Rel *joinrel; - Cost fitness; - List *temp; + Rel *joinrel; + Cost fitness; + List *temp; /* remember root->join_relation_list_ ... */ /* because root->join_relation_list_ will be changed during the following */ - temp = listCopy(root->join_relation_list_); + temp = listCopy(root->join_relation_list_); /* joinrel is readily processed query tree -- left-sided ! */ - joinrel = gimme_tree(root, tour, 0, num_gene, NULL); + joinrel = gimme_tree(root, tour, 0, num_gene, NULL); /* compute fitness */ - fitness = (Cost) joinrel->cheapestpath->path_cost; + fitness = (Cost) joinrel->cheapestpath->path_cost; - root->join_relation_list_ = listCopy(temp); + root->join_relation_list_ = listCopy(temp); - pfree(joinrel); - freeList(temp); + pfree(joinrel); + freeList(temp); - return(fitness); + return (fitness); } -/* +/* * gimme-tree -- - * this program presumes that only LEFT-SIDED TREES are considered! - * + * this program presumes that only LEFT-SIDED TREES are considered! + * * 'outer_rel' is the preceeding join - * + * * Returns a new join relation incorporating all joins in a left-sided tree. */ -Rel * -gimme_tree (Query *root, Gene *tour, int rel_count, int num_gene, Rel *outer_rel) +Rel * +gimme_tree(Query * root, Gene * tour, int rel_count, int num_gene, Rel * outer_rel) { - Rel *inner_rel; /* current relation */ - int base_rel_index; + Rel *inner_rel; /* current relation */ + int base_rel_index; - List *new_rels = NIL; - Rel *new_rel = NULL; + List *new_rels = NIL; + Rel *new_rel = NULL; - if (rel_count < num_gene ) { /* tree not yet finished */ + if (rel_count < num_gene) + { /* tree not yet finished */ - /* tour[0] = 3; tour[1] = 1; tour[2] = 2 */ - base_rel_index = (int) tour[rel_count]; + /* tour[0] = 3; tour[1] = 1; tour[2] = 2 */ + base_rel_index = (int) tour[rel_count]; - inner_rel = (Rel *) geqo_nth(base_rel_index,root->base_relation_list_); + inner_rel = (Rel *) geqo_nth(base_rel_index, root->base_relation_list_); - if (rel_count == 0) { /* processing first join with base_rel_index = (int) tour[0] */ - rel_count++; - return gimme_tree(root, tour, rel_count, num_gene, inner_rel); + if (rel_count == 0) + { /* processing first join with + * base_rel_index = (int) tour[0] */ + rel_count++; + return gimme_tree(root, tour, rel_count, num_gene, inner_rel); } - else { /* tree main part */ - - if(!(new_rels = gimme_clause_joins(root, outer_rel,inner_rel))) { - if (BushyPlanFlag) { - new_rels = lcons(gimme_clauseless_join(outer_rel,outer_rel),NIL); /* ??? MAU */ + else + { /* tree main part */ + + if (!(new_rels = gimme_clause_joins(root, outer_rel, inner_rel))) + { + if (BushyPlanFlag) + { + new_rels = lcons(gimme_clauseless_join(outer_rel, outer_rel), NIL); /* ??? MAU */ } - else { - new_rels = lcons(gimme_clauseless_join(outer_rel,inner_rel),NIL); + else + { + new_rels = lcons(gimme_clauseless_join(outer_rel, inner_rel), NIL); } } - /* process new_rel->pathlist */ - find_all_join_paths(root, new_rels); + /* process new_rel->pathlist */ + find_all_join_paths(root, new_rels); - /* prune new_rels */ - /* MAU: is this necessary? */ - /* what's the matter if more than one new rel is left till now? */ - /* joinrels in newrels with different ordering of relids are not possible */ - if (length(new_rels) > 1) new_rels = geqo_prune_rels(new_rels); + /* prune new_rels */ + /* MAU: is this necessary? */ - if (length(new_rels) > 1) { /* should never be reached ... */ - elog(DEBUG,"gimme_tree: still %d relations left", length(new_rels)); + /* + * what's the matter if more than one new rel is left till + * now? + */ + + /* + * joinrels in newrels with different ordering of relids are + * not possible + */ + if (length(new_rels) > 1) + new_rels = geqo_prune_rels(new_rels); + + if (length(new_rels) > 1) + { /* should never be reached ... */ + elog(DEBUG, "gimme_tree: still %d relations left", length(new_rels)); } - /* get essential new relation */ - new_rel = (Rel *) lfirst(new_rels); - rel_count++; + /* get essential new relation */ + new_rel = (Rel *) lfirst(new_rels); + rel_count++; - /* process new_rel->cheapestpath, new_rel->unorderedpath */ - geqo_rel_paths(new_rel); + /* process new_rel->cheapestpath, new_rel->unorderedpath */ + geqo_rel_paths(new_rel); - /* processing of other new_rel attributes */ - if ( new_rel->size <= 0 ) - new_rel->size = compute_rel_size(new_rel); - new_rel->width = compute_rel_width(new_rel); + /* processing of other new_rel attributes */ + if (new_rel->size <= 0) + new_rel->size = compute_rel_size(new_rel); + new_rel->width = compute_rel_width(new_rel); - root->join_relation_list_ = lcons(new_rel, NIL); + root->join_relation_list_ = lcons(new_rel, NIL); - return gimme_tree(root, tour, rel_count, num_gene, new_rel); + return gimme_tree(root, tour, rel_count, num_gene, new_rel); } } - return (outer_rel); /* tree finished ... */ + return (outer_rel); /* tree finished ... */ } -/* +/* * gimme-clause-joins-- * * 'outer-rel' is the relation entry for the outer relation * 'inner-rel' is the relation entry for the inner relation - * + * * Returns a list of new join relations. */ -static List * -gimme_clause_joins(Query *root, Rel *outer_rel, Rel *inner_rel) +static List * +gimme_clause_joins(Query * root, Rel * outer_rel, Rel * inner_rel) { - List *join_list = NIL; - List *i = NIL; - List *joininfo_list = (List *) outer_rel->joininfo; - - foreach (i, joininfo_list) { - JInfo *joininfo = (JInfo*)lfirst(i); - Rel *rel = NULL; - - if(!joininfo->inactive) { - List *other_rels = (List *)joininfo->otherrels; - - if(other_rels != NIL) { - if( (length(other_rels) == 1) ) { - - if( same(other_rels, inner_rel->relids) ) { /* look if inner_rel is it...*/ - rel = init_join_rel(outer_rel, inner_rel, joininfo); + List *join_list = NIL; + List *i = NIL; + List *joininfo_list = (List *) outer_rel->joininfo; + + foreach(i, joininfo_list) + { + JInfo *joininfo = (JInfo *) lfirst(i); + Rel *rel = NULL; + + if (!joininfo->inactive) + { + List *other_rels = (List *) joininfo->otherrels; + + if (other_rels != NIL) + { + if ((length(other_rels) == 1)) + { + + if (same(other_rels, inner_rel->relids)) + { /* look if inner_rel is it... */ + rel = init_join_rel(outer_rel, inner_rel, joininfo); } } - else if (BushyPlanFlag) { /* ?!? MAU */ - rel = init_join_rel(outer_rel, get_join_rel(root, other_rels), joininfo); - } - else { - rel = NULL; - } + else if (BushyPlanFlag) + { /* ?!? MAU */ + rel = init_join_rel(outer_rel, get_join_rel(root, other_rels), joininfo); + } + else + { + rel = NULL; + } - if (rel != NULL) - join_list = lappend(join_list, rel); + if (rel != NULL) + join_list = lappend(join_list, rel); } } } - return(join_list); + return (join_list); } -/* +/* * gimme-clauseless-join-- - * Given an outer relation 'outer-rel' and an inner relation - * 'inner-rel', create a join relation between 'outer-rel' and 'inner-rel' - * + * Given an outer relation 'outer-rel' and an inner relation + * 'inner-rel', create a join relation between 'outer-rel' and 'inner-rel' + * * Returns a new join relation. */ -static Rel * -gimme_clauseless_join(Rel *outer_rel, Rel *inner_rel) +static Rel * +gimme_clauseless_join(Rel * outer_rel, Rel * inner_rel) { - return(init_join_rel(outer_rel, inner_rel, (JInfo*)NULL)); + return (init_join_rel(outer_rel, inner_rel, (JInfo *) NULL)); } -/* +/* * init-join-rel-- - * Creates and initializes a new join relation. - * + * Creates and initializes a new join relation. + * * 'outer-rel' and 'inner-rel' are relation nodes for the relations to be - * joined + * joined * 'joininfo' is the joininfo node(join clause) containing both - * 'outer-rel' and 'inner-rel', if any exists - * + * 'outer-rel' and 'inner-rel', if any exists + * * Returns the new join relation node. */ -static Rel * -init_join_rel(Rel *outer_rel, Rel *inner_rel, JInfo *joininfo) +static Rel * +init_join_rel(Rel * outer_rel, Rel * inner_rel, JInfo * joininfo) { - Rel *joinrel = makeNode(Rel); - List *joinrel_joininfo_list = NIL; - List *new_outer_tlist; - List *new_inner_tlist; - - /* - * Create a new tlist by removing irrelevant elements from both - * tlists of the outer and inner join relations and then merging - * the results together. - */ - new_outer_tlist = - new_join_tlist(outer_rel->targetlist, /* XXX 1-based attnos */ - inner_rel->relids, 1); - new_inner_tlist = - new_join_tlist(inner_rel->targetlist, /* XXX 1-based attnos */ - outer_rel->relids, - length(new_outer_tlist) + 1); - - joinrel->relids = NIL; - joinrel->indexed = false; - joinrel->pages = 0; - joinrel->tuples = 0; - joinrel->width = 0; -/* joinrel->targetlist = NIL;*/ - joinrel->pathlist = NIL; - joinrel->unorderedpath = (Path *)NULL; - joinrel->cheapestpath = (Path *)NULL; - joinrel->pruneable = true; - joinrel->classlist = NULL; - joinrel->relam = InvalidOid; - joinrel->ordering = NULL; - joinrel->clauseinfo = NIL; - joinrel->joininfo = NULL; - joinrel->innerjoin = NIL; - joinrel->superrels = NIL; - - joinrel->relids = lcons(outer_rel->relids, lcons(inner_rel->relids, NIL)); - - new_outer_tlist = nconc(new_outer_tlist,new_inner_tlist); - joinrel->targetlist = new_outer_tlist; - - if (joininfo) { - joinrel->clauseinfo = joininfo->jinfoclauseinfo; - if (BushyPlanFlag) joininfo->inactive = true; - } - - joinrel_joininfo_list = - new_joininfo_list(append(outer_rel->joininfo, inner_rel->joininfo), - intAppend(outer_rel->relids, inner_rel->relids)); - - joinrel->joininfo = joinrel_joininfo_list; - - geqo_joinrel_size(joinrel, outer_rel, inner_rel); - - return(joinrel); + Rel *joinrel = makeNode(Rel); + List *joinrel_joininfo_list = NIL; + List *new_outer_tlist; + List *new_inner_tlist; + + /* + * Create a new tlist by removing irrelevant elements from both tlists + * of the outer and inner join relations and then merging the results + * together. + */ + new_outer_tlist = + new_join_tlist(outer_rel->targetlist, /* XXX 1-based attnos */ + inner_rel->relids, 1); + new_inner_tlist = + new_join_tlist(inner_rel->targetlist, /* XXX 1-based attnos */ + outer_rel->relids, + length(new_outer_tlist) + 1); + + joinrel->relids = NIL; + joinrel->indexed = false; + joinrel->pages = 0; + joinrel->tuples = 0; + joinrel->width = 0; +/* joinrel->targetlist = NIL;*/ + joinrel->pathlist = NIL; + joinrel->unorderedpath = (Path *) NULL; + joinrel->cheapestpath = (Path *) NULL; + joinrel->pruneable = true; + joinrel->classlist = NULL; + joinrel->relam = InvalidOid; + joinrel->ordering = NULL; + joinrel->clauseinfo = NIL; + joinrel->joininfo = NULL; + joinrel->innerjoin = NIL; + joinrel->superrels = NIL; + + joinrel->relids = lcons(outer_rel->relids, lcons(inner_rel->relids, NIL)); + + new_outer_tlist = nconc(new_outer_tlist, new_inner_tlist); + joinrel->targetlist = new_outer_tlist; + + if (joininfo) + { + joinrel->clauseinfo = joininfo->jinfoclauseinfo; + if (BushyPlanFlag) + joininfo->inactive = true; + } + + joinrel_joininfo_list = + new_joininfo_list(append(outer_rel->joininfo, inner_rel->joininfo), + intAppend(outer_rel->relids, inner_rel->relids)); + + joinrel->joininfo = joinrel_joininfo_list; + + geqo_joinrel_size(joinrel, outer_rel, inner_rel); + + return (joinrel); } -/* +/* * new-join-tlist-- - * Builds a join relations's target list by keeping those elements that - * will be in the final target list and any other elements that are still - * needed for future joins. For a target list entry to still be needed - * for future joins, its 'joinlist' field must not be empty after removal - * of all relids in 'other-relids'. - * + * Builds a join relations's target list by keeping those elements that + * will be in the final target list and any other elements that are still + * needed for future joins. For a target list entry to still be needed + * for future joins, its 'joinlist' field must not be empty after removal + * of all relids in 'other-relids'. + * * 'tlist' is the target list of one of the join relations * 'other-relids' is a list of relids contained within the other - * join relation + * join relation * 'first-resdomno' is the resdom number to use for the first created - * target list entry - * + * target list entry + * * Returns the new target list. */ -static List * -new_join_tlist(List *tlist, - List *other_relids, - int first_resdomno) +static List * +new_join_tlist(List * tlist, + List * other_relids, + int first_resdomno) { - int resdomno = first_resdomno - 1; - TargetEntry *xtl = NULL; - List *temp_node = NIL; - List *t_list = NIL; - List *i = NIL; - List *join_list = NIL; - bool in_final_tlist =false; - - - foreach(i,tlist) { - xtl= lfirst(i); - in_final_tlist = (join_list==NIL); - if( in_final_tlist) { - resdomno += 1; - temp_node = - lcons(create_tl_element(get_expr(xtl), - resdomno), - NIL); - t_list = nconc(t_list,temp_node); - } - } - - return(t_list); + int resdomno = first_resdomno - 1; + TargetEntry *xtl = NULL; + List *temp_node = NIL; + List *t_list = NIL; + List *i = NIL; + List *join_list = NIL; + bool in_final_tlist = false; + + + foreach(i, tlist) + { + xtl = lfirst(i); + in_final_tlist = (join_list == NIL); + if (in_final_tlist) + { + resdomno += 1; + temp_node = + lcons(create_tl_element(get_expr(xtl), + resdomno), + NIL); + t_list = nconc(t_list, temp_node); + } + } + + return (t_list); } -/* +/* * new-joininfo-list-- - * Builds a join relation's joininfo list by checking for join clauses - * which still need to used in future joins involving this relation. A - * join clause is still needed if there are still relations in the clause - * not contained in the list of relations comprising this join relation. - * New joininfo nodes are only created and added to - * 'current-joininfo-list' if a node for a particular join hasn't already - * been created. + * Builds a join relation's joininfo list by checking for join clauses + * which still need to used in future joins involving this relation. A + * join clause is still needed if there are still relations in the clause + * not contained in the list of relations comprising this join relation. + * New joininfo nodes are only created and added to + * 'current-joininfo-list' if a node for a particular join hasn't already + * been created. * - * 'current-joininfo-list' contains a list of those joininfo nodes that - * have already been built + * 'current-joininfo-list' contains a list of those joininfo nodes that + * have already been built * 'joininfo-list' is the list of join clauses involving this relation - * 'join-relids' is a list of relids corresponding to the relations - * currently being joined - * + * 'join-relids' is a list of relids corresponding to the relations + * currently being joined + * * Returns a list of joininfo nodes, new and old. */ -static List * -new_joininfo_list(List *joininfo_list, List *join_relids) +static List * +new_joininfo_list(List * joininfo_list, List * join_relids) { - List *current_joininfo_list = NIL; - List *new_otherrels = NIL; - JInfo *other_joininfo = (JInfo*)NULL; - List *xjoininfo = NIL; - - foreach (xjoininfo, joininfo_list) { - List *or; - JInfo *joininfo = (JInfo*)lfirst(xjoininfo); - - new_otherrels = joininfo->otherrels; - foreach (or, new_otherrels) - { - if ( intMember (lfirsti(or), join_relids) ) - new_otherrels = lremove ((void*)lfirst(or), new_otherrels); - } - joininfo->otherrels = new_otherrels; - if ( new_otherrels != NIL ) + List *current_joininfo_list = NIL; + List *new_otherrels = NIL; + JInfo *other_joininfo = (JInfo *) NULL; + List *xjoininfo = NIL; + + foreach(xjoininfo, joininfo_list) { - other_joininfo = joininfo_member(new_otherrels, - current_joininfo_list); - if(other_joininfo) { - other_joininfo->jinfoclauseinfo = - (List*)LispUnion(joininfo->jinfoclauseinfo, - other_joininfo->jinfoclauseinfo); - }else { - other_joininfo = makeNode(JInfo); - - other_joininfo->otherrels = - joininfo->otherrels; - other_joininfo->jinfoclauseinfo = - joininfo->jinfoclauseinfo; - other_joininfo->mergesortable = - joininfo->mergesortable; - other_joininfo->hashjoinable = - joininfo->hashjoinable; - other_joininfo->inactive = false; - - current_joininfo_list = lcons(other_joininfo, - current_joininfo_list); - } + List *or; + JInfo *joininfo = (JInfo *) lfirst(xjoininfo); + + new_otherrels = joininfo->otherrels; + foreach(or, new_otherrels) + { + if (intMember(lfirsti(or), join_relids)) + new_otherrels = lremove((void *) lfirst(or), new_otherrels); + } + joininfo->otherrels = new_otherrels; + if (new_otherrels != NIL) + { + other_joininfo = joininfo_member(new_otherrels, + current_joininfo_list); + if (other_joininfo) + { + other_joininfo->jinfoclauseinfo = + (List *) LispUnion(joininfo->jinfoclauseinfo, + other_joininfo->jinfoclauseinfo); + } + else + { + other_joininfo = makeNode(JInfo); + + other_joininfo->otherrels = + joininfo->otherrels; + other_joininfo->jinfoclauseinfo = + joininfo->jinfoclauseinfo; + other_joininfo->mergesortable = + joininfo->mergesortable; + other_joininfo->hashjoinable = + joininfo->hashjoinable; + other_joininfo->inactive = false; + + current_joininfo_list = lcons(other_joininfo, + current_joininfo_list); + } + } } - } - return(current_joininfo_list); + return (current_joininfo_list); } #ifdef NOTUSED /* * add-new-joininfos-- - * For each new join relation, create new joininfos that - * use the join relation as inner relation, and add - * the new joininfos to those rel nodes that still - * have joins with the join relation. + * For each new join relation, create new joininfos that + * use the join relation as inner relation, and add + * the new joininfos to those rel nodes that still + * have joins with the join relation. * * 'joinrels' is a list of join relations. * * Modifies the joininfo field of appropriate rel nodes. */ static void -geqo_add_new_joininfos(Query *root, List *joinrels, List *outerrels) +geqo_add_new_joininfos(Query * root, List * joinrels, List * outerrels) { - List *xjoinrel = NIL; - List *xrelid = NIL; - List *xrel = NIL; - List *xjoininfo = NIL; - - Rel *rel; - List *relids; - - List *super_rels; - List *xsuper_rel = NIL; - JInfo *new_joininfo; - - foreach(xjoinrel, joinrels) { - Rel *joinrel = (Rel *)lfirst(xjoinrel); - foreach(xrelid, joinrel->relids) { - /* length(joinrel->relids) should always be greater that 1, because of *JOIN* */ - /* ! BUG BUG ! - Relid relid = (Relid)lfirst(xrelid); - Rel *rel = get_join_rel(root, relid); - */ - - /* - if ( (root->join_relation_list_) != NIL ) { - rel = get_join_rel(root, xrelid); - } - else { - rel = get_base_rel(root, lfirsti(xrelid)); - } - */ - - /* NOTE: STILL BUGGY FOR CLAUSE-JOINS: */ - /* - relids = lconsi(lfirsti(xrelid), NIL); - rel = rel_member(relids, outerrels); - */ + List *xjoinrel = NIL; + List *xrelid = NIL; + List *xrel = NIL; + List *xjoininfo = NIL; + + Rel *rel; + List *relids; + + List *super_rels; + List *xsuper_rel = NIL; + JInfo *new_joininfo; + + foreach(xjoinrel, joinrels) + { + Rel *joinrel = (Rel *) lfirst(xjoinrel); + + foreach(xrelid, joinrel->relids) + { + + /* + * length(joinrel->relids) should always be greater that 1, + * because of *JOIN* + */ + + /* + * ! BUG BUG ! Relid relid = (Relid)lfirst(xrelid); Rel *rel = + * get_join_rel(root, relid); + */ - relids = lconsi(lfirsti(xrelid), NIL); - rel = rel_member(relids, root->base_relation_list_); + /* + * if ( (root->join_relation_list_) != NIL ) { rel = + * get_join_rel(root, xrelid); } else { rel = + * get_base_rel(root, lfirsti(xrelid)); } + */ - add_superrels(rel,joinrel); + /* NOTE: STILL BUGGY FOR CLAUSE-JOINS: */ + + /* + * relids = lconsi(lfirsti(xrelid), NIL); rel = + * rel_member(relids, outerrels); + */ + + relids = lconsi(lfirsti(xrelid), NIL); + rel = rel_member(relids, root->base_relation_list_); + + add_superrels(rel, joinrel); + } } - } - foreach(xjoinrel, joinrels) { - Rel *joinrel = (Rel *)lfirst(xjoinrel); - - foreach(xjoininfo, joinrel->joininfo) { - JInfo *joininfo = (JInfo*)lfirst(xjoininfo); - List *other_rels = joininfo->otherrels; - List *clause_info = joininfo->jinfoclauseinfo; - bool mergesortable = joininfo->mergesortable; - bool hashjoinable = joininfo->hashjoinable; - - foreach(xrelid, other_rels) { - /* ! BUG BUG ! - Relid relid = (Relid)lfirst(xrelid); - Rel *rel = get_join_rel(root, relid); - */ - - /* - if ( (root->join_relation_list_) != NIL ) { - rel = get_join_rel(root, xrelid); - } - else { - rel = get_base_rel(root, lfirsti(xrelid)); - } - */ - - /* NOTE: STILL BUGGY FOR CLAUSE-JOINS: */ - /* - relids = lconsi(lfirsti(xrelid), NIL); - rel = rel_member(relids, outerrels); - */ - - relids = lconsi(lfirsti(xrelid), NIL); - rel = rel_member(relids, root->base_relation_list_); - - super_rels = rel->superrels; - new_joininfo = makeNode(JInfo); - - new_joininfo->otherrels = joinrel->relids; - new_joininfo->jinfoclauseinfo = clause_info; - new_joininfo->mergesortable = mergesortable; - new_joininfo->hashjoinable = hashjoinable; - new_joininfo->inactive = false; - rel->joininfo = - lappend(rel->joininfo, new_joininfo); - - foreach(xsuper_rel, super_rels) { - Rel *super_rel = (Rel *)lfirst(xsuper_rel); - - if( nonoverlap_rels(super_rel,joinrel) ) { - List *new_relids = super_rel->relids; - JInfo *other_joininfo = - joininfo_member(new_relids, - joinrel->joininfo); - - if (other_joininfo) { - other_joininfo->jinfoclauseinfo = - (List*)LispUnion(clause_info, - other_joininfo->jinfoclauseinfo); - } else { - JInfo *new_joininfo = makeNode(JInfo); - - new_joininfo->otherrels = new_relids; - new_joininfo->jinfoclauseinfo = clause_info; - new_joininfo->mergesortable = mergesortable; - new_joininfo->hashjoinable = hashjoinable; - new_joininfo->inactive = false; - joinrel->joininfo = - lappend(joinrel->joininfo, - new_joininfo); + foreach(xjoinrel, joinrels) + { + Rel *joinrel = (Rel *) lfirst(xjoinrel); + + foreach(xjoininfo, joinrel->joininfo) + { + JInfo *joininfo = (JInfo *) lfirst(xjoininfo); + List *other_rels = joininfo->otherrels; + List *clause_info = joininfo->jinfoclauseinfo; + bool mergesortable = joininfo->mergesortable; + bool hashjoinable = joininfo->hashjoinable; + + foreach(xrelid, other_rels) + { + + /* + * ! BUG BUG ! Relid relid = (Relid)lfirst(xrelid); Rel + * *rel = get_join_rel(root, relid); + */ + + /* + * if ( (root->join_relation_list_) != NIL ) { rel = + * get_join_rel(root, xrelid); } else { rel = + * get_base_rel(root, lfirsti(xrelid)); } + */ + + /* NOTE: STILL BUGGY FOR CLAUSE-JOINS: */ + + /* + * relids = lconsi(lfirsti(xrelid), NIL); rel = + * rel_member(relids, outerrels); + */ + + relids = lconsi(lfirsti(xrelid), NIL); + rel = rel_member(relids, root->base_relation_list_); + + super_rels = rel->superrels; + new_joininfo = makeNode(JInfo); + + new_joininfo->otherrels = joinrel->relids; + new_joininfo->jinfoclauseinfo = clause_info; + new_joininfo->mergesortable = mergesortable; + new_joininfo->hashjoinable = hashjoinable; + new_joininfo->inactive = false; + rel->joininfo = + lappend(rel->joininfo, new_joininfo); + + foreach(xsuper_rel, super_rels) + { + Rel *super_rel = (Rel *) lfirst(xsuper_rel); + + if (nonoverlap_rels(super_rel, joinrel)) + { + List *new_relids = super_rel->relids; + JInfo *other_joininfo = + joininfo_member(new_relids, + joinrel->joininfo); + + if (other_joininfo) + { + other_joininfo->jinfoclauseinfo = + (List *) LispUnion(clause_info, + other_joininfo->jinfoclauseinfo); + } + else + { + JInfo *new_joininfo = makeNode(JInfo); + + new_joininfo->otherrels = new_relids; + new_joininfo->jinfoclauseinfo = clause_info; + new_joininfo->mergesortable = mergesortable; + new_joininfo->hashjoinable = hashjoinable; + new_joininfo->inactive = false; + joinrel->joininfo = + lappend(joinrel->joininfo, + new_joininfo); + } + } + } } - } } - } } - } - foreach(xrel, outerrels) { - rel = (Rel *)lfirst(xrel); - rel->superrels = NIL; - } + foreach(xrel, outerrels) + { + rel = (Rel *) lfirst(xrel); + rel->superrels = NIL; + } } /* * final-join-rels-- - * Find the join relation that includes all the original - * relations, i.e. the final join result. + * Find the join relation that includes all the original + * relations, i.e. the final join result. * * 'join-rel-list' is a list of join relations. * * Returns the list of final join relations. */ -static List * -geqo_final_join_rels(List *join_rel_list) +static List * +geqo_final_join_rels(List * join_rel_list) { - List *xrel = NIL; - List *temp = NIL; - List *t_list = NIL; - - /* - * find the relations that has no further joins, - * i.e., its joininfos all have otherrels nil. - */ - foreach(xrel,join_rel_list) { - Rel *rel = (Rel *)lfirst(xrel); - List *xjoininfo = NIL; - bool final = true; - - foreach (xjoininfo, rel->joininfo) { - JInfo *joininfo = (JInfo*)lfirst(xjoininfo); - - if (joininfo->otherrels != NIL) { - final = false; - break; - } - } - if (final) { - temp = lcons(rel, NIL); - t_list = nconc(t_list, temp); + List *xrel = NIL; + List *temp = NIL; + List *t_list = NIL; + + /* + * find the relations that has no further joins, i.e., its joininfos + * all have otherrels nil. + */ + foreach(xrel, join_rel_list) + { + Rel *rel = (Rel *) lfirst(xrel); + List *xjoininfo = NIL; + bool final = true; + + foreach(xjoininfo, rel->joininfo) + { + JInfo *joininfo = (JInfo *) lfirst(xjoininfo); + + if (joininfo->otherrels != NIL) + { + final = false; + break; + } + } + if (final) + { + temp = lcons(rel, NIL); + t_list = nconc(t_list, temp); + } } - } - return(t_list); + return (t_list); } /* * add_superrels-- - * add rel to the temporary property list superrels. + * add rel to the temporary property list superrels. * * 'rel' a rel node * 'super-rel' rel node of a join relation that includes rel @@ -599,65 +649,72 @@ geqo_final_join_rels(List *join_rel_list) * Modifies the superrels field of rel */ static void -add_superrels(Rel *rel, Rel *super_rel) +add_superrels(Rel * rel, Rel * super_rel) { - rel->superrels = lappend(rel->superrels, super_rel); + rel->superrels = lappend(rel->superrels, super_rel); } /* * nonoverlap-rels-- - * test if two join relations overlap, i.e., includes the same - * relation. + * test if two join relations overlap, i.e., includes the same + * relation. * * 'rel1' and 'rel2' are two join relations * * Returns non-nil if rel1 and rel2 do not overlap. */ -static bool -nonoverlap_rels(Rel *rel1, Rel *rel2) +static bool +nonoverlap_rels(Rel * rel1, Rel * rel2) { - return(nonoverlap_sets(rel1->relids, rel2->relids)); + return (nonoverlap_sets(rel1->relids, rel2->relids)); } -static bool -nonoverlap_sets(List *s1, List *s2) +static bool +nonoverlap_sets(List * s1, List * s2) { - List *x = NIL; - - foreach(x,s1) { - int e = lfirsti(x); - if(intMember(e,s2)) - return(false); - } - return(true); + List *x = NIL; + + foreach(x, s1) + { + int e = lfirsti(x); + + if (intMember(e, s2)) + return (false); + } + return (true); } -#endif /* NOTUSED */ + +#endif /* NOTUSED */ /* * geqo_joinrel_size-- - * compute estimate for join relation tuples, even for - * long join queries; so get logarithm of size when MAXINT overflow; + * compute estimate for join relation tuples, even for + * long join queries; so get logarithm of size when MAXINT overflow; */ static void -geqo_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel) +geqo_joinrel_size(Rel * joinrel, Rel * outer_rel, Rel * inner_rel) { - Cost temp; - int ntuples; - + Cost temp; + int ntuples; + temp = (Cost) inner_rel->tuples * (Cost) outer_rel->tuples; /* cartesian product */ - if (joinrel->clauseinfo) { + if (joinrel->clauseinfo) + { temp = temp * product_selec(joinrel->clauseinfo); - } - - if (temp >= (MAXINT -1)) { - ntuples = ceil( geqo_log((double)temp, (double) GEQO_LOG_BASE) ); - } - else { - ntuples = ceil((double)temp); - } + } - if (ntuples < 1) ntuples = 1; /* make the best case 1 instead of 0 */ + if (temp >= (MAXINT - 1)) + { + ntuples = ceil(geqo_log((double) temp, (double) GEQO_LOG_BASE)); + } + else + { + ntuples = ceil((double) temp); + } + + if (ntuples < 1) + ntuples = 1; /* make the best case 1 instead of 0 */ joinrel->tuples = ntuples; } @@ -665,19 +722,21 @@ geqo_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel) double geqo_log(double x, double b) { - return(log(x)/log(b)); + return (log(x) / log(b)); } -static Rel * -geqo_nth(int stop, List *rels) +static Rel * +geqo_nth(int stop, List * rels) { - List *r; - int i=1; + List *r; + int i = 1; - foreach(r, rels) { - if (i == stop) return lfirst(r); + foreach(r, rels) + { + if (i == stop) + return lfirst(r); i++; - } - elog(WARN,"geqo_nth: Internal error - ran off end of list"); - return NULL; /* to keep compiler happy */ + } + elog(WARN, "geqo_nth: Internal error - ran off end of list"); + return NULL; /* to keep compiler happy */ } diff --git a/src/backend/optimizer/geqo/geqo_main.c b/src/backend/optimizer/geqo/geqo_main.c index 4b450002885..eab939c03e6 100644 --- a/src/backend/optimizer/geqo/geqo_main.c +++ b/src/backend/optimizer/geqo/geqo_main.c @@ -1,21 +1,21 @@ /*------------------------------------------------------------------------ * * geqo_main.c-- - * solution of the query optimization problem - * by means of a Genetic Algorithm (GA) + * solution of the query optimization problem + * by means of a Genetic Algorithm (GA) * * Copyright (c) 1994, Regents of the University of California * - * $Id: geqo_main.c,v 1.3 1997/03/14 16:02:51 scrappy Exp $ + * $Id: geqo_main.c,v 1.4 1997/09/07 04:43:09 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ @@ -48,228 +48,241 @@ /* define edge recombination crossover [ERX] per default */ #if !defined(ERX) && \ - !defined(PMX) && \ - !defined(CX) && \ - !defined(PX) && \ - !defined(OX1) && \ - !defined(OX2) + !defined(PMX) && \ + !defined(CX) && \ + !defined(PX) && \ + !defined(OX1) && \ + !defined(OX2) #define ERX #endif /* * geqo-- - * solution of the query optimization problem - * similar to a constrained Traveling Salesman Problem (TSP) + * solution of the query optimization problem + * similar to a constrained Traveling Salesman Problem (TSP) */ -Rel * -geqo(Query *root) +Rel * +geqo(Query * root) { - int generation; - Chromosome *momma; - Chromosome *daddy; - Chromosome *kid; + int generation; + Chromosome *momma; + Chromosome *daddy; + Chromosome *kid; #if defined(ERX) - Edge *edge_table; /* list of edges */ - int edge_failures=0; - float difference; -#endif + Edge *edge_table; /* list of edges */ + int edge_failures = 0; + float difference; + +#endif #if defined(CX) || defined(PX) || defined(OX1) || defined(OX2) - City *city_table; /* list of cities */ + City *city_table; /* list of cities */ + #endif #if defined(CX) - int cycle_diffs=0; - int mutations=0; + int cycle_diffs = 0; + int mutations = 0; + #endif - int number_of_rels; + int number_of_rels; - Pool *pool; - int pool_size, number_generations, status_interval; + Pool *pool; + int pool_size, + number_generations, + status_interval; - Gene *best_tour; - Rel *best_rel; -/* Plan *best_plan; */ + Gene *best_tour; + Rel *best_rel; + +/* Plan *best_plan; */ /* set tour size */ - number_of_rels = length(root->base_relation_list_); + number_of_rels = length(root->base_relation_list_); /* set GA parameters */ - geqo_params(number_of_rels) ; /* out of "$PGDATA/pg_geqo" file */ - pool_size = PoolSize; - number_generations = Generations; - status_interval = 10; + geqo_params(number_of_rels);/* out of "$PGDATA/pg_geqo" file */ + pool_size = PoolSize; + number_generations = Generations; + status_interval = 10; /* seed random number generator */ - srandom(RandomSeed); + srandom(RandomSeed); /* allocate genetic pool memory */ - pool = alloc_pool(pool_size, number_of_rels); + pool = alloc_pool(pool_size, number_of_rels); /* random initialization of the pool */ - random_init_pool (root, pool, 0, pool->size); + random_init_pool(root, pool, 0, pool->size); /* sort the pool according to cheapest path as fitness */ - sort_pool (pool); /* we have to do it only one time, since all kids replace the worst individuals in future (-> geqo_pool.c:spread_chromo ) */ + sort_pool(pool); /* we have to do it only one time, since + * all kids replace the worst individuals + * in future (-> geqo_pool.c:spread_chromo + * ) */ /* allocate chromosome momma and daddy memory */ - momma = alloc_chromo(pool->string_length); - daddy = alloc_chromo(pool->string_length); + momma = alloc_chromo(pool->string_length); + daddy = alloc_chromo(pool->string_length); #if defined (ERX) - elog(DEBUG,"geqo_main: using edge recombination crossover [ERX]"); + elog(DEBUG, "geqo_main: using edge recombination crossover [ERX]"); /* allocate edge table memory */ - edge_table = alloc_edge_table(pool->string_length); + edge_table = alloc_edge_table(pool->string_length); #elif defined(PMX) - elog(DEBUG,"geqo_main: using partially matched crossover [PMX]"); + elog(DEBUG, "geqo_main: using partially matched crossover [PMX]"); /* allocate chromosome kid memory */ - kid = alloc_chromo(pool->string_length); + kid = alloc_chromo(pool->string_length); #elif defined(CX) - elog(DEBUG,"geqo_main: using cycle crossover [CX]"); + elog(DEBUG, "geqo_main: using cycle crossover [CX]"); /* allocate city table memory */ - kid = alloc_chromo(pool->string_length); - city_table = alloc_city_table(pool->string_length); + kid = alloc_chromo(pool->string_length); + city_table = alloc_city_table(pool->string_length); #elif defined(PX) - elog(DEBUG,"geqo_main: using position crossover [PX]"); + elog(DEBUG, "geqo_main: using position crossover [PX]"); /* allocate city table memory */ - kid = alloc_chromo(pool->string_length); - city_table = alloc_city_table(pool->string_length); + kid = alloc_chromo(pool->string_length); + city_table = alloc_city_table(pool->string_length); #elif defined(OX1) - elog(DEBUG,"geqo_main: using order crossover [OX1]"); + elog(DEBUG, "geqo_main: using order crossover [OX1]"); /* allocate city table memory */ - kid = alloc_chromo(pool->string_length); - city_table = alloc_city_table(pool->string_length); + kid = alloc_chromo(pool->string_length); + city_table = alloc_city_table(pool->string_length); #elif defined(OX2) - elog(DEBUG,"geqo_main: using order crossover [OX2]"); + elog(DEBUG, "geqo_main: using order crossover [OX2]"); /* allocate city table memory */ - kid = alloc_chromo(pool->string_length); - city_table = alloc_city_table(pool->string_length); + kid = alloc_chromo(pool->string_length); + city_table = alloc_city_table(pool->string_length); #endif /* my pain main part: */ /* iterative optimization */ - for (generation = 0; generation < number_generations; generation++) { + for (generation = 0; generation < number_generations; generation++) + { - /* SELECTION */ - geqo_selection(momma, daddy, pool, SelectionBias); /* using linear bias function */ + /* SELECTION */ + geqo_selection(momma, daddy, pool, SelectionBias); /* using linear bias + * function */ #if defined (ERX) - /* EDGE RECOMBINATION CROSSOVER */ - difference = gimme_edge_table(momma->string, daddy->string, pool->string_length, edge_table); + /* EDGE RECOMBINATION CROSSOVER */ + difference = gimme_edge_table(momma->string, daddy->string, pool->string_length, edge_table); - /* let the kid grow in momma's womb (storage) for nine months ;-) */ - /* sleep(23328000) -- har har har */ - kid = momma; + /* let the kid grow in momma's womb (storage) for nine months ;-) */ + /* sleep(23328000) -- har har har */ + kid = momma; - /* are there any edge failures ? */ - edge_failures += gimme_tour(edge_table, kid->string, pool->string_length); + /* are there any edge failures ? */ + edge_failures += gimme_tour(edge_table, kid->string, pool->string_length); #elif defined(PMX) - /* PARTIALLY MATCHED CROSSOVER */ - pmx(momma->string, daddy->string, kid->string, pool->string_length); + /* PARTIALLY MATCHED CROSSOVER */ + pmx(momma->string, daddy->string, kid->string, pool->string_length); #elif defined(CX) - /* CYCLE CROSSOVER */ - cycle_diffs = - cx(momma->string, daddy->string, kid->string, pool->string_length, city_table); - /* mutate the child */ - if (cycle_diffs == 0) { - mutations++; - geqo_mutation (kid->string, pool->string_length); - } + /* CYCLE CROSSOVER */ + cycle_diffs = + cx(momma->string, daddy->string, kid->string, pool->string_length, city_table); + /* mutate the child */ + if (cycle_diffs == 0) + { + mutations++; + geqo_mutation(kid->string, pool->string_length); + } #elif defined(PX) - /* POSITION CROSSOVER */ - px(momma->string, daddy->string, kid->string, pool->string_length, city_table); + /* POSITION CROSSOVER */ + px(momma->string, daddy->string, kid->string, pool->string_length, city_table); #elif defined(OX1) - /* ORDER CROSSOVER */ - ox1(momma->string, daddy->string, kid->string, pool->string_length, city_table); + /* ORDER CROSSOVER */ + ox1(momma->string, daddy->string, kid->string, pool->string_length, city_table); #elif defined(OX2) - /* ORDER CROSSOVER */ - ox2(momma->string, daddy->string, kid->string, pool->string_length, city_table); + /* ORDER CROSSOVER */ + ox2(momma->string, daddy->string, kid->string, pool->string_length, city_table); #endif - /* EVALUATE FITNESS */ - kid->worth = geqo_eval (root, kid->string, pool->string_length); + /* EVALUATE FITNESS */ + kid->worth = geqo_eval(root, kid->string, pool->string_length); - /* push the kid into the wilderness of life according to its worth */ - spread_chromo (kid, pool); + /* push the kid into the wilderness of life according to its worth */ + spread_chromo(kid, pool); #ifdef GEQO_DEBUG - if (status_interval && !(generation % status_interval)) - print_gen (stdout, pool, generation); + if (status_interval && !(generation % status_interval)) + print_gen(stdout, pool, generation); #endif - } /* end of iterative optimization */ + } /* end of iterative optimization */ #if defined(ERX) && defined(GEQO_DEBUG) -if (edge_failures != 0) - fprintf (stdout, "\nFailures: %d Avg: %d\n", edge_failures, (int) generation/edge_failures); + if (edge_failures != 0) + fprintf(stdout, "\nFailures: %d Avg: %d\n", edge_failures, (int) generation / edge_failures); -else fprintf (stdout, "No edge failures detected.\n"); + else + fprintf(stdout, "No edge failures detected.\n"); #endif #if defined(CX) && defined(GEQO_DEBUG) -if (mutations != 0) - fprintf (stdout, "\nMutations: %d Generations: %d\n", mutations, generation); + if (mutations != 0) + fprintf(stdout, "\nMutations: %d Generations: %d\n", mutations, generation); -else fprintf (stdout, "No mutations processed.\n"); + else + fprintf(stdout, "No mutations processed.\n"); #endif - + #ifdef GEQO_DEBUG -fprintf (stdout, "\n"); -print_pool (stdout, pool, 0, pool_size-1); + fprintf(stdout, "\n"); + print_pool(stdout, pool, 0, pool_size - 1); #endif /* got the cheapest query tree processed by geqo; first element of the population indicates the best query tree */ -best_tour = (Gene *) pool->data[0].string; + best_tour = (Gene *) pool->data[0].string; /* root->join_relation_list_ will be modified during this ! */ -best_rel = (Rel *) gimme_tree(root, best_tour, 0, pool->string_length, NULL); + best_rel = (Rel *) gimme_tree(root, best_tour, 0, pool->string_length, NULL); /* DBG: show the query plan print_plan(best_plan, root); DBG */ /* ... free memory stuff */ -free_chromo(momma); -free_chromo(daddy); + free_chromo(momma); + free_chromo(daddy); #if defined (ERX) -free_edge_table(edge_table); + free_edge_table(edge_table); #elif defined(PMX) -free_chromo(kid); + free_chromo(kid); #elif defined(CX) -free_chromo(kid); -free_city_table(city_table); + free_chromo(kid); + free_city_table(city_table); #elif defined(PX) -free_chromo(kid); -free_city_table(city_table); + free_chromo(kid); + free_city_table(city_table); #elif defined(OX1) -free_chromo(kid); -free_city_table(city_table); + free_chromo(kid); + free_city_table(city_table); #elif defined(OX2) -free_chromo(kid); -free_city_table(city_table); + free_chromo(kid); + free_city_table(city_table); #endif -free_pool(pool); + free_pool(pool); -return(best_rel); + return (best_rel); } - diff --git a/src/backend/optimizer/geqo/geqo_misc.c b/src/backend/optimizer/geqo/geqo_misc.c index 48ae78bdcda..67e810d87ca 100644 --- a/src/backend/optimizer/geqo/geqo_misc.c +++ b/src/backend/optimizer/geqo/geqo_misc.c @@ -1,20 +1,20 @@ /*------------------------------------------------------------------------ * * geqo_misc.c-- - * misc. printout and debug stuff + * misc. printout and debug stuff * * Copyright (c) 1994, Regents of the University of California * - * $Id: geqo_misc.c,v 1.2 1997/02/19 14:52:01 scrappy Exp $ + * $Id: geqo_misc.c,v 1.3 1997/09/07 04:43:10 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ @@ -41,91 +41,97 @@ #include "optimizer/geqo_recombination.h" #include "optimizer/geqo_misc.h" -static float avg_pool (Pool *pool); +static float avg_pool(Pool * pool); /* avg_pool-- * */ static float -avg_pool (Pool *pool) +avg_pool(Pool * pool) { - int i; - double cumulative = 0.0; - - if (pool->size==0) - elog(WARN,"avg_pool: pool_size of zero"); - - for (i=0; i<pool->size; i++) - cumulative = cumulative + pool->data[i].worth; - - return ((float) cumulative/pool->size); + int i; + double cumulative = 0.0; + + if (pool->size == 0) + elog(WARN, "avg_pool: pool_size of zero"); + + for (i = 0; i < pool->size; i++) + cumulative = cumulative + pool->data[i].worth; + + return ((float) cumulative / pool->size); } /* print_pool-- */ void -print_pool (FILE *fp, Pool *pool, int start, int stop) +print_pool(FILE * fp, Pool * pool, int start, int stop) { - int i, j; + int i, + j; - /* be extra careful that start and stop are valid inputs */ + /* be extra careful that start and stop are valid inputs */ - if (start < 0) start = 0; - if (stop > pool->size) stop = pool->size; + if (start < 0) + start = 0; + if (stop > pool->size) + stop = pool->size; - if (start+stop > pool->size) { - start = 0; - stop = pool->size; + if (start + stop > pool->size) + { + start = 0; + stop = pool->size; } - for (i=start; i<stop; i++) { - fprintf (fp, "%d)\t", i); - for (j=0; j<pool->string_length; j++) - fprintf (fp, "%d ", pool->data[i].string[j]); - fprintf (fp, "%f\n", pool->data[i].worth); + for (i = start; i < stop; i++) + { + fprintf(fp, "%d)\t", i); + for (j = 0; j < pool->string_length; j++) + fprintf(fp, "%d ", pool->data[i].string[j]); + fprintf(fp, "%f\n", pool->data[i].worth); } } /* print_gen-- * - * printout for chromosome: best, worst, mean, average + * printout for chromosome: best, worst, mean, average * */ void -print_gen(FILE *fp, Pool *pool, int generation) +print_gen(FILE * fp, Pool * pool, int generation) { - int lowest; - - /* Get index to lowest ranking gene in poplulation. */ - /* Use 2nd to last since last is buffer. */ - lowest = pool->size > 1 ? pool->size-2 : 0; - - fprintf (fp, - "%5d | Bst: %f Wst: %f Mean: %f Avg: %f\n", - generation, - pool->data[0].worth, - pool->data[lowest].worth, - pool->data[pool->size/2].worth, - avg_pool(pool)); + int lowest; + + /* Get index to lowest ranking gene in poplulation. */ + /* Use 2nd to last since last is buffer. */ + lowest = pool->size > 1 ? pool->size - 2 : 0; + + fprintf(fp, + "%5d | Bst: %f Wst: %f Mean: %f Avg: %f\n", + generation, + pool->data[0].worth, + pool->data[lowest].worth, + pool->data[pool->size / 2].worth, + avg_pool(pool)); } void -print_edge_table (FILE *fp, Edge *edge_table, int num_gene) +print_edge_table(FILE * fp, Edge * edge_table, int num_gene) { - int i,j; - - fprintf (fp, "\nEDGE TABLE\n"); - - for (i=1; i<=num_gene; i++) - { - fprintf (fp, "%d :", i); - for (j=0; j<edge_table[i].unused_edges; j++) - fprintf (fp, " %d", edge_table[i].edge_list[j]); - fprintf (fp, "\n"); - } - - fprintf (fp, "\n"); + int i, + j; + + fprintf(fp, "\nEDGE TABLE\n"); + + for (i = 1; i <= num_gene; i++) + { + fprintf(fp, "%d :", i); + for (j = 0; j < edge_table[i].unused_edges; j++) + fprintf(fp, " %d", edge_table[i].edge_list[j]); + fprintf(fp, "\n"); + } + + fprintf(fp, "\n"); } /************************************************************* @@ -133,116 +139,147 @@ print_edge_table (FILE *fp, Edge *edge_table, int num_gene) *************************************************************/ void -geqo_print_joinclauses(Query *root, List *clauses) +geqo_print_joinclauses(Query * root, List * clauses) { - List *l; - extern void print_expr(Node *expr, List *rtable); /* in print.c */ + List *l; + extern void print_expr(Node * expr, List * rtable); /* in print.c */ - foreach(l, clauses) { - CInfo *c = lfirst(l); + foreach(l, clauses) + { + CInfo *c = lfirst(l); - print_expr((Node*)c->clause, root->rtable); - if (lnext(l)) printf(" "); - } + print_expr((Node *) c->clause, root->rtable); + if (lnext(l)) + printf(" "); + } } void -geqo_print_path(Query *root, Path *path, int indent) +geqo_print_path(Query * root, Path * path, int indent) { - char *ptype = NULL; - JoinPath *jp; - bool join = false; - int i; - - for(i=0; i < indent; i++) - printf("\t"); - - switch(nodeTag(path)) { - case T_Path: - ptype = "SeqScan"; join=false; break; - case T_IndexPath: - ptype = "IdxScan"; join=false; break; - case T_JoinPath: - ptype = "Nestloop"; join=true; break; - case T_MergePath: - ptype = "MergeJoin"; join=true; break; - case T_HashPath: - ptype = "HashJoin"; join=true; break; - default: - break; - } - if (join) { - int size = path->parent->size; - jp = (JoinPath*)path; - printf("%s size=%d cost=%f\n", ptype, size, path->path_cost); - switch(nodeTag(path)) { + char *ptype = NULL; + JoinPath *jp; + bool join = false; + int i; + + for (i = 0; i < indent; i++) + printf("\t"); + + switch (nodeTag(path)) + { + case T_Path: + ptype = "SeqScan"; + join = false; + break; + case T_IndexPath: + ptype = "IdxScan"; + join = false; + break; + case T_JoinPath: + ptype = "Nestloop"; + join = true; + break; case T_MergePath: + ptype = "MergeJoin"; + join = true; + break; case T_HashPath: - for(i=0; i < indent+1; i++) - printf("\t"); - printf(" clauses=("); - geqo_print_joinclauses(root, - ((JoinPath*)path)->pathclauseinfo); - printf(")\n"); - - if (nodeTag(path)==T_MergePath) { - MergePath *mp = (MergePath*)path; - if (mp->outersortkeys || mp->innersortkeys) { - for(i=0; i < indent+1; i++) - printf("\t"); - printf(" sortouter=%d sortinner=%d\n", - ((mp->outersortkeys)?1:0), - ((mp->innersortkeys)?1:0)); - } - } - break; + ptype = "HashJoin"; + join = true; + break; default: - break; + break; } - geqo_print_path(root, jp->outerjoinpath, indent+1); - geqo_print_path(root, jp->innerjoinpath, indent+1); - } else { - int size = path->parent->size; - int relid = lfirsti(path->parent->relids); - printf("%s(%d) size=%d cost=%f", - ptype, relid, size, path->path_cost); - - if (nodeTag(path)==T_IndexPath) { - List *k, *l; - - printf(" keys="); - foreach (k, path->keys) { - printf("("); - foreach (l, lfirst(k)) { - Var *var = lfirst(l); - printf("%d.%d", var->varnoold, var->varoattno); - if (lnext(l)) printf(", "); + if (join) + { + int size = path->parent->size; + + jp = (JoinPath *) path; + printf("%s size=%d cost=%f\n", ptype, size, path->path_cost); + switch (nodeTag(path)) + { + case T_MergePath: + case T_HashPath: + for (i = 0; i < indent + 1; i++) + printf("\t"); + printf(" clauses=("); + geqo_print_joinclauses(root, + ((JoinPath *) path)->pathclauseinfo); + printf(")\n"); + + if (nodeTag(path) == T_MergePath) + { + MergePath *mp = (MergePath *) path; + + if (mp->outersortkeys || mp->innersortkeys) + { + for (i = 0; i < indent + 1; i++) + printf("\t"); + printf(" sortouter=%d sortinner=%d\n", + ((mp->outersortkeys) ? 1 : 0), + ((mp->innersortkeys) ? 1 : 0)); + } + } + break; + default: + break; } - printf(")"); - if (lnext(k)) printf(", "); - } + geqo_print_path(root, jp->outerjoinpath, indent + 1); + geqo_print_path(root, jp->innerjoinpath, indent + 1); + } + else + { + int size = path->parent->size; + int relid = lfirsti(path->parent->relids); + + printf("%s(%d) size=%d cost=%f", + ptype, relid, size, path->path_cost); + + if (nodeTag(path) == T_IndexPath) + { + List *k, + *l; + + printf(" keys="); + foreach(k, path->keys) + { + printf("("); + foreach(l, lfirst(k)) + { + Var *var = lfirst(l); + + printf("%d.%d", var->varnoold, var->varoattno); + if (lnext(l)) + printf(", "); + } + printf(")"); + if (lnext(k)) + printf(", "); + } + } + printf("\n"); } - printf("\n"); - } } -void -geqo_print_rel(Query *root, Rel *rel) +void +geqo_print_rel(Query * root, Rel * rel) { - List *l; - - printf("______________________________\n"); - printf("("); - foreach(l, rel->relids) { - printf("%d ", lfirsti(l)); - } - printf("): size=%d width=%d\n", rel->size, rel->width); - - printf("\tpath list:\n"); - foreach (l, rel->pathlist) { - geqo_print_path(root, lfirst(l), 1); - } - - printf("\tcheapest path:\n"); - geqo_print_path(root, rel->cheapestpath, 1); + List *l; + + printf("______________________________\n"); + printf("("); + foreach(l, rel->relids) + { + printf("%d ", lfirsti(l)); + } + printf("): size=%d width=%d\n", rel->size, rel->width); + + printf("\tpath list:\n"); + foreach(l, rel->pathlist) + { + geqo_print_path(root, lfirst(l), 1); + } + + printf("\tcheapest path:\n"); + geqo_print_path(root, rel->cheapestpath, 1); } diff --git a/src/backend/optimizer/geqo/geqo_mutation.c b/src/backend/optimizer/geqo/geqo_mutation.c index 9d544564210..a5a43e6e2b9 100644 --- a/src/backend/optimizer/geqo/geqo_mutation.c +++ b/src/backend/optimizer/geqo/geqo_mutation.c @@ -2,33 +2,33 @@ * * geqo_mutation.c-- * -* TSP mutation routines +* TSP mutation routines * -* $Id: geqo_mutation.c,v 1.1 1997/02/19 12:57:13 scrappy Exp $ +* $Id: geqo_mutation.c,v 1.2 1997/09/07 04:43:13 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ /* this is adopted from Genitor : */ /*************************************************************/ -/* */ -/* Copyright (c) 1990 */ -/* Darrell L. Whitley */ -/* Computer Science Department */ -/* Colorado State University */ -/* */ -/* Permission is hereby granted to copy all or any part of */ -/* this program for free distribution. The author's name */ -/* and this copyright notice must be included in any copy. */ -/* */ +/* */ +/* Copyright (c) 1990 */ +/* Darrell L. Whitley */ +/* Computer Science Department */ +/* Colorado State University */ +/* */ +/* Permission is hereby granted to copy all or any part of */ +/* this program for free distribution. The author's name */ +/* and this copyright notice must be included in any copy. */ +/* */ /*************************************************************/ #include "postgres.h" @@ -50,27 +50,28 @@ #include "optimizer/geqo_random.h" #include "optimizer/geqo_mutation.h" - void - geqo_mutation (Gene *tour, int num_gene) - { - int swap1; - int swap2; - int num_swaps = geqo_randint (num_gene/3, 0); - Gene temp; +void +geqo_mutation(Gene * tour, int num_gene) +{ + int swap1; + int swap2; + int num_swaps = geqo_randint(num_gene / 3, 0); + Gene temp; - while (num_swaps > 0) { - swap1 = geqo_randint (num_gene-1, 0); - swap2 = geqo_randint (num_gene-1, 0); + while (num_swaps > 0) + { + swap1 = geqo_randint(num_gene - 1, 0); + swap2 = geqo_randint(num_gene - 1, 0); - while (swap1 == swap2) - swap2 = geqo_randint (num_gene-1, 0); + while (swap1 == swap2) + swap2 = geqo_randint(num_gene - 1, 0); - temp = tour[swap1]; - tour[swap1] = tour[swap2]; - tour[swap2] = temp; + temp = tour[swap1]; + tour[swap1] = tour[swap2]; + tour[swap2] = temp; - num_swaps -= 1; - } + num_swaps -= 1; + } } diff --git a/src/backend/optimizer/geqo/geqo_ox1.c b/src/backend/optimizer/geqo/geqo_ox1.c index 329554f9aae..b88b8950673 100644 --- a/src/backend/optimizer/geqo/geqo_ox1.c +++ b/src/backend/optimizer/geqo/geqo_ox1.c @@ -2,35 +2,35 @@ * * geqo_ox1.c-- * -* order crossover [OX] routines; -* OX1 operator according to Davis -* (Proc Int'l Joint Conf on AI) +* order crossover [OX] routines; +* OX1 operator according to Davis +* (Proc Int'l Joint Conf on AI) * -* $Id: geqo_ox1.c,v 1.1 1997/03/14 16:02:58 scrappy Exp $ +* $Id: geqo_ox1.c,v 1.2 1997/09/07 04:43:14 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ /* the ox algorithm is adopted from Genitor : */ /*************************************************************/ -/* */ -/* Copyright (c) 1990 */ -/* Darrell L. Whitley */ -/* Computer Science Department */ -/* Colorado State University */ -/* */ -/* Permission is hereby granted to copy all or any part of */ -/* this program for free distribution. The author's name */ -/* and this copyright notice must be included in any copy. */ -/* */ +/* */ +/* Copyright (c) 1990 */ +/* Darrell L. Whitley */ +/* Computer Science Department */ +/* Colorado State University */ +/* */ +/* Permission is hereby granted to copy all or any part of */ +/* this program for free distribution. The author's name */ +/* and this copyright notice must be included in any copy. */ +/* */ /*************************************************************/ #include "postgres.h" @@ -56,48 +56,52 @@ /* ox1-- * - * position crossover + * position crossover */ void -ox1(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table) +ox1(Gene * tour1, Gene * tour2, Gene * offspring, int num_gene, City * city_table) { - int left, right, k, p, temp; - - /* initialize city table */ - for (k = 1; k <= num_gene; k++) - city_table[k].used = 0; - - /* select portion to copy from tour1 */ - left = geqo_randint (num_gene - 1, 0); - right = geqo_randint (num_gene - 1, 0); - - if (left > right) - { - temp = left; - left = right; - right = temp; - } - - /* copy portion from tour1 to offspring */ - for (k = left; k <= right; k++) - { - offspring[k] = tour1[k]; - city_table[(int) tour1[k]].used = 1; - } - - k = (right + 1) % num_gene; /* index into offspring */ - p = k; /* index into tour2 */ - - /* copy stuff from tour2 to offspring */ - while (k != left) - { - if (!city_table[(int) tour2[p]].used) - { - offspring[k] = tour2[p]; - k = (k + 1) % num_gene; - city_table[(int) tour2[p]].used = 1; - } - p = (p + 1) % num_gene; /* increment tour2-index */ - } - - } + int left, + right, + k, + p, + temp; + + /* initialize city table */ + for (k = 1; k <= num_gene; k++) + city_table[k].used = 0; + + /* select portion to copy from tour1 */ + left = geqo_randint(num_gene - 1, 0); + right = geqo_randint(num_gene - 1, 0); + + if (left > right) + { + temp = left; + left = right; + right = temp; + } + + /* copy portion from tour1 to offspring */ + for (k = left; k <= right; k++) + { + offspring[k] = tour1[k]; + city_table[(int) tour1[k]].used = 1; + } + + k = (right + 1) % num_gene; /* index into offspring */ + p = k; /* index into tour2 */ + + /* copy stuff from tour2 to offspring */ + while (k != left) + { + if (!city_table[(int) tour2[p]].used) + { + offspring[k] = tour2[p]; + k = (k + 1) % num_gene; + city_table[(int) tour2[p]].used = 1; + } + p = (p + 1) % num_gene; /* increment tour2-index */ + } + +} diff --git a/src/backend/optimizer/geqo/geqo_ox2.c b/src/backend/optimizer/geqo/geqo_ox2.c index 2afcece01ff..ef09925b4fa 100644 --- a/src/backend/optimizer/geqo/geqo_ox2.c +++ b/src/backend/optimizer/geqo/geqo_ox2.c @@ -2,35 +2,35 @@ * * geqo_ox2.c-- * -* order crossover [OX] routines; -* OX2 operator according to Syswerda -* (The Genetic Algorithms Handbook, ed L Davis) +* order crossover [OX] routines; +* OX2 operator according to Syswerda +* (The Genetic Algorithms Handbook, ed L Davis) * -* $Id: geqo_ox2.c,v 1.1 1997/03/14 16:03:02 scrappy Exp $ +* $Id: geqo_ox2.c,v 1.2 1997/09/07 04:43:15 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ /* the ox algorithm is adopted from Genitor : */ /*************************************************************/ -/* */ -/* Copyright (c) 1990 */ -/* Darrell L. Whitley */ -/* Computer Science Department */ -/* Colorado State University */ -/* */ -/* Permission is hereby granted to copy all or any part of */ -/* this program for free distribution. The author's name */ -/* and this copyright notice must be included in any copy. */ -/* */ +/* */ +/* Copyright (c) 1990 */ +/* Darrell L. Whitley */ +/* Computer Science Department */ +/* Colorado State University */ +/* */ +/* Permission is hereby granted to copy all or any part of */ +/* this program for free distribution. The author's name */ +/* and this copyright notice must be included in any copy. */ +/* */ /*************************************************************/ #include "postgres.h" @@ -56,58 +56,70 @@ /* ox2-- * - * position crossover + * position crossover */ void -ox2(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table) +ox2(Gene * tour1, Gene * tour2, Gene * offspring, int num_gene, City * city_table) { - int k, j, count, pos, select, num_positions; - - /* initialize city table */ - for (k = 1; k <= num_gene; k++) { - city_table[k].used = 0; - city_table[k-1].select_list = -1; - } - - /* determine the number of positions to be inherited from tour1 */ - num_positions = geqo_randint (2*num_gene/3, num_gene/3); - - /* make a list of selected cities */ - for (k=0; k<num_positions; k++) { - pos = geqo_randint (num_gene - 1, 0); - city_table[pos].select_list = (int) tour1[pos]; - city_table[(int) tour1[pos]].used = 1; /* mark used */ - } - - - count = 0; - k = 0; - - /* consolidate the select list to adjacent positions */ - while (count < num_positions) { - if (city_table[k].select_list == -1) { - j = k + 1; - while ((city_table[j].select_list == -1) && (j < num_gene)) - j++; - - city_table[k].select_list = city_table[j].select_list; - city_table[j].select_list = -1; - count ++; - } - else - count ++; - k++; - } - - select = 0; - - for (k=0; k<num_gene; k++) { - if (city_table[(int) tour2[k]].used) { - offspring[k] = (Gene) city_table[select].select_list; - select ++; /* next city in the select list */ - } - else /* city isn't used yet, so inherit from tour2 */ - offspring[k] = tour2[k]; - } + int k, + j, + count, + pos, + select, + num_positions; + + /* initialize city table */ + for (k = 1; k <= num_gene; k++) + { + city_table[k].used = 0; + city_table[k - 1].select_list = -1; + } + + /* determine the number of positions to be inherited from tour1 */ + num_positions = geqo_randint(2 * num_gene / 3, num_gene / 3); + + /* make a list of selected cities */ + for (k = 0; k < num_positions; k++) + { + pos = geqo_randint(num_gene - 1, 0); + city_table[pos].select_list = (int) tour1[pos]; + city_table[(int) tour1[pos]].used = 1; /* mark used */ + } + + + count = 0; + k = 0; + + /* consolidate the select list to adjacent positions */ + while (count < num_positions) + { + if (city_table[k].select_list == -1) + { + j = k + 1; + while ((city_table[j].select_list == -1) && (j < num_gene)) + j++; + + city_table[k].select_list = city_table[j].select_list; + city_table[j].select_list = -1; + count++; + } + else + count++; + k++; + } + + select = 0; + + for (k = 0; k < num_gene; k++) + { + if (city_table[(int) tour2[k]].used) + { + offspring[k] = (Gene) city_table[select].select_list; + select++; /* next city in the select list */ + } + else +/* city isn't used yet, so inherit from tour2 */ + offspring[k] = tour2[k]; + } } diff --git a/src/backend/optimizer/geqo/geqo_params.c b/src/backend/optimizer/geqo/geqo_params.c index 52c57c45378..45f7dfd5ddc 100644 --- a/src/backend/optimizer/geqo/geqo_params.c +++ b/src/backend/optimizer/geqo/geqo_params.c @@ -1,20 +1,20 @@ /*------------------------------------------------------------------------ * * geqo_params.c-- -* routines for determining necessary genetic optimization parameters +* routines for determining necessary genetic optimization parameters * * Copyright (c) 1994, Regents of the University of California * -* $Id: geqo_params.c,v 1.5 1997/08/18 02:14:41 momjian Exp $ +* $Id: geqo_params.c,v 1.6 1997/09/07 04:43:16 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ @@ -45,48 +45,48 @@ #include "storage/fd.h" -#define POOL_TAG "Pool_Size" -#define TRIAL_TAG "Generations" -#define RAND_TAG "Random_Seed" -#define BIAS_TAG "Selection_Bias" +#define POOL_TAG "Pool_Size" +#define TRIAL_TAG "Generations" +#define RAND_TAG "Random_Seed" +#define BIAS_TAG "Selection_Bias" -#define EFFORT_TAG "Effort" /* optimization effort and */ -#define LOW "low" /* corresponding tags */ -#define MEDIUM "medium" -#define HIGH "high" +#define EFFORT_TAG "Effort"/* optimization effort and */ +#define LOW "low" /* corresponding tags */ +#define MEDIUM "medium" +#define HIGH "high" -#define MAX_TOKEN 80 /* Maximum size of one token in the * - * configuration file */ +#define MAX_TOKEN 80 /* Maximum size of one token in the * + * configuration file */ -static int gimme_pool_size(int string_length); -static int gimme_number_generations(int pool_size, int effort); -static int next_token(FILE *, char *, int); +static int gimme_pool_size(int string_length); +static int gimme_number_generations(int pool_size, int effort); +static int next_token(FILE *, char *, int); /* * geqo_param-- - * get ga parameters out of "$PGDATA/pg_geqo" file. + * get ga parameters out of "$PGDATA/pg_geqo" file. */ void geqo_params(int string_length) { - int i; + int i; - char buf[MAX_TOKEN]; - FILE *file; + char buf[MAX_TOKEN]; + FILE *file; - char *conf_file; + char *conf_file; /* these static variables are used to signal that a value has been set */ - int pool_size = 0; - int number_trials = 0; - int random_seed = 0; - int selection_bias = 0; - int effort = 0; + int pool_size = 0; + int number_trials = 0; + int random_seed = 0; + int selection_bias = 0; + int effort = 0; /* put together the full pathname to the config file */ conf_file = - (char *) palloc((strlen(DataDir)+strlen(GEQO_FILE)+2)*sizeof(char)); + (char *) palloc((strlen(DataDir) + strlen(GEQO_FILE) + 2) * sizeof(char)); sprintf(conf_file, "%s/%s", DataDir, GEQO_FILE); @@ -94,99 +94,109 @@ geqo_params(int string_length) file = AllocateFile(conf_file, "r"); if (file) { + /* * empty and comment line stuff */ while ((i = next_token(file, buf, sizeof(buf))) != EOF) { - /* If only token on the line, ignore */ - if (i == '\n') continue; - - /* Comment -- read until end of line then next line */ - if (buf[0] == '#') - { - while (next_token(file, buf, sizeof(buf)) == 0) ; - continue; - } + /* If only token on the line, ignore */ + if (i == '\n') + continue; + + /* Comment -- read until end of line then next line */ + if (buf[0] == '#') + { + while (next_token(file, buf, sizeof(buf)) == 0); + continue; + } /* * get ga parameters by parsing */ - + /*------------------------------------------------- pool size */ - if ( strcmp(buf, POOL_TAG) == 0 ) + if (strcmp(buf, POOL_TAG) == 0) { i = next_token(file, buf, sizeof(buf)); /* get next token */ - - if (i != EOF) /* only ignore if we got no text at all */ + + if (i != EOF) /* only ignore if we got no text at all */ { - if (sscanf (buf, "%d", &PoolSize) == 1) pool_size = 1; + if (sscanf(buf, "%d", &PoolSize) == 1) + pool_size = 1; } - + } - + /*------------------------------------------------- number of trials */ - else if ( strcmp(buf, TRIAL_TAG) == 0 ) + else if (strcmp(buf, TRIAL_TAG) == 0) { i = next_token(file, buf, sizeof(buf)); - + if (i != EOF) { - if (sscanf (buf, "%d", &Generations) == 1) number_trials = 1; + if (sscanf(buf, "%d", &Generations) == 1) + number_trials = 1; } - + } - + /*------------------------------------------------- optimization effort */ - else if ( strcmp(buf, EFFORT_TAG) == 0 ) + else if (strcmp(buf, EFFORT_TAG) == 0) { i = next_token(file, buf, sizeof(buf)); - + if (i != EOF) { - if (strcmp (buf, LOW) == 0) effort = LOW_EFFORT; - else if (strcmp (buf, MEDIUM) == 0) effort = MEDIUM_EFFORT; - else if (strcmp (buf, HIGH) == 0) effort = HIGH_EFFORT; + if (strcmp(buf, LOW) == 0) + effort = LOW_EFFORT; + else if (strcmp(buf, MEDIUM) == 0) + effort = MEDIUM_EFFORT; + else if (strcmp(buf, HIGH) == 0) + effort = HIGH_EFFORT; } - + } - + /*------------------------------------------- random seed */ - else if ( strcmp(buf, RAND_TAG) == 0 ) - { + else if (strcmp(buf, RAND_TAG) == 0) + { i = next_token(file, buf, sizeof(buf)); - + if (i != EOF) { - if (sscanf (buf, "%ld", &RandomSeed) == 1) random_seed = 1; + if (sscanf(buf, "%ld", &RandomSeed) == 1) + random_seed = 1; } - + } - + /*------------------------------------------- selection bias */ - else if ( strcmp(buf, BIAS_TAG) == 0 ) + else if (strcmp(buf, BIAS_TAG) == 0) { i = next_token(file, buf, sizeof(buf)); - + if (i != EOF) { - if (sscanf (buf, "%lf", &SelectionBias) == 1) selection_bias = 1; + if (sscanf(buf, "%lf", &SelectionBias) == 1) + selection_bias = 1; } - + } - + /* unrecognized tags */ else { if (i != EOF) { } - - elog(DEBUG,"geqo_params: unknown parameter type \"%s\"\nin file \'%s\'", buf, conf_file); + + elog(DEBUG, "geqo_params: unknown parameter type \"%s\"\nin file \'%s\'", buf, conf_file); /* if not at end-of-line, keep reading til we are */ - while (i == 0) i = next_token(file, buf, sizeof(buf)); - } + while (i == 0) + i = next_token(file, buf, sizeof(buf)); + } } FreeFile(file); @@ -194,9 +204,9 @@ geqo_params(int string_length) pfree(conf_file); } - else + else { - elog(DEBUG,"geqo_params: ga parameter file\n\'%s\'\ndoes not exist or permissions are not setup correctly", conf_file); + elog(DEBUG, "geqo_params: ga parameter file\n\'%s\'\ndoes not exist or permissions are not setup correctly", conf_file); } /* @@ -204,49 +214,49 @@ geqo_params(int string_length) */ /**************** PoolSize: essential ****************/ - if ( !(pool_size) ) + if (!(pool_size)) { PoolSize = gimme_pool_size(string_length); - elog(DEBUG,"geqo_params: no pool size specified;\nusing computed value of %d", PoolSize); + elog(DEBUG, "geqo_params: no pool size specified;\nusing computed value of %d", PoolSize); } - - + + /**************** Effort: essential ****************/ - if ( !(effort) ) + if (!(effort)) { if (PoolSize == MAX_POOL) effort = HIGH_EFFORT; else effort = MEDIUM_EFFORT; - - elog(DEBUG,"geqo_params: no optimization effort specified;\nusing value of %d", effort); + + elog(DEBUG, "geqo_params: no optimization effort specified;\nusing value of %d", effort); } /**************** Generations: essential ****************/ - if ( !(number_trials) ) + if (!(number_trials)) { Generations = gimme_number_generations(PoolSize, effort); - - elog(DEBUG,"geqo_params: no number of trials specified;\nusing computed value of %d", Generations); + + elog(DEBUG, "geqo_params: no number of trials specified;\nusing computed value of %d", Generations); } /* RandomSeed: */ - if ( !(random_seed) ) + if (!(random_seed)) { RandomSeed = (long) time(NULL); - elog(DEBUG,"geqo_params: no random seed specified;\nusing computed value of %ld", RandomSeed); + elog(DEBUG, "geqo_params: no random seed specified;\nusing computed value of %ld", RandomSeed); } /* SelectionBias: */ - if ( !(selection_bias) ) + if (!(selection_bias)) { SelectionBias = SELECTION_BIAS; - elog(DEBUG,"geqo_params: no selection bias specified;\nusing default value of %f", SelectionBias); + elog(DEBUG, "geqo_params: no selection bias specified;\nusing default value of %f", SelectionBias); } } @@ -255,73 +265,79 @@ geqo_params(int string_length) /* * Grab one token out of fp. Defined as the next string of non-whitespace * in the file. After we get the token, continue reading until EOF, end of - * line or the next token. If it's the last token on the line, return '\n' + * line or the next token. If it's the last token on the line, return '\n' * for the value. If we get EOF before reading a token, return EOF. In all * other cases return 0. */ -static int -next_token(FILE *fp, char *buf, int bufsz) +static int +next_token(FILE * fp, char *buf, int bufsz) { - int c; - char *eb = buf+(bufsz-1); + int c; + char *eb = buf + (bufsz - 1); - /* Discard inital whitespace */ - while (isspace(c = getc(fp))) ; + /* Discard inital whitespace */ + while (isspace(c = getc(fp))); - /* EOF seen before any token so return EOF */ - if (c == EOF) return -1; + /* EOF seen before any token so return EOF */ + if (c == EOF) + return -1; - /* Form a token in buf */ - do { - if (buf < eb) *buf++ = c; - c = getc(fp); - } while (!isspace(c) && c != EOF); - *buf = '\0'; + /* Form a token in buf */ + do + { + if (buf < eb) + *buf++ = c; + c = getc(fp); + } while (!isspace(c) && c != EOF); + *buf = '\0'; - /* Discard trailing tabs and spaces */ - while (c == ' ' || c == '\t') c = getc(fp); + /* Discard trailing tabs and spaces */ + while (c == ' ' || c == '\t') + c = getc(fp); - /* Put back the char that was non-whitespace (putting back EOF is ok) */ - ungetc(c, fp); + /* Put back the char that was non-whitespace (putting back EOF is ok) */ + ungetc(c, fp); - /* If we ended with a newline, return that, otherwise return 0 */ - return (c == '\n' ? '\n' : 0); + /* If we ended with a newline, return that, otherwise return 0 */ + return (c == '\n' ? '\n' : 0); } /* gimme_pool_size-- - * compute good estimation for pool size - * according to number of involved rels in a query + * compute good estimation for pool size + * according to number of involved rels in a query */ -static int +static int gimme_pool_size(int string_length) { - double exponent; - double size; + double exponent; + double size; exponent = (double) string_length + 1.0; - size = pow (2.0, exponent); + size = pow(2.0, exponent); - if (size < MIN_POOL) { + if (size < MIN_POOL) + { return (MIN_POOL); - } - else if (size > MAX_POOL) { + } + else if (size > MAX_POOL) + { return (MAX_POOL); - } - else - return ( (int) ceil(size) ); + } + else + return ((int) ceil(size)); } /* gimme_number_generations-- - * compute good estimation for number of generations size - * for convergence + * compute good estimation for number of generations size + * for convergence */ -static int +static int gimme_number_generations(int pool_size, int effort) { - int number_gens; + int number_gens; - number_gens = (int) ceil ( geqo_log((double) pool_size, 2.0) ); + number_gens = (int) ceil(geqo_log((double) pool_size, 2.0)); return (effort * number_gens); } diff --git a/src/backend/optimizer/geqo/geqo_paths.c b/src/backend/optimizer/geqo/geqo_paths.c index a22be406f5a..d98855d2887 100644 --- a/src/backend/optimizer/geqo/geqo_paths.c +++ b/src/backend/optimizer/geqo/geqo_paths.c @@ -1,11 +1,11 @@ /*------------------------------------------------------------------------- * * geqo_paths.c-- - * Routines to process redundant paths and relations + * Routines to process redundant paths and relations * * Copyright (c) 1994, Regents of the University of California * - * $Id: geqo_paths.c,v 1.4 1997/06/11 02:44:12 vadim Exp $ + * $Id: geqo_paths.c,v 1.5 1997/09/07 04:43:17 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -28,120 +28,128 @@ #include "optimizer/geqo_paths.h" -static List *geqo_prune_rel(Rel *rel, List *other_rels); -static Path *set_paths(Rel *rel, Path *unorderedpath); +static List *geqo_prune_rel(Rel * rel, List * other_rels); +static Path *set_paths(Rel * rel, Path * unorderedpath); -/* +/* * geqo-prune-rels-- - * Removes any redundant relation entries from a list of rel nodes - * 'rel-list'. - * - * Returns the resulting list. - * + * Removes any redundant relation entries from a list of rel nodes + * 'rel-list'. + * + * Returns the resulting list. + * */ -List *geqo_prune_rels(List *rel_list) +List * +geqo_prune_rels(List * rel_list) { - List *temp_list = NIL; - - if (rel_list != NIL) { - temp_list = lcons(lfirst(rel_list), - geqo_prune_rels(geqo_prune_rel((Rel*)lfirst(rel_list), - lnext(rel_list)))); - } - return(temp_list); + List *temp_list = NIL; + + if (rel_list != NIL) + { + temp_list = lcons(lfirst(rel_list), + geqo_prune_rels(geqo_prune_rel((Rel *) lfirst(rel_list), + lnext(rel_list)))); + } + return (temp_list); } -/* +/* * geqo-prune-rel-- - * Prunes those relations from 'other-rels' that are redundant with - * 'rel'. A relation is redundant if it is built up of the same - * relations as 'rel'. Paths for the redundant relation are merged into - * the pathlist of 'rel'. - * + * Prunes those relations from 'other-rels' that are redundant with + * 'rel'. A relation is redundant if it is built up of the same + * relations as 'rel'. Paths for the redundant relation are merged into + * the pathlist of 'rel'. + * * Returns a list of non-redundant relations, and sets the pathlist field * of 'rel' appropriately. - * + * */ -static List * -geqo_prune_rel(Rel *rel, List *other_rels) +static List * +geqo_prune_rel(Rel * rel, List * other_rels) { - List *i = NIL; - List *t_list = NIL; - List *temp_node = NIL; - Rel *other_rel = (Rel *)NULL; - - foreach(i, other_rels) { - other_rel = (Rel*)lfirst(i); - if(same(rel->relids, other_rel->relids)) { - rel->pathlist = add_pathlist(rel, - rel->pathlist, - other_rel->pathlist); - t_list = nconc(t_list, NIL); /* XXX is this right ? */ - } else { - temp_node = lcons(other_rel, NIL); - t_list = nconc(t_list,temp_node); - } - } - return(t_list); + List *i = NIL; + List *t_list = NIL; + List *temp_node = NIL; + Rel *other_rel = (Rel *) NULL; + + foreach(i, other_rels) + { + other_rel = (Rel *) lfirst(i); + if (same(rel->relids, other_rel->relids)) + { + rel->pathlist = add_pathlist(rel, + rel->pathlist, + other_rel->pathlist); + t_list = nconc(t_list, NIL); /* XXX is this right ? */ + } + else + { + temp_node = lcons(other_rel, NIL); + t_list = nconc(t_list, temp_node); + } + } + return (t_list); } -/* +/* * geqo-rel-paths-- - * For a relation 'rel' (which corresponds to a join - * relation), set pointers to the unordered path and cheapest paths - * (if the unordered path isn't the cheapest, it is pruned), and - * reset the relation's size field to reflect the join. - * + * For a relation 'rel' (which corresponds to a join + * relation), set pointers to the unordered path and cheapest paths + * (if the unordered path isn't the cheapest, it is pruned), and + * reset the relation's size field to reflect the join. + * * Returns nothing of interest. - * + * */ void -geqo_rel_paths(Rel *rel) +geqo_rel_paths(Rel * rel) { - List *y = NIL; - Path *path = (Path*)NULL; - JoinPath *cheapest = (JoinPath*)NULL; - - rel->size = 0; - foreach(y, rel->pathlist) - { - path = (Path*)lfirst(y); - - if(!path->p_ordering.ord.sortop) + List *y = NIL; + Path *path = (Path *) NULL; + JoinPath *cheapest = (JoinPath *) NULL; + + rel->size = 0; + foreach(y, rel->pathlist) + { + path = (Path *) lfirst(y); + + if (!path->p_ordering.ord.sortop) break; - } + } - cheapest = (JoinPath*)set_paths(rel, path); - if ( IsA_JoinPath (cheapest) ) - rel->size = compute_joinrel_size(cheapest); + cheapest = (JoinPath *) set_paths(rel, path); + if (IsA_JoinPath(cheapest)) + rel->size = compute_joinrel_size(cheapest); } -/* +/* * set-path-- - * Compares the unordered path for a relation with the cheapest path. If - * the unordered path is not cheapest, it is pruned. - * - * Resets the pointers in 'rel' for unordered and cheapest paths. - * + * Compares the unordered path for a relation with the cheapest path. If + * the unordered path is not cheapest, it is pruned. + * + * Resets the pointers in 'rel' for unordered and cheapest paths. + * * Returns the cheapest path. - * + * */ -static Path * -set_paths(Rel *rel, Path *unorderedpath) +static Path * +set_paths(Rel * rel, Path * unorderedpath) { - Path *cheapest = set_cheapest(rel, rel->pathlist); - - /* don't prune if not pruneable -- JMH, 11/23/92 */ - if(unorderedpath != cheapest - && rel->pruneable) { - - rel->unorderedpath = (Path *)NULL; - rel->pathlist = lremove(unorderedpath, rel->pathlist); - } else { - rel->unorderedpath = (Path *)unorderedpath; - } - - return(cheapest); + Path *cheapest = set_cheapest(rel, rel->pathlist); + + /* don't prune if not pruneable -- JMH, 11/23/92 */ + if (unorderedpath != cheapest + && rel->pruneable) + { + + rel->unorderedpath = (Path *) NULL; + rel->pathlist = lremove(unorderedpath, rel->pathlist); + } + else + { + rel->unorderedpath = (Path *) unorderedpath; + } + + return (cheapest); } - diff --git a/src/backend/optimizer/geqo/geqo_pmx.c b/src/backend/optimizer/geqo/geqo_pmx.c index c6e699cfa9f..c9187fec54b 100644 --- a/src/backend/optimizer/geqo/geqo_pmx.c +++ b/src/backend/optimizer/geqo/geqo_pmx.c @@ -2,35 +2,35 @@ * * geqo_pmx.c-- * -* partially matched crossover [PMX] routines; -* PMX operator according to Goldberg & Lingle -* (Proc Int'l Conf on GA's) +* partially matched crossover [PMX] routines; +* PMX operator according to Goldberg & Lingle +* (Proc Int'l Conf on GA's) * -* $Id: geqo_pmx.c,v 1.1 1997/02/19 12:57:28 scrappy Exp $ +* $Id: geqo_pmx.c,v 1.2 1997/09/07 04:43:18 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ /* the pmx algorithm is adopted from Genitor : */ /*************************************************************/ -/* */ -/* Copyright (c) 1990 */ -/* Darrell L. Whitley */ -/* Computer Science Department */ -/* Colorado State University */ -/* */ -/* Permission is hereby granted to copy all or any part of */ -/* this program for free distribution. The author's name */ -/* and this copyright notice must be included in any copy. */ -/* */ +/* */ +/* Copyright (c) 1990 */ +/* Darrell L. Whitley */ +/* Computer Science Department */ +/* Colorado State University */ +/* */ +/* Permission is hereby granted to copy all or any part of */ +/* this program for free distribution. The author's name */ +/* and this copyright notice must be included in any copy. */ +/* */ /*************************************************************/ #include "postgres.h" @@ -56,155 +56,182 @@ /* pmx-- * - * partially matched crossover + * partially matched crossover */ void -pmx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene) +pmx(Gene * tour1, Gene * tour2, Gene * offspring, int num_gene) { - int *failed = (int *) palloc ((num_gene+1)*sizeof(int)); - int *from = (int *) palloc ((num_gene+1)*sizeof(int)); - int *indx = (int *) palloc ((num_gene+1)*sizeof(int)); - int *check_list = (int *) palloc ((num_gene+1)*sizeof(int)); + int *failed = (int *) palloc((num_gene + 1) * sizeof(int)); + int *from = (int *) palloc((num_gene + 1) * sizeof(int)); + int *indx = (int *) palloc((num_gene + 1) * sizeof(int)); + int *check_list = (int *) palloc((num_gene + 1) * sizeof(int)); + + int left, + right, + temp, + i, + j, + k; + int mx_fail, + found, + mx_hold; - int left, right, temp, i, j, k; - int mx_fail, found, mx_hold; - /* no mutation so start up the pmx replacement algorithm */ /* initialize failed[], from[], check_list[] */ - for (k = 0; k < num_gene; k++) { - failed[k] = -1; - from[k] = -1; - check_list[k+1] = 0; - } - + for (k = 0; k < num_gene; k++) + { + failed[k] = -1; + from[k] = -1; + check_list[k + 1] = 0; + } + /* locate crossover points */ - left = geqo_randint(num_gene-1, 0); - right = geqo_randint(num_gene-1, 0); + left = geqo_randint(num_gene - 1, 0); + right = geqo_randint(num_gene - 1, 0); - if (left > right) { - temp = left; - left = right; - right = temp; - } + if (left > right) + { + temp = left; + left = right; + right = temp; + } /* copy tour2 into offspring */ - for (k = 0; k < num_gene; k++) { - offspring[k] = tour2[k]; - from[k] = DAD; - check_list[tour2[k]]++; - } - + for (k = 0; k < num_gene; k++) + { + offspring[k] = tour2[k]; + from[k] = DAD; + check_list[tour2[k]]++; + } + /* copy tour1 into offspring */ - for (k = left; k <= right; k++) { - check_list[offspring[k]]--; - offspring[k] = tour1[k]; - from[k] = MOM; - check_list[tour1[k]]++; - } + for (k = left; k <= right; k++) + { + check_list[offspring[k]]--; + offspring[k] = tour1[k]; + from[k] = MOM; + check_list[tour1[k]]++; + } /* pmx main part */ - mx_fail = 0; + mx_fail = 0; /* STEP 1 */ - for (k = left; k <= right; k++) { /* for all elements in the tour1-2 */ - - if (tour1[k] == tour2[k]) found = 1; /* find match in tour2 */ + for (k = left; k <= right; k++) + { /* for all elements in the tour1-2 */ - else { - found = 0; /* substitute elements */ + if (tour1[k] == tour2[k]) + found = 1; /* find match in tour2 */ - j = 0; - while ( !(found) && (j < num_gene) ) { - if ( (offspring[j] == tour1[k]) && (from[j] == DAD) ) { + else + { + found = 0; /* substitute elements */ - check_list[offspring[j]]--; - offspring[j] = tour2[k]; - found = 1; - check_list[tour2[k]]++; - } + j = 0; + while (!(found) && (j < num_gene)) + { + if ((offspring[j] == tour1[k]) && (from[j] == DAD)) + { - j++; - } + check_list[offspring[j]]--; + offspring[j] = tour2[k]; + found = 1; + check_list[tour2[k]]++; + } - } + j++; + } - if ( !(found) ) { /* failed to replace gene */ - failed[mx_fail] = (int) tour1[k]; - indx[mx_fail] = k; - mx_fail++; - } - - } /* ... for */ - - -/* STEP 2 */ + } - /* see if any genes could not be replaced */ - if (mx_fail > 0) { - mx_hold = mx_fail; + if (!(found)) + { /* failed to replace gene */ + failed[mx_fail] = (int) tour1[k]; + indx[mx_fail] = k; + mx_fail++; + } - for (k = 0; k < mx_hold; k++) { - found = 0; + } /* ... for */ - j = 0; - while ( !(found) && (j < num_gene) ) { - if ( (failed[k] == (int) offspring[j]) && (from[j] == DAD) ) { - check_list[offspring[j]]--; - offspring[j] = tour2[indx[k]]; - check_list[tour2[indx[k]]]++; - - found = 1; - failed[k] = -1; - mx_fail--; - } +/* STEP 2 */ - j++; - } + /* see if any genes could not be replaced */ + if (mx_fail > 0) + { + mx_hold = mx_fail; - } /* ... for */ + for (k = 0; k < mx_hold; k++) + { + found = 0; - } /* ... if */ - + j = 0; + while (!(found) && (j < num_gene)) + { -/* STEP 3 */ + if ((failed[k] == (int) offspring[j]) && (from[j] == DAD)) + { + check_list[offspring[j]]--; + offspring[j] = tour2[indx[k]]; + check_list[tour2[indx[k]]]++; - for (k = 1; k <= num_gene; k++) { + found = 1; + failed[k] = -1; + mx_fail--; + } - if (check_list[k] > 1) { - i = 0; + j++; + } - while (i < num_gene) { - if ( (offspring[i] == (Gene) k) && (from[i] == DAD) ) { - j = 1; + } /* ... for */ - while (j <= num_gene) { - if (check_list[j] == 0) { - offspring[i] = (Gene) j; - check_list[k]--; - check_list[j]++; - i = num_gene + 1; - j = i; - } + } /* ... if */ - j++; - } - } /* ... if */ - - i++; - } /* end while */ +/* STEP 3 */ - } - } /* ... for */ - - pfree(failed); - pfree(from); - pfree(indx); - pfree(check_list); + for (k = 1; k <= num_gene; k++) + { + + if (check_list[k] > 1) + { + i = 0; + + while (i < num_gene) + { + if ((offspring[i] == (Gene) k) && (from[i] == DAD)) + { + j = 1; + + while (j <= num_gene) + { + if (check_list[j] == 0) + { + offspring[i] = (Gene) j; + check_list[k]--; + check_list[j]++; + i = num_gene + 1; + j = i; + } + + j++; + } + + } /* ... if */ + + i++; + } /* end while */ + + } + } /* ... for */ + + pfree(failed); + pfree(from); + pfree(indx); + pfree(check_list); } diff --git a/src/backend/optimizer/geqo/geqo_pool.c b/src/backend/optimizer/geqo/geqo_pool.c index 98a1a6e2a06..89c945d4ef4 100644 --- a/src/backend/optimizer/geqo/geqo_pool.c +++ b/src/backend/optimizer/geqo/geqo_pool.c @@ -1,20 +1,20 @@ /*------------------------------------------------------------------------ * * geqo_pool.c-- - * Genetic Algorithm (GA) pool stuff + * Genetic Algorithm (GA) pool stuff * * Copyright (c) 1994, Regents of the University of California * - * $Id: geqo_pool.c,v 1.1 1997/02/19 12:57:31 scrappy Exp $ + * $Id: geqo_pool.c,v 1.2 1997/09/07 04:43:19 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ @@ -44,205 +44,220 @@ #include "optimizer/geqo_recombination.h" -static int compare(void *arg1, void *arg2); +static int compare(void *arg1, void *arg2); /* * alloc-pool-- - * allocates memory for GA pool + * allocates memory for GA pool */ -Pool * +Pool * alloc_pool(int pool_size, int string_length) { - Pool *new_pool; - Chromosome *chromo; - int i; - - /* pool */ - new_pool = (Pool *) palloc (sizeof(Pool)); - new_pool->size = (int) pool_size; - new_pool->string_length = (int) string_length; - - /* all chromosome */ - new_pool->data = (Chromosome *) palloc (pool_size * sizeof(Chromosome)); - - /* all gene */ - chromo = (Chromosome *) new_pool->data; /* vector of all chromos */ - for (i=0; i<pool_size; i++) { - chromo[i].string = palloc((string_length+1)*sizeof(Gene)); + Pool *new_pool; + Chromosome *chromo; + int i; + + /* pool */ + new_pool = (Pool *) palloc(sizeof(Pool)); + new_pool->size = (int) pool_size; + new_pool->string_length = (int) string_length; + + /* all chromosome */ + new_pool->data = (Chromosome *) palloc(pool_size * sizeof(Chromosome)); + + /* all gene */ + chromo = (Chromosome *) new_pool->data; /* vector of all chromos */ + for (i = 0; i < pool_size; i++) + { + chromo[i].string = palloc((string_length + 1) * sizeof(Gene)); } - return (new_pool); + return (new_pool); } /* * free-pool-- - * deallocates memory for GA pool + * deallocates memory for GA pool */ void -free_pool (Pool *pool) +free_pool(Pool * pool) { - Chromosome *chromo; - int i; + Chromosome *chromo; + int i; - /* all gene */ - chromo = (Chromosome *) pool->data; /* vector of all chromos */ - for (i=0; i<pool->size; i++) pfree(chromo[i].string); + /* all gene */ + chromo = (Chromosome *) pool->data; /* vector of all chromos */ + for (i = 0; i < pool->size; i++) + pfree(chromo[i].string); - /* all chromosome */ - pfree (pool->data); + /* all chromosome */ + pfree(pool->data); - /* pool */ - pfree (pool); + /* pool */ + pfree(pool); } /* * random-init-pool-- - * initialize genetic pool + * initialize genetic pool */ void -random_init_pool (Query *root, Pool *pool, int strt, int stp) +random_init_pool(Query * root, Pool * pool, int strt, int stp) { - Chromosome *chromo = (Chromosome *) pool->data; - int i; + Chromosome *chromo = (Chromosome *) pool->data; + int i; - for (i=strt; i<stp; i++) { - init_tour(chromo[i].string, pool->string_length); /* from "geqo_recombination.c" */ + for (i = strt; i < stp; i++) + { + init_tour(chromo[i].string, pool->string_length); /* from + * "geqo_recombination.c" + * */ - pool->data[i].worth = - geqo_eval(root, chromo[i].string, pool->string_length); /* "from geqo_eval.c" */ + pool->data[i].worth = + geqo_eval(root, chromo[i].string, pool->string_length); /* "from geqo_eval.c" */ } } /* * sort-pool-- - * sorts input pool according to worth, from smallest to largest + * sorts input pool according to worth, from smallest to largest * - * maybe you have to change compare() for different ordering ... + * maybe you have to change compare() for different ordering ... */ void -sort_pool(Pool *pool) -{ - pg_qsort(pool->data, pool->size, sizeof(Chromosome), compare); +sort_pool(Pool * pool) +{ + pg_qsort(pool->data, pool->size, sizeof(Chromosome), compare); } /* * compare-- - * static input function for pg_sort + * static input function for pg_sort * - * return values for sort from smallest to largest are prooved! - * don't change them! + * return values for sort from smallest to largest are prooved! + * don't change them! */ static int compare(void *arg1, void *arg2) { - Chromosome chromo1 = *(Chromosome *) arg1; - Chromosome chromo2 = *(Chromosome *) arg2; - - if (chromo1.worth == chromo2.worth) - return(0); - else if (chromo1.worth > chromo2.worth) - return(1); - else - return(-1); + Chromosome chromo1 = *(Chromosome *) arg1; + Chromosome chromo2 = *(Chromosome *) arg2; + + if (chromo1.worth == chromo2.worth) + return (0); + else if (chromo1.worth > chromo2.worth) + return (1); + else + return (-1); } /* alloc_chromo-- - * allocates a chromosome and string space + * allocates a chromosome and string space */ -Chromosome * -alloc_chromo (int string_length) +Chromosome * +alloc_chromo(int string_length) { - Chromosome *chromo; + Chromosome *chromo; + + chromo = (Chromosome *) palloc(sizeof(Chromosome)); + chromo->string = (Gene *) palloc((string_length + 1) * sizeof(Gene)); - chromo = (Chromosome *) palloc (sizeof(Chromosome)); - chromo->string = (Gene *) palloc ((string_length+1)*sizeof(Gene)); - - return (chromo); + return (chromo); } /* free_chromo-- - * deallocates a chromosome and string space + * deallocates a chromosome and string space */ void -free_chromo (Chromosome *chromo) +free_chromo(Chromosome * chromo) { - pfree(chromo->string); - pfree(chromo); + pfree(chromo->string); + pfree(chromo); } /* spread_chromo-- - * inserts a new chromosome into the pool, displacing worst gene in pool - * assumes best->worst = smallest->largest + * inserts a new chromosome into the pool, displacing worst gene in pool + * assumes best->worst = smallest->largest */ void -spread_chromo (Chromosome *chromo, Pool *pool) +spread_chromo(Chromosome * chromo, Pool * pool) { - int top, mid, bot; - int i, index; - Chromosome swap_chromo, tmp_chromo; - - /* new chromo is so bad we can't use it */ - if (chromo->worth > pool->data[pool->size-1].worth) return; - - /* do a binary search to find the index of the new chromo */ - - top = 0; - mid = pool->size/2; - bot = pool->size-1; - index = -1; - - while (index == -1) { - /* these 4 cases find a new location */ - - if (chromo->worth <= pool->data[top].worth) - index = top; - else - if (chromo->worth == pool->data[mid].worth) - index = mid; - else - if (chromo->worth == pool->data[bot].worth) - index = bot; - else - if (bot-top <=1) - index = bot; - - - /* these 2 cases move the search indices since - a new location has not yet been found. */ - - else - if (chromo->worth < pool->data[mid].worth) { - bot = mid; - mid = top + ( (bot-top)/2 ); - } - else { /* (chromo->worth > pool->data[mid].worth) */ - top = mid; - mid = top + ( (bot-top)/2 ); - } - } /* ... while */ - - /* now we have index for chromo */ - - /* move every gene from index on down - one position to make room for chromo */ - - /* copy new gene into pool storage; - always replace worst gene in pool */ - - geqo_copy (&pool->data[pool->size-1], chromo, pool->string_length); - - swap_chromo.string = pool->data[pool->size-1].string; - swap_chromo.worth = pool->data[pool->size-1].worth; - - for (i=index; i<pool->size; i++) { - tmp_chromo.string = pool->data[i].string; - tmp_chromo.worth = pool->data[i].worth; - - pool->data[i].string = swap_chromo.string; - pool->data[i].worth = swap_chromo.worth; - - swap_chromo.string = tmp_chromo.string; - swap_chromo.worth = tmp_chromo.worth; - } + int top, + mid, + bot; + int i, + index; + Chromosome swap_chromo, + tmp_chromo; + + /* new chromo is so bad we can't use it */ + if (chromo->worth > pool->data[pool->size - 1].worth) + return; + + /* do a binary search to find the index of the new chromo */ + + top = 0; + mid = pool->size / 2; + bot = pool->size - 1; + index = -1; + + while (index == -1) + { + /* these 4 cases find a new location */ + + if (chromo->worth <= pool->data[top].worth) + index = top; + else if (chromo->worth == pool->data[mid].worth) + index = mid; + else if (chromo->worth == pool->data[bot].worth) + index = bot; + else if (bot - top <= 1) + index = bot; + + + /* + * these 2 cases move the search indices since a new location has + * not yet been found. + */ + + else if (chromo->worth < pool->data[mid].worth) + { + bot = mid; + mid = top + ((bot - top) / 2); + } + else + { /* (chromo->worth > pool->data[mid].worth) */ + top = mid; + mid = top + ((bot - top) / 2); + } + } /* ... while */ + + /* now we have index for chromo */ + + /* + * move every gene from index on down one position to make room for + * chromo + */ + + /* + * copy new gene into pool storage; always replace worst gene in pool + */ + + geqo_copy(&pool->data[pool->size - 1], chromo, pool->string_length); + + swap_chromo.string = pool->data[pool->size - 1].string; + swap_chromo.worth = pool->data[pool->size - 1].worth; + + for (i = index; i < pool->size; i++) + { + tmp_chromo.string = pool->data[i].string; + tmp_chromo.worth = pool->data[i].worth; + + pool->data[i].string = swap_chromo.string; + pool->data[i].worth = swap_chromo.worth; + + swap_chromo.string = tmp_chromo.string; + swap_chromo.worth = tmp_chromo.worth; + } } diff --git a/src/backend/optimizer/geqo/geqo_px.c b/src/backend/optimizer/geqo/geqo_px.c index f060561b516..71aa2415b55 100644 --- a/src/backend/optimizer/geqo/geqo_px.c +++ b/src/backend/optimizer/geqo/geqo_px.c @@ -2,35 +2,35 @@ * * geqo_px.c-- * -* position crossover [PX] routines; -* PX operator according to Syswerda -* (The Genetic Algorithms Handbook, L Davis, ed) +* position crossover [PX] routines; +* PX operator according to Syswerda +* (The Genetic Algorithms Handbook, L Davis, ed) * -* $Id: geqo_px.c,v 1.1 1997/02/19 12:57:37 scrappy Exp $ +* $Id: geqo_px.c,v 1.2 1997/09/07 04:43:20 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ /* the px algorithm is adopted from Genitor : */ /*************************************************************/ -/* */ -/* Copyright (c) 1990 */ -/* Darrell L. Whitley */ -/* Computer Science Department */ -/* Colorado State University */ -/* */ -/* Permission is hereby granted to copy all or any part of */ -/* this program for free distribution. The author's name */ -/* and this copyright notice must be included in any copy. */ -/* */ +/* */ +/* Copyright (c) 1990 */ +/* Darrell L. Whitley */ +/* Computer Science Department */ +/* Colorado State University */ +/* */ +/* Permission is hereby granted to copy all or any part of */ +/* this program for free distribution. The author's name */ +/* and this copyright notice must be included in any copy. */ +/* */ /*************************************************************/ #include "postgres.h" @@ -56,61 +56,70 @@ /* px-- * - * position crossover + * position crossover */ void -px(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table) +px(Gene * tour1, Gene * tour2, Gene * offspring, int num_gene, City * city_table) { - int num_positions; - int i, pos, tour2_index, offspring_index; + int num_positions; + int i, + pos, + tour2_index, + offspring_index; - /* initialize city table */ - for (i=1; i<=num_gene; i++) { - city_table[i].used = 0; - } + /* initialize city table */ + for (i = 1; i <= num_gene; i++) + { + city_table[i].used = 0; + } - /* choose random positions that will be inherited directly from parent */ - num_positions = geqo_randint (2*num_gene/3, num_gene/3); + /* choose random positions that will be inherited directly from parent */ + num_positions = geqo_randint(2 * num_gene / 3, num_gene / 3); - /* choose random position */ - for (i=0; i<num_positions; i++) { - pos = geqo_randint (num_gene - 1, 0); + /* choose random position */ + for (i = 0; i < num_positions; i++) + { + pos = geqo_randint(num_gene - 1, 0); - offspring[pos] = tour1[pos]; /* transfer cities to child */ - city_table[(int) tour1[pos]].used = 1; /* mark city used */ - } + offspring[pos] = tour1[pos]; /* transfer cities to child */ + city_table[(int) tour1[pos]].used = 1; /* mark city used */ + } - tour2_index = 0; - offspring_index = 0; + tour2_index = 0; + offspring_index = 0; - /* px main part */ + /* px main part */ - while (offspring_index < num_gene) { + while (offspring_index < num_gene) + { - /* next position in offspring filled */ - if (!city_table[(int) tour1[offspring_index]].used) { + /* next position in offspring filled */ + if (!city_table[(int) tour1[offspring_index]].used) + { - /* next city in tour1 not used */ - if (!city_table[(int) tour2[tour2_index]].used) { + /* next city in tour1 not used */ + if (!city_table[(int) tour2[tour2_index]].used) + { - /* inherit from tour1 */ - offspring[offspring_index] = tour2[tour2_index]; + /* inherit from tour1 */ + offspring[offspring_index] = tour2[tour2_index]; - tour2_index++; - offspring_index++; - } - else { /* next city in tour2 has been used */ - tour2_index++; - } + tour2_index++; + offspring_index++; + } + else + { /* next city in tour2 has been used */ + tour2_index++; + } - } - else { /* next position in offspring is filled */ - offspring_index++; - } + } + else + { /* next position in offspring is filled */ + offspring_index++; + } - } - - } + } +} diff --git a/src/backend/optimizer/geqo/geqo_recombination.c b/src/backend/optimizer/geqo/geqo_recombination.c index df175dcb866..53803079819 100644 --- a/src/backend/optimizer/geqo/geqo_recombination.c +++ b/src/backend/optimizer/geqo/geqo_recombination.c @@ -1,18 +1,18 @@ /*------------------------------------------------------------------------ * * geqo_recombination.c-- -* misc recombination procedures +* misc recombination procedures * -* $Id: geqo_recombination.c,v 1.1 1997/02/19 12:57:42 scrappy Exp $ +* $Id: geqo_recombination.c,v 1.2 1997/09/07 04:43:21 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ @@ -42,65 +42,70 @@ /* * init_tour-- * - * Randomly generates a legal "traveling salesman" tour - * (i.e. where each point is visited only once.) - * Essentially, this routine fills an array with all possible - * points on the tour and randomly chooses the 'next' city from - * this array. When a city is chosen, the array is shortened - * and the procedure repeated. + * Randomly generates a legal "traveling salesman" tour + * (i.e. where each point is visited only once.) + * Essentially, this routine fills an array with all possible + * points on the tour and randomly chooses the 'next' city from + * this array. When a city is chosen, the array is shortened + * and the procedure repeated. * */ void -init_tour(Gene *tour, int num_gene) +init_tour(Gene * tour, int num_gene) { -Gene *tmp; -int remainder; -int next, i; + Gene *tmp; + int remainder; + int next, + i; -tmp = (Gene *) palloc (num_gene*sizeof(Gene)); - -for(i = 0; i < num_gene; i++) { - tmp[i] = (Gene) i+1; /* builds tours "1 - 2 - 3" etc. */ - } + tmp = (Gene *) palloc(num_gene * sizeof(Gene)); -remainder = num_gene - 1; + for (i = 0; i < num_gene; i++) + { + tmp[i] = (Gene) i + 1; /* builds tours "1 - 2 - 3" etc. */ + } -for(i = 0; i < num_gene; i++) { - next = (int) geqo_randint(remainder, 0); /* choose city between 0 and remainder */ - tour[i] = tmp[next]; - tmp[next] = tmp[remainder]; - remainder--; - } + remainder = num_gene - 1; -pfree(tmp); -} + for (i = 0; i < num_gene; i++) + { + next = (int) geqo_randint(remainder, 0); /* choose city between 0 + * and remainder */ + tour[i] = tmp[next]; + tmp[next] = tmp[remainder]; + remainder--; + } + + pfree(tmp); +} /* alloc_city_table-- * - * allocate memory for city table + * allocate memory for city table * */ -City * +City * alloc_city_table(int num_gene) { - City *city_table; + City *city_table; - /* palloc one extra location so that nodes numbered - 1..n can be indexed directly; 0 will not be used */ + /* + * palloc one extra location so that nodes numbered 1..n can be + * indexed directly; 0 will not be used + */ - city_table = (City *) palloc ((num_gene+1)*sizeof(City)); + city_table = (City *) palloc((num_gene + 1) * sizeof(City)); - return (city_table); - } + return (city_table); +} /* free_city_table-- * - * deallocate memory of city table + * deallocate memory of city table * */ - void - free_city_table(City *city_table) - { - pfree(city_table); - } - +void +free_city_table(City * city_table) +{ + pfree(city_table); +} diff --git a/src/backend/optimizer/geqo/geqo_selection.c b/src/backend/optimizer/geqo/geqo_selection.c index 0c6502003bd..820de485fe4 100644 --- a/src/backend/optimizer/geqo/geqo_selection.c +++ b/src/backend/optimizer/geqo/geqo_selection.c @@ -1,36 +1,36 @@ /*------------------------------------------------------------------------- * * geqo_selection.c-- - * linear selection scheme for the genetic query optimizer + * linear selection scheme for the genetic query optimizer * * Copyright (c) 1994, Regents of the University of California * - * $Id: geqo_selection.c,v 1.1 1997/02/19 12:57:46 scrappy Exp $ + * $Id: geqo_selection.c,v 1.2 1997/09/07 04:43:24 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= - * Martin Utesch * Institute of Automatic Control * - = = University of Mining and Technology = - * utesch@aut.tu-freiberg.de * Freiberg, Germany * + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ /* this is adopted from D. Whitley's Genitor algorithm */ /*************************************************************/ -/* */ -/* Copyright (c) 1990 */ -/* Darrell L. Whitley */ -/* Computer Science Department */ -/* Colorado State University */ -/* */ -/* Permission is hereby granted to copy all or any part of */ -/* this program for free distribution. The author's name */ -/* and this copyright notice must be included in any copy. */ -/* */ +/* */ +/* Copyright (c) 1990 */ +/* Darrell L. Whitley */ +/* Computer Science Department */ +/* Colorado State University */ +/* */ +/* Permission is hereby granted to copy all or any part of */ +/* this program for free distribution. The author's name */ +/* and this copyright notice must be included in any copy. */ +/* */ /*************************************************************/ #include <math.h> @@ -55,49 +55,51 @@ #include "optimizer/geqo_copy.h" #include "optimizer/geqo_random.h" -static int linear(int max, double bias); +static int linear(int max, double bias); /* geqo_selection-- * - * according to bias described by input parameters, - * second genes are selected from the pool + * according to bias described by input parameters, + * second genes are selected from the pool */ void -geqo_selection (Chromosome *momma, Chromosome *daddy, Pool *pool, double bias) +geqo_selection(Chromosome * momma, Chromosome * daddy, Pool * pool, double bias) { - int first, second; - - first = (int) linear(pool->size, bias); - second = (int) linear(pool->size, bias); - - if (pool->size > 1) { - while(first==second) - second = (int) linear(pool->size, bias); - } - - geqo_copy (momma, &pool->data[first], pool->string_length); - geqo_copy (daddy, &pool->data[second], pool->string_length); + int first, + second; + + first = (int) linear(pool->size, bias); + second = (int) linear(pool->size, bias); + + if (pool->size > 1) + { + while (first == second) + second = (int) linear(pool->size, bias); + } + + geqo_copy(momma, &pool->data[first], pool->string_length); + geqo_copy(daddy, &pool->data[second], pool->string_length); } /* linear-- - * generates random integer between 0 and input max number - * using input linear bias + * generates random integer between 0 and input max number + * using input linear bias * - * probability distribution function is: f(x) = bias - 2(bias - 1)x - * bias = (prob of first rule) / (prob of middle rule) + * probability distribution function is: f(x) = bias - 2(bias - 1)x + * bias = (prob of first rule) / (prob of middle rule) * */ static int -linear(int pool_size, double bias) /* bias is y-intercept of linear distribution */ +linear(int pool_size, double bias) /* bias is y-intercept of linear + * distribution */ { - double index; /* index between 0 and pop_size */ - double max = (double) pool_size; + double index; /* index between 0 and pop_size */ + double max = (double) pool_size; - index = - max*( bias - sqrt ( (bias*bias) - 4.0*(bias-1.0)*geqo_rand() ) ) - / 2.0 / (bias-1.0); + index = + max * (bias - sqrt((bias * bias) - 4.0 * (bias - 1.0) * geqo_rand())) + / 2.0 / (bias - 1.0); - return((int) index); + return ((int) index); } - diff --git a/src/backend/optimizer/geqo/minspantree.c b/src/backend/optimizer/geqo/minspantree.c index 4e4c2ad11b4..1fcc2569478 100644 --- a/src/backend/optimizer/geqo/minspantree.c +++ b/src/backend/optimizer/geqo/minspantree.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------ * * minspantree.c-- -* routine to sort a join graph which is including cycles +* routine to sort a join graph which is including cycles * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION -* $Header: /cvsroot/pgsql/src/backend/optimizer/geqo/Attic/minspantree.c,v 1.1 1997/02/19 12:57:50 scrappy Exp $ +* $Header: /cvsroot/pgsql/src/backend/optimizer/geqo/Attic/minspantree.c,v 1.2 1997/09/07 04:43:25 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -33,166 +33,181 @@ /* * minspantree-- - * The function minspantree computes the minimum spanning tree - * for a given number of nodes and a given distance function. - * For each pair of nodes found to be connected, a given - * function is called. Nodes are denoted by the integer numbers - * 1 .. number_of_joins, where number_of_joins is the number of nodes. + * The function minspantree computes the minimum spanning tree + * for a given number of nodes and a given distance function. + * For each pair of nodes found to be connected, a given + * function is called. Nodes are denoted by the integer numbers + * 1 .. number_of_joins, where number_of_joins is the number of nodes. */ void -minspantree(Query *root, List *join_rels, Rel *garel) +minspantree(Query * root, List * join_rels, Rel * garel) { - int number_of_rels = length(root->base_relation_list_); - int number_of_joins = length(join_rels); - int *connectto; - /* connectto[i] = 0, if node i is already connected */ - /* to the tree, otherwise connectto[i] is the node */ - /* nearest to i, which is already connected. */ - - Cost *disttoconnect; /* disttoconnect[i]: distance between i and connectto[i] */ - - Cost dist, /* temporary */ - mindist; /* minimal distance between connected and unconnected node */ - - Cost mstlength = 0.0; /* the total length of the minimum spanning tree */ - - int count; - int n, /* newly attached node */ - nextn, /* next node to be attached */ - tempn; - - int i, id1, id2; - List *r = NIL; - Rel *joinrel = NULL; - Rel **tmprel_array; - - - /* allocate memory for matrix tmprel_array[x][y] */ - tmprel_array = (Rel **) palloc((number_of_rels+1)*sizeof(Rel *)); - for (i=0; i<=number_of_rels; i++) - (tmprel_array[i] = (Rel *) palloc ((number_of_rels+1)*sizeof(Rel))); - - /* read relations of join-relations into tmprel_array */ - - foreach(r, join_rels) { - joinrel = (Rel *)lfirst(r); - id1 = (int)lfirst(joinrel->relids); - id2 = (int)lsecond(joinrel->relids); - - if (id1 > id2) { - tmprel_array[id2][id1] = *(Rel *)joinrel; - } - else { - tmprel_array[id1][id2] = *(Rel *)joinrel; /* ever reached? */ - } - } - - /* Trivial special cases handled first */ - /* garel is global in "tsp.h" */ - - if (number_of_joins <= 2) - { - i=1; - foreach(r, join_rels) { - garel[i] = *(Rel *)lfirst(r); - i++; - } - } - - - else if (number_of_joins == 3) - { - Rel *rel12 = (Rel *) &tmprel_array[1][2]; - Rel *rel13 = (Rel *) &tmprel_array[1][3]; - Rel *rel23 = (Rel *) &tmprel_array[2][3]; - if (rel12->cheapestpath->path_cost > rel13->cheapestpath->path_cost) - { - garel[1] = tmprel_array[1][3]; - if (rel12->cheapestpath->path_cost > rel23->cheapestpath->path_cost) + int number_of_rels = length(root->base_relation_list_); + int number_of_joins = length(join_rels); + int *connectto; + + /* connectto[i] = 0, if node i is already connected */ + /* to the tree, otherwise connectto[i] is the node */ + /* nearest to i, which is already connected. */ + + Cost *disttoconnect; /* disttoconnect[i]: distance + * between i and connectto[i] */ + + Cost dist, /* temporary */ + mindist; /* minimal distance between connected and + * unconnected node */ + + Cost mstlength = 0.0; /* the total length of the minimum + * spanning tree */ + + int count; + int n, /* newly attached node */ + nextn, /* next node to be attached */ + tempn; + + int i, + id1, + id2; + List *r = NIL; + Rel *joinrel = NULL; + Rel **tmprel_array; + + + /* allocate memory for matrix tmprel_array[x][y] */ + tmprel_array = (Rel **) palloc((number_of_rels + 1) * sizeof(Rel *)); + for (i = 0; i <= number_of_rels; i++) + (tmprel_array[i] = (Rel *) palloc((number_of_rels + 1) * sizeof(Rel))); + + /* read relations of join-relations into tmprel_array */ + + foreach(r, join_rels) { - garel[2] = tmprel_array[2][3]; + joinrel = (Rel *) lfirst(r); + id1 = (int) lfirst(joinrel->relids); + id2 = (int) lsecond(joinrel->relids); + + if (id1 > id2) + { + tmprel_array[id2][id1] = *(Rel *) joinrel; + } + else + { + tmprel_array[id1][id2] = *(Rel *) joinrel; /* ever reached? */ + } } - else + + /* Trivial special cases handled first */ + /* garel is global in "tsp.h" */ + + if (number_of_joins <= 2) { - garel[2] = tmprel_array[1][2]; + i = 1; + foreach(r, join_rels) + { + garel[i] = *(Rel *) lfirst(r); + i++; + } } - } - else - { - garel[1] = tmprel_array[1][2]; - if (rel13->cheapestpath->path_cost > rel23->cheapestpath->path_cost) + + + else if (number_of_joins == 3) { - garel[2] = tmprel_array[2][3]; + Rel *rel12 = (Rel *) & tmprel_array[1][2]; + Rel *rel13 = (Rel *) & tmprel_array[1][3]; + Rel *rel23 = (Rel *) & tmprel_array[2][3]; + + if (rel12->cheapestpath->path_cost > rel13->cheapestpath->path_cost) + { + garel[1] = tmprel_array[1][3]; + if (rel12->cheapestpath->path_cost > rel23->cheapestpath->path_cost) + { + garel[2] = tmprel_array[2][3]; + } + else + { + garel[2] = tmprel_array[1][2]; + } + } + else + { + garel[1] = tmprel_array[1][2]; + if (rel13->cheapestpath->path_cost > rel23->cheapestpath->path_cost) + { + garel[2] = tmprel_array[2][3]; + } + else + { + garel[2] = tmprel_array[1][3]; + } + } } + + + /* now the general case */ else { - garel[2] = tmprel_array[1][3]; - } - } - } - - - /* now the general case */ - else - { - connectto = (int *) palloc((number_of_rels+1)*sizeof(int)); - disttoconnect = (Cost *) palloc((number_of_rels+1)*sizeof(Cost)); - - nextn = 2; - for (tempn = 2; tempn <= number_of_rels; tempn++ ) - { - connectto[tempn] = 1; - disttoconnect[tempn] = (Cost) MAXFLOAT; - } - - joinrel = NULL; - n = 1; - i = 1; - for (count = 2; count <= number_of_rels; count++ ) - { - connectto[n] = 0; - mindist = (Cost) MAXFLOAT; - for (tempn = 2; tempn <= number_of_rels; tempn++ ) - { - if (connectto[tempn] != 0) - { - if (n > tempn) { - joinrel = (Rel *) &tmprel_array[tempn][n]; - } - else { - joinrel = (Rel *) &tmprel_array[n][tempn]; - } - dist = joinrel->cheapestpath->path_cost; - - if (dist < disttoconnect[tempn]) - { - disttoconnect[tempn] = dist; - connectto[tempn] = n; - } - if (disttoconnect[tempn] < mindist) - { - mindist = disttoconnect[tempn]; - nextn = tempn; + connectto = (int *) palloc((number_of_rels + 1) * sizeof(int)); + disttoconnect = (Cost *) palloc((number_of_rels + 1) * sizeof(Cost)); + + nextn = 2; + for (tempn = 2; tempn <= number_of_rels; tempn++) + { + connectto[tempn] = 1; + disttoconnect[tempn] = (Cost) MAXFLOAT; + } + + joinrel = NULL; + n = 1; + i = 1; + for (count = 2; count <= number_of_rels; count++) + { + connectto[n] = 0; + mindist = (Cost) MAXFLOAT; + for (tempn = 2; tempn <= number_of_rels; tempn++) + { + if (connectto[tempn] != 0) + { + if (n > tempn) + { + joinrel = (Rel *) & tmprel_array[tempn][n]; + } + else + { + joinrel = (Rel *) & tmprel_array[n][tempn]; + } + dist = joinrel->cheapestpath->path_cost; + + if (dist < disttoconnect[tempn]) + { + disttoconnect[tempn] = dist; + connectto[tempn] = n; + } + if (disttoconnect[tempn] < mindist) + { + mindist = disttoconnect[tempn]; + nextn = tempn; + } + } + } + n = nextn; + if (n > connectto[n]) + { + garel[i] = tmprel_array[connectto[n]][n]; + } + else + { + garel[i] = tmprel_array[n][connectto[n]]; + } + i++; + } + + pfree(connectto); + pfree(disttoconnect); + } - } - } - n = nextn; - if (n > connectto[n]) { - garel[i] = tmprel_array[connectto[n]][n]; - } - else { - garel[i] = tmprel_array[n][connectto[n]]; - } - i++; - } - - pfree(connectto); - pfree(disttoconnect); - - } - - for (i=0; i<=number_of_rels; i++) pfree(tmprel_array[i]); - pfree(tmprel_array); -} + for (i = 0; i <= number_of_rels; i++) + pfree(tmprel_array[i]); + pfree(tmprel_array); +} diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index d27b31cfbd7..7c4576d6f02 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * allpaths.c-- - * Routines to find possible search paths for processing a query + * Routines to find possible search paths for processing a query * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.10 1997/06/10 07:55:45 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.11 1997/09/07 04:43:27 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -34,226 +34,245 @@ #include "optimizer/geqo.h" #ifdef GEQO -bool _use_geqo_ = true; +bool _use_geqo_ = true; + #else -bool _use_geqo_ = false; +bool _use_geqo_ = false; + #endif -int32 _use_geqo_rels_ = GEQO_RELS; +int32 _use_geqo_rels_ = GEQO_RELS; -static void find_rel_paths(Query *root, List *rels); -static List *find_join_paths(Query *root, List *outer_rels, int levels_left); +static void find_rel_paths(Query * root, List * rels); +static List *find_join_paths(Query * root, List * outer_rels, int levels_left); -/* +/* * find-paths-- - * Finds all possible access paths for executing a query, returning the - * top level list of relation entries. - * + * Finds all possible access paths for executing a query, returning the + * top level list of relation entries. + * * 'rels' is the list of single relation entries appearing in the query */ -List * -find_paths(Query *root, List *rels) +List * +find_paths(Query * root, List * rels) { - int levels_left; - - /* - * Set the number of join (not nesting) levels yet to be processed. - */ - levels_left = length(rels); - - if (levels_left <= 0) - return NIL; - - /* - * Find the base relation paths. - */ - find_rel_paths(root, rels); - - if (levels_left <= 1) { + int levels_left; + /* - * Unsorted single relation, no more processing is required. + * Set the number of join (not nesting) levels yet to be processed. */ - return (rels); - }else { - /* - * this means that joins or sorts are required. - * set selectivities of clauses that have not been set - * by an index. + levels_left = length(rels); + + if (levels_left <= 0) + return NIL; + + /* + * Find the base relation paths. */ - set_rest_relselec(root, rels); + find_rel_paths(root, rels); + + if (levels_left <= 1) + { - return(find_join_paths(root, rels, levels_left-1)); - } + /* + * Unsorted single relation, no more processing is required. + */ + return (rels); + } + else + { + + /* + * this means that joins or sorts are required. set selectivities + * of clauses that have not been set by an index. + */ + set_rest_relselec(root, rels); + + return (find_join_paths(root, rels, levels_left - 1)); + } } -/* +/* * find-rel-paths-- - * Finds all paths available for scanning each relation entry in - * 'rels'. Sequential scan and any available indices are considered - * if possible(indices are not considered for lower nesting levels). - * All unique paths are attached to the relation's 'pathlist' field. - * - * MODIFIES: rels + * Finds all paths available for scanning each relation entry in + * 'rels'. Sequential scan and any available indices are considered + * if possible(indices are not considered for lower nesting levels). + * All unique paths are attached to the relation's 'pathlist' field. + * + * MODIFIES: rels */ static void -find_rel_paths(Query *root, List *rels) +find_rel_paths(Query * root, List * rels) { - List *temp; - Rel *rel; - List *lastpath; - - foreach(temp, rels) { - List *sequential_scan_list; - List *rel_index_scan_list; - List *or_index_scan_list; - - rel = (Rel *)lfirst(temp); - sequential_scan_list = lcons(create_seqscan_path(rel), - NIL); - - rel_index_scan_list = - find_index_paths(root, - rel, - find_relation_indices(root,rel), - rel->clauseinfo, - rel->joininfo); - - or_index_scan_list = - create_or_index_paths(root, rel, rel->clauseinfo); - - rel->pathlist = add_pathlist(rel, - sequential_scan_list, - append(rel_index_scan_list, - or_index_scan_list)); - - /* The unordered path is always the last in the list. - * If it is not the cheapest path, prune it. - */ - lastpath = rel->pathlist; - while(lnext(lastpath)!=NIL) - lastpath=lnext(lastpath); - prune_rel_path(rel, (Path*)lfirst(lastpath)); - /* - * if there is a qualification of sequential scan the selec. - * value is not set -- so set it explicitly -- Sunita - */ - set_rest_selec(root, rel->clauseinfo); - rel->size = compute_rel_size(rel); - rel->width = compute_rel_width(rel); - } - return; + List *temp; + Rel *rel; + List *lastpath; + + foreach(temp, rels) + { + List *sequential_scan_list; + List *rel_index_scan_list; + List *or_index_scan_list; + + rel = (Rel *) lfirst(temp); + sequential_scan_list = lcons(create_seqscan_path(rel), + NIL); + + rel_index_scan_list = + find_index_paths(root, + rel, + find_relation_indices(root, rel), + rel->clauseinfo, + rel->joininfo); + + or_index_scan_list = + create_or_index_paths(root, rel, rel->clauseinfo); + + rel->pathlist = add_pathlist(rel, + sequential_scan_list, + append(rel_index_scan_list, + or_index_scan_list)); + + /* + * The unordered path is always the last in the list. If it is not + * the cheapest path, prune it. + */ + lastpath = rel->pathlist; + while (lnext(lastpath) != NIL) + lastpath = lnext(lastpath); + prune_rel_path(rel, (Path *) lfirst(lastpath)); + + /* + * if there is a qualification of sequential scan the selec. value + * is not set -- so set it explicitly -- Sunita + */ + set_rest_selec(root, rel->clauseinfo); + rel->size = compute_rel_size(rel); + rel->width = compute_rel_width(rel); + } + return; } -/* +/* * find-join-paths-- - * Find all possible joinpaths for a query by successively finding ways - * to join single relations into join relations. + * Find all possible joinpaths for a query by successively finding ways + * to join single relations into join relations. * - * if BushyPlanFlag is set, bushy tree plans will be generated: - * Find all possible joinpaths(bushy trees) for a query by systematically - * finding ways to join relations(both original and derived) together. - * - * 'outer-rels' is the current list of relations for which join paths - * are to be found, i.e., he current list of relations that - * have already been derived. + * if BushyPlanFlag is set, bushy tree plans will be generated: + * Find all possible joinpaths(bushy trees) for a query by systematically + * finding ways to join relations(both original and derived) together. + * + * 'outer-rels' is the current list of relations for which join paths + * are to be found, i.e., he current list of relations that + * have already been derived. * 'levels-left' is the current join level being processed, where '1' is - * the "last" level - * + * the "last" level + * * Returns the final level of join relations, i.e., the relation that is * the result of joining all the original relations togehter. */ -static List * -find_join_paths(Query *root, List *outer_rels, int levels_left) +static List * +find_join_paths(Query * root, List * outer_rels, int levels_left) { - List *x; - List *new_rels; - Rel *rel; - - /******************************************* - * genetic query optimizer entry point * - * <utesch@aut.tu-freiberg.de> * - *******************************************/ - - if ( (_use_geqo_) && length(root->base_relation_list_) >= _use_geqo_rels_ ) - return lcons(geqo(root), NIL); /* returns *one* Rel, so lcons it */ - - /******************************************* - * rest will be deprecated in case of GEQO * - *******************************************/ - - /* - * Determine all possible pairs of relations to be joined at this level. - * Determine paths for joining these relation pairs and modify 'new-rels' - * accordingly, then eliminate redundant join relations. - */ - new_rels = find_join_rels(root, outer_rels); - - find_all_join_paths(root, new_rels); - - new_rels = prune_joinrels(new_rels); - -#if 0 - /* - ** for each expensive predicate in each path in each distinct rel, - ** consider doing pullup -- JMH - */ - if (XfuncMode != XFUNC_NOPULL && XfuncMode != XFUNC_OFF) - foreach(x, new_rels) - xfunc_trypullup((Rel*)lfirst(x)); -#endif + List *x; + List *new_rels; + Rel *rel; - prune_rel_paths(new_rels); + /******************************************* + * genetic query optimizer entry point * + * <utesch@aut.tu-freiberg.de> * + *******************************************/ + + if ((_use_geqo_) && length(root->base_relation_list_) >= _use_geqo_rels_) + return lcons(geqo(root), NIL); /* returns *one* Rel, so lcons it */ + + /******************************************* + * rest will be deprecated in case of GEQO * + *******************************************/ - if(BushyPlanFlag) { /* - * In case of bushy trees - * if there is still a join between a join relation and another - * relation, add a new joininfo that involves the join relation - * to the joininfo list of the other relation + * Determine all possible pairs of relations to be joined at this + * level. Determine paths for joining these relation pairs and modify + * 'new-rels' accordingly, then eliminate redundant join relations. */ - add_new_joininfos(root, new_rels,outer_rels); - } + new_rels = find_join_rels(root, outer_rels); + + find_all_join_paths(root, new_rels); + + new_rels = prune_joinrels(new_rels); - foreach(x, new_rels) { - rel = (Rel*)lfirst(x); - if ( rel->size <= 0 ) - rel->size = compute_rel_size(rel); - rel->width = compute_rel_width(rel); +#if 0 + + /* + * * for each expensive predicate in each path in each distinct rel, * + * consider doing pullup -- JMH + */ + if (XfuncMode != XFUNC_NOPULL && XfuncMode != XFUNC_OFF) + foreach(x, new_rels) + xfunc_trypullup((Rel *) lfirst(x)); +#endif + + prune_rel_paths(new_rels); + + if (BushyPlanFlag) + { + + /* + * In case of bushy trees if there is still a join between a join + * relation and another relation, add a new joininfo that involves + * the join relation to the joininfo list of the other relation + */ + add_new_joininfos(root, new_rels, outer_rels); + } + + foreach(x, new_rels) + { + rel = (Rel *) lfirst(x); + if (rel->size <= 0) + rel->size = compute_rel_size(rel); + rel->width = compute_rel_width(rel); /*#define OPTIMIZER_DEBUG*/ #ifdef OPTIMIZER_DEBUG - printf("levels left: %d\n", levels_left); - debug_print_rel(root, rel); -#endif - } - - if(BushyPlanFlag) { - /* - * prune rels that have been completely incorporated into - * new join rels - */ - outer_rels = prune_oldrels(outer_rels); - /* - * merge join rels if then contain the same list of base rels - */ - outer_rels = merge_joinrels(new_rels,outer_rels); - root->join_relation_list_ = outer_rels; - } - else { - root->join_relation_list_ = new_rels; - } - - if(levels_left == 1) { - if(BushyPlanFlag) - return(final_join_rels(outer_rels)); + printf("levels left: %d\n", levels_left); + debug_print_rel(root, rel); +#endif + } + + if (BushyPlanFlag) + { + + /* + * prune rels that have been completely incorporated into new join + * rels + */ + outer_rels = prune_oldrels(outer_rels); + + /* + * merge join rels if then contain the same list of base rels + */ + outer_rels = merge_joinrels(new_rels, outer_rels); + root->join_relation_list_ = outer_rels; + } else - return(new_rels); - } else { - if(BushyPlanFlag) - return(find_join_paths(root, outer_rels, levels_left - 1)); + { + root->join_relation_list_ = new_rels; + } + + if (levels_left == 1) + { + if (BushyPlanFlag) + return (final_join_rels(outer_rels)); + else + return (new_rels); + } else - return(find_join_paths(root, new_rels, levels_left - 1)); - } + { + if (BushyPlanFlag) + return (find_join_paths(root, outer_rels, levels_left - 1)); + else + return (find_join_paths(root, new_rels, levels_left - 1)); + } } /***************************************************************************** @@ -262,115 +281,147 @@ find_join_paths(Query *root, List *outer_rels, int levels_left) #ifdef OPTIMIZER_DEBUG static void -print_joinclauses(Query *root, List *clauses) +print_joinclauses(Query * root, List * clauses) { - List *l; - extern void print_expr(Node *expr, List *rtable); /* in print.c */ + List *l; + extern void print_expr(Node * expr, List * rtable); /* in print.c */ - foreach(l, clauses) { - CInfo *c = lfirst(l); + foreach(l, clauses) + { + CInfo *c = lfirst(l); - print_expr((Node*)c->clause, root->rtable); - if (lnext(l)) printf(" "); - } + print_expr((Node *) c->clause, root->rtable); + if (lnext(l)) + printf(" "); + } } static void -print_path(Query *root, Path *path, int indent) +print_path(Query * root, Path * path, int indent) { - char *ptype = NULL; - JoinPath *jp; - bool join = false; - int i; - - for(i=0; i < indent; i++) - printf("\t"); - - switch(nodeTag(path)) { - case T_Path: - ptype = "SeqScan"; join=false; break; - case T_IndexPath: - ptype = "IdxScan"; join=false; break; - case T_JoinPath: - ptype = "Nestloop"; join=true; break; - case T_MergePath: - ptype = "MergeJoin"; join=true; break; - case T_HashPath: - ptype = "HashJoin"; join=true; break; - default: - break; - } - if (join) { - int size = path->parent->size; - jp = (JoinPath*)path; - printf("%s size=%d cost=%f\n", ptype, size, path->path_cost); - switch(nodeTag(path)) { + char *ptype = NULL; + JoinPath *jp; + bool join = false; + int i; + + for (i = 0; i < indent; i++) + printf("\t"); + + switch (nodeTag(path)) + { + case T_Path: + ptype = "SeqScan"; + join = false; + break; + case T_IndexPath: + ptype = "IdxScan"; + join = false; + break; + case T_JoinPath: + ptype = "Nestloop"; + join = true; + break; case T_MergePath: + ptype = "MergeJoin"; + join = true; + break; case T_HashPath: - for(i=0; i < indent+1; i++) - printf("\t"); - printf(" clauses=("); - print_joinclauses(root, - ((JoinPath*)path)->pathclauseinfo); - printf(")\n"); - - if (nodeTag(path)==T_MergePath) { - MergePath *mp = (MergePath*)path; - if (mp->outersortkeys || mp->innersortkeys) { - for(i=0; i < indent+1; i++) - printf("\t"); - printf(" sortouter=%d sortinner=%d\n", - ((mp->outersortkeys)?1:0), - ((mp->innersortkeys)?1:0)); - } - } - break; + ptype = "HashJoin"; + join = true; + break; default: - break; + break; } - print_path(root, jp->outerjoinpath, indent+1); - print_path(root, jp->innerjoinpath, indent+1); - } else { - int size = path->parent->size; - int relid = lfirsti(path->parent->relids); - printf("%s(%d) size=%d cost=%f", - ptype, relid, size, path->path_cost); - - if (nodeTag(path)==T_IndexPath) { - List *k, *l; - - printf(" keys="); - foreach (k, path->keys) { - printf("("); - foreach (l, lfirst(k)) { - Var *var = lfirst(l); - printf("%d.%d", var->varnoold, var->varoattno); - if (lnext(l)) printf(", "); + if (join) + { + int size = path->parent->size; + + jp = (JoinPath *) path; + printf("%s size=%d cost=%f\n", ptype, size, path->path_cost); + switch (nodeTag(path)) + { + case T_MergePath: + case T_HashPath: + for (i = 0; i < indent + 1; i++) + printf("\t"); + printf(" clauses=("); + print_joinclauses(root, + ((JoinPath *) path)->pathclauseinfo); + printf(")\n"); + + if (nodeTag(path) == T_MergePath) + { + MergePath *mp = (MergePath *) path; + + if (mp->outersortkeys || mp->innersortkeys) + { + for (i = 0; i < indent + 1; i++) + printf("\t"); + printf(" sortouter=%d sortinner=%d\n", + ((mp->outersortkeys) ? 1 : 0), + ((mp->innersortkeys) ? 1 : 0)); + } + } + break; + default: + break; } - printf(")"); - if (lnext(k)) printf(", "); - } + print_path(root, jp->outerjoinpath, indent + 1); + print_path(root, jp->innerjoinpath, indent + 1); + } + else + { + int size = path->parent->size; + int relid = lfirsti(path->parent->relids); + + printf("%s(%d) size=%d cost=%f", + ptype, relid, size, path->path_cost); + + if (nodeTag(path) == T_IndexPath) + { + List *k, + *l; + + printf(" keys="); + foreach(k, path->keys) + { + printf("("); + foreach(l, lfirst(k)) + { + Var *var = lfirst(l); + + printf("%d.%d", var->varnoold, var->varoattno); + if (lnext(l)) + printf(", "); + } + printf(")"); + if (lnext(k)) + printf(", "); + } + } + printf("\n"); } - printf("\n"); - } } -static void -debug_print_rel(Query *root, Rel *rel) +static void +debug_print_rel(Query * root, Rel * rel) { - List *l; - - printf("("); - foreach(l, rel->relids) { - printf("%d ", lfirsti(l)); - } - printf("): size=%d width=%d\n", rel->size, rel->width); - - printf("\tpath list:\n"); - foreach (l, rel->pathlist) { - print_path(root, lfirst(l), 1); - } - printf("\tcheapest path:\n"); - print_path(root, rel->cheapestpath, 1); + List *l; + + printf("("); + foreach(l, rel->relids) + { + printf("%d ", lfirsti(l)); + } + printf("): size=%d width=%d\n", rel->size, rel->width); + + printf("\tpath list:\n"); + foreach(l, rel->pathlist) + { + print_path(root, lfirst(l), 1); + } + printf("\tcheapest path:\n"); + print_path(root, rel->cheapestpath, 1); } -#endif /* OPTIMIZER_DEBUG */ + +#endif /* OPTIMIZER_DEBUG */ diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index 634e1130794..0ce580754e3 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * clausesel.c-- - * Routines to compute and set clause selectivities + * Routines to compute and set clause selectivities * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.1.1.1 1996/07/09 06:21:35 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.2 1997/09/07 04:43:31 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -23,7 +23,7 @@ #include "optimizer/cost.h" #include "optimizer/plancat.h" -#include "parser/parsetree.h" /* for getrelid() */ +#include "parser/parsetree.h" /* for getrelid() */ #include "catalog/pg_proc.h" #include "catalog/pg_operator.h" @@ -31,301 +31,353 @@ #include "utils/elog.h" #include "utils/lsyscache.h" -static Cost compute_selec(Query *root, List *clauses, List *or_selectivities); +static Cost compute_selec(Query * root, List * clauses, List * or_selectivities); /**************************************************************************** - * ROUTINES TO SET CLAUSE SELECTIVITIES + * ROUTINES TO SET CLAUSE SELECTIVITIES ****************************************************************************/ -/* +/* * set_clause_selectivities - - * Sets the selectivity field for each of clause in 'clauseinfo-list' - * to 'new-selectivity'. If the selectivity has already been set, reset - * it only if the new one is better. - * + * Sets the selectivity field for each of clause in 'clauseinfo-list' + * to 'new-selectivity'. If the selectivity has already been set, reset + * it only if the new one is better. + * * Returns nothing of interest. * */ void -set_clause_selectivities(List *clauseinfo_list, Cost new_selectivity) +set_clause_selectivities(List * clauseinfo_list, Cost new_selectivity) { - List *temp; - CInfo *clausenode; - Cost cost_clause; - - foreach (temp,clauseinfo_list) { - clausenode = (CInfo*)lfirst(temp); - cost_clause = clausenode->selectivity; - if ( FLOAT_IS_ZERO(cost_clause) || new_selectivity < cost_clause) { - clausenode->selectivity = new_selectivity; + List *temp; + CInfo *clausenode; + Cost cost_clause; + + foreach(temp, clauseinfo_list) + { + clausenode = (CInfo *) lfirst(temp); + cost_clause = clausenode->selectivity; + if (FLOAT_IS_ZERO(cost_clause) || new_selectivity < cost_clause) + { + clausenode->selectivity = new_selectivity; + } } - } } -/* +/* * product_selec - - * Multiplies the selectivities of each clause in 'clauseinfo-list'. - * + * Multiplies the selectivities of each clause in 'clauseinfo-list'. + * * Returns a flonum corresponding to the selectivity of 'clauseinfo-list'. */ Cost -product_selec(List *clauseinfo_list) +product_selec(List * clauseinfo_list) { - Cost result = 1.0; - if (clauseinfo_list!=NIL) { - List *xclausenode = NIL; - Cost temp; - - foreach(xclausenode,clauseinfo_list) { - temp = ((CInfo *)lfirst(xclausenode))->selectivity; - result = result * temp; + Cost result = 1.0; + + if (clauseinfo_list != NIL) + { + List *xclausenode = NIL; + Cost temp; + + foreach(xclausenode, clauseinfo_list) + { + temp = ((CInfo *) lfirst(xclausenode))->selectivity; + result = result * temp; + } } - } - return(result); + return (result); } -/* +/* * set_rest_relselec - - * Scans through clauses on each relation and assigns a selectivity to - * those clauses that haven't been assigned a selectivity by an index. - * + * Scans through clauses on each relation and assigns a selectivity to + * those clauses that haven't been assigned a selectivity by an index. + * * Returns nothing of interest. * MODIFIES: selectivities of the various rel's clauseinfo - * slots. + * slots. */ void -set_rest_relselec(Query *root, List *rel_list) +set_rest_relselec(Query * root, List * rel_list) { - Rel *rel; - List *x; + Rel *rel; + List *x; - foreach (x,rel_list) { - rel = (Rel*)lfirst(x); - set_rest_selec(root, rel->clauseinfo); - } + foreach(x, rel_list) + { + rel = (Rel *) lfirst(x); + set_rest_selec(root, rel->clauseinfo); + } } -/* +/* * set_rest_selec - - * Sets the selectivity fields for those clauses within a single - * relation's 'clauseinfo-list' that haven't already been set. - * + * Sets the selectivity fields for those clauses within a single + * relation's 'clauseinfo-list' that haven't already been set. + * * Returns nothing of interest. - * + * */ void -set_rest_selec(Query *root, List *clauseinfo_list) +set_rest_selec(Query * root, List * clauseinfo_list) { - List *temp = NIL; - CInfo *clausenode = (CInfo*)NULL; - Cost cost_clause; - - foreach (temp,clauseinfo_list) { - clausenode = (CInfo*)lfirst(temp); - cost_clause = clausenode->selectivity; + List *temp = NIL; + CInfo *clausenode = (CInfo *) NULL; + Cost cost_clause; - /* - * Check to see if the selectivity of this clause or any 'or' - * subclauses (if any) haven't been set yet. - */ - if (valid_or_clause(clausenode) || FLOAT_IS_ZERO(cost_clause)) { - clausenode->selectivity = - compute_clause_selec(root, - (Node*)clausenode->clause, - lcons(makeFloat(cost_clause), NIL)); + foreach(temp, clauseinfo_list) + { + clausenode = (CInfo *) lfirst(temp); + cost_clause = clausenode->selectivity; + + /* + * Check to see if the selectivity of this clause or any 'or' + * subclauses (if any) haven't been set yet. + */ + if (valid_or_clause(clausenode) || FLOAT_IS_ZERO(cost_clause)) + { + clausenode->selectivity = + compute_clause_selec(root, + (Node *) clausenode->clause, + lcons(makeFloat(cost_clause), NIL)); + } } - } } /**************************************************************************** - * ROUTINES TO COMPUTE SELECTIVITIES + * ROUTINES TO COMPUTE SELECTIVITIES ****************************************************************************/ -/* +/* * compute_clause_selec - - * Given a clause, this routine will compute the selectivity of the - * clause by calling 'compute_selec' with the appropriate parameters - * and possibly use that return value to compute the real selectivity - * of a clause. - * + * Given a clause, this routine will compute the selectivity of the + * clause by calling 'compute_selec' with the appropriate parameters + * and possibly use that return value to compute the real selectivity + * of a clause. + * * 'or-selectivities' are selectivities that have already been assigned - * to subclauses of an 'or' clause. - * + * to subclauses of an 'or' clause. + * * Returns a flonum corresponding to the clause selectivity. - * + * */ Cost -compute_clause_selec(Query *root, Node *clause, List *or_selectivities) +compute_clause_selec(Query * root, Node * clause, List * or_selectivities) { - if (!is_opclause (clause)) { - /* if it's not an operator clause, then it is a boolean clause -jolly*/ - /* - * Boolean variables get a selectivity of 1/2. - */ - return(0.1); - } else if (not_clause (clause)) { - /* - * 'not' gets "1.0 - selectivity-of-inner-clause". - */ - return (1.000000 - compute_selec(root, - lcons(get_notclausearg((Expr*)clause), - NIL), - or_selectivities)); - } else if (or_clause(clause)) { - /* - * Both 'or' and 'and' clauses are evaluated as described in - * (compute_selec). - */ - return (compute_selec(root, - ((Expr*)clause)->args, or_selectivities)); - } else { - return(compute_selec(root, - lcons(clause,NIL),or_selectivities)); - } + if (!is_opclause(clause)) + { + + /* + * if it's not an operator clause, then it is a boolean clause + * -jolly + */ + + /* + * Boolean variables get a selectivity of 1/2. + */ + return (0.1); + } + else if (not_clause(clause)) + { + + /* + * 'not' gets "1.0 - selectivity-of-inner-clause". + */ + return (1.000000 - compute_selec(root, + lcons(get_notclausearg((Expr *) clause), + NIL), + or_selectivities)); + } + else if (or_clause(clause)) + { + + /* + * Both 'or' and 'and' clauses are evaluated as described in + * (compute_selec). + */ + return (compute_selec(root, + ((Expr *) clause)->args, or_selectivities)); + } + else + { + return (compute_selec(root, + lcons(clause, NIL), or_selectivities)); + } } -/* - * compute_selec - - * Computes the selectivity of a clause. - * - * If there is more than one clause in the argument 'clauses', then the - * desired selectivity is that of an 'or' clause. Selectivities for an - * 'or' clause such as (OR a b) are computed by finding the selectivity - * of a (s1) and b (s2) and computing s1+s2 - s1*s2. - * - * In addition, if the clause is an 'or' clause, individual selectivities - * may have already been assigned by indices to subclauses. These values - * are contained in the list 'or-selectivities'. - * +/* + * compute_selec - + * Computes the selectivity of a clause. + * + * If there is more than one clause in the argument 'clauses', then the + * desired selectivity is that of an 'or' clause. Selectivities for an + * 'or' clause such as (OR a b) are computed by finding the selectivity + * of a (s1) and b (s2) and computing s1+s2 - s1*s2. + * + * In addition, if the clause is an 'or' clause, individual selectivities + * may have already been assigned by indices to subclauses. These values + * are contained in the list 'or-selectivities'. + * * Returns the clause selectivity as a flonum. - * + * */ -static Cost -compute_selec(Query *root, List *clauses, List *or_selectivities) +static Cost +compute_selec(Query * root, List * clauses, List * or_selectivities) { - Cost s1 = 0; - List *clause = lfirst(clauses); - - if (clauses==NULL) { - s1 = 1.0; - } else if (IsA(clause,Param)) { - /* XXX How're we handling this before?? -ay */ - s1 = 1.0; - } else if (IsA(clause,Const)) { - s1 = ((bool) ((Const*) clause)->constvalue) ? 1.0 : 0.0; - } else if (IsA(clause,Var)) { - Oid relid = getrelid(((Var*)clause)->varno, - root->rtable); + Cost s1 = 0; + List *clause = lfirst(clauses); - /* - * we have a bool Var. This is exactly equivalent to the clause: - * reln.attribute = 't' - * so we compute the selectivity as if that is what we have. The - * magic #define constants are a hack. I didn't want to have to - * do system cache look ups to find out all of that info. - */ + if (clauses == NULL) + { + s1 = 1.0; + } + else if (IsA(clause, Param)) + { + /* XXX How're we handling this before?? -ay */ + s1 = 1.0; + } + else if (IsA(clause, Const)) + { + s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0; + } + else if (IsA(clause, Var)) + { + Oid relid = getrelid(((Var *) clause)->varno, + root->rtable); - s1 = restriction_selectivity(EqualSelectivityProcedure, - BooleanEqualOperator, - relid, - ((Var*)clause)->varoattno, - "t", - _SELEC_CONSTANT_RIGHT_); - } else if (or_selectivities) { - /* If s1 has already been assigned by an index, use that value. */ - List *this_sel = lfirst(or_selectivities); - - s1 = floatVal(this_sel); - } else if (is_funcclause((Node*)clause)) { - /* this isn't an Oper, it's a Func!! */ - /* - ** This is not an operator, so we guess at the selectivity. - ** THIS IS A HACK TO GET V4 OUT THE DOOR. FUNCS SHOULD BE - ** ABLE TO HAVE SELECTIVITIES THEMSELVES. - ** -- JMH 7/9/92 - */ - s1 = 0.1; - } else if (NumRelids((Node*) clause) == 1) { - /* ...otherwise, calculate s1 from 'clauses'. - * The clause is not a join clause, since there is - * only one relid in the clause. The clause - * selectivity will be based on the operator - * selectivity and operand values. - */ - Oid opno = ((Oper*)((Expr*)clause)->oper)->opno; - RegProcedure oprrest = get_oprrest(opno); - Oid relid; - int relidx; - AttrNumber attno; - Datum constval; - int flag; - - get_relattval((Node*)clause, &relidx, &attno, &constval, &flag); - relid = getrelid(relidx, root->rtable); - - /* if the oprrest procedure is missing for whatever reason, - use a selectivity of 0.5*/ - if (!oprrest) - s1 = (Cost) (0.5); + /* + * we have a bool Var. This is exactly equivalent to the clause: + * reln.attribute = 't' so we compute the selectivity as if that + * is what we have. The magic #define constants are a hack. I + * didn't want to have to do system cache look ups to find out all + * of that info. + */ + + s1 = restriction_selectivity(EqualSelectivityProcedure, + BooleanEqualOperator, + relid, + ((Var *) clause)->varoattno, + "t", + _SELEC_CONSTANT_RIGHT_); + } + else if (or_selectivities) + { + /* If s1 has already been assigned by an index, use that value. */ + List *this_sel = lfirst(or_selectivities); + + s1 = floatVal(this_sel); + } + else if (is_funcclause((Node *) clause)) + { + /* this isn't an Oper, it's a Func!! */ + + /* + * * This is not an operator, so we guess at the selectivity. * + * THIS IS A HACK TO GET V4 OUT THE DOOR. FUNCS SHOULD BE * ABLE + * TO HAVE SELECTIVITIES THEMSELVES. * -- JMH 7/9/92 + */ + s1 = 0.1; + } + else if (NumRelids((Node *) clause) == 1) + { + + /* + * ...otherwise, calculate s1 from 'clauses'. The clause is not a + * join clause, since there is only one relid in the clause. The + * clause selectivity will be based on the operator selectivity + * and operand values. + */ + Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno; + RegProcedure oprrest = get_oprrest(opno); + Oid relid; + int relidx; + AttrNumber attno; + Datum constval; + int flag; + + get_relattval((Node *) clause, &relidx, &attno, &constval, &flag); + relid = getrelid(relidx, root->rtable); + + /* + * if the oprrest procedure is missing for whatever reason, use a + * selectivity of 0.5 + */ + if (!oprrest) + s1 = (Cost) (0.5); + else if (attno == InvalidAttrNumber) + { + + /* + * attno can be Invalid if the clause had a function in it, + * i.e. WHERE myFunc(f) = 10 + */ + /* this should be FIXED somehow to use function selectivity */ + s1 = (Cost) (0.5); + } + else + s1 = (Cost) restriction_selectivity(oprrest, + opno, + relid, + attno, + (char *) constval, + flag); + + } else - if (attno == InvalidAttrNumber) { - /* attno can be Invalid if the clause had a function in it, - i.e. WHERE myFunc(f) = 10 */ - /* this should be FIXED somehow to use function selectivity */ - s1 = (Cost) (0.5); - } else - s1 = (Cost) restriction_selectivity(oprrest, - opno, - relid, - attno, - (char *)constval, - flag); - - } else { - /* The clause must be a join clause. The clause - * selectivity will be based on the relations to be - * scanned and the attributes they are to be joined - * on. + { + + /* + * The clause must be a join clause. The clause selectivity will + * be based on the relations to be scanned and the attributes they + * are to be joined on. + */ + Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno; + RegProcedure oprjoin = get_oprjoin(opno); + int relid1, + relid2; + AttrNumber attno1, + attno2; + + get_rels_atts((Node *) clause, &relid1, &attno1, &relid2, &attno2); + relid1 = getrelid(relid1, root->rtable); + relid2 = getrelid(relid2, root->rtable); + + /* + * if the oprjoin procedure is missing for whatever reason, use a + * selectivity of 0.5 + */ + if (!oprjoin) + s1 = (Cost) (0.5); + else + s1 = (Cost) join_selectivity(oprjoin, + opno, + relid1, + attno1, + relid2, + attno2); + } + + /* + * A null clause list eliminates no tuples, so return a selectivity of + * 1.0. If there is only one clause, the selectivity is not that of + * an 'or' clause, but rather that of the single clause. */ - Oid opno = ((Oper*)((Expr*)clause)->oper)->opno; - RegProcedure oprjoin = get_oprjoin (opno); - int relid1, relid2; - AttrNumber attno1, attno2; - - get_rels_atts((Node*)clause, &relid1, &attno1, &relid2, &attno2); - relid1 = getrelid(relid1, root->rtable); - relid2 = getrelid(relid2, root->rtable); - - /* if the oprjoin procedure is missing for whatever reason, - use a selectivity of 0.5*/ - if (!oprjoin) - s1 = (Cost) (0.5); - else - s1 = (Cost) join_selectivity(oprjoin, - opno, - relid1, - attno1, - relid2, - attno2); - } - - /* A null clause list eliminates no tuples, so return a selectivity - * of 1.0. If there is only one clause, the selectivity is not - * that of an 'or' clause, but rather that of the single clause. - */ - - if (length (clauses) < 2) { - return(s1); - } else { - /* Compute selectivity of the 'or'ed subclauses. */ - /* Added check for taking lnext(NIL). -- JMH 3/9/92 */ - Cost s2; - - if (or_selectivities != NIL) - s2 = compute_selec(root, lnext(clauses), lnext(or_selectivities)); + + if (length(clauses) < 2) + { + return (s1); + } else - s2 = compute_selec(root, lnext(clauses), NIL); - return(s1 + s2 - s1 * s2); - } -} + { + /* Compute selectivity of the 'or'ed subclauses. */ + /* Added check for taking lnext(NIL). -- JMH 3/9/92 */ + Cost s2; + if (or_selectivities != NIL) + s2 = compute_selec(root, lnext(clauses), lnext(or_selectivities)); + else + s2 = compute_selec(root, lnext(clauses), NIL); + return (s1 + s2 - s1 * s2); + } +} diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 35453fb3870..2873e62c48c 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * costsize.c-- - * Routines to compute (and set) relation sizes and path costs + * Routines to compute (and set) relation sizes and path costs * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.16 1997/08/19 21:31:48 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.17 1997/09/07 04:43:33 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -17,15 +17,15 @@ #include <math.h> #ifdef HAVE_LIMITS_H -# include <limits.h> -# ifndef MAXINT -# define MAXINT INT_MAX -# endif +#include <limits.h> +#ifndef MAXINT +#define MAXINT INT_MAX +#endif #else -# ifdef HAVE_VALUES_H -# include <values.h> -# endif -#endif +#ifdef HAVE_VALUES_H +#include <values.h> +#endif +#endif #include <utils/lsyscache.h> #include "nodes/relation.h" @@ -35,77 +35,81 @@ #include "optimizer/keys.h" #include "optimizer/tlist.h" -#include "storage/bufmgr.h" /* for BLCKSZ */ +#include "storage/bufmgr.h" /* for BLCKSZ */ -extern int NBuffers; +extern int NBuffers; -static int compute_attribute_width(TargetEntry *tlistentry); -static double base_log(double x, double b); -static int compute_targetlist_width(List *targetlist); +static int compute_attribute_width(TargetEntry * tlistentry); +static double base_log(double x, double b); +static int compute_targetlist_width(List * targetlist); -int _disable_cost_ = 30000000; - -bool _enable_seqscan_ = true; -bool _enable_indexscan_ = true; -bool _enable_sort_ = true; -bool _enable_hash_ = true; -bool _enable_nestloop_ = true; -bool _enable_mergesort_ = true; -bool _enable_hashjoin_ = true; +int _disable_cost_ = 30000000; -Cost _cpu_page_wight_ = _CPU_PAGE_WEIGHT_; -Cost _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_; +bool _enable_seqscan_ = true; +bool _enable_indexscan_ = true; +bool _enable_sort_ = true; +bool _enable_hash_ = true; +bool _enable_nestloop_ = true; +bool _enable_mergesort_ = true; +bool _enable_hashjoin_ = true; -/* +Cost _cpu_page_wight_ = _CPU_PAGE_WEIGHT_; +Cost _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_; + +/* * cost_seqscan-- - * Determines and returns the cost of scanning a relation sequentially. - * If the relation is a temporary to be materialized from a query - * embedded within a data field (determined by 'relid' containing an - * attribute reference), then a predetermined constant is returned (we - * have NO IDEA how big the result of a POSTQUEL procedure is going to - * be). - * - * disk = p - * cpu = *CPU-PAGE-WEIGHT* * t - * + * Determines and returns the cost of scanning a relation sequentially. + * If the relation is a temporary to be materialized from a query + * embedded within a data field (determined by 'relid' containing an + * attribute reference), then a predetermined constant is returned (we + * have NO IDEA how big the result of a POSTQUEL procedure is going to + * be). + * + * disk = p + * cpu = *CPU-PAGE-WEIGHT* * t + * * 'relid' is the relid of the relation to be scanned * 'relpages' is the number of pages in the relation to be scanned - * (as determined from the system catalogs) + * (as determined from the system catalogs) * 'reltuples' is the number of tuples in the relation to be scanned - * + * * Returns a flonum. - * + * */ Cost cost_seqscan(int relid, int relpages, int reltuples) { - Cost temp = 0; + Cost temp = 0; - if ( !_enable_seqscan_ ) - temp += _disable_cost_; + if (!_enable_seqscan_) + temp += _disable_cost_; - if (relid < 0) { - /* - * cost of sequentially scanning a materialized temporary relation - */ - temp += _TEMP_SCAN_COST_; - } else { - temp += relpages; - temp += _cpu_page_wight_ * reltuples; - } - Assert(temp >= 0); - return(temp); + if (relid < 0) + { + + /* + * cost of sequentially scanning a materialized temporary relation + */ + temp += _TEMP_SCAN_COST_; + } + else + { + temp += relpages; + temp += _cpu_page_wight_ * reltuples; + } + Assert(temp >= 0); + return (temp); } -/* +/* * cost_index-- - * Determines and returns the cost of scanning a relation using an index. - * - * disk = expected-index-pages + expected-data-pages - * cpu = *CPU-PAGE-WEIGHT* * - * (expected-index-tuples + expected-data-tuples) - * + * Determines and returns the cost of scanning a relation using an index. + * + * disk = expected-index-pages + expected-data-pages + * cpu = *CPU-PAGE-WEIGHT* * + * (expected-index-tuples + expected-data-tuples) + * * 'indexid' is the index OID * 'expected-indexpages' is the number of index pages examined in the scan * 'selec' is the selectivity of the index @@ -113,100 +117,102 @@ cost_seqscan(int relid, int relpages, int reltuples) * 'reltuples' is the number of tuples in the main relation * 'indexpages' is the number of pages in the index relation * 'indextuples' is the number of tuples in the index relation - * + * * Returns a flonum. - * + * */ Cost cost_index(Oid indexid, - int expected_indexpages, - Cost selec, - int relpages, - int reltuples, - int indexpages, - int indextuples, - bool is_injoin) + int expected_indexpages, + Cost selec, + int relpages, + int reltuples, + int indexpages, + int indextuples, + bool is_injoin) { - Cost temp; - double temp2; + Cost temp; + double temp2; + + temp = (Cost) 0; - temp = (Cost) 0; + if (!_enable_indexscan_ && !is_injoin) + temp += _disable_cost_; - if (!_enable_indexscan_ && !is_injoin) - temp += _disable_cost_; + /* expected index relation pages */ + temp += expected_indexpages; - /* expected index relation pages */ - temp += expected_indexpages; + /* expected base relation pages */ + temp2 = (reltuples == 0) ? (double) 0 : (double) relpages / reltuples; + temp2 = temp2 * (double) selec *indextuples; - /* expected base relation pages */ - temp2 = ( reltuples == 0 ) ? (double)0 : (double)relpages/reltuples; - temp2 = temp2 * (double)selec * indextuples; - temp += Min (relpages, (int)ceil (temp2)); + temp += Min(relpages, (int) ceil(temp2)); - /* per index tuples */ - temp = temp + (_cpu_index_page_wight_ * selec * indextuples); + /* per index tuples */ + temp = temp + (_cpu_index_page_wight_ * selec * indextuples); - /* per heap tuples */ - temp = temp + (_cpu_page_wight_ * selec * reltuples); + /* per heap tuples */ + temp = temp + (_cpu_page_wight_ * selec * reltuples); - Assert(temp >= 0); - return(temp); + Assert(temp >= 0); + return (temp); } -/* +/* * cost_sort-- - * Determines and returns the cost of sorting a relation by considering - * 1. the cost of doing an external sort: XXX this is probably too low - * disk = (p lg p) - * cpu = *CPU-PAGE-WEIGHT* * (t lg t) - * 2. the cost of reading the sort result into memory (another seqscan) - * unless 'noread' is set - * + * Determines and returns the cost of sorting a relation by considering + * 1. the cost of doing an external sort: XXX this is probably too low + * disk = (p lg p) + * cpu = *CPU-PAGE-WEIGHT* * (t lg t) + * 2. the cost of reading the sort result into memory (another seqscan) + * unless 'noread' is set + * * 'keys' is a list of sort keys * 'tuples' is the number of tuples in the relation * 'width' is the average tuple width in bytes * 'noread' is a flag indicating that the sort result can remain on disk - * (i.e., the sort result is the result relation) - * + * (i.e., the sort result is the result relation) + * * Returns a flonum. - * + * */ Cost -cost_sort(List *keys, int tuples, int width, bool noread) +cost_sort(List * keys, int tuples, int width, bool noread) { - Cost temp = 0; - int npages = page_size (tuples,width); - Cost pages = (Cost)npages; - Cost numTuples = tuples; - - if ( !_enable_sort_ ) - temp += _disable_cost_ ; - if (tuples == 0 || keys==NULL) + Cost temp = 0; + int npages = page_size(tuples, width); + Cost pages = (Cost) npages; + Cost numTuples = tuples; + + if (!_enable_sort_) + temp += _disable_cost_; + if (tuples == 0 || keys == NULL) { - Assert(temp >= 0); - return(temp); + Assert(temp >= 0); + return (temp); } - temp += pages * base_log((double)pages, (double)2.0); + temp += pages * base_log((double) pages, (double) 2.0); - /* - * could be base_log(pages, NBuffers), but we are only doing 2-way merges - */ - temp += _cpu_page_wight_ * - numTuples * base_log((double)pages,(double)2.0); + /* + * could be base_log(pages, NBuffers), but we are only doing 2-way + * merges + */ + temp += _cpu_page_wight_ * + numTuples * base_log((double) pages, (double) 2.0); - if( !noread ) - temp = temp + cost_seqscan(_TEMP_RELATION_ID_, npages, tuples); - Assert(temp >= 0); + if (!noread) + temp = temp + cost_seqscan(_TEMP_RELATION_ID_, npages, tuples); + Assert(temp >= 0); - return(temp); + return (temp); } -/* +/* * cost_result-- - * Determines and returns the cost of writing a relation of 'tuples' - * tuples of 'width' bytes out to a result relation. - * + * Determines and returns the cost of writing a relation of 'tuples' + * tuples of 'width' bytes out to a result relation. + * * Returns a flonum. * */ @@ -214,257 +220,273 @@ cost_sort(List *keys, int tuples, int width, bool noread) Cost cost_result(int tuples, int width) { - Cost temp =0; - temp = temp + page_size(tuples,width); - temp = temp + _cpu_page_wight_ * tuples; - Assert(temp >= 0); - return(temp); + Cost temp = 0; + + temp = temp + page_size(tuples, width); + temp = temp + _cpu_page_wight_ * tuples; + Assert(temp >= 0); + return (temp); } + #endif -/* +/* * cost_nestloop-- - * Determines and returns the cost of joining two relations using the - * nested loop algorithm. - * + * Determines and returns the cost of joining two relations using the + * nested loop algorithm. + * * 'outercost' is the (disk+cpu) cost of scanning the outer relation * 'innercost' is the (disk+cpu) cost of scanning the inner relation * 'outertuples' is the number of tuples in the outer relation - * + * * Returns a flonum. * */ Cost cost_nestloop(Cost outercost, - Cost innercost, - int outertuples, - int innertuples, - int outerpages, - bool is_indexjoin) + Cost innercost, + int outertuples, + int innertuples, + int outerpages, + bool is_indexjoin) { - Cost temp =0; + Cost temp = 0; - if ( !_enable_nestloop_ ) - temp += _disable_cost_; - temp += outercost; - temp += outertuples * innercost; - Assert(temp >= 0); + if (!_enable_nestloop_) + temp += _disable_cost_; + temp += outercost; + temp += outertuples * innercost; + Assert(temp >= 0); - return(temp); + return (temp); } -/* +/* * cost_mergesort-- - * 'outercost' and 'innercost' are the (disk+cpu) costs of scanning the - * outer and inner relations - * 'outersortkeys' and 'innersortkeys' are lists of the keys to be used - * to sort the outer and inner relations - * 'outertuples' and 'innertuples' are the number of tuples in the outer - * and inner relations - * 'outerwidth' and 'innerwidth' are the (typical) widths (in bytes) - * of the tuples of the outer and inner relations - * + * 'outercost' and 'innercost' are the (disk+cpu) costs of scanning the + * outer and inner relations + * 'outersortkeys' and 'innersortkeys' are lists of the keys to be used + * to sort the outer and inner relations + * 'outertuples' and 'innertuples' are the number of tuples in the outer + * and inner relations + * 'outerwidth' and 'innerwidth' are the (typical) widths (in bytes) + * of the tuples of the outer and inner relations + * * Returns a flonum. - * + * */ Cost cost_mergesort(Cost outercost, - Cost innercost, - List *outersortkeys, - List *innersortkeys, - int outersize, - int innersize, - int outerwidth, - int innerwidth) + Cost innercost, + List * outersortkeys, + List * innersortkeys, + int outersize, + int innersize, + int outerwidth, + int innerwidth) { - Cost temp = 0; - - if ( !_enable_mergesort_ ) - temp += _disable_cost_; - - temp += outercost; - temp += innercost; - temp += cost_sort(outersortkeys,outersize,outerwidth,false); - temp += cost_sort(innersortkeys,innersize,innerwidth,false); - temp += _cpu_page_wight_ * (outersize + innersize); - Assert(temp >= 0); - - return(temp); + Cost temp = 0; + + if (!_enable_mergesort_) + temp += _disable_cost_; + + temp += outercost; + temp += innercost; + temp += cost_sort(outersortkeys, outersize, outerwidth, false); + temp += cost_sort(innersortkeys, innersize, innerwidth, false); + temp += _cpu_page_wight_ * (outersize + innersize); + Assert(temp >= 0); + + return (temp); } -/* - * cost_hashjoin-- XXX HASH - * 'outercost' and 'innercost' are the (disk+cpu) costs of scanning the - * outer and inner relations - * 'outerkeys' and 'innerkeys' are lists of the keys to be used - * to hash the outer and inner relations - * 'outersize' and 'innersize' are the number of tuples in the outer - * and inner relations - * 'outerwidth' and 'innerwidth' are the (typical) widths (in bytes) - * of the tuples of the outer and inner relations - * +/* + * cost_hashjoin-- XXX HASH + * 'outercost' and 'innercost' are the (disk+cpu) costs of scanning the + * outer and inner relations + * 'outerkeys' and 'innerkeys' are lists of the keys to be used + * to hash the outer and inner relations + * 'outersize' and 'innersize' are the number of tuples in the outer + * and inner relations + * 'outerwidth' and 'innerwidth' are the (typical) widths (in bytes) + * of the tuples of the outer and inner relations + * * Returns a flonum. */ Cost cost_hashjoin(Cost outercost, - Cost innercost, - List *outerkeys, - List *innerkeys, - int outersize, - int innersize, - int outerwidth, - int innerwidth) + Cost innercost, + List * outerkeys, + List * innerkeys, + int outersize, + int innersize, + int outerwidth, + int innerwidth) { - Cost temp = 0; - int outerpages = page_size (outersize,outerwidth); - int innerpages = page_size (innersize,innerwidth); - int nrun = ceil((double)outerpages/(double)NBuffers); - - if (outerpages < innerpages) - return _disable_cost_; - if ( !_enable_hashjoin_ ) - temp += _disable_cost_; - /* - temp += outercost + (nrun + 1) * innercost; - * - * the innercost shouldn't be used it. Instead the - * cost of hashing the innerpath should be used - * - * ASSUME innercost is 1 for now -- a horrible hack - * - jolly - temp += outercost + (nrun + 1); - * - * But we must add innercost to result. - vadim 04/24/97 - */ - temp += outercost + innercost + (nrun + 1); - - temp += _cpu_page_wight_ * (outersize + nrun * innersize); - Assert(temp >= 0); - - return(temp); + Cost temp = 0; + int outerpages = page_size(outersize, outerwidth); + int innerpages = page_size(innersize, innerwidth); + int nrun = ceil((double) outerpages / (double) NBuffers); + + if (outerpages < innerpages) + return _disable_cost_; + if (!_enable_hashjoin_) + temp += _disable_cost_; + + /* + * temp += outercost + (nrun + 1) * innercost; + * + * the innercost shouldn't be used it. Instead the cost of hashing the + * innerpath should be used + * + * ASSUME innercost is 1 for now -- a horrible hack - jolly temp += + * outercost + (nrun + 1); + * + * But we must add innercost to result. - vadim 04/24/97 + */ + temp += outercost + innercost + (nrun + 1); + + temp += _cpu_page_wight_ * (outersize + nrun * innersize); + Assert(temp >= 0); + + return (temp); } -/* +/* * compute-rel-size-- - * Computes the size of each relation in 'rel-list' (after applying - * restrictions), by multiplying the selectivity of each restriction - * by the original size of the relation. - * - * Sets the 'size' field for each relation entry with this computed size. - * + * Computes the size of each relation in 'rel-list' (after applying + * restrictions), by multiplying the selectivity of each restriction + * by the original size of the relation. + * + * Sets the 'size' field for each relation entry with this computed size. + * * Returns the size. */ -int compute_rel_size(Rel *rel) +int +compute_rel_size(Rel * rel) { - Cost temp; - int temp1; - - temp = rel->tuples * product_selec(rel->clauseinfo); - Assert(temp >= 0); - if (temp >= (MAXINT - 1)) { - temp1 = MAXINT; - } else { - temp1 = ceil((double) temp); - } - Assert(temp1 >= 0); - Assert(temp1 <= MAXINT); - return(temp1); + Cost temp; + int temp1; + + temp = rel->tuples * product_selec(rel->clauseinfo); + Assert(temp >= 0); + if (temp >= (MAXINT - 1)) + { + temp1 = MAXINT; + } + else + { + temp1 = ceil((double) temp); + } + Assert(temp1 >= 0); + Assert(temp1 <= MAXINT); + return (temp1); } -/* +/* * compute-rel-width-- - * Computes the width in bytes of a tuple from 'rel'. - * + * Computes the width in bytes of a tuple from 'rel'. + * * Returns the width of the tuple as a fixnum. */ int -compute_rel_width(Rel *rel) +compute_rel_width(Rel * rel) { - return (compute_targetlist_width(get_actual_tlist(rel->targetlist))); + return (compute_targetlist_width(get_actual_tlist(rel->targetlist))); } -/* +/* * compute-targetlist-width-- - * Computes the width in bytes of a tuple made from 'targetlist'. - * + * Computes the width in bytes of a tuple made from 'targetlist'. + * * Returns the width of the tuple as a fixnum. */ static int -compute_targetlist_width(List *targetlist) +compute_targetlist_width(List * targetlist) { - List *temp_tl; - int tuple_width = 0; - - foreach (temp_tl, targetlist) { - tuple_width = tuple_width + - compute_attribute_width(lfirst(temp_tl)); - } - return(tuple_width); + List *temp_tl; + int tuple_width = 0; + + foreach(temp_tl, targetlist) + { + tuple_width = tuple_width + + compute_attribute_width(lfirst(temp_tl)); + } + return (tuple_width); } -/* +/* * compute-attribute-width-- - * Given a target list entry, find the size in bytes of the attribute. - * - * If a field is variable-length, it is assumed to be at least the size - * of a TID field. - * + * Given a target list entry, find the size in bytes of the attribute. + * + * If a field is variable-length, it is assumed to be at least the size + * of a TID field. + * * Returns the width of the attribute as a fixnum. */ static int -compute_attribute_width(TargetEntry *tlistentry) +compute_attribute_width(TargetEntry * tlistentry) { - int width = get_typlen(tlistentry->resdom->restype); - if (width < 0) - return(_DEFAULT_ATTRIBUTE_WIDTH_); - else - return(width); + int width = get_typlen(tlistentry->resdom->restype); + + if (width < 0) + return (_DEFAULT_ATTRIBUTE_WIDTH_); + else + return (width); } -/* +/* * compute-joinrel-size-- - * Computes the size of the join relation 'joinrel'. - * + * Computes the size of the join relation 'joinrel'. + * * Returns a fixnum. */ int -compute_joinrel_size(JoinPath *joinpath) +compute_joinrel_size(JoinPath * joinpath) { - Cost temp = 1.0; - int temp1 = 0; - - temp *= ((Path*)joinpath->outerjoinpath)->parent->size; - temp *= ((Path*)joinpath->innerjoinpath)->parent->size; - - temp = temp * product_selec(joinpath->pathclauseinfo); - if (temp >= (MAXINT -1)) { - temp1 = MAXINT; - } else { - /* should be ceil here, we don't want joinrel size's of one, do we? */ - temp1 = ceil((double)temp); - } - Assert(temp1 >= 0); - - return(temp1); + Cost temp = 1.0; + int temp1 = 0; + + temp *= ((Path *) joinpath->outerjoinpath)->parent->size; + temp *= ((Path *) joinpath->innerjoinpath)->parent->size; + + temp = temp * product_selec(joinpath->pathclauseinfo); + if (temp >= (MAXINT - 1)) + { + temp1 = MAXINT; + } + else + { + + /* + * should be ceil here, we don't want joinrel size's of one, do + * we? + */ + temp1 = ceil((double) temp); + } + Assert(temp1 >= 0); + + return (temp1); } -/* +/* * page-size-- - * Returns an estimate of the number of pages covered by a given - * number of tuples of a given width (size in bytes). + * Returns an estimate of the number of pages covered by a given + * number of tuples of a given width (size in bytes). */ -int page_size(int tuples, int width) +int +page_size(int tuples, int width) { - int temp =0; + int temp = 0; - temp = ceil((double)(tuples * (width + sizeof(HeapTupleData))) - / BLCKSZ); - Assert(temp >= 0); - return(temp); + temp = ceil((double) (tuples * (width + sizeof(HeapTupleData))) + / BLCKSZ); + Assert(temp >= 0); + return (temp); } static double base_log(double x, double b) { - return(log(x)/log(b)); + return (log(x) / log(b)); } diff --git a/src/backend/optimizer/path/hashutils.c b/src/backend/optimizer/path/hashutils.c index cdbd9b6d901..5ec592ad1f9 100644 --- a/src/backend/optimizer/path/hashutils.c +++ b/src/backend/optimizer/path/hashutils.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * hashutils.c-- - * Utilities for finding applicable merge clauses and pathkeys + * Utilities for finding applicable merge clauses and pathkeys * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/hashutils.c,v 1.1.1.1 1996/07/09 06:21:35 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/hashutils.c,v 1.2 1997/09/07 04:43:34 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -20,101 +20,109 @@ #include "optimizer/clauses.h" -static HInfo *match_hashop_hashinfo(Oid hashop, List *hashinfo_list); +static HInfo *match_hashop_hashinfo(Oid hashop, List * hashinfo_list); -/* +/* * group-clauses-by-hashop-- - * If a join clause node in 'clauseinfo-list' is hashjoinable, store - * it within a hashinfo node containing other clause nodes with the same - * hash operator. - * + * If a join clause node in 'clauseinfo-list' is hashjoinable, store + * it within a hashinfo node containing other clause nodes with the same + * hash operator. + * * 'clauseinfo-list' is the list of clauseinfo nodes * 'inner-relid' is the relid of the inner join relation - * + * * Returns the new list of hashinfo nodes. - * + * */ -List * -group_clauses_by_hashop(List *clauseinfo_list, - int inner_relid) +List * +group_clauses_by_hashop(List * clauseinfo_list, + int inner_relid) { - List *hashinfo_list = NIL; - CInfo *clauseinfo = (CInfo*)NULL; - List *i = NIL; - Oid hashjoinop = 0; - - foreach (i,clauseinfo_list) { - clauseinfo = (CInfo*)lfirst(i); - hashjoinop = clauseinfo->hashjoinoperator; - - /* - * Create a new hashinfo node and add it to 'hashinfo-list' if one - * does not yet exist for this hash operator. - */ - if (hashjoinop ) { - HInfo *xhashinfo = (HInfo*)NULL; - Expr *clause = clauseinfo->clause; - Var *leftop = get_leftop(clause); - Var *rightop = get_rightop(clause); - JoinKey *keys = (JoinKey*)NULL; - - xhashinfo = - match_hashop_hashinfo(hashjoinop,hashinfo_list); - - if (inner_relid == leftop->varno){ - keys = makeNode(JoinKey); - keys->outer = rightop; - keys->inner = leftop; - } else { - keys = makeNode(JoinKey); - keys->outer = leftop; - keys->inner = rightop; - } - - if (xhashinfo==NULL) { - xhashinfo = makeNode(HInfo); - xhashinfo->hashop = hashjoinop; - - xhashinfo->jmethod.jmkeys = NIL; - xhashinfo->jmethod.clauses = NIL; - - /* XXX was push */ - hashinfo_list = lappend(hashinfo_list,xhashinfo); - hashinfo_list = nreverse(hashinfo_list); - } - - xhashinfo->jmethod.clauses = - lcons(clause, xhashinfo->jmethod.clauses); - - xhashinfo->jmethod.jmkeys = - lcons(keys, xhashinfo->jmethod.jmkeys); + List *hashinfo_list = NIL; + CInfo *clauseinfo = (CInfo *) NULL; + List *i = NIL; + Oid hashjoinop = 0; + + foreach(i, clauseinfo_list) + { + clauseinfo = (CInfo *) lfirst(i); + hashjoinop = clauseinfo->hashjoinoperator; + + /* + * Create a new hashinfo node and add it to 'hashinfo-list' if one + * does not yet exist for this hash operator. + */ + if (hashjoinop) + { + HInfo *xhashinfo = (HInfo *) NULL; + Expr *clause = clauseinfo->clause; + Var *leftop = get_leftop(clause); + Var *rightop = get_rightop(clause); + JoinKey *keys = (JoinKey *) NULL; + + xhashinfo = + match_hashop_hashinfo(hashjoinop, hashinfo_list); + + if (inner_relid == leftop->varno) + { + keys = makeNode(JoinKey); + keys->outer = rightop; + keys->inner = leftop; + } + else + { + keys = makeNode(JoinKey); + keys->outer = leftop; + keys->inner = rightop; + } + + if (xhashinfo == NULL) + { + xhashinfo = makeNode(HInfo); + xhashinfo->hashop = hashjoinop; + + xhashinfo->jmethod.jmkeys = NIL; + xhashinfo->jmethod.clauses = NIL; + + /* XXX was push */ + hashinfo_list = lappend(hashinfo_list, xhashinfo); + hashinfo_list = nreverse(hashinfo_list); + } + + xhashinfo->jmethod.clauses = + lcons(clause, xhashinfo->jmethod.clauses); + + xhashinfo->jmethod.jmkeys = + lcons(keys, xhashinfo->jmethod.jmkeys); + } } - } - return(hashinfo_list); + return (hashinfo_list); } -/* +/* * match-hashop-hashinfo-- - * Searches the list 'hashinfo-list' for a hashinfo node whose hash op - * field equals 'hashop'. - * + * Searches the list 'hashinfo-list' for a hashinfo node whose hash op + * field equals 'hashop'. + * * Returns the node if it exists. - * + * */ -static HInfo * -match_hashop_hashinfo(Oid hashop, List *hashinfo_list) +static HInfo * +match_hashop_hashinfo(Oid hashop, List * hashinfo_list) { - Oid key = 0; - HInfo *xhashinfo = (HInfo*)NULL; - List *i = NIL; - - foreach( i, hashinfo_list) { - xhashinfo = (HInfo*)lfirst(i); - key = xhashinfo->hashop; - if (hashop == key) { /* found */ - return(xhashinfo); /* should be a hashinfo node ! */ + Oid key = 0; + HInfo *xhashinfo = (HInfo *) NULL; + List *i = NIL; + + foreach(i, hashinfo_list) + { + xhashinfo = (HInfo *) lfirst(i); + key = xhashinfo->hashop; + if (hashop == key) + { /* found */ + return (xhashinfo); /* should be a hashinfo node ! */ + } } - } - return((HInfo*)NIL); + return ((HInfo *) NIL); } diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index f5b70e43a0f..bd9bc15ace0 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -1,14 +1,14 @@ /*------------------------------------------------------------------------- * * indxpath.c-- - * Routines to determine which indices are usable for scanning a - * given relation + * Routines to determine which indices are usable for scanning a + * given relation * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.8 1997/08/12 22:53:12 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.9 1997/09/07 04:43:36 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -43,308 +43,321 @@ #include "catalog/pg_proc.h" #include "executor/executor.h" -#include "parser/parsetree.h" /* for getrelid() */ - - -static void match_index_orclauses(Rel *rel, Rel *index, int indexkey, - int xclass, List *clauseinfo_list); -static bool match_index_to_operand(int indexkey, Expr *operand, - Rel *rel, Rel *index); -static List *match_index_orclause(Rel *rel, Rel *index, int indexkey, - int xclass, List *or_clauses, List *other_matching_indices); -static List *group_clauses_by_indexkey(Rel *rel, Rel *index, - int *indexkeys, Oid *classes, List *clauseinfo_list); -static List *group_clauses_by_ikey_for_joins(Rel *rel, Rel *index, - int *indexkeys, Oid *classes, List *join_cinfo_list, List *restr_cinfo_list); -static CInfo *match_clause_to_indexkey(Rel *rel, Rel *index, int indexkey, - int xclass, CInfo *clauseInfo, bool join); -static bool pred_test(List *predicate_list, List *clauseinfo_list, - List *joininfo_list); -static bool one_pred_test(Expr *predicate, List *clauseinfo_list); -static bool one_pred_clause_expr_test(Expr *predicate, Node *clause); -static bool one_pred_clause_test(Expr *predicate, Node *clause); -static bool clause_pred_clause_test(Expr *predicate, Node *clause); -static List *indexable_joinclauses (Rel *rel, Rel *index, - List *joininfo_list, List *clauseinfo_list); -static List *index_innerjoin(Query *root, Rel *rel, - List *clausegroup_list, Rel *index); -static List *create_index_paths(Query *root, Rel *rel, Rel *index, - List *clausegroup_list, bool join); -static List *add_index_paths(List *indexpaths, List *new_indexpaths); -static bool function_index_operand(Expr *funcOpnd, Rel *rel, Rel *index); -static bool SingleAttributeIndex(Rel *index); +#include "parser/parsetree.h" /* for getrelid() */ + + +static void +match_index_orclauses(Rel * rel, Rel * index, int indexkey, + int xclass, List * clauseinfo_list); +static bool +match_index_to_operand(int indexkey, Expr * operand, + Rel * rel, Rel * index); +static List * +match_index_orclause(Rel * rel, Rel * index, int indexkey, + int xclass, List * or_clauses, List * other_matching_indices); +static List * +group_clauses_by_indexkey(Rel * rel, Rel * index, + int *indexkeys, Oid * classes, List * clauseinfo_list); +static List * +group_clauses_by_ikey_for_joins(Rel * rel, Rel * index, + int *indexkeys, Oid * classes, List * join_cinfo_list, List * restr_cinfo_list); +static CInfo * +match_clause_to_indexkey(Rel * rel, Rel * index, int indexkey, + int xclass, CInfo * clauseInfo, bool join); +static bool +pred_test(List * predicate_list, List * clauseinfo_list, + List * joininfo_list); +static bool one_pred_test(Expr * predicate, List * clauseinfo_list); +static bool one_pred_clause_expr_test(Expr * predicate, Node * clause); +static bool one_pred_clause_test(Expr * predicate, Node * clause); +static bool clause_pred_clause_test(Expr * predicate, Node * clause); +static List * +indexable_joinclauses(Rel * rel, Rel * index, + List * joininfo_list, List * clauseinfo_list); +static List * +index_innerjoin(Query * root, Rel * rel, + List * clausegroup_list, Rel * index); +static List * +create_index_paths(Query * root, Rel * rel, Rel * index, + List * clausegroup_list, bool join); +static List *add_index_paths(List * indexpaths, List * new_indexpaths); +static bool function_index_operand(Expr * funcOpnd, Rel * rel, Rel * index); +static bool SingleAttributeIndex(Rel * index); /* If Spyros can use a constant PRS2_BOOL_TYPEID, I can use this */ #define BOOL_TYPEID ((Oid) 16) -/* +/* * find-index-paths-- - * Finds all possible index paths by determining which indices in the - * list 'indices' are usable. - * - * To be usable, an index must match against either a set of - * restriction clauses or join clauses. - * - * Note that the current implementation requires that there exist - * matching clauses for every key in the index (i.e., no partial - * matches are allowed). - * - * If an index can't be used with restriction clauses, but its keys - * match those of the result sort order (according to information stored - * within 'sortkeys'), then the index is also considered. + * Finds all possible index paths by determining which indices in the + * list 'indices' are usable. + * + * To be usable, an index must match against either a set of + * restriction clauses or join clauses. + * + * Note that the current implementation requires that there exist + * matching clauses for every key in the index (i.e., no partial + * matches are allowed). + * + * If an index can't be used with restriction clauses, but its keys + * match those of the result sort order (according to information stored + * within 'sortkeys'), then the index is also considered. * * 'rel' is the relation entry to which these index paths correspond * 'indices' is a list of possible index paths * 'clauseinfo-list' is a list of restriction clauseinfo nodes for 'rel' * 'joininfo-list' is a list of joininfo nodes for 'rel' * 'sortkeys' is a node describing the result sort order (from - * (find_sortkeys)) - * + * (find_sortkeys)) + * * Returns a list of index nodes. - * + * */ -List * -find_index_paths (Query *root, - Rel *rel, - List *indices, - List *clauseinfo_list, - List *joininfo_list) +List * +find_index_paths(Query * root, + Rel * rel, + List * indices, + List * clauseinfo_list, + List * joininfo_list) { - List *scanclausegroups = NIL; - List *scanpaths = NIL; - Rel *index = (Rel *)NULL; - List *joinclausegroups = NIL; - List *joinpaths = NIL; - List *retval = NIL; - - if(indices == NIL) - return(NULL); - - index = (Rel*)lfirst (indices); - - retval = find_index_paths(root, - rel, - lnext (indices), - clauseinfo_list, - joininfo_list); - - /* If this is a partial index, return if it fails the predicate test */ - if (index->indpred != NIL) - if (!pred_test(index->indpred, clauseinfo_list, joininfo_list)) - return retval; - - /* 1. If this index has only one key, try matching it against - * subclauses of an 'or' clause. The fields of the clauseinfo - * nodes are marked with lists of the matching indices no path - * are actually created. - * - * XXX NOTE: Currently btrees dos not support indices with - * > 1 key, so the following test will always be true for - * now but we have decided not to support index-scans - * on disjunction . -- lp - */ - if (SingleAttributeIndex(index)) - { - match_index_orclauses (rel, - index, - index->indexkeys[0], - index->classlist[0], - clauseinfo_list); - } + List *scanclausegroups = NIL; + List *scanpaths = NIL; + Rel *index = (Rel *) NULL; + List *joinclausegroups = NIL; + List *joinpaths = NIL; + List *retval = NIL; + + if (indices == NIL) + return (NULL); + + index = (Rel *) lfirst(indices); + + retval = find_index_paths(root, + rel, + lnext(indices), + clauseinfo_list, + joininfo_list); - /* - * 2. If the keys of this index match any of the available - * restriction clauses, then create pathnodes corresponding - * to each group of usable clauses. - */ - scanclausegroups = group_clauses_by_indexkey(rel, - index, - index->indexkeys, - index->classlist, - clauseinfo_list); - - scanpaths = NIL; - if (scanclausegroups != NIL) - scanpaths = create_index_paths (root, - rel, - index, - scanclausegroups, - false); - - /* - * 3. If this index can be used with any join clause, then - * create pathnodes for each group of usable clauses. An - * index can be used with a join clause if its ordering is - * useful for a mergejoin, or if the index can possibly be - * used for scanning the inner relation of a nestloop join. - */ - joinclausegroups = indexable_joinclauses(rel,index,joininfo_list, clauseinfo_list); - joinpaths = NIL; - - if (joinclausegroups != NIL) + /* If this is a partial index, return if it fails the predicate test */ + if (index->indpred != NIL) + if (!pred_test(index->indpred, clauseinfo_list, joininfo_list)) + return retval; + + /* + * 1. If this index has only one key, try matching it against + * subclauses of an 'or' clause. The fields of the clauseinfo nodes + * are marked with lists of the matching indices no path are actually + * created. + * + * XXX NOTE: Currently btrees dos not support indices with > 1 key, so + * the following test will always be true for now but we have decided + * not to support index-scans on disjunction . -- lp + */ + if (SingleAttributeIndex(index)) { - List *new_join_paths = create_index_paths(root, rel, + match_index_orclauses(rel, index, - joinclausegroups, - true); - List *innerjoin_paths = index_innerjoin(root, rel,joinclausegroups,index); + index->indexkeys[0], + index->classlist[0], + clauseinfo_list); + } + + /* + * 2. If the keys of this index match any of the available restriction + * clauses, then create pathnodes corresponding to each group of + * usable clauses. + */ + scanclausegroups = group_clauses_by_indexkey(rel, + index, + index->indexkeys, + index->classlist, + clauseinfo_list); + + scanpaths = NIL; + if (scanclausegroups != NIL) + scanpaths = create_index_paths(root, + rel, + index, + scanclausegroups, + false); + + /* + * 3. If this index can be used with any join clause, then create + * pathnodes for each group of usable clauses. An index can be used + * with a join clause if its ordering is useful for a mergejoin, or if + * the index can possibly be used for scanning the inner relation of a + * nestloop join. + */ + joinclausegroups = indexable_joinclauses(rel, index, joininfo_list, clauseinfo_list); + joinpaths = NIL; - rel->innerjoin = nconc (rel->innerjoin, innerjoin_paths); - joinpaths = new_join_paths; + if (joinclausegroups != NIL) + { + List *new_join_paths = create_index_paths(root, rel, + index, + joinclausegroups, + true); + List *innerjoin_paths = index_innerjoin(root, rel, joinclausegroups, index); + + rel->innerjoin = nconc(rel->innerjoin, innerjoin_paths); + joinpaths = new_join_paths; } - - /* - * Some sanity checks to make sure that - * the indexpath is valid. - */ - if (joinpaths!=NULL) - retval = add_index_paths(joinpaths,retval); - if (scanpaths!=NULL) - retval = add_index_paths(scanpaths,retval); - - return retval; + + /* + * Some sanity checks to make sure that the indexpath is valid. + */ + if (joinpaths != NULL) + retval = add_index_paths(joinpaths, retval); + if (scanpaths != NULL) + retval = add_index_paths(scanpaths, retval); + + return retval; } /**************************************************************************** - * ---- ROUTINES TO MATCH 'OR' CLAUSES ---- + * ---- ROUTINES TO MATCH 'OR' CLAUSES ---- ****************************************************************************/ -/* +/* * match-index-orclauses-- - * Attempt to match an index against subclauses within 'or' clauses. - * If the index does match, then the clause is marked with information - * about the index. - * - * Essentially, this adds 'index' to the list of indices in the - * ClauseInfo field of each of the clauses which it matches. - * + * Attempt to match an index against subclauses within 'or' clauses. + * If the index does match, then the clause is marked with information + * about the index. + * + * Essentially, this adds 'index' to the list of indices in the + * ClauseInfo field of each of the clauses which it matches. + * * 'rel' is the node of the relation on which the index is defined. * 'index' is the index node. * 'indexkey' is the (single) key of the index * 'class' is the class of the operator corresponding to 'indexkey'. * 'clauseinfo-list' is the list of available restriction clauses. - * + * * Returns nothing. - * + * */ static void -match_index_orclauses(Rel *rel, - Rel *index, - int indexkey, - int xclass, - List *clauseinfo_list) +match_index_orclauses(Rel * rel, + Rel * index, + int indexkey, + int xclass, + List * clauseinfo_list) { - CInfo *clauseinfo = (CInfo*)NULL; - List *i = NIL; - - foreach (i, clauseinfo_list) { - clauseinfo = (CInfo*)lfirst(i); - if (valid_or_clause(clauseinfo)) { - - /* Mark the 'or' clause with a list of indices which - * match each of its subclauses. The list is - * generated by adding 'index' to the existing - * list where appropriate. - */ - clauseinfo->indexids = - match_index_orclause (rel,index,indexkey, - xclass, - clauseinfo->clause->args, - clauseinfo->indexids); + CInfo *clauseinfo = (CInfo *) NULL; + List *i = NIL; + + foreach(i, clauseinfo_list) + { + clauseinfo = (CInfo *) lfirst(i); + if (valid_or_clause(clauseinfo)) + { + + /* + * Mark the 'or' clause with a list of indices which match + * each of its subclauses. The list is generated by adding + * 'index' to the existing list where appropriate. + */ + clauseinfo->indexids = + match_index_orclause(rel, index, indexkey, + xclass, + clauseinfo->clause->args, + clauseinfo->indexids); + } } - } } /* * match_index_operand-- - * Generalize test for a match between an existing index's key - * and the operand on the rhs of a restriction clause. Now check - * for functional indices as well. + * Generalize test for a match between an existing index's key + * and the operand on the rhs of a restriction clause. Now check + * for functional indices as well. */ -static bool +static bool match_index_to_operand(int indexkey, - Expr *operand, - Rel *rel, - Rel *index) + Expr * operand, + Rel * rel, + Rel * index) { - /* - * Normal index. - */ - if (index->indproc == InvalidOid) - return match_indexkey_operand(indexkey, (Var*)operand, rel); - - /* - * functional index check - */ - return (function_index_operand(operand, rel, index)); + + /* + * Normal index. + */ + if (index->indproc == InvalidOid) + return match_indexkey_operand(indexkey, (Var *) operand, rel); + + /* + * functional index check + */ + return (function_index_operand(operand, rel, index)); } -/* +/* * match-index-orclause-- - * Attempts to match an index against the subclauses of an 'or' clause. - * - * A match means that: - * (1) the operator within the subclause can be used with one - * of the index's operator classes, and - * (2) there is a usable key that matches the variable within a - * sargable clause. - * + * Attempts to match an index against the subclauses of an 'or' clause. + * + * A match means that: + * (1) the operator within the subclause can be used with one + * of the index's operator classes, and + * (2) there is a usable key that matches the variable within a + * sargable clause. + * * 'or-clauses' are the remaining subclauses within the 'or' clause * 'other-matching-indices' is the list of information on other indices - * that have already been matched to subclauses within this - * particular 'or' clause (i.e., a list previously generated by - * this routine) - * + * that have already been matched to subclauses within this + * particular 'or' clause (i.e., a list previously generated by + * this routine) + * * Returns a list of the form ((a b c) (d e f) nil (g h) ...) where * a,b,c are nodes of indices that match the first subclause in * 'or-clauses', d,e,f match the second subclause, no indices * match the third, g,h match the fourth, etc. */ -static List * -match_index_orclause(Rel *rel, - Rel *index, - int indexkey, - int xclass, - List *or_clauses, - List *other_matching_indices) +static List * +match_index_orclause(Rel * rel, + Rel * index, + int indexkey, + int xclass, + List * or_clauses, + List * other_matching_indices) { - Node *clause = NULL; - List *matched_indices = other_matching_indices; - List *index_list = NIL; - List *clist; - List *ind; - - if (!matched_indices) - matched_indices = lcons(NIL, NIL); - - for (clist = or_clauses, ind = matched_indices; - clist; - clist = lnext(clist), ind = lnext(ind)) + Node *clause = NULL; + List *matched_indices = other_matching_indices; + List *index_list = NIL; + List *clist; + List *ind; + + if (!matched_indices) + matched_indices = lcons(NIL, NIL); + + for (clist = or_clauses, ind = matched_indices; + clist; + clist = lnext(clist), ind = lnext(ind)) { - clause = lfirst(clist); - if (is_opclause (clause) && - op_class(((Oper*)((Expr*)clause)->oper)->opno, - xclass, index->relam) && - match_index_to_operand(indexkey, - (Expr*)get_leftop((Expr*)clause), - rel, - index) && - IsA(get_rightop((Expr*)clause),Const)) { - - matched_indices = lcons(index, matched_indices); - index_list = lappend(index_list, - matched_indices); - } + clause = lfirst(clist); + if (is_opclause(clause) && + op_class(((Oper *) ((Expr *) clause)->oper)->opno, + xclass, index->relam) && + match_index_to_operand(indexkey, + (Expr *) get_leftop((Expr *) clause), + rel, + index) && + IsA(get_rightop((Expr *) clause), Const)) + { + + matched_indices = lcons(index, matched_indices); + index_list = lappend(index_list, + matched_indices); + } } - return(index_list); - + return (index_list); + } /**************************************************************************** - * ---- ROUTINES TO CHECK RESTRICTIONS ---- + * ---- ROUTINES TO CHECK RESTRICTIONS ---- ****************************************************************************/ @@ -358,176 +371,177 @@ match_index_orclause(Rel *rel, * keys list represent the arguments to the function. -mer 3 Oct. 1991 */ #define DoneMatchingIndexKeys(indexkeys, index) \ - (indexkeys[0] == 0 || \ - (index->indproc != InvalidOid)) + (indexkeys[0] == 0 || \ + (index->indproc != InvalidOid)) -/* +/* * group-clauses-by-indexkey-- - * Determines whether there are clauses which will match each and every - * one of the remaining keys of an index. - * + * Determines whether there are clauses which will match each and every + * one of the remaining keys of an index. + * * 'rel' is the node of the relation corresponding to the index. * 'indexkeys' are the remaining index keys to be matched. * 'classes' are the classes of the index operators on those keys. * 'clauses' is either: - * (1) the list of available restriction clauses on a single - * relation, or - * (2) a list of join clauses between 'rel' and a fixed set of - * relations, - * depending on the value of 'join'. + * (1) the list of available restriction clauses on a single + * relation, or + * (2) a list of join clauses between 'rel' and a fixed set of + * relations, + * depending on the value of 'join'. + * + * NOTE: it works now for restriction clauses only. - vadim 03/18/97 * - * NOTE: it works now for restriction clauses only. - vadim 03/18/97 - * * Returns all possible groups of clauses that will match (given that * one or more clauses can match any of the remaining keys). - * E.g., if you have clauses A, B, and C, ((A B) (A C)) might be + * E.g., if you have clauses A, B, and C, ((A B) (A C)) might be * returned for an index with 2 keys. - * + * */ -static List * -group_clauses_by_indexkey(Rel *rel, - Rel *index, - int *indexkeys, - Oid *classes, - List *clauseinfo_list) +static List * +group_clauses_by_indexkey(Rel * rel, + Rel * index, + int *indexkeys, + Oid * classes, + List * clauseinfo_list) { - List *curCinfo = NIL; - CInfo *matched_clause = (CInfo*)NULL; - List *clausegroup = NIL; - int curIndxKey; - Oid curClass; + List *curCinfo = NIL; + CInfo *matched_clause = (CInfo *) NULL; + List *clausegroup = NIL; + int curIndxKey; + Oid curClass; - if (clauseinfo_list == NIL) - return NIL; + if (clauseinfo_list == NIL) + return NIL; - while ( !DoneMatchingIndexKeys(indexkeys, index) ) - { - List *tempgroup = NIL; - - curIndxKey = indexkeys[0]; - curClass = classes[0]; - - foreach (curCinfo,clauseinfo_list) - { - CInfo *temp = (CInfo*)lfirst(curCinfo); - - matched_clause = match_clause_to_indexkey (rel, - index, - curIndxKey, - curClass, - temp, - false); - if (!matched_clause) - continue; - - tempgroup = lappend(tempgroup, matched_clause); - } - if ( tempgroup == NIL ) - break; + while (!DoneMatchingIndexKeys(indexkeys, index)) + { + List *tempgroup = NIL; + + curIndxKey = indexkeys[0]; + curClass = classes[0]; + + foreach(curCinfo, clauseinfo_list) + { + CInfo *temp = (CInfo *) lfirst(curCinfo); + + matched_clause = match_clause_to_indexkey(rel, + index, + curIndxKey, + curClass, + temp, + false); + if (!matched_clause) + continue; - clausegroup = nconc (clausegroup, tempgroup); - - indexkeys++; - classes++; - - } + tempgroup = lappend(tempgroup, matched_clause); + } + if (tempgroup == NIL) + break; - /* clausegroup holds all matched clauses ordered by indexkeys */ + clausegroup = nconc(clausegroup, tempgroup); + + indexkeys++; + classes++; + + } - if (clausegroup != NIL) - return(lcons(clausegroup, NIL)); - return NIL; + /* clausegroup holds all matched clauses ordered by indexkeys */ + + if (clausegroup != NIL) + return (lcons(clausegroup, NIL)); + return NIL; } -/* +/* * group-clauses-by-ikey-for-joins-- - * special edition of group-clauses-by-indexkey - will - * match join & restriction clauses. See comment in indexable_joinclauses. - * - vadim 03/18/97 - * + * special edition of group-clauses-by-indexkey - will + * match join & restriction clauses. See comment in indexable_joinclauses. + * - vadim 03/18/97 + * */ -static List * -group_clauses_by_ikey_for_joins(Rel *rel, - Rel *index, - int *indexkeys, - Oid *classes, - List *join_cinfo_list, - List *restr_cinfo_list) +static List * +group_clauses_by_ikey_for_joins(Rel * rel, + Rel * index, + int *indexkeys, + Oid * classes, + List * join_cinfo_list, + List * restr_cinfo_list) { - List *curCinfo = NIL; - CInfo *matched_clause = (CInfo*)NULL; - List *clausegroup = NIL; - int curIndxKey; - Oid curClass; - bool jfound = false; - - if (join_cinfo_list == NIL) - return NIL; + List *curCinfo = NIL; + CInfo *matched_clause = (CInfo *) NULL; + List *clausegroup = NIL; + int curIndxKey; + Oid curClass; + bool jfound = false; + + if (join_cinfo_list == NIL) + return NIL; + + while (!DoneMatchingIndexKeys(indexkeys, index)) + { + List *tempgroup = NIL; + + curIndxKey = indexkeys[0]; + curClass = classes[0]; + + foreach(curCinfo, join_cinfo_list) + { + CInfo *temp = (CInfo *) lfirst(curCinfo); + + matched_clause = match_clause_to_indexkey(rel, + index, + curIndxKey, + curClass, + temp, + true); + if (!matched_clause) + continue; + + tempgroup = lappend(tempgroup, matched_clause); + jfound = true; + } + foreach(curCinfo, restr_cinfo_list) + { + CInfo *temp = (CInfo *) lfirst(curCinfo); + + matched_clause = match_clause_to_indexkey(rel, + index, + curIndxKey, + curClass, + temp, + false); + if (!matched_clause) + continue; + + tempgroup = lappend(tempgroup, matched_clause); + } + if (tempgroup == NIL) + break; + + clausegroup = nconc(clausegroup, tempgroup); + + indexkeys++; + classes++; - while ( !DoneMatchingIndexKeys(indexkeys, index) ) - { - List *tempgroup = NIL; - - curIndxKey = indexkeys[0]; - curClass = classes[0]; - - foreach (curCinfo,join_cinfo_list) - { - CInfo *temp = (CInfo*)lfirst(curCinfo); - - matched_clause = match_clause_to_indexkey (rel, - index, - curIndxKey, - curClass, - temp, - true); - if (!matched_clause) - continue; - - tempgroup = lappend(tempgroup, matched_clause); - jfound = true; } - foreach (curCinfo,restr_cinfo_list) - { - CInfo *temp = (CInfo*)lfirst(curCinfo); - - matched_clause = match_clause_to_indexkey (rel, - index, - curIndxKey, - curClass, - temp, - false); - if (!matched_clause) - continue; - - tempgroup = lappend(tempgroup, matched_clause); + + /* clausegroup holds all matched clauses ordered by indexkeys */ + + if (clausegroup != NIL) + { + + /* + * if no one join clause was matched then there ain't clauses for + * joins at all. + */ + if (!jfound) + { + freeList(clausegroup); + return NIL; + } + return (lcons(clausegroup, NIL)); } - if ( tempgroup == NIL ) - break; - - clausegroup = nconc (clausegroup, tempgroup); - - indexkeys++; - classes++; - - } - - /* clausegroup holds all matched clauses ordered by indexkeys */ - - if (clausegroup != NIL) - { - /* - * if no one join clause was matched then there ain't clauses - * for joins at all. - */ - if ( !jfound ) - { - freeList (clausegroup); - return NIL; - } - return(lcons(clausegroup, NIL)); - } - return NIL; + return NIL; } /* @@ -537,798 +551,867 @@ group_clauses_by_ikey_for_joins(Rel *rel, * Now we can match with functional indices. */ #define IndexScanableOperand(opnd, indkeys, rel, index) \ - ((index->indproc == InvalidOid) ? \ - match_indexkey_operand(indkeys, opnd, rel) : \ - function_index_operand((Expr*)opnd,rel,index)) + ((index->indproc == InvalidOid) ? \ + match_indexkey_operand(indkeys, opnd, rel) : \ + function_index_operand((Expr*)opnd,rel,index)) /* * There was - * equal_indexkey_var(indkeys,opnd) : \ + * equal_indexkey_var(indkeys,opnd) : \ * above, and now - * match_indexkey_operand(indkeys, opnd, rel) : \ + * match_indexkey_operand(indkeys, opnd, rel) : \ * - vadim 01/22/97 */ -/* +/* * match_clause_to-indexkey-- - * Finds the first of a relation's available restriction clauses that - * matches a key of an index. - * - * To match, the clause must: - * (1) be in the form (op var const) if the clause is a single- - * relation clause, and - * (2) contain an operator which is in the same class as the index - * operator for this key. - * - * If the clause being matched is a join clause, then 'join' is t. - * - * Returns a single clauseinfo node corresponding to the matching + * Finds the first of a relation's available restriction clauses that + * matches a key of an index. + * + * To match, the clause must: + * (1) be in the form (op var const) if the clause is a single- + * relation clause, and + * (2) contain an operator which is in the same class as the index + * operator for this key. + * + * If the clause being matched is a join clause, then 'join' is t. + * + * Returns a single clauseinfo node corresponding to the matching * clause. * * NOTE: returns nil if clause is an or_clause. - * + * */ -static CInfo * -match_clause_to_indexkey(Rel *rel, - Rel *index, - int indexkey, - int xclass, - CInfo *clauseInfo, - bool join) +static CInfo * +match_clause_to_indexkey(Rel * rel, + Rel * index, + int indexkey, + int xclass, + CInfo * clauseInfo, + bool join) { - Expr *clause = clauseInfo->clause; - Var *leftop, *rightop; - Oid join_op = InvalidOid; - Oid restrict_op = InvalidOid; - bool isIndexable = false; - - if (or_clause((Node*)clause) || - not_clause((Node*)clause) || single_node((Node*)clause)) - return ((CInfo*)NULL); - - leftop = get_leftop(clause); - rightop = get_rightop(clause); - /* - * If this is not a join clause, check for clauses of the form: - * (operator var/func constant) and (operator constant var/func) - */ - if (!join) - { + Expr *clause = clauseInfo->clause; + Var *leftop, + *rightop; + Oid join_op = InvalidOid; + Oid restrict_op = InvalidOid; + bool isIndexable = false; + + if (or_clause((Node *) clause) || + not_clause((Node *) clause) || single_node((Node *) clause)) + return ((CInfo *) NULL); + + leftop = get_leftop(clause); + rightop = get_rightop(clause); + /* - * Check for standard s-argable clause + * If this is not a join clause, check for clauses of the form: + * (operator var/func constant) and (operator constant var/func) */ -#ifdef INDEXSCAN_PATCH - /* Handle also function parameters. DZ - 27-8-1996 */ - if ((rightop && IsA(rightop,Const)) || - (rightop && IsA(rightop,Param))) -#else - if (rightop && IsA(rightop,Const)) -#endif + if (!join) { - restrict_op = ((Oper*)((Expr*)clause)->oper)->opno; - isIndexable = - ( op_class(restrict_op, xclass, index->relam) && - IndexScanableOperand(leftop, - indexkey, - rel, - index) ); - } - /* - * Must try to commute the clause to standard s-arg format. - */ + /* + * Check for standard s-argable clause + */ #ifdef INDEXSCAN_PATCH - /* ...And here... - vadim 01/22/97 */ - else if ((leftop && IsA(leftop,Const)) || - (leftop && IsA(leftop,Param))) + /* Handle also function parameters. DZ - 27-8-1996 */ + if ((rightop && IsA(rightop, Const)) || + (rightop && IsA(rightop, Param))) #else - else if (leftop && IsA(leftop,Const)) + if (rightop && IsA(rightop, Const)) #endif - { - restrict_op = - get_commutator(((Oper*)((Expr*)clause)->oper)->opno); - - if ( (restrict_op != InvalidOid) && - op_class(restrict_op, xclass, index->relam) && - IndexScanableOperand(rightop, - indexkey,rel,index) ) - { - isIndexable = true; + { + restrict_op = ((Oper *) ((Expr *) clause)->oper)->opno; + isIndexable = + (op_class(restrict_op, xclass, index->relam) && + IndexScanableOperand(leftop, + indexkey, + rel, + index)); + } + /* - * In place list modification. - * (op const var/func) -> (op var/func const) + * Must try to commute the clause to standard s-arg format. */ - CommuteClause((Node*)clause); - } - } - } - /* - * Check for an indexable scan on one of the join relations. - * clause is of the form (operator var/func var/func) - */ - else - { - if (rightop - && match_index_to_operand(indexkey,(Expr*)rightop,rel,index)) - { - - join_op = get_commutator(((Oper*)((Expr*)clause)->oper)->opno); - - } else if (leftop - && match_index_to_operand(indexkey, - (Expr*)leftop,rel,index)) - { - join_op = ((Oper*)((Expr*)clause)->oper)->opno; +#ifdef INDEXSCAN_PATCH + /* ...And here... - vadim 01/22/97 */ + else if ((leftop && IsA(leftop, Const)) || + (leftop && IsA(leftop, Param))) +#else + else if (leftop && IsA(leftop, Const)) +#endif + { + restrict_op = + get_commutator(((Oper *) ((Expr *) clause)->oper)->opno); + + if ((restrict_op != InvalidOid) && + op_class(restrict_op, xclass, index->relam) && + IndexScanableOperand(rightop, + indexkey, rel, index)) + { + isIndexable = true; + + /* + * In place list modification. (op const var/func) -> (op + * var/func const) + */ + CommuteClause((Node *) clause); + } + } } - if ( join_op && op_class(join_op,xclass,index->relam) && - join_clause_p((Node*)clause)) + /* + * Check for an indexable scan on one of the join relations. clause is + * of the form (operator var/func var/func) + */ + else { - isIndexable = true; - - /* - * If we're using the operand's commutator we must - * commute the clause. - */ - if (join_op != ((Oper*)((Expr*)clause)->oper)->opno) - CommuteClause((Node*)clause); + if (rightop + && match_index_to_operand(indexkey, (Expr *) rightop, rel, index)) + { + + join_op = get_commutator(((Oper *) ((Expr *) clause)->oper)->opno); + + } + else if (leftop + && match_index_to_operand(indexkey, + (Expr *) leftop, rel, index)) + { + join_op = ((Oper *) ((Expr *) clause)->oper)->opno; + } + + if (join_op && op_class(join_op, xclass, index->relam) && + join_clause_p((Node *) clause)) + { + isIndexable = true; + + /* + * If we're using the operand's commutator we must commute the + * clause. + */ + if (join_op != ((Oper *) ((Expr *) clause)->oper)->opno) + CommuteClause((Node *) clause); + } } - } - if (isIndexable) - return(clauseInfo); + if (isIndexable) + return (clauseInfo); - return(NULL); + return (NULL); } /**************************************************************************** - * ---- ROUTINES TO DO PARTIAL INDEX PREDICATE TESTS ---- + * ---- ROUTINES TO DO PARTIAL INDEX PREDICATE TESTS ---- ****************************************************************************/ -/* +/* * pred_test-- - * Does the "predicate inclusion test" for partial indexes. + * Does the "predicate inclusion test" for partial indexes. * - * Recursively checks whether the clauses in clauseinfo_list imply - * that the given predicate is true. + * Recursively checks whether the clauses in clauseinfo_list imply + * that the given predicate is true. * - * This routine (together with the routines it calls) iterates over - * ANDs in the predicate first, then reduces the qualification - * clauses down to their constituent terms, and iterates over ORs - * in the predicate last. This order is important to make the test - * succeed whenever possible (assuming the predicate has been - * successfully cnfify()-ed). --Nels, Jan '93 + * This routine (together with the routines it calls) iterates over + * ANDs in the predicate first, then reduces the qualification + * clauses down to their constituent terms, and iterates over ORs + * in the predicate last. This order is important to make the test + * succeed whenever possible (assuming the predicate has been + * successfully cnfify()-ed). --Nels, Jan '93 */ -static bool -pred_test(List *predicate_list, List *clauseinfo_list, List *joininfo_list) +static bool +pred_test(List * predicate_list, List * clauseinfo_list, List * joininfo_list) { - List *pred, *items, *item; - - /* - * Note: if Postgres tried to optimize queries by forming equivalence - * classes over equi-joined attributes (i.e., if it recognized that a - * qualification such as "where a.b=c.d and a.b=5" could make use of - * an index on c.d), then we could use that equivalence class info - * here with joininfo_list to do more complete tests for the usability - * of a partial index. For now, the test only uses restriction - * clauses (those in clauseinfo_list). --Nels, Dec '92 - */ - - if (predicate_list == NULL) - return true; /* no predicate: the index is usable */ - if (clauseinfo_list == NULL) - return false; /* no restriction clauses: the test must fail */ - - foreach (pred, predicate_list) { - /* if any clause is not implied, the whole predicate is not implied */ - if (and_clause(lfirst(pred))) { - items = ((Expr*)lfirst(pred))->args; - foreach (item, items) { - if (!one_pred_test(lfirst(item), clauseinfo_list)) - return false; - } + List *pred, + *items, + *item; + + /* + * Note: if Postgres tried to optimize queries by forming equivalence + * classes over equi-joined attributes (i.e., if it recognized that a + * qualification such as "where a.b=c.d and a.b=5" could make use of + * an index on c.d), then we could use that equivalence class info + * here with joininfo_list to do more complete tests for the usability + * of a partial index. For now, the test only uses restriction + * clauses (those in clauseinfo_list). --Nels, Dec '92 + */ + + if (predicate_list == NULL) + return true; /* no predicate: the index is usable */ + if (clauseinfo_list == NULL) + return false; /* no restriction clauses: the test must + * fail */ + + foreach(pred, predicate_list) + { + + /* + * if any clause is not implied, the whole predicate is not + * implied + */ + if (and_clause(lfirst(pred))) + { + items = ((Expr *) lfirst(pred))->args; + foreach(item, items) + { + if (!one_pred_test(lfirst(item), clauseinfo_list)) + return false; + } + } + else if (!one_pred_test(lfirst(pred), clauseinfo_list)) + return false; } - else if (!one_pred_test(lfirst(pred), clauseinfo_list)) - return false; - } - return true; + return true; } -/* +/* * one_pred_test-- - * Does the "predicate inclusion test" for one conjunct of a predicate - * expression. + * Does the "predicate inclusion test" for one conjunct of a predicate + * expression. */ -static bool -one_pred_test(Expr *predicate, List *clauseinfo_list) +static bool +one_pred_test(Expr * predicate, List * clauseinfo_list) { - CInfo *clauseinfo; - List *item; - - Assert(predicate != NULL); - foreach (item, clauseinfo_list) { - clauseinfo = (CInfo *)lfirst(item); - /* if any clause implies the predicate, return true */ - if (one_pred_clause_expr_test(predicate, (Node*)clauseinfo->clause)) - return true; - } - return false; + CInfo *clauseinfo; + List *item; + + Assert(predicate != NULL); + foreach(item, clauseinfo_list) + { + clauseinfo = (CInfo *) lfirst(item); + /* if any clause implies the predicate, return true */ + if (one_pred_clause_expr_test(predicate, (Node *) clauseinfo->clause)) + return true; + } + return false; } -/* +/* * one_pred_clause_expr_test-- - * Does the "predicate inclusion test" for a general restriction-clause - * expression. + * Does the "predicate inclusion test" for a general restriction-clause + * expression. */ -static bool -one_pred_clause_expr_test(Expr *predicate, Node *clause) +static bool +one_pred_clause_expr_test(Expr * predicate, Node * clause) { - List *items, *item; - - if (is_opclause(clause)) - return one_pred_clause_test(predicate, clause); - else if (or_clause(clause)) { - items = ((Expr*)clause)->args; - foreach (item, items) { - /* if any OR item doesn't imply the predicate, clause doesn't */ - if (!one_pred_clause_expr_test(predicate, lfirst(item))) + List *items, + *item; + + if (is_opclause(clause)) + return one_pred_clause_test(predicate, clause); + else if (or_clause(clause)) + { + items = ((Expr *) clause)->args; + foreach(item, items) + { + /* if any OR item doesn't imply the predicate, clause doesn't */ + if (!one_pred_clause_expr_test(predicate, lfirst(item))) + return false; + } + return true; + } + else if (and_clause(clause)) + { + items = ((Expr *) clause)->args; + foreach(item, items) + { + + /* + * if any AND item implies the predicate, the whole clause + * does + */ + if (one_pred_clause_expr_test(predicate, lfirst(item))) + return true; + } return false; } - return true; - }else if (and_clause(clause)) { - items = ((Expr*)clause)->args; - foreach (item, items) { - /* if any AND item implies the predicate, the whole clause does */ - if (one_pred_clause_expr_test(predicate, lfirst(item))) - return true; + else + { + /* unknown clause type never implies the predicate */ + return false; } - return false; - }else { - /* unknown clause type never implies the predicate */ - return false; - } } -/* +/* * one_pred_clause_test-- - * Does the "predicate inclusion test" for one conjunct of a predicate - * expression for a simple restriction clause. + * Does the "predicate inclusion test" for one conjunct of a predicate + * expression for a simple restriction clause. */ -static bool -one_pred_clause_test(Expr *predicate, Node *clause) +static bool +one_pred_clause_test(Expr * predicate, Node * clause) { - List *items, *item; - - if (is_opclause((Node*)predicate)) - return clause_pred_clause_test(predicate, clause); - else if (or_clause((Node*)predicate)) { - items = predicate->args; - foreach (item, items) { - /* if any item is implied, the whole predicate is implied */ - if (one_pred_clause_test(lfirst(item), clause)) + List *items, + *item; + + if (is_opclause((Node *) predicate)) + return clause_pred_clause_test(predicate, clause); + else if (or_clause((Node *) predicate)) + { + items = predicate->args; + foreach(item, items) + { + /* if any item is implied, the whole predicate is implied */ + if (one_pred_clause_test(lfirst(item), clause)) + return true; + } + return false; + } + else if (and_clause((Node *) predicate)) + { + items = predicate->args; + foreach(item, items) + { + + /* + * if any item is not implied, the whole predicate is not + * implied + */ + if (!one_pred_clause_test(lfirst(item), clause)) + return false; + } return true; } - return false; - }else if (and_clause((Node*)predicate)) { - items = predicate->args; - foreach (item, items) { - /* - * if any item is not implied, the whole predicate is not - * implied - */ - if (!one_pred_clause_test(lfirst(item), clause)) + else + { + elog(DEBUG, "Unsupported predicate type, index will not be used"); return false; } - return true; - } - else { - elog(DEBUG, "Unsupported predicate type, index will not be used"); - return false; - } } /* * Define an "operator implication table" for btree operators ("strategies"). - * The "strategy numbers" are: (1) < (2) <= (3) = (4) >= (5) > + * The "strategy numbers" are: (1) < (2) <= (3) = (4) >= (5) > * * The interpretation of: * - * test_op = BT_implic_table[given_op-1][target_op-1] + * test_op = BT_implic_table[given_op-1][target_op-1] * * where test_op, given_op and target_op are strategy numbers (from 1 to 5) * of btree operators, is as follows: * - * If you know, for some ATTR, that "ATTR given_op CONST1" is true, and you - * want to determine whether "ATTR target_op CONST2" must also be true, then - * you can use "CONST1 test_op CONST2" as a test. If this test returns true, - * then the target expression must be true; if the test returns false, then - * the target expression may be false. + * If you know, for some ATTR, that "ATTR given_op CONST1" is true, and you + * want to determine whether "ATTR target_op CONST2" must also be true, then + * you can use "CONST1 test_op CONST2" as a test. If this test returns true, + * then the target expression must be true; if the test returns false, then + * the target expression may be false. * * An entry where test_op==0 means the implication cannot be determined, i.e., * this test should always be considered false. */ -StrategyNumber BT_implic_table[BTMaxStrategyNumber][BTMaxStrategyNumber] = { - {2, 2, 0, 0, 0}, - {1, 2, 0, 0, 0}, - {1, 2, 3, 4, 5}, - {0, 0, 0, 4, 5}, - {0, 0, 0, 4, 4} +StrategyNumber BT_implic_table[BTMaxStrategyNumber][BTMaxStrategyNumber] = { + {2, 2, 0, 0, 0}, + {1, 2, 0, 0, 0}, + {1, 2, 3, 4, 5}, + {0, 0, 0, 4, 5}, + {0, 0, 0, 4, 4} }; -/* +/* * clause_pred_clause_test-- - * Use operator class info to check whether clause implies predicate. - * - * Does the "predicate inclusion test" for a "simple clause" predicate - * for a single "simple clause" restriction. Currently, this only handles - * (binary boolean) operators that are in some btree operator class. - * Eventually, rtree operators could also be handled by defining an - * appropriate "RT_implic_table" array. + * Use operator class info to check whether clause implies predicate. + * + * Does the "predicate inclusion test" for a "simple clause" predicate + * for a single "simple clause" restriction. Currently, this only handles + * (binary boolean) operators that are in some btree operator class. + * Eventually, rtree operators could also be handled by defining an + * appropriate "RT_implic_table" array. */ -static bool -clause_pred_clause_test(Expr *predicate, Node *clause) +static bool +clause_pred_clause_test(Expr * predicate, Node * clause) { - Var *pred_var, *clause_var; - Const *pred_const, *clause_const; - Oid pred_op, clause_op, test_op; - Oid opclass_id; - StrategyNumber pred_strategy, clause_strategy, test_strategy; - Oper *test_oper; - Expr *test_expr; - bool test_result, isNull; - Relation relation; - HeapScanDesc scan; - HeapTuple tuple; - ScanKeyData entry[3]; - Form_pg_amop form; - - pred_var = (Var*)get_leftop(predicate); - pred_const = (Const*)get_rightop(predicate); - clause_var = (Var*)get_leftop((Expr*)clause); - clause_const = (Const*)get_rightop((Expr*)clause); - - /* Check the basic form; for now, only allow the simplest case */ - if (!is_opclause(clause) || - !IsA(clause_var,Var) || - !IsA(clause_const,Const) || - !IsA(predicate->oper,Oper) || - !IsA(pred_var,Var) || - !IsA(pred_const,Const)) { - return false; - } + Var *pred_var, + *clause_var; + Const *pred_const, + *clause_const; + Oid pred_op, + clause_op, + test_op; + Oid opclass_id; + StrategyNumber pred_strategy, + clause_strategy, + test_strategy; + Oper *test_oper; + Expr *test_expr; + bool test_result, + isNull; + Relation relation; + HeapScanDesc scan; + HeapTuple tuple; + ScanKeyData entry[3]; + Form_pg_amop form; + + pred_var = (Var *) get_leftop(predicate); + pred_const = (Const *) get_rightop(predicate); + clause_var = (Var *) get_leftop((Expr *) clause); + clause_const = (Const *) get_rightop((Expr *) clause); + + /* Check the basic form; for now, only allow the simplest case */ + if (!is_opclause(clause) || + !IsA(clause_var, Var) || + !IsA(clause_const, Const) || + !IsA(predicate->oper, Oper) || + !IsA(pred_var, Var) || + !IsA(pred_const, Const)) + { + return false; + } - /* - * The implication can't be determined unless the predicate and the clause - * refer to the same attribute. - */ - if (clause_var->varattno != pred_var->varattno) - return false; + /* + * The implication can't be determined unless the predicate and the + * clause refer to the same attribute. + */ + if (clause_var->varattno != pred_var->varattno) + return false; - /* Get the operators for the two clauses we're comparing */ - pred_op = ((Oper*)((Expr*)predicate)->oper)->opno; - clause_op = ((Oper*)((Expr*)clause)->oper)->opno; - - - /* - * 1. Find a "btree" strategy number for the pred_op - */ - /* XXX - hardcoded amopid value 403 to find "btree" operator classes */ - ScanKeyEntryInitialize(&entry[0], 0, - Anum_pg_amop_amopid, - ObjectIdEqualRegProcedure, - ObjectIdGetDatum(403)); - - ScanKeyEntryInitialize(&entry[1], 0, - Anum_pg_amop_amopopr, - ObjectIdEqualRegProcedure, - ObjectIdGetDatum(pred_op)); - - relation = heap_openr(AccessMethodOperatorRelationName); - - /* - * The following assumes that any given operator will only be in a single - * btree operator class. This is true at least for all the pre-defined - * operator classes. If it isn't true, then whichever operator class - * happens to be returned first for the given operator will be used to - * find the associated strategy numbers for the test. --Nels, Jan '93 - */ - scan = heap_beginscan(relation, false, NowTimeQual, 2, entry); - tuple = heap_getnext(scan, false, (Buffer *)NULL); - if (! HeapTupleIsValid(tuple)) { - elog(DEBUG, "clause_pred_clause_test: unknown pred_op"); - return false; - } - form = (Form_pg_amop) GETSTRUCT(tuple); + /* Get the operators for the two clauses we're comparing */ + pred_op = ((Oper *) ((Expr *) predicate)->oper)->opno; + clause_op = ((Oper *) ((Expr *) clause)->oper)->opno; - /* Get the predicate operator's strategy number (1 to 5) */ - pred_strategy = (StrategyNumber)form->amopstrategy; - /* Remember which operator class this strategy number came from */ - opclass_id = form->amopclaid; + /* + * 1. Find a "btree" strategy number for the pred_op + */ + /* XXX - hardcoded amopid value 403 to find "btree" operator classes */ + ScanKeyEntryInitialize(&entry[0], 0, + Anum_pg_amop_amopid, + ObjectIdEqualRegProcedure, + ObjectIdGetDatum(403)); - heap_endscan(scan); + ScanKeyEntryInitialize(&entry[1], 0, + Anum_pg_amop_amopopr, + ObjectIdEqualRegProcedure, + ObjectIdGetDatum(pred_op)); + relation = heap_openr(AccessMethodOperatorRelationName); - /* - * 2. From the same opclass, find a strategy num for the clause_op - */ - ScanKeyEntryInitialize(&entry[1], 0, - Anum_pg_amop_amopclaid, - ObjectIdEqualRegProcedure, - ObjectIdGetDatum(opclass_id)); + /* + * The following assumes that any given operator will only be in a + * single btree operator class. This is true at least for all the + * pre-defined operator classes. If it isn't true, then whichever + * operator class happens to be returned first for the given operator + * will be used to find the associated strategy numbers for the test. + * --Nels, Jan '93 + */ + scan = heap_beginscan(relation, false, NowTimeQual, 2, entry); + tuple = heap_getnext(scan, false, (Buffer *) NULL); + if (!HeapTupleIsValid(tuple)) + { + elog(DEBUG, "clause_pred_clause_test: unknown pred_op"); + return false; + } + form = (Form_pg_amop) GETSTRUCT(tuple); - ScanKeyEntryInitialize(&entry[2], 0, - Anum_pg_amop_amopopr, - ObjectIdEqualRegProcedure, - ObjectIdGetDatum(clause_op)); + /* Get the predicate operator's strategy number (1 to 5) */ + pred_strategy = (StrategyNumber) form->amopstrategy; - scan = heap_beginscan(relation, false, NowTimeQual, 3, entry); - tuple = heap_getnext(scan, false, (Buffer *)NULL); - if (! HeapTupleIsValid(tuple)) { - elog(DEBUG, "clause_pred_clause_test: unknown clause_op"); - return false; - } - form = (Form_pg_amop) GETSTRUCT(tuple); + /* Remember which operator class this strategy number came from */ + opclass_id = form->amopclaid; - /* Get the restriction clause operator's strategy number (1 to 5) */ - clause_strategy = (StrategyNumber)form->amopstrategy; - heap_endscan(scan); + heap_endscan(scan); - /* - * 3. Look up the "test" strategy number in the implication table - */ + /* + * 2. From the same opclass, find a strategy num for the clause_op + */ + ScanKeyEntryInitialize(&entry[1], 0, + Anum_pg_amop_amopclaid, + ObjectIdEqualRegProcedure, + ObjectIdGetDatum(opclass_id)); + + ScanKeyEntryInitialize(&entry[2], 0, + Anum_pg_amop_amopopr, + ObjectIdEqualRegProcedure, + ObjectIdGetDatum(clause_op)); + + scan = heap_beginscan(relation, false, NowTimeQual, 3, entry); + tuple = heap_getnext(scan, false, (Buffer *) NULL); + if (!HeapTupleIsValid(tuple)) + { + elog(DEBUG, "clause_pred_clause_test: unknown clause_op"); + return false; + } + form = (Form_pg_amop) GETSTRUCT(tuple); - test_strategy = BT_implic_table[clause_strategy-1][pred_strategy-1]; - if (test_strategy == 0) - return false; /* the implication cannot be determined */ + /* Get the restriction clause operator's strategy number (1 to 5) */ + clause_strategy = (StrategyNumber) form->amopstrategy; + heap_endscan(scan); - /* - * 4. From the same opclass, find the operator for the test strategy - */ + /* + * 3. Look up the "test" strategy number in the implication table + */ - ScanKeyEntryInitialize(&entry[2], 0, - Anum_pg_amop_amopstrategy, - Integer16EqualRegProcedure, - Int16GetDatum(test_strategy)); + test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1]; + if (test_strategy == 0) + return false; /* the implication cannot be determined */ - scan = heap_beginscan(relation, false, NowTimeQual, 3, entry); - tuple = heap_getnext(scan, false, (Buffer *)NULL); - if (! HeapTupleIsValid(tuple)) { - elog(DEBUG, "clause_pred_clause_test: unknown test_op"); - return false; - } - form = (Form_pg_amop) GETSTRUCT(tuple); - /* Get the test operator */ - test_op = form->amopopr; - heap_endscan(scan); + /* + * 4. From the same opclass, find the operator for the test strategy + */ + ScanKeyEntryInitialize(&entry[2], 0, + Anum_pg_amop_amopstrategy, + Integer16EqualRegProcedure, + Int16GetDatum(test_strategy)); - /* - * 5. Evaluate the test - */ - test_oper = makeOper(test_op, /* opno */ - InvalidOid, /* opid */ - BOOL_TYPEID, /* opresulttype */ - 0, /* opsize */ - NULL); /* op_fcache */ - replace_opid(test_oper); + scan = heap_beginscan(relation, false, NowTimeQual, 3, entry); + tuple = heap_getnext(scan, false, (Buffer *) NULL); + if (!HeapTupleIsValid(tuple)) + { + elog(DEBUG, "clause_pred_clause_test: unknown test_op"); + return false; + } + form = (Form_pg_amop) GETSTRUCT(tuple); + + /* Get the test operator */ + test_op = form->amopopr; + heap_endscan(scan); - test_expr = make_opclause(test_oper, - copyObject(clause_const), - copyObject(pred_const)); + + /* + * 5. Evaluate the test + */ + test_oper = makeOper(test_op, /* opno */ + InvalidOid, /* opid */ + BOOL_TYPEID, /* opresulttype */ + 0, /* opsize */ + NULL); /* op_fcache */ + replace_opid(test_oper); + + test_expr = make_opclause(test_oper, + copyObject(clause_const), + copyObject(pred_const)); #ifndef OMIT_PARTIAL_INDEX - test_result = ExecEvalExpr((Node*)test_expr, NULL, &isNull, NULL); -#endif /* OMIT_PARTIAL_INDEX */ - if (isNull) { - elog(DEBUG, "clause_pred_clause_test: null test result"); - return false; - } - return test_result; + test_result = ExecEvalExpr((Node *) test_expr, NULL, &isNull, NULL); +#endif /* OMIT_PARTIAL_INDEX */ + if (isNull) + { + elog(DEBUG, "clause_pred_clause_test: null test result"); + return false; + } + return test_result; } /**************************************************************************** - * ---- ROUTINES TO CHECK JOIN CLAUSES ---- + * ---- ROUTINES TO CHECK JOIN CLAUSES ---- ****************************************************************************/ -/* +/* * indexable-joinclauses-- - * Finds all groups of join clauses from among 'joininfo-list' that can - * be used in conjunction with 'index'. - * - * The first clause in the group is marked as having the other relation - * in the join clause as its outer join relation. - * + * Finds all groups of join clauses from among 'joininfo-list' that can + * be used in conjunction with 'index'. + * + * The first clause in the group is marked as having the other relation + * in the join clause as its outer join relation. + * * Returns a list of these clause groups. * - * Added: clauseinfo_list - list of restriction CInfos. It's to - * support multi-column indices in joins and for cases - * when a key is in both join & restriction clauses. - vadim 03/18/97 - * + * Added: clauseinfo_list - list of restriction CInfos. It's to + * support multi-column indices in joins and for cases + * when a key is in both join & restriction clauses. - vadim 03/18/97 + * */ -static List * -indexable_joinclauses(Rel *rel, Rel *index, - List *joininfo_list, List *clauseinfo_list) +static List * +indexable_joinclauses(Rel * rel, Rel * index, + List * joininfo_list, List * clauseinfo_list) { - JInfo *joininfo = (JInfo*)NULL; - List *cg_list = NIL; - List *i = NIL; - List *clausegroups = NIL; - - foreach(i,joininfo_list) { - joininfo = (JInfo*)lfirst(i); - - if ( joininfo->jinfoclauseinfo == NIL ) - continue; - clausegroups = - group_clauses_by_ikey_for_joins (rel, - index, - index->indexkeys, - index->classlist, - joininfo->jinfoclauseinfo, - clauseinfo_list); - - if (clausegroups != NIL) { - List *clauses = lfirst(clausegroups); - - ((CInfo*)lfirst(clauses))->cinfojoinid = - joininfo->otherrels; + JInfo *joininfo = (JInfo *) NULL; + List *cg_list = NIL; + List *i = NIL; + List *clausegroups = NIL; + + foreach(i, joininfo_list) + { + joininfo = (JInfo *) lfirst(i); + + if (joininfo->jinfoclauseinfo == NIL) + continue; + clausegroups = + group_clauses_by_ikey_for_joins(rel, + index, + index->indexkeys, + index->classlist, + joininfo->jinfoclauseinfo, + clauseinfo_list); + + if (clausegroups != NIL) + { + List *clauses = lfirst(clausegroups); + + ((CInfo *) lfirst(clauses))->cinfojoinid = + joininfo->otherrels; + } + cg_list = nconc(cg_list, clausegroups); } - cg_list = nconc(cg_list,clausegroups); - } - return(cg_list); + return (cg_list); } /**************************************************************************** - * ---- PATH CREATION UTILITIES ---- + * ---- PATH CREATION UTILITIES ---- ****************************************************************************/ /* * extract_restrict_clauses - - * the list of clause info contains join clauses and restriction clauses. - * This routine returns the restriction clauses only. + * the list of clause info contains join clauses and restriction clauses. + * This routine returns the restriction clauses only. */ #ifdef NOT_USED -static List * -extract_restrict_clauses(List *clausegroup) +static List * +extract_restrict_clauses(List * clausegroup) { - List *restrict_cls = NIL; - List *l; - - foreach (l, clausegroup) { - CInfo *cinfo = lfirst(l); - - if (!join_clause_p((Node*)cinfo->clause)) { - restrict_cls = lappend(restrict_cls, cinfo); + List *restrict_cls = NIL; + List *l; + + foreach(l, clausegroup) + { + CInfo *cinfo = lfirst(l); + + if (!join_clause_p((Node *) cinfo->clause)) + { + restrict_cls = lappend(restrict_cls, cinfo); + } } - } - return restrict_cls; + return restrict_cls; } + #endif -/* +/* * index-innerjoin-- - * Creates index path nodes corresponding to paths to be used as inner - * relations in nestloop joins. + * Creates index path nodes corresponding to paths to be used as inner + * relations in nestloop joins. * * 'clausegroup-list' is a list of list of clauseinfo nodes which can use * 'index' on their inner relation. - * + * * Returns a list of index pathnodes. - * + * */ -static List * -index_innerjoin(Query *root, Rel *rel, List *clausegroup_list, Rel *index) +static List * +index_innerjoin(Query * root, Rel * rel, List * clausegroup_list, Rel * index) { - List *clausegroup = NIL; - List *cg_list = NIL; - List *i = NIL; - IndexPath *pathnode = (IndexPath*)NULL; - Cost temp_selec; - float temp_pages; - - foreach(i,clausegroup_list) { - List *attnos, *values, *flags; - - clausegroup = lfirst(i); - pathnode = makeNode(IndexPath); - - get_joinvars(lfirsti(rel->relids),clausegroup, - &attnos, &values, &flags); - index_selectivity(lfirsti(index->relids), - index->classlist, - get_opnos(clausegroup), - getrelid(lfirsti(rel->relids), - root->rtable), - attnos, - values, - flags, - length(clausegroup), - &temp_pages, - &temp_selec); - pathnode->path.pathtype = T_IndexScan; - pathnode->path.parent = rel; - pathnode->indexid = index->relids; - pathnode->indexkeys = index->indexkeys; - pathnode->indexqual = clausegroup; - - pathnode->path.joinid = ((CInfo*)lfirst(clausegroup))->cinfojoinid; - - pathnode->path.path_cost = - cost_index((Oid)lfirsti(index->relids), - (int)temp_pages, - temp_selec, - rel->pages, - rel->tuples, - index->pages, - index->tuples, - true); - - /* copy clauseinfo list into path for expensive function processing - -- JMH, 7/7/92 */ - pathnode->path.locclauseinfo = - set_difference(copyObject((Node*)rel->clauseinfo), - clausegroup); - -#if 0 /* fix xfunc */ - /* add in cost for expensive functions! -- JMH, 7/7/92 */ - if (XfuncMode != XFUNC_OFF) { - ((Path*)pathnode)->path_cost += - xfunc_get_path_cost((Path*)pathnode); - } + List *clausegroup = NIL; + List *cg_list = NIL; + List *i = NIL; + IndexPath *pathnode = (IndexPath *) NULL; + Cost temp_selec; + float temp_pages; + + foreach(i, clausegroup_list) + { + List *attnos, + *values, + *flags; + + clausegroup = lfirst(i); + pathnode = makeNode(IndexPath); + + get_joinvars(lfirsti(rel->relids), clausegroup, + &attnos, &values, &flags); + index_selectivity(lfirsti(index->relids), + index->classlist, + get_opnos(clausegroup), + getrelid(lfirsti(rel->relids), + root->rtable), + attnos, + values, + flags, + length(clausegroup), + &temp_pages, + &temp_selec); + pathnode->path.pathtype = T_IndexScan; + pathnode->path.parent = rel; + pathnode->indexid = index->relids; + pathnode->indexkeys = index->indexkeys; + pathnode->indexqual = clausegroup; + + pathnode->path.joinid = ((CInfo *) lfirst(clausegroup))->cinfojoinid; + + pathnode->path.path_cost = + cost_index((Oid) lfirsti(index->relids), + (int) temp_pages, + temp_selec, + rel->pages, + rel->tuples, + index->pages, + index->tuples, + true); + + /* + * copy clauseinfo list into path for expensive function + * processing -- JMH, 7/7/92 + */ + pathnode->path.locclauseinfo = + set_difference(copyObject((Node *) rel->clauseinfo), + clausegroup); + +#if 0 /* fix xfunc */ + /* add in cost for expensive functions! -- JMH, 7/7/92 */ + if (XfuncMode != XFUNC_OFF) + { + ((Path *) pathnode)->path_cost += + xfunc_get_path_cost((Path *) pathnode); + } #endif - cg_list = lappend(cg_list,pathnode); - } - return(cg_list); + cg_list = lappend(cg_list, pathnode); + } + return (cg_list); } -/* +/* * create-index-paths-- - * Creates a list of index path nodes for each group of clauses - * (restriction or join) that can be used in conjunction with an index. - * + * Creates a list of index path nodes for each group of clauses + * (restriction or join) that can be used in conjunction with an index. + * * 'rel' is the relation for which 'index' is defined - * 'clausegroup-list' is the list of clause groups (lists of clauseinfo - * nodes) grouped by mergesortorder + * 'clausegroup-list' is the list of clause groups (lists of clauseinfo + * nodes) grouped by mergesortorder * 'join' is a flag indicating whether or not the clauses are join - * clauses - * + * clauses + * * Returns a list of new index path nodes. - * + * */ -static List * -create_index_paths(Query *root, - Rel *rel, - Rel *index, - List *clausegroup_list, - bool join) +static List * +create_index_paths(Query * root, + Rel * rel, + Rel * index, + List * clausegroup_list, + bool join) { - List *clausegroup = NIL; - List *ip_list = NIL; - List *i = NIL; - List *j = NIL; - IndexPath *temp_path; - - foreach(i, clausegroup_list) { - CInfo *clauseinfo; - List *temp_node = NIL; - bool temp = true; - - clausegroup = lfirst(i); - - foreach (j,clausegroup) { - clauseinfo = (CInfo*)lfirst(j); - if (!(join_clause_p((Node*)clauseinfo->clause) && - equal_path_merge_ordering(index->ordering, - clauseinfo->mergesortorder))) { - temp = false; - } - } + List *clausegroup = NIL; + List *ip_list = NIL; + List *i = NIL; + List *j = NIL; + IndexPath *temp_path; - if (!join || temp) { /* restriction, ordering scan */ - temp_path = create_index_path (root, rel,index,clausegroup,join); - temp_node = - lcons(temp_path, NIL); - ip_list = nconc(ip_list,temp_node); - } - } - return(ip_list); + foreach(i, clausegroup_list) + { + CInfo *clauseinfo; + List *temp_node = NIL; + bool temp = true; + + clausegroup = lfirst(i); + + foreach(j, clausegroup) + { + clauseinfo = (CInfo *) lfirst(j); + if (!(join_clause_p((Node *) clauseinfo->clause) && + equal_path_merge_ordering(index->ordering, + clauseinfo->mergesortorder))) + { + temp = false; + } + } + + if (!join || temp) + { /* restriction, ordering scan */ + temp_path = create_index_path(root, rel, index, clausegroup, join); + temp_node = + lcons(temp_path, NIL); + ip_list = nconc(ip_list, temp_node); + } + } + return (ip_list); } -static List * -add_index_paths(List *indexpaths, List *new_indexpaths) +static List * +add_index_paths(List * indexpaths, List * new_indexpaths) { - return append(indexpaths, new_indexpaths); + return append(indexpaths, new_indexpaths); } -static bool -function_index_operand(Expr *funcOpnd, Rel *rel, Rel *index) +static bool +function_index_operand(Expr * funcOpnd, Rel * rel, Rel * index) { - Oid heapRelid = (Oid)lfirsti(rel->relids); - Func *function; - List *funcargs; - int *indexKeys = index->indexkeys; - List *arg; - int i; - - /* - * sanity check, make sure we know what we're dealing with here. - */ - if (funcOpnd==NULL || - nodeTag(funcOpnd)!=T_Expr || funcOpnd->opType!=FUNC_EXPR || - funcOpnd->oper==NULL || indexKeys==NULL) - return false; + Oid heapRelid = (Oid) lfirsti(rel->relids); + Func *function; + List *funcargs; + int *indexKeys = index->indexkeys; + List *arg; + int i; - function = (Func*)funcOpnd->oper; - funcargs = funcOpnd->args; + /* + * sanity check, make sure we know what we're dealing with here. + */ + if (funcOpnd == NULL || + nodeTag(funcOpnd) != T_Expr || funcOpnd->opType != FUNC_EXPR || + funcOpnd->oper == NULL || indexKeys == NULL) + return false; - if (function->funcid != index->indproc) - return false; + function = (Func *) funcOpnd->oper; + funcargs = funcOpnd->args; + + if (function->funcid != index->indproc) + return false; + + /* + * Check that the arguments correspond to the same arguments used to + * create the functional index. To do this we must check that 1. + * refer to the right relatiion. 2. the args have the right attr. + * numbers in the right order. + * + * + * Check all args refer to the correct relation (i.e. the one with the + * functional index defined on it (rel). To do this we can simply + * compare range table entry numbers, they must be the same. + */ + foreach(arg, funcargs) + { + if (heapRelid != ((Var *) lfirst(arg))->varno) + return false; + } + + /* + * check attr numbers and order. + */ + i = 0; + foreach(arg, funcargs) + { + + if (indexKeys[i] == 0) + return (false); - /* - * Check that the arguments correspond to the same arguments used - * to create the functional index. To do this we must check that - * 1. refer to the right relatiion. - * 2. the args have the right attr. numbers in the right order. - * - * - * Check all args refer to the correct relation (i.e. the one with - * the functional index defined on it (rel). To do this we can - * simply compare range table entry numbers, they must be the same. - */ - foreach (arg, funcargs) { - if (heapRelid != ((Var*)lfirst(arg))->varno) - return false; - } - - /* - * check attr numbers and order. - */ - i = 0; - foreach (arg, funcargs) { - - if (indexKeys[i]==0) - return (false); - - if (((Var*)lfirst(arg))->varattno != indexKeys[i]) - return (false); - - i++; - } - - return true; + if (((Var *) lfirst(arg))->varattno != indexKeys[i]) + return (false); + + i++; + } + + return true; } -static bool -SingleAttributeIndex(Rel *index) +static bool +SingleAttributeIndex(Rel * index) { - /* - * return false for now as I don't know if we support index scans - * on disjunction and the code doesn't work - */ - return (false); + + /* + * return false for now as I don't know if we support index scans on + * disjunction and the code doesn't work + */ + return (false); #if 0 - /* - * Non-functional indices. - */ - if (index->indproc == InvalidOid) - return (index->indexkeys[0] != 0 && - index->indexkeys[1] == 0); - - /* - * We have a functional index which is a single attr index - */ - return true; + + /* + * Non-functional indices. + */ + if (index->indproc == InvalidOid) + return (index->indexkeys[0] != 0 && + index->indexkeys[1] == 0); + + /* + * We have a functional index which is a single attr index + */ + return true; #endif } diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index 87365278ffa..c20558cf42b 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * joinpath.c-- - * Routines to find all possible paths for processing a set of joins + * Routines to find all possible paths for processing a set of joins * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.2 1996/10/31 10:59:00 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.3 1997/09/07 04:43:38 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -26,269 +26,286 @@ #include "optimizer/paths.h" #include "optimizer/pathnode.h" #include "optimizer/keys.h" -#include "optimizer/cost.h" /* for _enable_{hashjoin, _enable_mergesort} */ - -static Path *best_innerjoin(List *join_paths, List *outer_relid); -static List *sort_inner_and_outer(Rel *joinrel, Rel *outerrel, Rel *innerrel, - List *mergeinfo_list); -static List *match_unsorted_outer(Rel *joinrel, Rel *outerrel, Rel *innerrel, - List *outerpath_list, Path *cheapest_inner, Path *best_innerjoin, - List *mergeinfo_list); -static List *match_unsorted_inner(Rel *joinrel, Rel *outerrel, Rel *innerrel, - List *innerpath_list, List *mergeinfo_list); -static bool EnoughMemoryForHashjoin(Rel *hashrel); -static List *hash_inner_and_outer(Rel *joinrel, Rel *outerrel, Rel *innerrel, - List *hashinfo_list); - -/* +#include "optimizer/cost.h" /* for _enable_{hashjoin, + * _enable_mergesort} */ + +static Path *best_innerjoin(List * join_paths, List * outer_relid); +static List * +sort_inner_and_outer(Rel * joinrel, Rel * outerrel, Rel * innerrel, + List * mergeinfo_list); +static List * +match_unsorted_outer(Rel * joinrel, Rel * outerrel, Rel * innerrel, + List * outerpath_list, Path * cheapest_inner, Path * best_innerjoin, + List * mergeinfo_list); +static List * +match_unsorted_inner(Rel * joinrel, Rel * outerrel, Rel * innerrel, + List * innerpath_list, List * mergeinfo_list); +static bool EnoughMemoryForHashjoin(Rel * hashrel); +static List * +hash_inner_and_outer(Rel * joinrel, Rel * outerrel, Rel * innerrel, + List * hashinfo_list); + +/* * find-all-join-paths-- - * Creates all possible ways to process joins for each of the join - * relations in the list 'joinrels.' Each unique path will be included - * in the join relation's 'pathlist' field. - * - * In postgres, n-way joins are handled left-only(permuting clauseless - * joins doesn't usually win much). - * - * if BushyPlanFlag is true, bushy tree plans will be generated + * Creates all possible ways to process joins for each of the join + * relations in the list 'joinrels.' Each unique path will be included + * in the join relation's 'pathlist' field. + * + * In postgres, n-way joins are handled left-only(permuting clauseless + * joins doesn't usually win much). + * + * if BushyPlanFlag is true, bushy tree plans will be generated * * 'joinrels' is the list of relation entries to be joined - * + * * Modifies the pathlist field of the appropriate rel node to contain * the unique join paths. * If bushy trees are considered, may modify the relid field of the * join rel nodes to flatten the lists. - * - * Returns nothing of interest. (?) + * + * Returns nothing of interest. (?) * It does a destructive modification. */ void -find_all_join_paths(Query *root, List *joinrels) +find_all_join_paths(Query * root, List * joinrels) { - List *mergeinfo_list = NIL; - List *hashinfo_list = NIL; - List *temp_list = NIL; - List *path = NIL; - - while (joinrels != NIL) { - Rel *joinrel = (Rel *)lfirst(joinrels); - List *innerrelids; - List *outerrelids; - Rel *innerrel; - Rel *outerrel; - Path *bestinnerjoin; - List *pathlist = NIL; - - innerrelids = lsecond(joinrel->relids); - outerrelids = lfirst(joinrel->relids); - - /* - * base relation id is an integer and join relation relid is a - * list of integers. - */ - innerrel = (length(innerrelids)==1)? - get_base_rel(root, lfirsti(innerrelids)) : get_join_rel(root,innerrelids); - outerrel = (length(outerrelids)==1)? - get_base_rel(root, lfirsti(outerrelids)) : get_join_rel(root, outerrelids); - - bestinnerjoin = best_innerjoin(innerrel->innerjoin, - outerrel->relids); - if( _enable_mergesort_ ) { - mergeinfo_list = - group_clauses_by_order(joinrel->clauseinfo, - lfirsti(innerrel->relids)); - } - - if( _enable_hashjoin_ ) { - hashinfo_list = - group_clauses_by_hashop(joinrel->clauseinfo, - lfirsti(innerrel->relids)); - } - - /* need to flatten the relids list */ - joinrel->relids = intAppend(outerrelids, innerrelids); - - /* - * 1. Consider mergesort paths where both relations must be - * explicitly sorted. - */ - pathlist = sort_inner_and_outer(joinrel,outerrel, - innerrel,mergeinfo_list); - - /* - * 2. Consider paths where the outer relation need not be explicitly - * sorted. This may include either nestloops and mergesorts where - * the outer path is already ordered. - */ - pathlist = - add_pathlist(joinrel, pathlist, - match_unsorted_outer(joinrel, - outerrel, - innerrel, - outerrel->pathlist, - (Path*)innerrel->cheapestpath, - bestinnerjoin, - mergeinfo_list)); - - /* - * 3. Consider paths where the inner relation need not be explicitly - * sorted. This may include nestloops and mergesorts the actual - * nestloop nodes were constructed in (match-unsorted-outer). - */ - pathlist = - add_pathlist(joinrel,pathlist, - match_unsorted_inner(joinrel,outerrel, - innerrel, - innerrel->pathlist, - mergeinfo_list)); - - /* - * 4. Consider paths where both outer and inner relations must be - * hashed before being joined. - */ - - pathlist = - add_pathlist(joinrel, pathlist, - hash_inner_and_outer(joinrel,outerrel, - innerrel,hashinfo_list)); - - joinrel->pathlist = pathlist; - - /* - * 'OuterJoinCost is only valid when calling (match-unsorted-inner) - * with the same arguments as the previous invokation of - * (match-unsorted-outer), so clear the field before going on. - */ - temp_list = innerrel->pathlist; - foreach(path, temp_list) { - - /* - * XXX - * - * This gross hack is to get around an apparent optimizer bug on - * Sparc (or maybe it is a bug of ours?) that causes really wierd - * behavior. - */ - if (IsA_JoinPath(path)) { - ((Path*)lfirst(path))->outerjoincost = (Cost) 0; - } - - /* do it iff it is a join path, which is not always - true, esp since the base level */ + List *mergeinfo_list = NIL; + List *hashinfo_list = NIL; + List *temp_list = NIL; + List *path = NIL; + + while (joinrels != NIL) + { + Rel *joinrel = (Rel *) lfirst(joinrels); + List *innerrelids; + List *outerrelids; + Rel *innerrel; + Rel *outerrel; + Path *bestinnerjoin; + List *pathlist = NIL; + + innerrelids = lsecond(joinrel->relids); + outerrelids = lfirst(joinrel->relids); + + /* + * base relation id is an integer and join relation relid is a + * list of integers. + */ + innerrel = (length(innerrelids) == 1) ? + get_base_rel(root, lfirsti(innerrelids)) : get_join_rel(root, innerrelids); + outerrel = (length(outerrelids) == 1) ? + get_base_rel(root, lfirsti(outerrelids)) : get_join_rel(root, outerrelids); + + bestinnerjoin = best_innerjoin(innerrel->innerjoin, + outerrel->relids); + if (_enable_mergesort_) + { + mergeinfo_list = + group_clauses_by_order(joinrel->clauseinfo, + lfirsti(innerrel->relids)); + } + + if (_enable_hashjoin_) + { + hashinfo_list = + group_clauses_by_hashop(joinrel->clauseinfo, + lfirsti(innerrel->relids)); + } + + /* need to flatten the relids list */ + joinrel->relids = intAppend(outerrelids, innerrelids); + + /* + * 1. Consider mergesort paths where both relations must be + * explicitly sorted. + */ + pathlist = sort_inner_and_outer(joinrel, outerrel, + innerrel, mergeinfo_list); + + /* + * 2. Consider paths where the outer relation need not be + * explicitly sorted. This may include either nestloops and + * mergesorts where the outer path is already ordered. + */ + pathlist = + add_pathlist(joinrel, pathlist, + match_unsorted_outer(joinrel, + outerrel, + innerrel, + outerrel->pathlist, + (Path *) innerrel->cheapestpath, + bestinnerjoin, + mergeinfo_list)); + + /* + * 3. Consider paths where the inner relation need not be + * explicitly sorted. This may include nestloops and mergesorts + * the actual nestloop nodes were constructed in + * (match-unsorted-outer). + */ + pathlist = + add_pathlist(joinrel, pathlist, + match_unsorted_inner(joinrel, outerrel, + innerrel, + innerrel->pathlist, + mergeinfo_list)); + + /* + * 4. Consider paths where both outer and inner relations must be + * hashed before being joined. + */ + + pathlist = + add_pathlist(joinrel, pathlist, + hash_inner_and_outer(joinrel, outerrel, + innerrel, hashinfo_list)); + + joinrel->pathlist = pathlist; + + /* + * 'OuterJoinCost is only valid when calling + * (match-unsorted-inner) with the same arguments as the previous + * invokation of (match-unsorted-outer), so clear the field before + * going on. + */ + temp_list = innerrel->pathlist; + foreach(path, temp_list) + { + + /* + * XXX + * + * This gross hack is to get around an apparent optimizer bug on + * Sparc (or maybe it is a bug of ours?) that causes really + * wierd behavior. + */ + if (IsA_JoinPath(path)) + { + ((Path *) lfirst(path))->outerjoincost = (Cost) 0; + } + + /* + * do it iff it is a join path, which is not always true, esp + * since the base level + */ + } + + joinrels = lnext(joinrels); } - - joinrels = lnext(joinrels); - } } -/* +/* * best-innerjoin-- - * Find the cheapest index path that has already been identified by - * (indexable_joinclauses) as being a possible inner path for the given - * outer relation in a nestloop join. - * + * Find the cheapest index path that has already been identified by + * (indexable_joinclauses) as being a possible inner path for the given + * outer relation in a nestloop join. + * * 'join-paths' is a list of join nodes * 'outer-relid' is the relid of the outer join relation - * + * * Returns the pathnode of the selected path. */ -static Path * -best_innerjoin(List *join_paths, List *outer_relids) +static Path * +best_innerjoin(List * join_paths, List * outer_relids) { - Path *cheapest = (Path*)NULL; - List *join_path; - - foreach(join_path, join_paths) { - Path *path = (Path *)lfirst(join_path); + Path *cheapest = (Path *) NULL; + List *join_path; + + foreach(join_path, join_paths) + { + Path *path = (Path *) lfirst(join_path); - if (intMember(lfirsti(path->joinid), outer_relids) - && ((cheapest==NULL || - path_is_cheaper((Path*)lfirst(join_path),cheapest)))) { + if (intMember(lfirsti(path->joinid), outer_relids) + && ((cheapest == NULL || + path_is_cheaper((Path *) lfirst(join_path), cheapest)))) + { - cheapest = (Path*)lfirst(join_path); + cheapest = (Path *) lfirst(join_path); + } } - } - return(cheapest); + return (cheapest); } -/* +/* * sort-inner-and-outer-- - * Create mergesort join paths by explicitly sorting both the outer and - * inner join relations on each available merge ordering. - * + * Create mergesort join paths by explicitly sorting both the outer and + * inner join relations on each available merge ordering. + * * 'joinrel' is the join relation * 'outerrel' is the outer join relation * 'innerrel' is the inner join relation * 'mergeinfo-list' is a list of nodes containing info on(mergesortable) - * clauses for joining the relations - * + * clauses for joining the relations + * * Returns a list of mergesort paths. */ -static List * -sort_inner_and_outer(Rel *joinrel, - Rel *outerrel, - Rel *innerrel, - List *mergeinfo_list) +static List * +sort_inner_and_outer(Rel * joinrel, + Rel * outerrel, + Rel * innerrel, + List * mergeinfo_list) { - List *ms_list = NIL; - MInfo *xmergeinfo = (MInfo*)NULL; - MergePath *temp_node = (MergePath*)NULL; - List *i; - List *outerkeys = NIL; - List *innerkeys = NIL; - List *merge_pathkeys = NIL; - - foreach(i, mergeinfo_list) { - xmergeinfo = (MInfo *)lfirst(i); - - outerkeys = - extract_path_keys(xmergeinfo->jmethod.jmkeys, - outerrel->targetlist, - OUTER); - - innerkeys = - extract_path_keys(xmergeinfo->jmethod.jmkeys, - innerrel->targetlist, - INNER); - - merge_pathkeys = - new_join_pathkeys(outerkeys, joinrel->targetlist, - xmergeinfo->jmethod.clauses); - - temp_node = - create_mergesort_path(joinrel, - outerrel->size, - innerrel->size, - outerrel->width, - innerrel->width, - (Path*)outerrel->cheapestpath, - (Path*)innerrel->cheapestpath, - merge_pathkeys, - xmergeinfo->m_ordering, - xmergeinfo->jmethod.clauses, - outerkeys, - innerkeys); - - ms_list = lappend(ms_list, temp_node); - } - return(ms_list); + List *ms_list = NIL; + MInfo *xmergeinfo = (MInfo *) NULL; + MergePath *temp_node = (MergePath *) NULL; + List *i; + List *outerkeys = NIL; + List *innerkeys = NIL; + List *merge_pathkeys = NIL; + + foreach(i, mergeinfo_list) + { + xmergeinfo = (MInfo *) lfirst(i); + + outerkeys = + extract_path_keys(xmergeinfo->jmethod.jmkeys, + outerrel->targetlist, + OUTER); + + innerkeys = + extract_path_keys(xmergeinfo->jmethod.jmkeys, + innerrel->targetlist, + INNER); + + merge_pathkeys = + new_join_pathkeys(outerkeys, joinrel->targetlist, + xmergeinfo->jmethod.clauses); + + temp_node = + create_mergesort_path(joinrel, + outerrel->size, + innerrel->size, + outerrel->width, + innerrel->width, + (Path *) outerrel->cheapestpath, + (Path *) innerrel->cheapestpath, + merge_pathkeys, + xmergeinfo->m_ordering, + xmergeinfo->jmethod.clauses, + outerkeys, + innerkeys); + + ms_list = lappend(ms_list, temp_node); + } + return (ms_list); } -/* +/* * match-unsorted-outer-- - * Creates possible join paths for processing a single join relation - * 'joinrel' by employing either iterative substitution or - * mergesorting on each of its possible outer paths(assuming that the - * outer relation need not be explicitly sorted). - * - * 1. The inner path is the cheapest available inner path. - * 2. Mergesort wherever possible. Mergesorts are considered if there - * are mergesortable join clauses between the outer and inner join - * relations such that the outer path is keyed on the variables - * appearing in the clauses. The corresponding inner merge path is - * either a path whose keys match those of the outer path(if such a - * path is available) or an explicit sort on the appropriate inner - * join keys, whichever is cheaper. - * + * Creates possible join paths for processing a single join relation + * 'joinrel' by employing either iterative substitution or + * mergesorting on each of its possible outer paths(assuming that the + * outer relation need not be explicitly sorted). + * + * 1. The inner path is the cheapest available inner path. + * 2. Mergesort wherever possible. Mergesorts are considered if there + * are mergesortable join clauses between the outer and inner join + * relations such that the outer path is keyed on the variables + * appearing in the clauses. The corresponding inner merge path is + * either a path whose keys match those of the outer path(if such a + * path is available) or an explicit sort on the appropriate inner + * join keys, whichever is cheaper. + * * 'joinrel' is the join relation * 'outerrel' is the outer join relation * 'innerrel' is the inner join relation @@ -296,331 +313,355 @@ sort_inner_and_outer(Rel *joinrel, * 'cheapest-inner' is the cheapest inner path * 'best-innerjoin' is the best inner index path(if any) * 'mergeinfo-list' is a list of nodes containing info on mergesortable - * clauses - * + * clauses + * * Returns a list of possible join path nodes. */ -static List * -match_unsorted_outer(Rel *joinrel, - Rel *outerrel, - Rel *innerrel, - List *outerpath_list, - Path *cheapest_inner, - Path *best_innerjoin, - List *mergeinfo_list) +static List * +match_unsorted_outer(Rel * joinrel, + Rel * outerrel, + Rel * innerrel, + List * outerpath_list, + Path * cheapest_inner, + Path * best_innerjoin, + List * mergeinfo_list) { - Path *outerpath = (Path*)NULL; - List *jp_list = NIL; - List *temp_node = NIL; - List *merge_pathkeys = NIL; - Path *nestinnerpath =(Path*)NULL; - List *paths = NIL; - List *i = NIL; - PathOrder *outerpath_ordering = NULL; - - foreach(i,outerpath_list) { - List *clauses = NIL; - List *matchedJoinKeys = NIL; - List *matchedJoinClauses = NIL; - MInfo *xmergeinfo = (MInfo*)NULL; - - outerpath = (Path*)lfirst(i); - - outerpath_ordering = &outerpath->p_ordering; - - if (outerpath_ordering) { - xmergeinfo = - match_order_mergeinfo(outerpath_ordering, - mergeinfo_list); - } - - if (xmergeinfo) { - clauses = xmergeinfo->jmethod.clauses; - } - - if (clauses) { - List *keys = xmergeinfo->jmethod.jmkeys; - List *clauses = xmergeinfo->jmethod.clauses; - - matchedJoinKeys = - match_pathkeys_joinkeys(outerpath->keys, - keys, - clauses, - OUTER, - &matchedJoinClauses); - merge_pathkeys = - new_join_pathkeys(outerpath->keys, - joinrel->targetlist, clauses); - } else { - merge_pathkeys = outerpath->keys; - } - - if(best_innerjoin && - path_is_cheaper(best_innerjoin, cheapest_inner)) { - nestinnerpath = best_innerjoin; - } else { - nestinnerpath = cheapest_inner; - } - - paths = lcons(create_nestloop_path(joinrel, - outerrel, - outerpath, - nestinnerpath, - merge_pathkeys), - NIL); - - if (clauses && matchedJoinKeys) { - bool path_is_cheaper_than_sort; - List *varkeys = NIL; - Path *mergeinnerpath = - match_paths_joinkeys(matchedJoinKeys, - outerpath_ordering, - innerrel->pathlist, - INNER); - - path_is_cheaper_than_sort = - (bool) (mergeinnerpath && - (mergeinnerpath->path_cost < - (cheapest_inner->path_cost + - cost_sort(matchedJoinKeys, - innerrel->size, - innerrel->width, - false)))); - if(!path_is_cheaper_than_sort) { - varkeys = - extract_path_keys(matchedJoinKeys, - innerrel->targetlist, - INNER); - } - - - /* - * Keep track of the cost of the outer path used with - * this ordered inner path for later processing in - * (match-unsorted-inner), since it isn't a sort and - * thus wouldn't otherwise be considered. - */ - if (path_is_cheaper_than_sort) { - mergeinnerpath->outerjoincost = outerpath->path_cost; - } else { - mergeinnerpath = cheapest_inner; - } - - temp_node = - lcons(create_mergesort_path(joinrel, - outerrel->size, - innerrel->size, - outerrel->width, - innerrel->width, - outerpath, - mergeinnerpath, - merge_pathkeys, - xmergeinfo->m_ordering, - matchedJoinClauses, - NIL, - varkeys), - paths); - } else { - temp_node = paths; - } - jp_list = nconc(jp_list, temp_node); - } - return(jp_list); + Path *outerpath = (Path *) NULL; + List *jp_list = NIL; + List *temp_node = NIL; + List *merge_pathkeys = NIL; + Path *nestinnerpath = (Path *) NULL; + List *paths = NIL; + List *i = NIL; + PathOrder *outerpath_ordering = NULL; + + foreach(i, outerpath_list) + { + List *clauses = NIL; + List *matchedJoinKeys = NIL; + List *matchedJoinClauses = NIL; + MInfo *xmergeinfo = (MInfo *) NULL; + + outerpath = (Path *) lfirst(i); + + outerpath_ordering = &outerpath->p_ordering; + + if (outerpath_ordering) + { + xmergeinfo = + match_order_mergeinfo(outerpath_ordering, + mergeinfo_list); + } + + if (xmergeinfo) + { + clauses = xmergeinfo->jmethod.clauses; + } + + if (clauses) + { + List *keys = xmergeinfo->jmethod.jmkeys; + List *clauses = xmergeinfo->jmethod.clauses; + + matchedJoinKeys = + match_pathkeys_joinkeys(outerpath->keys, + keys, + clauses, + OUTER, + &matchedJoinClauses); + merge_pathkeys = + new_join_pathkeys(outerpath->keys, + joinrel->targetlist, clauses); + } + else + { + merge_pathkeys = outerpath->keys; + } + + if (best_innerjoin && + path_is_cheaper(best_innerjoin, cheapest_inner)) + { + nestinnerpath = best_innerjoin; + } + else + { + nestinnerpath = cheapest_inner; + } + + paths = lcons(create_nestloop_path(joinrel, + outerrel, + outerpath, + nestinnerpath, + merge_pathkeys), + NIL); + + if (clauses && matchedJoinKeys) + { + bool path_is_cheaper_than_sort; + List *varkeys = NIL; + Path *mergeinnerpath = + match_paths_joinkeys(matchedJoinKeys, + outerpath_ordering, + innerrel->pathlist, + INNER); + + path_is_cheaper_than_sort = + (bool) (mergeinnerpath && + (mergeinnerpath->path_cost < + (cheapest_inner->path_cost + + cost_sort(matchedJoinKeys, + innerrel->size, + innerrel->width, + false)))); + if (!path_is_cheaper_than_sort) + { + varkeys = + extract_path_keys(matchedJoinKeys, + innerrel->targetlist, + INNER); + } + + + /* + * Keep track of the cost of the outer path used with this + * ordered inner path for later processing in + * (match-unsorted-inner), since it isn't a sort and thus + * wouldn't otherwise be considered. + */ + if (path_is_cheaper_than_sort) + { + mergeinnerpath->outerjoincost = outerpath->path_cost; + } + else + { + mergeinnerpath = cheapest_inner; + } + + temp_node = + lcons(create_mergesort_path(joinrel, + outerrel->size, + innerrel->size, + outerrel->width, + innerrel->width, + outerpath, + mergeinnerpath, + merge_pathkeys, + xmergeinfo->m_ordering, + matchedJoinClauses, + NIL, + varkeys), + paths); + } + else + { + temp_node = paths; + } + jp_list = nconc(jp_list, temp_node); + } + return (jp_list); } -/* +/* * match-unsorted-inner -- - * Find the cheapest ordered join path for a given(ordered, unsorted) - * inner join path. - * - * Scans through each path available on an inner join relation and tries - * matching its ordering keys against those of mergejoin clauses. - * If 1. an appropriately-ordered inner path and matching mergeclause are - * found, and - * 2. sorting the cheapest outer path is cheaper than using an ordered - * but unsorted outer path(as was considered in - * (match-unsorted-outer)), - * then this merge path is considered. - * + * Find the cheapest ordered join path for a given(ordered, unsorted) + * inner join path. + * + * Scans through each path available on an inner join relation and tries + * matching its ordering keys against those of mergejoin clauses. + * If 1. an appropriately-ordered inner path and matching mergeclause are + * found, and + * 2. sorting the cheapest outer path is cheaper than using an ordered + * but unsorted outer path(as was considered in + * (match-unsorted-outer)), + * then this merge path is considered. + * * 'joinrel' is the join result relation * 'outerrel' is the outer join relation * 'innerrel' is the inner join relation * 'innerpath-list' is the list of possible inner join paths * 'mergeinfo-list' is a list of nodes containing info on mergesortable - * clauses - * + * clauses + * * Returns a list of possible merge paths. */ -static List * -match_unsorted_inner(Rel *joinrel, - Rel *outerrel, - Rel *innerrel, - List *innerpath_list, - List *mergeinfo_list) +static List * +match_unsorted_inner(Rel * joinrel, + Rel * outerrel, + Rel * innerrel, + List * innerpath_list, + List * mergeinfo_list) { - Path *innerpath = (Path*)NULL; - List *mp_list = NIL; - List *temp_node = NIL; - PathOrder *innerpath_ordering = NULL; - Cost temp1 = 0.0; - bool temp2 = false; - List *i = NIL; - - foreach (i, innerpath_list) { - MInfo *xmergeinfo = (MInfo*)NULL; - List *clauses = NIL; - List *matchedJoinKeys = NIL; - List *matchedJoinClauses = NIL; - - innerpath = (Path*)lfirst(i); - - innerpath_ordering = &innerpath->p_ordering; - - if (innerpath_ordering) { - xmergeinfo = - match_order_mergeinfo(innerpath_ordering, - mergeinfo_list); - } - - if (xmergeinfo) { - clauses = ((JoinMethod*)xmergeinfo)->clauses; - } - - if (clauses) { - List *keys = xmergeinfo->jmethod.jmkeys; - List *cls = xmergeinfo->jmethod.clauses; - - matchedJoinKeys = - match_pathkeys_joinkeys(innerpath->keys, - keys, - cls, - INNER, - &matchedJoinClauses); - } - - /* - * (match-unsorted-outer) if it is applicable. - * 'OuterJoinCost was set above in - */ - if (clauses && matchedJoinKeys) { - temp1 = outerrel->cheapestpath->path_cost + - cost_sort(matchedJoinKeys, outerrel->size, outerrel->width, - false); - - temp2 = (bool) (FLOAT_IS_ZERO(innerpath->outerjoincost) - || (innerpath->outerjoincost > temp1)); - - if(temp2) { - List *outerkeys = - extract_path_keys(matchedJoinKeys, - outerrel->targetlist, - OUTER); - List *merge_pathkeys = - new_join_pathkeys(outerkeys, - joinrel->targetlist, - clauses); - - temp_node = - lcons(create_mergesort_path(joinrel, - outerrel->size, - innerrel->size, - outerrel->width, - innerrel->width, - (Path*)outerrel->cheapestpath, - innerpath, - merge_pathkeys, - xmergeinfo->m_ordering, - matchedJoinClauses, - outerkeys, - NIL), - NIL); - - mp_list = nconc(mp_list,temp_node); - } + Path *innerpath = (Path *) NULL; + List *mp_list = NIL; + List *temp_node = NIL; + PathOrder *innerpath_ordering = NULL; + Cost temp1 = 0.0; + bool temp2 = false; + List *i = NIL; + + foreach(i, innerpath_list) + { + MInfo *xmergeinfo = (MInfo *) NULL; + List *clauses = NIL; + List *matchedJoinKeys = NIL; + List *matchedJoinClauses = NIL; + + innerpath = (Path *) lfirst(i); + + innerpath_ordering = &innerpath->p_ordering; + + if (innerpath_ordering) + { + xmergeinfo = + match_order_mergeinfo(innerpath_ordering, + mergeinfo_list); + } + + if (xmergeinfo) + { + clauses = ((JoinMethod *) xmergeinfo)->clauses; + } + + if (clauses) + { + List *keys = xmergeinfo->jmethod.jmkeys; + List *cls = xmergeinfo->jmethod.clauses; + + matchedJoinKeys = + match_pathkeys_joinkeys(innerpath->keys, + keys, + cls, + INNER, + &matchedJoinClauses); + } + + /* + * (match-unsorted-outer) if it is applicable. 'OuterJoinCost was + * set above in + */ + if (clauses && matchedJoinKeys) + { + temp1 = outerrel->cheapestpath->path_cost + + cost_sort(matchedJoinKeys, outerrel->size, outerrel->width, + false); + + temp2 = (bool) (FLOAT_IS_ZERO(innerpath->outerjoincost) + || (innerpath->outerjoincost > temp1)); + + if (temp2) + { + List *outerkeys = + extract_path_keys(matchedJoinKeys, + outerrel->targetlist, + OUTER); + List *merge_pathkeys = + new_join_pathkeys(outerkeys, + joinrel->targetlist, + clauses); + + temp_node = + lcons(create_mergesort_path(joinrel, + outerrel->size, + innerrel->size, + outerrel->width, + innerrel->width, + (Path *) outerrel->cheapestpath, + innerpath, + merge_pathkeys, + xmergeinfo->m_ordering, + matchedJoinClauses, + outerkeys, + NIL), + NIL); + + mp_list = nconc(mp_list, temp_node); + } + } } - } - return(mp_list); - + return (mp_list); + } -static bool -EnoughMemoryForHashjoin(Rel *hashrel) +static bool +EnoughMemoryForHashjoin(Rel * hashrel) { - int ntuples; - int tupsize; - int pages; - - ntuples = hashrel->size; - if (ntuples == 0) ntuples = 1000; - tupsize = hashrel->width + sizeof(HeapTupleData); - pages = page_size(ntuples, tupsize); - /* - * if amount of buffer space below hashjoin threshold, - * return false - */ - if (ceil(sqrt((double)pages)) > NBuffers) - return false; - return true; + int ntuples; + int tupsize; + int pages; + + ntuples = hashrel->size; + if (ntuples == 0) + ntuples = 1000; + tupsize = hashrel->width + sizeof(HeapTupleData); + pages = page_size(ntuples, tupsize); + + /* + * if amount of buffer space below hashjoin threshold, return false + */ + if (ceil(sqrt((double) pages)) > NBuffers) + return false; + return true; } -/* - * hash-inner-and-outer-- XXX HASH - * Create hashjoin join paths by explicitly hashing both the outer and - * inner join relations on each available hash op. - * +/* + * hash-inner-and-outer-- XXX HASH + * Create hashjoin join paths by explicitly hashing both the outer and + * inner join relations on each available hash op. + * * 'joinrel' is the join relation * 'outerrel' is the outer join relation * 'innerrel' is the inner join relation * 'hashinfo-list' is a list of nodes containing info on(hashjoinable) - * clauses for joining the relations - * + * clauses for joining the relations + * * Returns a list of hashjoin paths. */ -static List * -hash_inner_and_outer(Rel *joinrel, - Rel *outerrel, - Rel *innerrel, - List *hashinfo_list) +static List * +hash_inner_and_outer(Rel * joinrel, + Rel * outerrel, + Rel * innerrel, + List * hashinfo_list) { - HInfo *xhashinfo = (HInfo*)NULL; - List *hjoin_list = NIL; - HashPath *temp_node = (HashPath*)NULL; - List *i = NIL; - List *outerkeys = NIL; - List *innerkeys = NIL; - List *hash_pathkeys = NIL; - - foreach (i, hashinfo_list) { - xhashinfo = (HInfo*)lfirst(i); - outerkeys = - extract_path_keys(((JoinMethod*)xhashinfo)->jmkeys, - outerrel->targetlist, - OUTER); - innerkeys = - extract_path_keys(((JoinMethod*)xhashinfo)->jmkeys, - innerrel->targetlist, - INNER); - hash_pathkeys = - new_join_pathkeys(outerkeys, - joinrel->targetlist, - ((JoinMethod*)xhashinfo)->clauses); - - if (EnoughMemoryForHashjoin(innerrel)) { - temp_node = create_hashjoin_path(joinrel, - outerrel->size, - innerrel->size, - outerrel->width, - innerrel->width, - (Path*)outerrel->cheapestpath, - (Path*)innerrel->cheapestpath, - hash_pathkeys, - xhashinfo->hashop, - ((JoinMethod*)xhashinfo)->clauses, - outerkeys, - innerkeys); - hjoin_list = lappend(hjoin_list, temp_node); + HInfo *xhashinfo = (HInfo *) NULL; + List *hjoin_list = NIL; + HashPath *temp_node = (HashPath *) NULL; + List *i = NIL; + List *outerkeys = NIL; + List *innerkeys = NIL; + List *hash_pathkeys = NIL; + + foreach(i, hashinfo_list) + { + xhashinfo = (HInfo *) lfirst(i); + outerkeys = + extract_path_keys(((JoinMethod *) xhashinfo)->jmkeys, + outerrel->targetlist, + OUTER); + innerkeys = + extract_path_keys(((JoinMethod *) xhashinfo)->jmkeys, + innerrel->targetlist, + INNER); + hash_pathkeys = + new_join_pathkeys(outerkeys, + joinrel->targetlist, + ((JoinMethod *) xhashinfo)->clauses); + + if (EnoughMemoryForHashjoin(innerrel)) + { + temp_node = create_hashjoin_path(joinrel, + outerrel->size, + innerrel->size, + outerrel->width, + innerrel->width, + (Path *) outerrel->cheapestpath, + (Path *) innerrel->cheapestpath, + hash_pathkeys, + xhashinfo->hashop, + ((JoinMethod *) xhashinfo)->clauses, + outerkeys, + innerkeys); + hjoin_list = lappend(hjoin_list, temp_node); + } } - } - return(hjoin_list); + return (hjoin_list); } - diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 00f8a04a050..98762f9800c 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * joinrels.c-- - * Routines to determine which relations should be joined + * Routines to determine which relations should be joined * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.4 1997/06/05 09:33:52 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.5 1997/09/07 04:43:40 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -24,467 +24,508 @@ #include "optimizer/pathnode.h" #ifdef USE_RIGHT_SIDED_PLANS -bool _use_right_sided_plans_ = true; +bool _use_right_sided_plans_ = true; + #else -bool _use_right_sided_plans_ = false; +bool _use_right_sided_plans_ = false; + #endif -static List *find_clause_joins(Query *root, Rel *outer_rel, List *joininfo_list); -static List *find_clauseless_joins(Rel *outer_rel, List *inner_rels); -static Rel *init_join_rel(Rel *outer_rel, Rel *inner_rel, JInfo *joininfo); -static List *new_join_tlist(List *tlist, List *other_relids, - int first_resdomno); -static List *new_joininfo_list(List *joininfo_list, List *join_relids); -static void add_superrels(Rel *rel, Rel *super_rel); -static bool nonoverlap_rels(Rel *rel1, Rel *rel2); -static bool nonoverlap_sets(List *s1, List *s2); -static void set_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel, - JInfo *jinfo); - -/* +static List *find_clause_joins(Query * root, Rel * outer_rel, List * joininfo_list); +static List *find_clauseless_joins(Rel * outer_rel, List * inner_rels); +static Rel *init_join_rel(Rel * outer_rel, Rel * inner_rel, JInfo * joininfo); +static List * +new_join_tlist(List * tlist, List * other_relids, + int first_resdomno); +static List *new_joininfo_list(List * joininfo_list, List * join_relids); +static void add_superrels(Rel * rel, Rel * super_rel); +static bool nonoverlap_rels(Rel * rel1, Rel * rel2); +static bool nonoverlap_sets(List * s1, List * s2); +static void +set_joinrel_size(Rel * joinrel, Rel * outer_rel, Rel * inner_rel, + JInfo * jinfo); + +/* * find-join-rels-- - * Find all possible joins for each of the outer join relations in - * 'outer-rels'. A rel node is created for each possible join relation, - * and the resulting list of nodes is returned. If at all possible, only - * those relations for which join clauses exist are considered. If none - * of these exist for a given relation, all remaining possibilities are - * considered. - * + * Find all possible joins for each of the outer join relations in + * 'outer-rels'. A rel node is created for each possible join relation, + * and the resulting list of nodes is returned. If at all possible, only + * those relations for which join clauses exist are considered. If none + * of these exist for a given relation, all remaining possibilities are + * considered. + * * 'outer-rels' is the list of rel nodes - * + * * Returns a list of rel nodes corresponding to the new join relations. */ -List * -find_join_rels(Query *root, List *outer_rels) +List * +find_join_rels(Query * root, List * outer_rels) { - List *joins = NIL; - List *join_list = NIL; - List *r = NIL; - - foreach(r, outer_rels) { - Rel *outer_rel = (Rel *)lfirst(r); - - if(!(joins = find_clause_joins(root, outer_rel,outer_rel->joininfo))) - if (BushyPlanFlag) - joins = find_clauseless_joins(outer_rel,outer_rels); - else - joins = find_clauseless_joins(outer_rel,root->base_relation_list_); - - join_list = nconc(join_list, joins); - } - - return(join_list); + List *joins = NIL; + List *join_list = NIL; + List *r = NIL; + + foreach(r, outer_rels) + { + Rel *outer_rel = (Rel *) lfirst(r); + + if (!(joins = find_clause_joins(root, outer_rel, outer_rel->joininfo))) + if (BushyPlanFlag) + joins = find_clauseless_joins(outer_rel, outer_rels); + else + joins = find_clauseless_joins(outer_rel, root->base_relation_list_); + + join_list = nconc(join_list, joins); + } + + return (join_list); } -/* +/* * find-clause-joins-- - * Determines whether joins can be performed between an outer relation - * 'outer-rel' and those relations within 'outer-rel's joininfo nodes - * (i.e., relations that participate in join clauses that 'outer-rel' - * participates in). This is possible if all but one of the relations - * contained within the join clauses of the joininfo node are already - * contained within 'outer-rel'. + * Determines whether joins can be performed between an outer relation + * 'outer-rel' and those relations within 'outer-rel's joininfo nodes + * (i.e., relations that participate in join clauses that 'outer-rel' + * participates in). This is possible if all but one of the relations + * contained within the join clauses of the joininfo node are already + * contained within 'outer-rel'. * * 'outer-rel' is the relation entry for the outer relation - * 'joininfo-list' is a list of join clauses which 'outer-rel' - * participates in - * + * 'joininfo-list' is a list of join clauses which 'outer-rel' + * participates in + * * Returns a list of new join relations. */ -static List * -find_clause_joins(Query *root, Rel *outer_rel, List *joininfo_list) +static List * +find_clause_joins(Query * root, Rel * outer_rel, List * joininfo_list) { - List *join_list = NIL; - List *i = NIL; - - foreach (i, joininfo_list) { - JInfo *joininfo = (JInfo*)lfirst(i); - Rel *rel; - - if(!joininfo->inactive) { - List *other_rels = joininfo->otherrels; - - if(other_rels != NIL) { - if(length(other_rels) == 1) { - rel = init_join_rel(outer_rel, - get_base_rel(root, lfirsti(other_rels)), - joininfo); - /* how about right-sided plan ? */ - if ( _use_right_sided_plans_ && - length (outer_rel->relids) > 1 ) - { - if (rel != NULL) - join_list = lappend(join_list, rel); - rel = init_join_rel(get_base_rel(root, lfirsti(other_rels)), - outer_rel, - joininfo); - } - } else if (BushyPlanFlag) { - rel = init_join_rel(outer_rel, - get_join_rel(root, other_rels), - joininfo); - } else { - rel = NULL; - } + List *join_list = NIL; + List *i = NIL; - if (rel != NULL) - join_list = lappend(join_list, rel); - } + foreach(i, joininfo_list) + { + JInfo *joininfo = (JInfo *) lfirst(i); + Rel *rel; + + if (!joininfo->inactive) + { + List *other_rels = joininfo->otherrels; + + if (other_rels != NIL) + { + if (length(other_rels) == 1) + { + rel = init_join_rel(outer_rel, + get_base_rel(root, lfirsti(other_rels)), + joininfo); + /* how about right-sided plan ? */ + if (_use_right_sided_plans_ && + length(outer_rel->relids) > 1) + { + if (rel != NULL) + join_list = lappend(join_list, rel); + rel = init_join_rel(get_base_rel(root, lfirsti(other_rels)), + outer_rel, + joininfo); + } + } + else if (BushyPlanFlag) + { + rel = init_join_rel(outer_rel, + get_join_rel(root, other_rels), + joininfo); + } + else + { + rel = NULL; + } + + if (rel != NULL) + join_list = lappend(join_list, rel); + } + } } - } - return(join_list); + return (join_list); } -/* +/* * find-clauseless-joins-- - * Given an outer relation 'outer-rel' and a list of inner relations - * 'inner-rels', create a join relation between 'outer-rel' and each - * member of 'inner-rels' that isn't already included in 'outer-rel'. - * + * Given an outer relation 'outer-rel' and a list of inner relations + * 'inner-rels', create a join relation between 'outer-rel' and each + * member of 'inner-rels' that isn't already included in 'outer-rel'. + * * Returns a list of new join relations. */ -static List * -find_clauseless_joins(Rel *outer_rel, List *inner_rels) +static List * +find_clauseless_joins(Rel * outer_rel, List * inner_rels) { - Rel *inner_rel; - List *t_list = NIL; - List *temp_node = NIL; - List *i = NIL; - - foreach (i, inner_rels) { - inner_rel = (Rel *)lfirst(i); - if(nonoverlap_rels(inner_rel, outer_rel)) { - temp_node = lcons(init_join_rel(outer_rel, - inner_rel, - (JInfo*)NULL), - NIL); - t_list = nconc(t_list,temp_node); - } - } - - return(t_list); + Rel *inner_rel; + List *t_list = NIL; + List *temp_node = NIL; + List *i = NIL; + + foreach(i, inner_rels) + { + inner_rel = (Rel *) lfirst(i); + if (nonoverlap_rels(inner_rel, outer_rel)) + { + temp_node = lcons(init_join_rel(outer_rel, + inner_rel, + (JInfo *) NULL), + NIL); + t_list = nconc(t_list, temp_node); + } + } + + return (t_list); } -/* +/* * init-join-rel-- - * Creates and initializes a new join relation. - * + * Creates and initializes a new join relation. + * * 'outer-rel' and 'inner-rel' are relation nodes for the relations to be - * joined + * joined * 'joininfo' is the joininfo node(join clause) containing both - * 'outer-rel' and 'inner-rel', if any exists - * + * 'outer-rel' and 'inner-rel', if any exists + * * Returns the new join relation node. */ -static Rel * -init_join_rel(Rel *outer_rel, Rel *inner_rel, JInfo *joininfo) +static Rel * +init_join_rel(Rel * outer_rel, Rel * inner_rel, JInfo * joininfo) { - Rel *joinrel = makeNode(Rel); - List *joinrel_joininfo_list = NIL; - List *new_outer_tlist; - List *new_inner_tlist; - - /* - * Create a new tlist by removing irrelevant elements from both - * tlists of the outer and inner join relations and then merging - * the results together. - */ - new_outer_tlist = - new_join_tlist(outer_rel->targetlist, /* XXX 1-based attnos */ - inner_rel->relids, 1); - new_inner_tlist = - new_join_tlist(inner_rel->targetlist, /* XXX 1-based attnos */ - outer_rel->relids, - length(new_outer_tlist) + 1); - - joinrel->relids = NIL; - joinrel->indexed = false; - joinrel->pages = 0; - joinrel->tuples = 0; - joinrel->width = 0; -/* joinrel->targetlist = NIL;*/ - joinrel->pathlist = NIL; - joinrel->unorderedpath = (Path *)NULL; - joinrel->cheapestpath = (Path *)NULL; - joinrel->pruneable = true; - joinrel->classlist = NULL; - joinrel->relam = InvalidOid; - joinrel->ordering = NULL; - joinrel->clauseinfo = NIL; - joinrel->joininfo = NULL; - joinrel->innerjoin = NIL; - joinrel->superrels = NIL; - - joinrel->relids = lcons(outer_rel->relids, /* ??? aren't they lists? -ay */ - lcons(inner_rel->relids, NIL)); - - new_outer_tlist = nconc(new_outer_tlist,new_inner_tlist); - joinrel->targetlist = new_outer_tlist; - - if (joininfo) { - joinrel->clauseinfo = joininfo->jinfoclauseinfo; - if (BushyPlanFlag) - joininfo->inactive = true; - } - - joinrel_joininfo_list = - new_joininfo_list(append(outer_rel->joininfo, inner_rel->joininfo), - intAppend(outer_rel->relids, inner_rel->relids)); - - joinrel->joininfo = joinrel_joininfo_list; - - set_joinrel_size(joinrel, outer_rel, inner_rel, joininfo); - - return(joinrel); + Rel *joinrel = makeNode(Rel); + List *joinrel_joininfo_list = NIL; + List *new_outer_tlist; + List *new_inner_tlist; + + /* + * Create a new tlist by removing irrelevant elements from both tlists + * of the outer and inner join relations and then merging the results + * together. + */ + new_outer_tlist = + new_join_tlist(outer_rel->targetlist, /* XXX 1-based attnos */ + inner_rel->relids, 1); + new_inner_tlist = + new_join_tlist(inner_rel->targetlist, /* XXX 1-based attnos */ + outer_rel->relids, + length(new_outer_tlist) + 1); + + joinrel->relids = NIL; + joinrel->indexed = false; + joinrel->pages = 0; + joinrel->tuples = 0; + joinrel->width = 0; +/* joinrel->targetlist = NIL;*/ + joinrel->pathlist = NIL; + joinrel->unorderedpath = (Path *) NULL; + joinrel->cheapestpath = (Path *) NULL; + joinrel->pruneable = true; + joinrel->classlist = NULL; + joinrel->relam = InvalidOid; + joinrel->ordering = NULL; + joinrel->clauseinfo = NIL; + joinrel->joininfo = NULL; + joinrel->innerjoin = NIL; + joinrel->superrels = NIL; + + joinrel->relids = lcons(outer_rel->relids, /* ??? aren't they lists? + * -ay */ + lcons(inner_rel->relids, NIL)); + + new_outer_tlist = nconc(new_outer_tlist, new_inner_tlist); + joinrel->targetlist = new_outer_tlist; + + if (joininfo) + { + joinrel->clauseinfo = joininfo->jinfoclauseinfo; + if (BushyPlanFlag) + joininfo->inactive = true; + } + + joinrel_joininfo_list = + new_joininfo_list(append(outer_rel->joininfo, inner_rel->joininfo), + intAppend(outer_rel->relids, inner_rel->relids)); + + joinrel->joininfo = joinrel_joininfo_list; + + set_joinrel_size(joinrel, outer_rel, inner_rel, joininfo); + + return (joinrel); } -/* +/* * new-join-tlist-- - * Builds a join relations's target list by keeping those elements that - * will be in the final target list and any other elements that are still - * needed for future joins. For a target list entry to still be needed - * for future joins, its 'joinlist' field must not be empty after removal - * of all relids in 'other-relids'. - * + * Builds a join relations's target list by keeping those elements that + * will be in the final target list and any other elements that are still + * needed for future joins. For a target list entry to still be needed + * for future joins, its 'joinlist' field must not be empty after removal + * of all relids in 'other-relids'. + * * 'tlist' is the target list of one of the join relations * 'other-relids' is a list of relids contained within the other - * join relation + * join relation * 'first-resdomno' is the resdom number to use for the first created - * target list entry - * + * target list entry + * * Returns the new target list. */ -static List * -new_join_tlist(List *tlist, - List *other_relids, - int first_resdomno) +static List * +new_join_tlist(List * tlist, + List * other_relids, + int first_resdomno) { - int resdomno = first_resdomno - 1; - TargetEntry *xtl = NULL; - List *temp_node = NIL; - List *t_list = NIL; - List *i = NIL; - List *join_list = NIL; - bool in_final_tlist =false; - - - foreach(i,tlist) { - xtl= lfirst(i); - in_final_tlist = (join_list==NIL); - if( in_final_tlist) { - resdomno += 1; - temp_node = - lcons(create_tl_element(get_expr(xtl), - resdomno), - NIL); - t_list = nconc(t_list,temp_node); - } - } - - return(t_list); + int resdomno = first_resdomno - 1; + TargetEntry *xtl = NULL; + List *temp_node = NIL; + List *t_list = NIL; + List *i = NIL; + List *join_list = NIL; + bool in_final_tlist = false; + + + foreach(i, tlist) + { + xtl = lfirst(i); + in_final_tlist = (join_list == NIL); + if (in_final_tlist) + { + resdomno += 1; + temp_node = + lcons(create_tl_element(get_expr(xtl), + resdomno), + NIL); + t_list = nconc(t_list, temp_node); + } + } + + return (t_list); } -/* +/* * new-joininfo-list-- - * Builds a join relation's joininfo list by checking for join clauses - * which still need to used in future joins involving this relation. A - * join clause is still needed if there are still relations in the clause - * not contained in the list of relations comprising this join relation. - * New joininfo nodes are only created and added to - * 'current-joininfo-list' if a node for a particular join hasn't already - * been created. + * Builds a join relation's joininfo list by checking for join clauses + * which still need to used in future joins involving this relation. A + * join clause is still needed if there are still relations in the clause + * not contained in the list of relations comprising this join relation. + * New joininfo nodes are only created and added to + * 'current-joininfo-list' if a node for a particular join hasn't already + * been created. * - * 'current-joininfo-list' contains a list of those joininfo nodes that - * have already been built + * 'current-joininfo-list' contains a list of those joininfo nodes that + * have already been built * 'joininfo-list' is the list of join clauses involving this relation - * 'join-relids' is a list of relids corresponding to the relations - * currently being joined - * + * 'join-relids' is a list of relids corresponding to the relations + * currently being joined + * * Returns a list of joininfo nodes, new and old. */ -static List * -new_joininfo_list(List *joininfo_list, List *join_relids) +static List * +new_joininfo_list(List * joininfo_list, List * join_relids) { - List *current_joininfo_list = NIL; - List *new_otherrels = NIL; - JInfo *other_joininfo = (JInfo*)NULL; - List *xjoininfo = NIL; - - foreach (xjoininfo, joininfo_list) { - List *or; - JInfo *joininfo = (JInfo*)lfirst(xjoininfo); - - new_otherrels = joininfo->otherrels; - foreach (or, new_otherrels) - { - if ( intMember (lfirsti(or), join_relids) ) - new_otherrels = lremove ((void*)lfirst(or), new_otherrels); - } - joininfo->otherrels = new_otherrels; - if ( new_otherrels != NIL ) + List *current_joininfo_list = NIL; + List *new_otherrels = NIL; + JInfo *other_joininfo = (JInfo *) NULL; + List *xjoininfo = NIL; + + foreach(xjoininfo, joininfo_list) { - other_joininfo = joininfo_member(new_otherrels, - current_joininfo_list); - if(other_joininfo) { - other_joininfo->jinfoclauseinfo = - (List*)LispUnion(joininfo->jinfoclauseinfo, - other_joininfo->jinfoclauseinfo); - }else { - other_joininfo = makeNode(JInfo); - - other_joininfo->otherrels = - joininfo->otherrels; - other_joininfo->jinfoclauseinfo = - joininfo->jinfoclauseinfo; - other_joininfo->mergesortable = - joininfo->mergesortable; - other_joininfo->hashjoinable = - joininfo->hashjoinable; - other_joininfo->inactive = false; - - current_joininfo_list = lcons(other_joininfo, - current_joininfo_list); - } + List *or; + JInfo *joininfo = (JInfo *) lfirst(xjoininfo); + + new_otherrels = joininfo->otherrels; + foreach(or, new_otherrels) + { + if (intMember(lfirsti(or), join_relids)) + new_otherrels = lremove((void *) lfirst(or), new_otherrels); + } + joininfo->otherrels = new_otherrels; + if (new_otherrels != NIL) + { + other_joininfo = joininfo_member(new_otherrels, + current_joininfo_list); + if (other_joininfo) + { + other_joininfo->jinfoclauseinfo = + (List *) LispUnion(joininfo->jinfoclauseinfo, + other_joininfo->jinfoclauseinfo); + } + else + { + other_joininfo = makeNode(JInfo); + + other_joininfo->otherrels = + joininfo->otherrels; + other_joininfo->jinfoclauseinfo = + joininfo->jinfoclauseinfo; + other_joininfo->mergesortable = + joininfo->mergesortable; + other_joininfo->hashjoinable = + joininfo->hashjoinable; + other_joininfo->inactive = false; + + current_joininfo_list = lcons(other_joininfo, + current_joininfo_list); + } + } } - } - return(current_joininfo_list); + return (current_joininfo_list); } /* * add-new-joininfos-- - * For each new join relation, create new joininfos that - * use the join relation as inner relation, and add - * the new joininfos to those rel nodes that still - * have joins with the join relation. + * For each new join relation, create new joininfos that + * use the join relation as inner relation, and add + * the new joininfos to those rel nodes that still + * have joins with the join relation. * * 'joinrels' is a list of join relations. * * Modifies the joininfo field of appropriate rel nodes. */ void -add_new_joininfos(Query *root, List *joinrels, List *outerrels) +add_new_joininfos(Query * root, List * joinrels, List * outerrels) { - List *xjoinrel = NIL; - List *xrelid = NIL; - List *xrel = NIL; - List *xjoininfo = NIL; - - foreach(xjoinrel, joinrels) { - Rel *joinrel = (Rel *)lfirst(xjoinrel); - foreach(xrelid, joinrel->relids) { - Relid relid = (Relid)lfirst(xrelid); - Rel *rel = get_join_rel(root, relid); - add_superrels(rel,joinrel); + List *xjoinrel = NIL; + List *xrelid = NIL; + List *xrel = NIL; + List *xjoininfo = NIL; + + foreach(xjoinrel, joinrels) + { + Rel *joinrel = (Rel *) lfirst(xjoinrel); + + foreach(xrelid, joinrel->relids) + { + Relid relid = (Relid) lfirst(xrelid); + Rel *rel = get_join_rel(root, relid); + + add_superrels(rel, joinrel); + } } - } - foreach(xjoinrel, joinrels) { - Rel *joinrel = (Rel *)lfirst(xjoinrel); - - foreach(xjoininfo, joinrel->joininfo) { - JInfo *joininfo = (JInfo*)lfirst(xjoininfo); - List *other_rels = joininfo->otherrels; - List *clause_info = joininfo->jinfoclauseinfo; - bool mergesortable = joininfo->mergesortable; - bool hashjoinable = joininfo->hashjoinable; - - foreach(xrelid, other_rels) { - Relid relid = (Relid)lfirst(xrelid); - Rel *rel = get_join_rel(root, relid); - List *super_rels = rel->superrels; - List *xsuper_rel = NIL; - JInfo *new_joininfo = makeNode(JInfo); - - new_joininfo->otherrels = joinrel->relids; - new_joininfo->jinfoclauseinfo = clause_info; - new_joininfo->mergesortable = mergesortable; - new_joininfo->hashjoinable = hashjoinable; - new_joininfo->inactive = false; - rel->joininfo = - lappend(rel->joininfo, new_joininfo); - - foreach(xsuper_rel, super_rels) { - Rel *super_rel = (Rel *)lfirst(xsuper_rel); - - if( nonoverlap_rels(super_rel,joinrel) ) { - List *new_relids = super_rel->relids; - JInfo *other_joininfo = - joininfo_member(new_relids, - joinrel->joininfo); - - if (other_joininfo) { - other_joininfo->jinfoclauseinfo = - (List*)LispUnion(clause_info, - other_joininfo->jinfoclauseinfo); - } else { - JInfo *new_joininfo = makeNode(JInfo); - - new_joininfo->otherrels = new_relids; - new_joininfo->jinfoclauseinfo = clause_info; - new_joininfo->mergesortable = mergesortable; - new_joininfo->hashjoinable = hashjoinable; - new_joininfo->inactive = false; - joinrel->joininfo = - lappend(joinrel->joininfo, - new_joininfo); + foreach(xjoinrel, joinrels) + { + Rel *joinrel = (Rel *) lfirst(xjoinrel); + + foreach(xjoininfo, joinrel->joininfo) + { + JInfo *joininfo = (JInfo *) lfirst(xjoininfo); + List *other_rels = joininfo->otherrels; + List *clause_info = joininfo->jinfoclauseinfo; + bool mergesortable = joininfo->mergesortable; + bool hashjoinable = joininfo->hashjoinable; + + foreach(xrelid, other_rels) + { + Relid relid = (Relid) lfirst(xrelid); + Rel *rel = get_join_rel(root, relid); + List *super_rels = rel->superrels; + List *xsuper_rel = NIL; + JInfo *new_joininfo = makeNode(JInfo); + + new_joininfo->otherrels = joinrel->relids; + new_joininfo->jinfoclauseinfo = clause_info; + new_joininfo->mergesortable = mergesortable; + new_joininfo->hashjoinable = hashjoinable; + new_joininfo->inactive = false; + rel->joininfo = + lappend(rel->joininfo, new_joininfo); + + foreach(xsuper_rel, super_rels) + { + Rel *super_rel = (Rel *) lfirst(xsuper_rel); + + if (nonoverlap_rels(super_rel, joinrel)) + { + List *new_relids = super_rel->relids; + JInfo *other_joininfo = + joininfo_member(new_relids, + joinrel->joininfo); + + if (other_joininfo) + { + other_joininfo->jinfoclauseinfo = + (List *) LispUnion(clause_info, + other_joininfo->jinfoclauseinfo); + } + else + { + JInfo *new_joininfo = makeNode(JInfo); + + new_joininfo->otherrels = new_relids; + new_joininfo->jinfoclauseinfo = clause_info; + new_joininfo->mergesortable = mergesortable; + new_joininfo->hashjoinable = hashjoinable; + new_joininfo->inactive = false; + joinrel->joininfo = + lappend(joinrel->joininfo, + new_joininfo); + } + } + } } - } } - } } - } - foreach(xrel, outerrels) { - Rel *rel = (Rel *)lfirst(xrel); - rel->superrels = NIL; - } + foreach(xrel, outerrels) + { + Rel *rel = (Rel *) lfirst(xrel); + + rel->superrels = NIL; + } } /* * final-join-rels-- - * Find the join relation that includes all the original - * relations, i.e. the final join result. + * Find the join relation that includes all the original + * relations, i.e. the final join result. * * 'join-rel-list' is a list of join relations. * * Returns the list of final join relations. */ -List * -final_join_rels(List *join_rel_list) +List * +final_join_rels(List * join_rel_list) { - List *xrel = NIL; - List *temp = NIL; - List *t_list = NIL; - - /* - * find the relations that has no further joins, - * i.e., its joininfos all have otherrels nil. - */ - foreach(xrel,join_rel_list) { - Rel *rel = (Rel *)lfirst(xrel); - List *xjoininfo = NIL; - bool final = true; - - foreach (xjoininfo, rel->joininfo) { - JInfo *joininfo = (JInfo*)lfirst(xjoininfo); - - if (joininfo->otherrels != NIL) { - final = false; - break; - } - } - if (final) { - temp = lcons(rel, NIL); - t_list = nconc(t_list, temp); + List *xrel = NIL; + List *temp = NIL; + List *t_list = NIL; + + /* + * find the relations that has no further joins, i.e., its joininfos + * all have otherrels nil. + */ + foreach(xrel, join_rel_list) + { + Rel *rel = (Rel *) lfirst(xrel); + List *xjoininfo = NIL; + bool final = true; + + foreach(xjoininfo, rel->joininfo) + { + JInfo *joininfo = (JInfo *) lfirst(xjoininfo); + + if (joininfo->otherrels != NIL) + { + final = false; + break; + } + } + if (final) + { + temp = lcons(rel, NIL); + t_list = nconc(t_list, temp); + } } - } - return(t_list); + return (t_list); } /* * add_superrels-- - * add rel to the temporary property list superrels. + * add rel to the temporary property list superrels. * * 'rel' a rel node * 'super-rel' rel node of a join relation that includes rel @@ -492,60 +533,69 @@ final_join_rels(List *join_rel_list) * Modifies the superrels field of rel */ static void -add_superrels(Rel *rel, Rel *super_rel) +add_superrels(Rel * rel, Rel * super_rel) { - rel->superrels = lappend(rel->superrels, super_rel); + rel->superrels = lappend(rel->superrels, super_rel); } /* * nonoverlap-rels-- - * test if two join relations overlap, i.e., includes the same - * relation. + * test if two join relations overlap, i.e., includes the same + * relation. * * 'rel1' and 'rel2' are two join relations * * Returns non-nil if rel1 and rel2 do not overlap. */ -static bool -nonoverlap_rels(Rel *rel1, Rel *rel2) +static bool +nonoverlap_rels(Rel * rel1, Rel * rel2) { - return(nonoverlap_sets(rel1->relids, rel2->relids)); + return (nonoverlap_sets(rel1->relids, rel2->relids)); } -static bool -nonoverlap_sets(List *s1, List *s2) +static bool +nonoverlap_sets(List * s1, List * s2) { - List *x = NIL; - - foreach(x,s1) { - int e = lfirsti(x); - if(intMember(e,s2)) - return(false); - } - return(true); + List *x = NIL; + + foreach(x, s1) + { + int e = lfirsti(x); + + if (intMember(e, s2)) + return (false); + } + return (true); } static void -set_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel, JInfo *jinfo) +set_joinrel_size(Rel * joinrel, Rel * outer_rel, Rel * inner_rel, JInfo * jinfo) { - int ntuples; - float selec; - - /* voodoo magic. but better than a size of 0. I have no idea why - we didn't set the size before. -ay 2/95 */ - if (jinfo==NULL) { - /* worst case: the cartesian product */ - ntuples = outer_rel->tuples * inner_rel->tuples; - } else { - selec = product_selec(jinfo->jinfoclauseinfo); -/* ntuples = Min(outer_rel->tuples,inner_rel->tuples) * selec; */ - ntuples = outer_rel->tuples * inner_rel->tuples * selec; - } - - /* I bet sizes less than 1 will screw up optimization so - make the best case 1 instead of 0 - jolly*/ - if (ntuples < 1) - ntuples = 1; - - joinrel->tuples = ntuples; + int ntuples; + float selec; + + /* + * voodoo magic. but better than a size of 0. I have no idea why we + * didn't set the size before. -ay 2/95 + */ + if (jinfo == NULL) + { + /* worst case: the cartesian product */ + ntuples = outer_rel->tuples * inner_rel->tuples; + } + else + { + selec = product_selec(jinfo->jinfoclauseinfo); +/* ntuples = Min(outer_rel->tuples,inner_rel->tuples) * selec; */ + ntuples = outer_rel->tuples * inner_rel->tuples * selec; + } + + /* + * I bet sizes less than 1 will screw up optimization so make the best + * case 1 instead of 0 - jolly + */ + if (ntuples < 1) + ntuples = 1; + + joinrel->tuples = ntuples; } diff --git a/src/backend/optimizer/path/joinutils.c b/src/backend/optimizer/path/joinutils.c index 1be5a57f2ec..c88d3cf19e8 100644 --- a/src/backend/optimizer/path/joinutils.c +++ b/src/backend/optimizer/path/joinutils.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * joinutils.c-- - * Utilities for matching and building join and path keys + * Utilities for matching and building join and path keys * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/joinutils.c,v 1.1.1.1 1996/07/09 06:21:36 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/joinutils.c,v 1.2 1997/09/07 04:43:42 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -26,407 +26,440 @@ #include "optimizer/ordering.h" -static int match_pathkey_joinkeys(List *pathkey, List *joinkeys, - int which_subkey); -static bool every_func(List *joinkeys, List *pathkey, - int which_subkey); -static List *new_join_pathkey(List *subkeys, - List *considered_subkeys, List *join_rel_tlist, - List *joinclauses); -static List *new_matching_subkeys(Var *subkey, List *considered_subkeys, - List *join_rel_tlist, List *joinclauses); +static int +match_pathkey_joinkeys(List * pathkey, List * joinkeys, + int which_subkey); +static bool +every_func(List * joinkeys, List * pathkey, + int which_subkey); +static List * +new_join_pathkey(List * subkeys, + List * considered_subkeys, List * join_rel_tlist, + List * joinclauses); +static List * +new_matching_subkeys(Var * subkey, List * considered_subkeys, + List * join_rel_tlist, List * joinclauses); /**************************************************************************** - * KEY COMPARISONS + * KEY COMPARISONS ****************************************************************************/ -/* +/* * match-pathkeys-joinkeys-- - * Attempts to match the keys of a path against the keys of join clauses. - * This is done by looking for a matching join key in 'joinkeys' for - * every path key in the list 'pathkeys'. If there is a matching join key - * (not necessarily unique) for every path key, then the list of - * corresponding join keys and join clauses are returned in the order in - * which the keys matched the path keys. - * + * Attempts to match the keys of a path against the keys of join clauses. + * This is done by looking for a matching join key in 'joinkeys' for + * every path key in the list 'pathkeys'. If there is a matching join key + * (not necessarily unique) for every path key, then the list of + * corresponding join keys and join clauses are returned in the order in + * which the keys matched the path keys. + * * 'pathkeys' is a list of path keys: - * ( ( (var) (var) ... ) ( (var) ... ) ) + * ( ( (var) (var) ... ) ( (var) ... ) ) * 'joinkeys' is a list of join keys: - * ( (outer inner) (outer inner) ... ) + * ( (outer inner) (outer inner) ... ) * 'joinclauses' is a list of clauses corresponding to the join keys in - * 'joinkeys' + * 'joinkeys' * 'which-subkey' is a flag that selects the desired subkey of a join key - * in 'joinkeys' - * + * in 'joinkeys' + * * Returns the join keys and corresponding join clauses in a list if all * of the path keys were matched: - * ( - * ( (outerkey0 innerkey0) ... (outerkeyN innerkeyN) ) - * ( clause0 ... clauseN ) - * ) + * ( + * ( (outerkey0 innerkey0) ... (outerkeyN innerkeyN) ) + * ( clause0 ... clauseN ) + * ) * and nil otherwise. - * + * * Returns a list of matched join keys and a list of matched join clauses * in matchedJoinClausesPtr. - ay 11/94 */ -List * -match_pathkeys_joinkeys(List *pathkeys, - List *joinkeys, - List *joinclauses, - int which_subkey, - List **matchedJoinClausesPtr) +List * +match_pathkeys_joinkeys(List * pathkeys, + List * joinkeys, + List * joinclauses, + int which_subkey, + List ** matchedJoinClausesPtr) { - List *matched_joinkeys = NIL; - List *matched_joinclauses = NIL; - List *pathkey = NIL; - List *i = NIL; - int matched_joinkey_index = -1; - - foreach(i, pathkeys) { - pathkey = lfirst(i); - matched_joinkey_index = - match_pathkey_joinkeys(pathkey, joinkeys, which_subkey); - - if (matched_joinkey_index != -1 ) { - List *xjoinkey = nth(matched_joinkey_index,joinkeys); - List *joinclause = nth(matched_joinkey_index,joinclauses); - - /* XXX was "push" function */ - matched_joinkeys = lappend(matched_joinkeys,xjoinkey); - matched_joinkeys = nreverse(matched_joinkeys); - - matched_joinclauses = lappend(matched_joinclauses,joinclause); - matched_joinclauses = nreverse(matched_joinclauses); - joinkeys = LispRemove(xjoinkey,joinkeys); - } else { - return(NIL); - } - - } - if(matched_joinkeys==NULL || - length(matched_joinkeys) != length(pathkeys)) { - return NIL; - } - - *matchedJoinClausesPtr = nreverse(matched_joinclauses); - return (nreverse(matched_joinkeys)); + List *matched_joinkeys = NIL; + List *matched_joinclauses = NIL; + List *pathkey = NIL; + List *i = NIL; + int matched_joinkey_index = -1; + + foreach(i, pathkeys) + { + pathkey = lfirst(i); + matched_joinkey_index = + match_pathkey_joinkeys(pathkey, joinkeys, which_subkey); + + if (matched_joinkey_index != -1) + { + List *xjoinkey = nth(matched_joinkey_index, joinkeys); + List *joinclause = nth(matched_joinkey_index, joinclauses); + + /* XXX was "push" function */ + matched_joinkeys = lappend(matched_joinkeys, xjoinkey); + matched_joinkeys = nreverse(matched_joinkeys); + + matched_joinclauses = lappend(matched_joinclauses, joinclause); + matched_joinclauses = nreverse(matched_joinclauses); + joinkeys = LispRemove(xjoinkey, joinkeys); + } + else + { + return (NIL); + } + + } + if (matched_joinkeys == NULL || + length(matched_joinkeys) != length(pathkeys)) + { + return NIL; + } + + *matchedJoinClausesPtr = nreverse(matched_joinclauses); + return (nreverse(matched_joinkeys)); } -/* +/* * match-pathkey-joinkeys-- - * Returns the 0-based index into 'joinkeys' of the first joinkey whose - * outer or inner subkey matches any subkey of 'pathkey'. + * Returns the 0-based index into 'joinkeys' of the first joinkey whose + * outer or inner subkey matches any subkey of 'pathkey'. */ static int -match_pathkey_joinkeys(List *pathkey, - List *joinkeys, - int which_subkey) +match_pathkey_joinkeys(List * pathkey, + List * joinkeys, + int which_subkey) { - Var *path_subkey; - int pos; - List *i = NIL; - List *x = NIL; - JoinKey *jk; - - foreach(i, pathkey) { - path_subkey = (Var *)lfirst(i); - pos = 0; - foreach(x, joinkeys) { - jk = (JoinKey*)lfirst(x); - if(var_equal(path_subkey, - extract_subkey(jk, which_subkey))) - return(pos); - pos++; + Var *path_subkey; + int pos; + List *i = NIL; + List *x = NIL; + JoinKey *jk; + + foreach(i, pathkey) + { + path_subkey = (Var *) lfirst(i); + pos = 0; + foreach(x, joinkeys) + { + jk = (JoinKey *) lfirst(x); + if (var_equal(path_subkey, + extract_subkey(jk, which_subkey))) + return (pos); + pos++; + } } - } - return(-1); /* no index found */ + return (-1); /* no index found */ } -/* +/* * match-paths-joinkeys-- - * Attempts to find a path in 'paths' whose keys match a set of join - * keys 'joinkeys'. To match, - * 1. the path node ordering must equal 'ordering'. - * 2. each subkey of a given path must match(i.e., be(var_equal) to) the - * appropriate subkey of the corresponding join key in 'joinkeys', - * i.e., the Nth path key must match its subkeys against the subkey of - * the Nth join key in 'joinkeys'. - * - * 'joinkeys' is the list of key pairs to which the path keys must be - * matched + * Attempts to find a path in 'paths' whose keys match a set of join + * keys 'joinkeys'. To match, + * 1. the path node ordering must equal 'ordering'. + * 2. each subkey of a given path must match(i.e., be(var_equal) to) the + * appropriate subkey of the corresponding join key in 'joinkeys', + * i.e., the Nth path key must match its subkeys against the subkey of + * the Nth join key in 'joinkeys'. + * + * 'joinkeys' is the list of key pairs to which the path keys must be + * matched * 'ordering' is the ordering of the(outer) path to which 'joinkeys' - * must correspond + * must correspond * 'paths' is a list of(inner) paths which are to be matched against - * each join key in 'joinkeys' + * each join key in 'joinkeys' * 'which-subkey' is a flag that selects the desired subkey of a join key - * in 'joinkeys' - * + * in 'joinkeys' + * * Returns the matching path node if one exists, nil otherwise. */ -static bool -every_func(List *joinkeys, List *pathkey, int which_subkey) +static bool +every_func(List * joinkeys, List * pathkey, int which_subkey) { - JoinKey *xjoinkey; - Var *temp; - Var *tempkey = NULL; - bool found = false; - List *i = NIL; - List *j = NIL; - - foreach(i,joinkeys) { - xjoinkey = (JoinKey*)lfirst(i); - found = false; - foreach(j,pathkey) { - temp = (Var*)lfirst((List*)lfirst(j)); - if(temp == NULL) continue; - tempkey = extract_subkey(xjoinkey,which_subkey); - if(var_equal(tempkey, temp)) { - found = true; - break; - } + JoinKey *xjoinkey; + Var *temp; + Var *tempkey = NULL; + bool found = false; + List *i = NIL; + List *j = NIL; + + foreach(i, joinkeys) + { + xjoinkey = (JoinKey *) lfirst(i); + found = false; + foreach(j, pathkey) + { + temp = (Var *) lfirst((List *) lfirst(j)); + if (temp == NULL) + continue; + tempkey = extract_subkey(xjoinkey, which_subkey); + if (var_equal(tempkey, temp)) + { + found = true; + break; + } + } + if (found == false) + return (false); } - if(found == false) - return(false); - } - return(found); + return (found); } /* * match_paths_joinkeys - - * find the cheapest path that matches the join keys + * find the cheapest path that matches the join keys */ -Path * -match_paths_joinkeys(List *joinkeys, - PathOrder *ordering, - List *paths, - int which_subkey) +Path * +match_paths_joinkeys(List * joinkeys, + PathOrder * ordering, + List * paths, + int which_subkey) { - Path *matched_path = NULL ; - bool key_match = false; - List *i = NIL; - - foreach(i,paths) { - Path *path = (Path*)lfirst(i); - - key_match = every_func(joinkeys, path->keys, which_subkey); - - if (equal_path_path_ordering(ordering, - &path->p_ordering) && - length(joinkeys) == length(path->keys) && - key_match) { - - if (matched_path) { - if (path->path_cost < matched_path->path_cost) - matched_path = path; - } else { - matched_path = path; - } + Path *matched_path = NULL; + bool key_match = false; + List *i = NIL; + + foreach(i, paths) + { + Path *path = (Path *) lfirst(i); + + key_match = every_func(joinkeys, path->keys, which_subkey); + + if (equal_path_path_ordering(ordering, + &path->p_ordering) && + length(joinkeys) == length(path->keys) && + key_match) + { + + if (matched_path) + { + if (path->path_cost < matched_path->path_cost) + matched_path = path; + } + else + { + matched_path = path; + } + } } - } - return matched_path; + return matched_path; } -/* +/* * extract-path-keys-- - * Builds a subkey list for a path by pulling one of the subkeys from - * a list of join keys 'joinkeys' and then finding the var node in the - * target list 'tlist' that corresponds to that subkey. - * + * Builds a subkey list for a path by pulling one of the subkeys from + * a list of join keys 'joinkeys' and then finding the var node in the + * target list 'tlist' that corresponds to that subkey. + * * 'joinkeys' is a list of join key pairs * 'tlist' is a relation target list * 'which-subkey' is a flag that selects the desired subkey of a join key - * in 'joinkeys' - * + * in 'joinkeys' + * * Returns a list of pathkeys: ((tlvar1)(tlvar2)...(tlvarN)). * [I've no idea why they have to be list of lists. Should be fixed. -ay 12/94] */ -List * -extract_path_keys(List *joinkeys, - List *tlist, - int which_subkey) +List * +extract_path_keys(List * joinkeys, + List * tlist, + int which_subkey) { - List *pathkeys = NIL; - List *jk; - - foreach(jk, joinkeys) { - JoinKey *jkey = (JoinKey*)lfirst(jk); - Var *var, *key; - List *p; - - /* - * find the right Var in the target list for this key - */ - var = (Var*)extract_subkey(jkey, which_subkey); - key = (Var*)matching_tlvar(var, tlist); - - /* - * include it in the pathkeys list if we haven't already done so - */ - foreach(p, pathkeys) { - Var *pkey = lfirst((List*)lfirst(p)); /* XXX fix me */ - if (key == pkey) - break; - } - if (p!=NIL) - continue; /* key already in pathkeys */ + List *pathkeys = NIL; + List *jk; + + foreach(jk, joinkeys) + { + JoinKey *jkey = (JoinKey *) lfirst(jk); + Var *var, + *key; + List *p; - pathkeys = - lappend(pathkeys, lcons(key,NIL)); - } - return(pathkeys); + /* + * find the right Var in the target list for this key + */ + var = (Var *) extract_subkey(jkey, which_subkey); + key = (Var *) matching_tlvar(var, tlist); + + /* + * include it in the pathkeys list if we haven't already done so + */ + foreach(p, pathkeys) + { + Var *pkey = lfirst((List *) lfirst(p)); /* XXX fix me */ + + if (key == pkey) + break; + } + if (p != NIL) + continue; /* key already in pathkeys */ + + pathkeys = + lappend(pathkeys, lcons(key, NIL)); + } + return (pathkeys); } /**************************************************************************** - * NEW PATHKEY FORMATION + * NEW PATHKEY FORMATION ****************************************************************************/ -/* +/* * new-join-pathkeys-- - * Find the path keys for a join relation by finding all vars in the list - * of join clauses 'joinclauses' such that: - * (1) the var corresponding to the outer join relation is a - * key on the outer path - * (2) the var appears in the target list of the join relation - * In other words, add to each outer path key the inner path keys that - * are required for qualification. - * + * Find the path keys for a join relation by finding all vars in the list + * of join clauses 'joinclauses' such that: + * (1) the var corresponding to the outer join relation is a + * key on the outer path + * (2) the var appears in the target list of the join relation + * In other words, add to each outer path key the inner path keys that + * are required for qualification. + * * 'outer-pathkeys' is the list of the outer path's path keys * 'join-rel-tlist' is the target list of the join relation * 'joinclauses' is the list of restricting join clauses - * - * Returns the list of new path keys. - * + * + * Returns the list of new path keys. + * */ -List * -new_join_pathkeys(List *outer_pathkeys, - List *join_rel_tlist, - List *joinclauses) -{ - List *outer_pathkey = NIL; - List *t_list = NIL; - List *x; - List *i = NIL; - - foreach(i, outer_pathkeys) { - outer_pathkey = lfirst(i); - x = new_join_pathkey(outer_pathkey, NIL, - join_rel_tlist,joinclauses); - if (x!=NIL) { - t_list = lappend(t_list, x); +List * +new_join_pathkeys(List * outer_pathkeys, + List * join_rel_tlist, + List * joinclauses) +{ + List *outer_pathkey = NIL; + List *t_list = NIL; + List *x; + List *i = NIL; + + foreach(i, outer_pathkeys) + { + outer_pathkey = lfirst(i); + x = new_join_pathkey(outer_pathkey, NIL, + join_rel_tlist, joinclauses); + if (x != NIL) + { + t_list = lappend(t_list, x); + } } - } - return(t_list); + return (t_list); } -/* +/* * new-join-pathkey-- - * Finds new vars that become subkeys due to qualification clauses that - * contain any previously considered subkeys. These new subkeys plus the - * subkeys from 'subkeys' form a new pathkey for the join relation. - * - * Note that each returned subkey is the var node found in - * 'join-rel-tlist' rather than the joinclause var node. - * + * Finds new vars that become subkeys due to qualification clauses that + * contain any previously considered subkeys. These new subkeys plus the + * subkeys from 'subkeys' form a new pathkey for the join relation. + * + * Note that each returned subkey is the var node found in + * 'join-rel-tlist' rather than the joinclause var node. + * * 'subkeys' is a list of subkeys for which matching subkeys are to be - * found + * found * 'considered-subkeys' is the current list of all subkeys corresponding - * to a given pathkey - * + * to a given pathkey + * * Returns a new pathkey(list of subkeys). - * + * */ -static List * -new_join_pathkey(List *subkeys, - List *considered_subkeys, - List *join_rel_tlist, - List *joinclauses) +static List * +new_join_pathkey(List * subkeys, + List * considered_subkeys, + List * join_rel_tlist, + List * joinclauses) { - List *t_list = NIL; - Var *subkey; - List *i = NIL; - List *matched_subkeys = NIL; - Expr *tlist_key = (Expr*)NULL; - List *newly_considered_subkeys = NIL; - - foreach (i, subkeys) { - subkey = (Var *)lfirst(i); - if(subkey == NULL) - break; /* XXX something is wrong */ - matched_subkeys = - new_matching_subkeys(subkey,considered_subkeys, - join_rel_tlist,joinclauses); - tlist_key = matching_tlvar(subkey,join_rel_tlist); - newly_considered_subkeys = NIL; - - if (tlist_key) { - if(!member(tlist_key, matched_subkeys)) - newly_considered_subkeys = lcons(tlist_key, - matched_subkeys); - } - else { - newly_considered_subkeys = matched_subkeys; - } - - considered_subkeys = - append(considered_subkeys, newly_considered_subkeys); - - t_list = nconc(t_list,newly_considered_subkeys); - } - return(t_list); + List *t_list = NIL; + Var *subkey; + List *i = NIL; + List *matched_subkeys = NIL; + Expr *tlist_key = (Expr *) NULL; + List *newly_considered_subkeys = NIL; + + foreach(i, subkeys) + { + subkey = (Var *) lfirst(i); + if (subkey == NULL) + break; /* XXX something is wrong */ + matched_subkeys = + new_matching_subkeys(subkey, considered_subkeys, + join_rel_tlist, joinclauses); + tlist_key = matching_tlvar(subkey, join_rel_tlist); + newly_considered_subkeys = NIL; + + if (tlist_key) + { + if (!member(tlist_key, matched_subkeys)) + newly_considered_subkeys = lcons(tlist_key, + matched_subkeys); + } + else + { + newly_considered_subkeys = matched_subkeys; + } + + considered_subkeys = + append(considered_subkeys, newly_considered_subkeys); + + t_list = nconc(t_list, newly_considered_subkeys); + } + return (t_list); } -/* +/* * new-matching-subkeys-- - * Returns a list of new subkeys: - * (1) which are not listed in 'considered-subkeys' - * (2) for which the "other" variable in some clause in 'joinclauses' is - * 'subkey' - * (3) which are mentioned in 'join-rel-tlist' - * - * Note that each returned subkey is the var node found in - * 'join-rel-tlist' rather than the joinclause var node. - * + * Returns a list of new subkeys: + * (1) which are not listed in 'considered-subkeys' + * (2) for which the "other" variable in some clause in 'joinclauses' is + * 'subkey' + * (3) which are mentioned in 'join-rel-tlist' + * + * Note that each returned subkey is the var node found in + * 'join-rel-tlist' rather than the joinclause var node. + * * 'subkey' is the var node for which we are trying to find matching - * clauses - * + * clauses + * * Returns a list of new subkeys. * */ -static List * -new_matching_subkeys(Var *subkey, - List *considered_subkeys, - List *join_rel_tlist, - List *joinclauses) +static List * +new_matching_subkeys(Var * subkey, + List * considered_subkeys, + List * join_rel_tlist, + List * joinclauses) { - Expr *joinclause = NULL; - List *t_list = NIL; - List *temp = NIL; - List *i = NIL; - Expr *tlist_other_var = (Expr *)NULL; - - foreach(i,joinclauses) { - joinclause = lfirst(i); - tlist_other_var = - matching_tlvar(other_join_clause_var(subkey,joinclause), - join_rel_tlist); - - if(tlist_other_var && - !(member(tlist_other_var,considered_subkeys))) { - - /* XXX was "push" function */ - considered_subkeys = lappend(considered_subkeys, - tlist_other_var); - - /* considered_subkeys = nreverse(considered_subkeys); - XXX -- I am not sure of this. */ - - temp = lcons(tlist_other_var, NIL); - t_list = nconc(t_list,temp); - } - } - return(t_list); + Expr *joinclause = NULL; + List *t_list = NIL; + List *temp = NIL; + List *i = NIL; + Expr *tlist_other_var = (Expr *) NULL; + + foreach(i, joinclauses) + { + joinclause = lfirst(i); + tlist_other_var = + matching_tlvar(other_join_clause_var(subkey, joinclause), + join_rel_tlist); + + if (tlist_other_var && + !(member(tlist_other_var, considered_subkeys))) + { + + /* XXX was "push" function */ + considered_subkeys = lappend(considered_subkeys, + tlist_other_var); + + /* + * considered_subkeys = nreverse(considered_subkeys); XXX -- I + * am not sure of this. + */ + + temp = lcons(tlist_other_var, NIL); + t_list = nconc(t_list, temp); + } + } + return (t_list); } diff --git a/src/backend/optimizer/path/mergeutils.c b/src/backend/optimizer/path/mergeutils.c index d5f0fdcb65b..93004a6741e 100644 --- a/src/backend/optimizer/path/mergeutils.c +++ b/src/backend/optimizer/path/mergeutils.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * mergeutils.c-- - * Utilities for finding applicable merge clauses and pathkeys + * Utilities for finding applicable merge clauses and pathkeys * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/mergeutils.c,v 1.1.1.1 1996/07/09 06:21:36 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/mergeutils.c,v 1.2 1997/09/07 04:43:45 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -21,102 +21,110 @@ #include "optimizer/clauses.h" #include "optimizer/ordering.h" -/* +/* * group-clauses-by-order-- - * If a join clause node in 'clauseinfo-list' is mergesortable, store - * it within a mergeinfo node containing other clause nodes with the same - * mergesort ordering. - * + * If a join clause node in 'clauseinfo-list' is mergesortable, store + * it within a mergeinfo node containing other clause nodes with the same + * mergesort ordering. + * * 'clauseinfo-list' is the list of clauseinfo nodes * 'inner-relid' is the relid of the inner join relation - * + * * Returns the new list of mergeinfo nodes. - * + * */ -List * -group_clauses_by_order(List *clauseinfo_list, - int inner_relid) +List * +group_clauses_by_order(List * clauseinfo_list, + int inner_relid) { - List *mergeinfo_list = NIL; - List *xclauseinfo = NIL; - - foreach (xclauseinfo, clauseinfo_list) { - CInfo *clauseinfo = (CInfo *)lfirst(xclauseinfo); - MergeOrder *merge_ordering = clauseinfo->mergesortorder; - - if (merge_ordering) { - /* - * Create a new mergeinfo node and add it to - * 'mergeinfo-list' if one does not yet exist for this - * merge ordering. - */ - PathOrder p_ordering; - MInfo *xmergeinfo; - Expr *clause = clauseinfo->clause; - Var *leftop = get_leftop (clause); - Var *rightop = get_rightop (clause); - JoinKey *keys; - - p_ordering.ordtype = MERGE_ORDER; - p_ordering.ord.merge = merge_ordering; - xmergeinfo = - match_order_mergeinfo(&p_ordering, mergeinfo_list); - if (inner_relid == leftop->varno) { - keys = makeNode(JoinKey); - keys->outer = rightop; - keys->inner = leftop; - } else { - keys = makeNode(JoinKey); - keys->outer = leftop; - keys->inner = rightop; - } - - if (xmergeinfo==NULL) { - xmergeinfo = makeNode(MInfo); - - xmergeinfo->m_ordering = merge_ordering; - mergeinfo_list = lcons(xmergeinfo, - mergeinfo_list); - } - - ((JoinMethod *)xmergeinfo)->clauses = - lcons(clause, - ((JoinMethod *)xmergeinfo)->clauses); - ((JoinMethod *)xmergeinfo)->jmkeys = - lcons(keys, - ((JoinMethod *)xmergeinfo)->jmkeys); + List *mergeinfo_list = NIL; + List *xclauseinfo = NIL; + + foreach(xclauseinfo, clauseinfo_list) + { + CInfo *clauseinfo = (CInfo *) lfirst(xclauseinfo); + MergeOrder *merge_ordering = clauseinfo->mergesortorder; + + if (merge_ordering) + { + + /* + * Create a new mergeinfo node and add it to 'mergeinfo-list' + * if one does not yet exist for this merge ordering. + */ + PathOrder p_ordering; + MInfo *xmergeinfo; + Expr *clause = clauseinfo->clause; + Var *leftop = get_leftop(clause); + Var *rightop = get_rightop(clause); + JoinKey *keys; + + p_ordering.ordtype = MERGE_ORDER; + p_ordering.ord.merge = merge_ordering; + xmergeinfo = + match_order_mergeinfo(&p_ordering, mergeinfo_list); + if (inner_relid == leftop->varno) + { + keys = makeNode(JoinKey); + keys->outer = rightop; + keys->inner = leftop; + } + else + { + keys = makeNode(JoinKey); + keys->outer = leftop; + keys->inner = rightop; + } + + if (xmergeinfo == NULL) + { + xmergeinfo = makeNode(MInfo); + + xmergeinfo->m_ordering = merge_ordering; + mergeinfo_list = lcons(xmergeinfo, + mergeinfo_list); + } + + ((JoinMethod *) xmergeinfo)->clauses = + lcons(clause, + ((JoinMethod *) xmergeinfo)->clauses); + ((JoinMethod *) xmergeinfo)->jmkeys = + lcons(keys, + ((JoinMethod *) xmergeinfo)->jmkeys); + } } - } - return(mergeinfo_list); + return (mergeinfo_list); } -/* +/* * match-order-mergeinfo-- - * Searches the list 'mergeinfo-list' for a mergeinfo node whose order - * field equals 'ordering'. - * + * Searches the list 'mergeinfo-list' for a mergeinfo node whose order + * field equals 'ordering'. + * * Returns the node if it exists. - * + * */ -MInfo * -match_order_mergeinfo(PathOrder *ordering, List *mergeinfo_list) +MInfo * +match_order_mergeinfo(PathOrder * ordering, List * mergeinfo_list) { - MergeOrder *xmergeorder; - List *xmergeinfo = NIL; + MergeOrder *xmergeorder; + List *xmergeinfo = NIL; - foreach(xmergeinfo, mergeinfo_list) { - MInfo *mergeinfo = (MInfo*)lfirst(xmergeinfo); + foreach(xmergeinfo, mergeinfo_list) + { + MInfo *mergeinfo = (MInfo *) lfirst(xmergeinfo); - xmergeorder = mergeinfo->m_ordering; + xmergeorder = mergeinfo->m_ordering; - if ((ordering->ordtype==MERGE_ORDER && - equal_merge_merge_ordering(ordering->ord.merge, xmergeorder)) || - (ordering->ordtype==SORTOP_ORDER && - equal_path_merge_ordering(ordering->ord.sortop, xmergeorder))) { + if ((ordering->ordtype == MERGE_ORDER && + equal_merge_merge_ordering(ordering->ord.merge, xmergeorder)) || + (ordering->ordtype == SORTOP_ORDER && + equal_path_merge_ordering(ordering->ord.sortop, xmergeorder))) + { - return (mergeinfo); + return (mergeinfo); + } } - } - return((MInfo*) NIL); + return ((MInfo *) NIL); } diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c index e040675e6ec..96408b78905 100644 --- a/src/backend/optimizer/path/orindxpath.c +++ b/src/backend/optimizer/path/orindxpath.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * orindxpath.c-- - * Routines to find index paths that match a set of 'or' clauses + * Routines to find index paths that match a set of 'or' clauses * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.1.1.1 1996/07/09 06:21:36 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.2 1997/09/07 04:43:46 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -31,241 +31,267 @@ #include "parser/parsetree.h" -static void best_or_subclause_indices(Query *root, Rel *rel, List *subclauses, - List *indices, List *examined_indexids, Cost subcost, List *selectivities, - List **indexids, Cost *cost, List **selecs); -static void best_or_subclause_index(Query *root, Rel *rel, Expr *subclause, - List *indices, int *indexid, Cost *cost, Cost *selec); +static void +best_or_subclause_indices(Query * root, Rel * rel, List * subclauses, + List * indices, List * examined_indexids, Cost subcost, List * selectivities, + List ** indexids, Cost * cost, List ** selecs); +static void +best_or_subclause_index(Query * root, Rel * rel, Expr * subclause, + List * indices, int *indexid, Cost * cost, Cost * selec); -/* +/* * create-or-index-paths-- - * Creates index paths for indices that match 'or' clauses. - * + * Creates index paths for indices that match 'or' clauses. + * * 'rel' is the relation entry for which the paths are to be defined on * 'clauses' is the list of available restriction clause nodes - * + * * Returns a list of these index path nodes. - * + * */ -List * -create_or_index_paths(Query *root, - Rel *rel, List *clauses) +List * +create_or_index_paths(Query * root, + Rel * rel, List * clauses) { - List *t_list = NIL; - - if (clauses != NIL) { - CInfo *clausenode = (CInfo *) (lfirst (clauses)); - - /* Check to see if this clause is an 'or' clause, and, if so, - * whether or not each of the subclauses within the 'or' clause has - * been matched by an index (the 'Index field was set in - * (match_or) if no index matches a given subclause, one of the - * lists of index nodes returned by (get_index) will be 'nil'). - */ - if (valid_or_clause(clausenode) && - clausenode->indexids) { - List *temp = NIL; - List *index_list = NIL; - bool index_flag = true; - - index_list = clausenode->indexids; - foreach(temp,index_list) { - if (!temp) - index_flag = false; - } - if (index_flag) { /* used to be a lisp every function */ - IndexPath *pathnode = makeNode(IndexPath); - List *indexids; - Cost cost; - List *selecs; + List *t_list = NIL; + + if (clauses != NIL) + { + CInfo *clausenode = (CInfo *) (lfirst(clauses)); + + /* + * Check to see if this clause is an 'or' clause, and, if so, + * whether or not each of the subclauses within the 'or' clause + * has been matched by an index (the 'Index field was set in + * (match_or) if no index matches a given subclause, one of the + * lists of index nodes returned by (get_index) will be 'nil'). + */ + if (valid_or_clause(clausenode) && + clausenode->indexids) + { + List *temp = NIL; + List *index_list = NIL; + bool index_flag = true; + + index_list = clausenode->indexids; + foreach(temp, index_list) + { + if (!temp) + index_flag = false; + } + if (index_flag) + { /* used to be a lisp every function */ + IndexPath *pathnode = makeNode(IndexPath); + List *indexids; + Cost cost; + List *selecs; - best_or_subclause_indices(root, - rel, - clausenode->clause->args, - clausenode->indexids, - NIL, - (Cost)0, - NIL, - &indexids, - &cost, - &selecs); - - pathnode->path.pathtype = T_IndexScan; - pathnode->path.parent = rel; - pathnode->indexqual = - lcons(clausenode,NIL); - pathnode->indexid = indexids; - pathnode->path.path_cost = cost; - - /* copy clauseinfo list into path for expensive - function processing -- JMH, 7/7/92 */ - pathnode->path.locclauseinfo = - set_difference(clauses, - copyObject((Node*) - rel->clauseinfo)); - -#if 0 /* fix xfunc */ - /* add in cost for expensive functions! -- JMH, 7/7/92 */ - if (XfuncMode != XFUNC_OFF) { - ((Path*)pathnode)->path_cost += - xfunc_get_path_cost((Path)pathnode); + best_or_subclause_indices(root, + rel, + clausenode->clause->args, + clausenode->indexids, + NIL, + (Cost) 0, + NIL, + &indexids, + &cost, + &selecs); + + pathnode->path.pathtype = T_IndexScan; + pathnode->path.parent = rel; + pathnode->indexqual = + lcons(clausenode, NIL); + pathnode->indexid = indexids; + pathnode->path.path_cost = cost; + + /* + * copy clauseinfo list into path for expensive function + * processing -- JMH, 7/7/92 + */ + pathnode->path.locclauseinfo = + set_difference(clauses, + copyObject((Node *) + rel->clauseinfo)); + +#if 0 /* fix xfunc */ + /* add in cost for expensive functions! -- JMH, 7/7/92 */ + if (XfuncMode != XFUNC_OFF) + { + ((Path *) pathnode)->path_cost += + xfunc_get_path_cost((Path) pathnode); + } +#endif + clausenode->selectivity = (Cost) floatVal(selecs); + t_list = + lcons(pathnode, + create_or_index_paths(root, rel, lnext(clauses))); + } + else + { + t_list = create_or_index_paths(root, rel, lnext(clauses)); + } } -#endif - clausenode->selectivity = (Cost)floatVal(selecs); - t_list = - lcons(pathnode, - create_or_index_paths(root, rel,lnext(clauses))); - } else { - t_list = create_or_index_paths(root, rel,lnext(clauses)); - } } - } - return(t_list); + return (t_list); } -/* +/* * best-or-subclause-indices-- - * Determines the best index to be used in conjunction with each subclause - * of an 'or' clause and the cost of scanning a relation using these - * indices. The cost is the sum of the individual index costs. - * + * Determines the best index to be used in conjunction with each subclause + * of an 'or' clause and the cost of scanning a relation using these + * indices. The cost is the sum of the individual index costs. + * * 'rel' is the node of the relation on which the index is defined * 'subclauses' are the subclauses of the 'or' clause * 'indices' are those index nodes that matched subclauses of the 'or' - * clause - * 'examined-indexids' is a list of those index ids to be used with - * subclauses that have already been examined + * clause + * 'examined-indexids' is a list of those index ids to be used with + * subclauses that have already been examined * 'subcost' is the cost of using the indices in 'examined-indexids' * 'selectivities' is a list of the selectivities of subclauses that - * have already been examined - * + * have already been examined + * * Returns a list of the indexids, cost, and selectivities of each * subclause, e.g., ((i1 i2 i3) cost (s1 s2 s3)), where 'i' is an OID, * 'cost' is a flonum, and 's' is a flonum. */ static void -best_or_subclause_indices(Query *root, - Rel *rel, - List *subclauses, - List *indices, - List *examined_indexids, - Cost subcost, - List *selectivities, - List **indexids, /* return value */ - Cost *cost, /* return value */ - List **selecs) /* return value */ +best_or_subclause_indices(Query * root, + Rel * rel, + List * subclauses, + List * indices, + List * examined_indexids, + Cost subcost, + List * selectivities, + List ** indexids, /* return value */ + Cost * cost, /* return value */ + List ** selecs) /* return value */ { - if (subclauses==NIL) { - *indexids = nreverse(examined_indexids); - *cost = subcost; - *selecs = nreverse(selectivities); - } else { - int best_indexid; - Cost best_cost; - Cost best_selec; - - best_or_subclause_index(root, rel, lfirst(subclauses), lfirst(indices), - &best_indexid, &best_cost, &best_selec); - - best_or_subclause_indices(root, - rel, - lnext(subclauses), - lnext(indices), - lconsi(best_indexid, examined_indexids), - subcost + best_cost, - lcons(makeFloat(best_selec), selectivities), - indexids, - cost, - selecs); - } - return; -} + if (subclauses == NIL) + { + *indexids = nreverse(examined_indexids); + *cost = subcost; + *selecs = nreverse(selectivities); + } + else + { + int best_indexid; + Cost best_cost; + Cost best_selec; + + best_or_subclause_index(root, rel, lfirst(subclauses), lfirst(indices), + &best_indexid, &best_cost, &best_selec); -/* + best_or_subclause_indices(root, + rel, + lnext(subclauses), + lnext(indices), + lconsi(best_indexid, examined_indexids), + subcost + best_cost, + lcons(makeFloat(best_selec), selectivities), + indexids, + cost, + selecs); + } + return; +} + +/* * best-or-subclause-index-- - * Determines which is the best index to be used with a subclause of - * an 'or' clause by estimating the cost of using each index and selecting - * the least expensive. - * + * Determines which is the best index to be used with a subclause of + * an 'or' clause by estimating the cost of using each index and selecting + * the least expensive. + * * 'rel' is the node of the relation on which the index is defined * 'subclause' is the subclause * 'indices' is a list of index nodes that match the subclause - * + * * Returns a list (index-id index-subcost index-selectivity) * (a fixnum, a fixnum, and a flonum respectively). - * + * */ static void -best_or_subclause_index(Query *root, - Rel *rel, - Expr *subclause, - List *indices, - int *retIndexid, /* return value */ - Cost *retCost, /* return value */ - Cost *retSelec) /* return value */ +best_or_subclause_index(Query * root, + Rel * rel, + Expr * subclause, + List * indices, + int *retIndexid, /* return value */ + Cost * retCost, /* return value */ + Cost * retSelec) /* return value */ { - if (indices != NIL) { - Datum value; - int flag = 0; - Cost subcost; - Rel *index = (Rel *)lfirst (indices); - AttrNumber attno = (get_leftop (subclause))->varattno ; - Oid opno = ((Oper*)subclause->oper)->opno; - bool constant_on_right = non_null((Expr*)get_rightop(subclause)); - float npages, selec; - int subclause_indexid; - Cost subclause_cost; - Cost subclause_selec; - - if(constant_on_right) { - value = ((Const*)get_rightop (subclause))->constvalue; - } else { - value = NameGetDatum(""); - } - if(constant_on_right) { - flag = (_SELEC_IS_CONSTANT_ ||_SELEC_CONSTANT_RIGHT_); - } else { - flag = _SELEC_CONSTANT_RIGHT_; - } - index_selectivity(lfirsti(index->relids), - index->classlist, - lconsi(opno,NIL), - getrelid(lfirsti(rel->relids), - root->rtable), - lconsi(attno,NIL), - lconsi(value,NIL), - lconsi(flag,NIL), - 1, - &npages, - &selec); - - subcost = cost_index((Oid) lfirsti(index->relids), - (int)npages, - (Cost)selec, - rel->pages, - rel->tuples, - index->pages, - index->tuples, - false); - best_or_subclause_index(root, - rel, - subclause, - lnext(indices), - &subclause_indexid, - &subclause_cost, - &subclause_selec); + if (indices != NIL) + { + Datum value; + int flag = 0; + Cost subcost; + Rel *index = (Rel *) lfirst(indices); + AttrNumber attno = (get_leftop(subclause))->varattno; + Oid opno = ((Oper *) subclause->oper)->opno; + bool constant_on_right = non_null((Expr *) get_rightop(subclause)); + float npages, + selec; + int subclause_indexid; + Cost subclause_cost; + Cost subclause_selec; - if (subclause_indexid==0 || subcost < subclause_cost) { - *retIndexid = lfirsti(index->relids); - *retCost = subcost; - *retSelec = selec; - } else { - *retIndexid = 0; - *retCost = 0.0; - *retSelec = 0.0; - } - } - return; + if (constant_on_right) + { + value = ((Const *) get_rightop(subclause))->constvalue; + } + else + { + value = NameGetDatum(""); + } + if (constant_on_right) + { + flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_); + } + else + { + flag = _SELEC_CONSTANT_RIGHT_; + } + index_selectivity(lfirsti(index->relids), + index->classlist, + lconsi(opno, NIL), + getrelid(lfirsti(rel->relids), + root->rtable), + lconsi(attno, NIL), + lconsi(value, NIL), + lconsi(flag, NIL), + 1, + &npages, + &selec); + + subcost = cost_index((Oid) lfirsti(index->relids), + (int) npages, + (Cost) selec, + rel->pages, + rel->tuples, + index->pages, + index->tuples, + false); + best_or_subclause_index(root, + rel, + subclause, + lnext(indices), + &subclause_indexid, + &subclause_cost, + &subclause_selec); + + if (subclause_indexid == 0 || subcost < subclause_cost) + { + *retIndexid = lfirsti(index->relids); + *retCost = subcost; + *retSelec = selec; + } + else + { + *retIndexid = 0; + *retCost = 0.0; + *retSelec = 0.0; + } + } + return; } diff --git a/src/backend/optimizer/path/predmig.c b/src/backend/optimizer/path/predmig.c index 241ab4a12d7..c302af3b581 100644 --- a/src/backend/optimizer/path/predmig.c +++ b/src/backend/optimizer/path/predmig.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * predmig.c-- - * + * * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/predmig.c,v 1.2 1996/10/23 07:14:41 bryanh Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/predmig.c,v 1.3 1997/09/07 04:43:47 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -16,23 +16,23 @@ ** Main Routines to handle Predicate Migration (i.e. correct optimization ** of queries with expensive functions.) ** -** The reasoning behind some of these algorithms is rather detailed. -** Have a look at Sequoia Tech Report 92/13 for more info. Also +** The reasoning behind some of these algorithms is rather detailed. +** Have a look at Sequoia Tech Report 92/13 for more info. Also ** see Monma and Sidney's paper "Sequencing with Series-Parallel ** Precedence Constraints", in "Mathematics of Operations Research", ** volume 4 (1979), pp. 215-224. ** -** The main thing that this code does that wasn't handled in xfunc.c is +** The main thing that this code does that wasn't handled in xfunc.c is ** it considers the possibility that two joins in a stream may not ** be ordered by ascending rank -- in such a scenario, it may be optimal ** to pullup more restrictions than we did via xfunc_try_pullup. ** -** This code in some sense generalizes xfunc_try_pullup; if you +** This code in some sense generalizes xfunc_try_pullup; if you ** run postgres -x noprune, you'll turn off xfunc_try_pullup, and this ** code will do everything that xfunc_try_pullup would have, and maybe -** more. However, this results in no pruning, which may slow down the +** more. However, this results in no pruning, which may slow down the ** optimizer and/or cause the system to run out of memory. -** -- JMH, 11/13/92 +** -- JMH, 11/13/92 */ #include "nodes/pg_list.h" @@ -49,331 +49,350 @@ #include "optimizer/tlist.h" #include "lib/qsort.h" -#define is_clause(node) (get_cinfo(node)) /* a stream node represents a - clause (not a join) iff it - has a non-NULL cinfo field */ - -static void xfunc_predmig(JoinPath pathnode, Stream streamroot, - Stream laststream, bool *progressp); -static bool xfunc_series_llel(Stream stream); -static bool xfunc_llel_chains(Stream root, Stream bottom); -static Stream xfunc_complete_stream(Stream stream); -static bool xfunc_prdmig_pullup(Stream origstream, Stream pullme, - JoinPath joinpath); -static void xfunc_form_groups(Stream root, Stream bottom); -static void xfunc_free_stream(Stream root); -static Stream xfunc_add_clauses(Stream current); -static void xfunc_setup_group(Stream node, Stream bottom); -static Stream xfunc_streaminsert(CInfo clauseinfo, Stream current, - int clausetype); -static int xfunc_num_relids(Stream node); +#define is_clause(node) (get_cinfo(node)) /* a stream node + * represents a clause + * (not a join) iff it has + * a non-NULL cinfo field */ + +static void +xfunc_predmig(JoinPath pathnode, Stream streamroot, + Stream laststream, bool * progressp); +static bool xfunc_series_llel(Stream stream); +static bool xfunc_llel_chains(Stream root, Stream bottom); +static Stream xfunc_complete_stream(Stream stream); +static bool +xfunc_prdmig_pullup(Stream origstream, Stream pullme, + JoinPath joinpath); +static void xfunc_form_groups(Stream root, Stream bottom); +static void xfunc_free_stream(Stream root); +static Stream xfunc_add_clauses(Stream current); +static void xfunc_setup_group(Stream node, Stream bottom); +static Stream +xfunc_streaminsert(CInfo clauseinfo, Stream current, + int clausetype); +static int xfunc_num_relids(Stream node); static StreamPtr xfunc_get_downjoin(Stream node); static StreamPtr xfunc_get_upjoin(Stream node); -static Stream xfunc_stream_qsort(Stream root, Stream bottom); -static int xfunc_stream_compare(void *arg1, void *arg2); -static bool xfunc_check_stream(Stream node); -static bool xfunc_in_stream(Stream node, Stream stream); +static Stream xfunc_stream_qsort(Stream root, Stream bottom); +static int xfunc_stream_compare(void *arg1, void *arg2); +static bool xfunc_check_stream(Stream node); +static bool xfunc_in_stream(Stream node, Stream stream); -/* ----------------- MAIN FUNCTIONS ------------------------ */ +/* ----------------- MAIN FUNCTIONS ------------------------ */ /* ** xfunc_do_predmig -** wrapper for Predicate Migration. It calls xfunc_predmig until no +** wrapper for Predicate Migration. It calls xfunc_predmig until no ** more progress is made. -** return value says if any changes were ever made. +** return value says if any changes were ever made. */ -bool xfunc_do_predmig(Path root) +bool +xfunc_do_predmig(Path root) { - bool progress, changed = false; - - if (is_join(root)) - do - { - progress = false; - Assert(IsA(root,JoinPath)); - xfunc_predmig((JoinPath)root, (Stream)NULL, (Stream)NULL, - &progress); - if (changed && progress) - elog(DEBUG, "Needed to do a second round of predmig!\n"); - if (progress) changed = true; - } while (progress); - return(changed); + bool progress, + changed = false; + + if (is_join(root)) + do + { + progress = false; + Assert(IsA(root, JoinPath)); + xfunc_predmig((JoinPath) root, (Stream) NULL, (Stream) NULL, + &progress); + if (changed && progress) + elog(DEBUG, "Needed to do a second round of predmig!\n"); + if (progress) + changed = true; + } while (progress); + return (changed); } /* ** xfunc_predmig - ** The main routine for Predicate Migration. It traverses a join tree, - ** and for each root-to-leaf path in the plan tree it constructs a + ** The main routine for Predicate Migration. It traverses a join tree, + ** and for each root-to-leaf path in the plan tree it constructs a ** "Stream", which it passes to xfunc_series_llel for optimization. ** Destructively modifies the join tree (via predicate pullup). */ static void -xfunc_predmig(JoinPath pathnode, /* root of the join tree */ - Stream streamroot, - Stream laststream, /* for recursive calls -- these are - the root of the stream under - construction, and the lowest node - created so far */ - bool *progressp) +xfunc_predmig(JoinPath pathnode,/* root of the join tree */ + Stream streamroot, + Stream laststream,/* for recursive calls -- these are the + * root of the stream under construction, + * and the lowest node created so far */ + bool * progressp) { - Stream newstream; - - /* - ** traverse the join tree dfs-style, constructing a stream as you go. - ** When you hit a scan node, pass the stream off to xfunc_series_llel. - */ - - /* sanity check */ - if ((!streamroot && laststream) || - (streamroot && !laststream)) - elog(WARN, "called xfunc_predmig with bad inputs"); - if (streamroot) Assert(xfunc_check_stream(streamroot)); - - /* add path node to stream */ - newstream = RMakeStream(); - if (!streamroot) - streamroot = newstream; - set_upstream(newstream, (StreamPtr)laststream); - if (laststream) - set_downstream(laststream, (StreamPtr)newstream); - set_downstream(newstream, (StreamPtr)NULL); - set_pathptr(newstream, (pathPtr)pathnode); - set_cinfo(newstream, (CInfo)NULL); - set_clausetype(newstream, XFUNC_UNKNOWN); - - /* base case: we're at a leaf, call xfunc_series_llel */ - if (!is_join(pathnode)) + Stream newstream; + + /* + * * traverse the join tree dfs-style, constructing a stream as you + * go. * When you hit a scan node, pass the stream off to + * xfunc_series_llel. + */ + + /* sanity check */ + if ((!streamroot && laststream) || + (streamroot && !laststream)) + elog(WARN, "called xfunc_predmig with bad inputs"); + if (streamroot) + Assert(xfunc_check_stream(streamroot)); + + /* add path node to stream */ + newstream = RMakeStream(); + if (!streamroot) + streamroot = newstream; + set_upstream(newstream, (StreamPtr) laststream); + if (laststream) + set_downstream(laststream, (StreamPtr) newstream); + set_downstream(newstream, (StreamPtr) NULL); + set_pathptr(newstream, (pathPtr) pathnode); + set_cinfo(newstream, (CInfo) NULL); + set_clausetype(newstream, XFUNC_UNKNOWN); + + /* base case: we're at a leaf, call xfunc_series_llel */ + if (!is_join(pathnode)) { - /* form a fleshed-out copy of the stream */ - Stream fullstream = xfunc_complete_stream(streamroot); - - /* sort it via series-llel */ - if (xfunc_series_llel(fullstream)) - *progressp = true; - - /* free up the copy */ - xfunc_free_stream(fullstream); + /* form a fleshed-out copy of the stream */ + Stream fullstream = xfunc_complete_stream(streamroot); + + /* sort it via series-llel */ + if (xfunc_series_llel(fullstream)) + *progressp = true; + + /* free up the copy */ + xfunc_free_stream(fullstream); } - else + else { - /* visit left child */ - xfunc_predmig((JoinPath)get_outerjoinpath(pathnode), - streamroot, newstream, progressp); - - /* visit right child */ - xfunc_predmig((JoinPath)get_innerjoinpath(pathnode), - streamroot, newstream, progressp); + /* visit left child */ + xfunc_predmig((JoinPath) get_outerjoinpath(pathnode), + streamroot, newstream, progressp); + + /* visit right child */ + xfunc_predmig((JoinPath) get_innerjoinpath(pathnode), + streamroot, newstream, progressp); } - - /* remove this node */ - if (get_upstream(newstream)) - set_downstream((Stream)get_upstream(newstream), (StreamPtr)NULL); - pfree(newstream); + + /* remove this node */ + if (get_upstream(newstream)) + set_downstream((Stream) get_upstream(newstream), (StreamPtr) NULL); + pfree(newstream); } /* ** xfunc_series_llel ** A flavor of Monma and Sidney's Series-Parallel algorithm. - ** Traverse stream downwards. When you find a node with restrictions on it, + ** Traverse stream downwards. When you find a node with restrictions on it, ** call xfunc_llel_chains on the substream from root to that node. */ -static bool xfunc_series_llel(Stream stream) +static bool +xfunc_series_llel(Stream stream) { - Stream temp, next; - bool progress = false; - - for (temp = stream; temp != (Stream)NULL; temp = next) + Stream temp, + next; + bool progress = false; + + for (temp = stream; temp != (Stream) NULL; temp = next) { - next = (Stream)xfunc_get_downjoin(temp); - /* - ** if there are restrictions/secondary join clauses above this - ** node, call xfunc_llel_chains - */ - if (get_upstream(temp) && is_clause((Stream)get_upstream(temp))) - if (xfunc_llel_chains(stream, temp)) - progress = true; + next = (Stream) xfunc_get_downjoin(temp); + + /* + * * if there are restrictions/secondary join clauses above this * + * node, call xfunc_llel_chains + */ + if (get_upstream(temp) && is_clause((Stream) get_upstream(temp))) + if (xfunc_llel_chains(stream, temp)) + progress = true; } - return(progress); + return (progress); } /* ** xfunc_llel_chains ** A flavor of Monma and Sidney's Parallel Chains algorithm. ** Given a stream which has been well-ordered except for its lowermost - ** restrictions/2-ary joins, pull up the restrictions/2-arys as appropriate. + ** restrictions/2-ary joins, pull up the restrictions/2-arys as appropriate. ** What that means here is to form groups in the chain above the lowest - ** join node above bottom inclusive, and then take all the restrictions + ** join node above bottom inclusive, and then take all the restrictions ** following bottom, and try to pull them up as far as possible. */ -static bool xfunc_llel_chains(Stream root, Stream bottom) +static bool +xfunc_llel_chains(Stream root, Stream bottom) { - bool progress = false; - Stream origstream; - Stream tmpstream, pathstream; - Stream rootcopy = root; - - Assert(xfunc_check_stream(root)); - - /* xfunc_prdmig_pullup will need an unmodified copy of the stream */ - origstream = (Stream)copyObject((Node)root); - - /* form groups among ill-ordered nodes */ - xfunc_form_groups(root, bottom); - - /* sort chain by rank */ - Assert(xfunc_in_stream(bottom, root)); - rootcopy = xfunc_stream_qsort(root, bottom); - - /* - ** traverse sorted stream -- if any restriction has moved above a join, - ** we must pull it up in the plan. That is, make plan tree - ** reflect order of sorted stream. - */ - for (tmpstream = rootcopy, - pathstream = (Stream)xfunc_get_downjoin(rootcopy); - tmpstream != (Stream)NULL && pathstream != (Stream)NULL; - tmpstream = (Stream)get_downstream(tmpstream)) + bool progress = false; + Stream origstream; + Stream tmpstream, + pathstream; + Stream rootcopy = root; + + Assert(xfunc_check_stream(root)); + + /* xfunc_prdmig_pullup will need an unmodified copy of the stream */ + origstream = (Stream) copyObject((Node) root); + + /* form groups among ill-ordered nodes */ + xfunc_form_groups(root, bottom); + + /* sort chain by rank */ + Assert(xfunc_in_stream(bottom, root)); + rootcopy = xfunc_stream_qsort(root, bottom); + + /* + * * traverse sorted stream -- if any restriction has moved above a + * join, * we must pull it up in the plan. That is, make plan tree * + * reflect order of sorted stream. + */ + for (tmpstream = rootcopy, + pathstream = (Stream) xfunc_get_downjoin(rootcopy); + tmpstream != (Stream) NULL && pathstream != (Stream) NULL; + tmpstream = (Stream) get_downstream(tmpstream)) { - if (is_clause(tmpstream) - && get_pathptr(pathstream) != get_pathptr(tmpstream)) + if (is_clause(tmpstream) + && get_pathptr(pathstream) != get_pathptr(tmpstream)) { - /* - ** If restriction moved above a Join after sort, we pull it - ** up in the join plan. - ** If restriction moved down, we ignore it. - ** This is because Joey's Sequoia paper proves that - ** restrictions should never move down. If this - ** one were moved down, it would violate "semantic correctness", - ** i.e. it would be lower than the attributes it references. - */ - Assert(xfunc_num_relids(pathstream)>xfunc_num_relids(tmpstream)); - progress = - xfunc_prdmig_pullup(origstream, tmpstream, - (JoinPath)get_pathptr(pathstream)); + + /* + * * If restriction moved above a Join after sort, we pull it * + * up in the join plan. * If restriction moved down, we + * ignore it. * This is because Joey's Sequoia paper proves + * that * restrictions should never move down. If this * one + * were moved down, it would violate "semantic correctness", * + * i.e. it would be lower than the attributes it references. + */ + Assert(xfunc_num_relids(pathstream) > xfunc_num_relids(tmpstream)); + progress = + xfunc_prdmig_pullup(origstream, tmpstream, + (JoinPath) get_pathptr(pathstream)); } - if (get_downstream(tmpstream)) - pathstream = - (Stream)xfunc_get_downjoin((Stream)get_downstream(tmpstream)); + if (get_downstream(tmpstream)) + pathstream = + (Stream) xfunc_get_downjoin((Stream) get_downstream(tmpstream)); } - - /* free up origstream */ - xfunc_free_stream(origstream); - return(progress); + + /* free up origstream */ + xfunc_free_stream(origstream); + return (progress); } /* ** xfunc_complete_stream -- ** Given a stream composed of join nodes only, make a copy containing the - ** join nodes along with the associated restriction nodes. + ** join nodes along with the associated restriction nodes. */ -static Stream xfunc_complete_stream(Stream stream) +static Stream +xfunc_complete_stream(Stream stream) { - Stream tmpstream, copystream, curstream = (Stream)NULL; - - copystream = (Stream)copyObject((Node)stream); - Assert(xfunc_check_stream(copystream)); - - curstream = copystream; - Assert(!is_clause(curstream)); - - /* curstream = (Stream)xfunc_get_downjoin(curstream); */ - - while(curstream != (Stream)NULL) + Stream tmpstream, + copystream, + curstream = (Stream) NULL; + + copystream = (Stream) copyObject((Node) stream); + Assert(xfunc_check_stream(copystream)); + + curstream = copystream; + Assert(!is_clause(curstream)); + + /* curstream = (Stream)xfunc_get_downjoin(curstream); */ + + while (curstream != (Stream) NULL) { - xfunc_add_clauses(curstream); - curstream = (Stream)xfunc_get_downjoin(curstream); + xfunc_add_clauses(curstream); + curstream = (Stream) xfunc_get_downjoin(curstream); } - - /* find top of stream and return it */ - for (tmpstream = copystream; get_upstream(tmpstream) != (StreamPtr)NULL; - tmpstream = (Stream)get_upstream(tmpstream)) - /* no body in for loop */; - - return(tmpstream); + + /* find top of stream and return it */ + for (tmpstream = copystream; get_upstream(tmpstream) != (StreamPtr) NULL; + tmpstream = (Stream) get_upstream(tmpstream)) + /* no body in for loop */ ; + + return (tmpstream); } /* ** xfunc_prdmig_pullup ** pullup a clause in a path above joinpath. Since the JoinPath tree - ** doesn't have upward pointers, it's difficult to deal with. Thus we + ** doesn't have upward pointers, it's difficult to deal with. Thus we ** require the original stream, which maintains pointers to all the path - ** nodes. We use the original stream to find out what joins are + ** nodes. We use the original stream to find out what joins are ** above the clause. */ -static bool +static bool xfunc_prdmig_pullup(Stream origstream, Stream pullme, JoinPath joinpath) { - CInfo clauseinfo = get_cinfo(pullme); - bool progress = false; - Stream upjoin, orignode, temp; - int whichchild; - - /* find node in origstream that contains clause */ - for (orignode = origstream; - orignode != (Stream) NULL - && get_cinfo(orignode) != clauseinfo; - orignode = (Stream)get_downstream(orignode)) - /* empty body in for loop */ ; - if (!orignode) - elog(WARN, "Didn't find matching node in original stream"); - - - /* pull up this node as far as it should go */ - for (upjoin = (Stream)xfunc_get_upjoin(orignode); - upjoin != (Stream)NULL - && (JoinPath)get_pathptr((Stream)xfunc_get_downjoin(upjoin)) - != joinpath; - upjoin = (Stream)xfunc_get_upjoin(upjoin)) + CInfo clauseinfo = get_cinfo(pullme); + bool progress = false; + Stream upjoin, + orignode, + temp; + int whichchild; + + /* find node in origstream that contains clause */ + for (orignode = origstream; + orignode != (Stream) NULL + && get_cinfo(orignode) != clauseinfo; + orignode = (Stream) get_downstream(orignode)) + /* empty body in for loop */ ; + if (!orignode) + elog(WARN, "Didn't find matching node in original stream"); + + + /* pull up this node as far as it should go */ + for (upjoin = (Stream) xfunc_get_upjoin(orignode); + upjoin != (Stream) NULL + && (JoinPath) get_pathptr((Stream) xfunc_get_downjoin(upjoin)) + != joinpath; + upjoin = (Stream) xfunc_get_upjoin(upjoin)) { -#ifdef DEBUG - elog(DEBUG, "pulling up in xfunc_predmig_pullup!"); +#ifdef DEBUG + elog(DEBUG, "pulling up in xfunc_predmig_pullup!"); #endif - /* move clause up in path */ - if (get_pathptr((Stream)get_downstream(upjoin)) - == (pathPtr)get_outerjoinpath((JoinPath)get_pathptr(upjoin))) - whichchild = OUTER; - else whichchild = INNER; - clauseinfo = xfunc_pullup((Path)get_pathptr((Stream)get_downstream(upjoin)), - (JoinPath)get_pathptr(upjoin), - clauseinfo, - whichchild, - get_clausetype(orignode)); - set_pathptr(pullme, get_pathptr(upjoin)); - /* pullme has been moved into locclauseinfo */ - set_clausetype(pullme, XFUNC_LOCPRD); - - /* - ** xfunc_pullup makes new path nodes for children of - ** get_pathptr(current). We must modify the stream nodes to point - ** to these path nodes - */ - if (whichchild == OUTER) + /* move clause up in path */ + if (get_pathptr((Stream) get_downstream(upjoin)) + == (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(upjoin))) + whichchild = OUTER; + else + whichchild = INNER; + clauseinfo = xfunc_pullup((Path) get_pathptr((Stream) get_downstream(upjoin)), + (JoinPath) get_pathptr(upjoin), + clauseinfo, + whichchild, + get_clausetype(orignode)); + set_pathptr(pullme, get_pathptr(upjoin)); + /* pullme has been moved into locclauseinfo */ + set_clausetype(pullme, XFUNC_LOCPRD); + + /* + * * xfunc_pullup makes new path nodes for children of * + * get_pathptr(current). We must modify the stream nodes to point * + * to these path nodes + */ + if (whichchild == OUTER) { - for(temp = (Stream)get_downstream(upjoin); is_clause(temp); - temp = (Stream)get_downstream(temp)) + for (temp = (Stream) get_downstream(upjoin); is_clause(temp); + temp = (Stream) get_downstream(temp)) + set_pathptr + (temp, (pathPtr) + get_outerjoinpath((JoinPath) get_pathptr(upjoin))); set_pathptr - (temp, (pathPtr) - get_outerjoinpath((JoinPath)get_pathptr(upjoin))); - set_pathptr - (temp, - (pathPtr)get_outerjoinpath((JoinPath)get_pathptr(upjoin))); + (temp, + (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(upjoin))); } - else + else { - for(temp = (Stream)get_downstream(upjoin); is_clause(temp); - temp = (Stream)get_downstream(temp)) + for (temp = (Stream) get_downstream(upjoin); is_clause(temp); + temp = (Stream) get_downstream(temp)) + set_pathptr + (temp, (pathPtr) + get_innerjoinpath((JoinPath) get_pathptr(upjoin))); set_pathptr - (temp, (pathPtr) - get_innerjoinpath((JoinPath)get_pathptr(upjoin))); - set_pathptr - (temp, (pathPtr) - get_innerjoinpath((JoinPath)get_pathptr(upjoin))); + (temp, (pathPtr) + get_innerjoinpath((JoinPath) get_pathptr(upjoin))); } - progress = true; + progress = true; } - if (!progress) - elog(DEBUG, "didn't succeed in pulling up in xfunc_prdmig_pullup"); - return(progress); + if (!progress) + elog(DEBUG, "didn't succeed in pulling up in xfunc_prdmig_pullup"); + return (progress); } /* @@ -386,143 +405,151 @@ xfunc_prdmig_pullup(Stream origstream, Stream pullme, JoinPath joinpath) ** equal to the cost of the first plus the selectivity of the first times the ** cost of the second. We define each node to be in a group by itself, ** and then repeatedly find adjacent groups which are ordered by descending - ** rank, and make larger groups. You know that two adjacent nodes are in a - ** group together if the lower has groupup set to true. They will both have + ** rank, and make larger groups. You know that two adjacent nodes are in a + ** group together if the lower has groupup set to true. They will both have ** the same groupcost and groupsel (since they're in the same group!) */ -static void xfunc_form_groups(Query* queryInfo, Stream root, Stream bottom) +static void +xfunc_form_groups(Query * queryInfo, Stream root, Stream bottom) { - Stream temp, parent; - int lowest = xfunc_num_relids((Stream)xfunc_get_upjoin(bottom)); - bool progress; - LispValue primjoin; - int whichchild; - - if (!lowest) return; /* no joins in stream, so no groups */ - - /* initialize groups to be single nodes */ - for (temp = root; - temp != (Stream)NULL && temp != bottom; - temp = (Stream)get_downstream(temp)) + Stream temp, + parent; + int lowest = xfunc_num_relids((Stream) xfunc_get_upjoin(bottom)); + bool progress; + LispValue primjoin; + int whichchild; + + if (!lowest) + return; /* no joins in stream, so no groups */ + + /* initialize groups to be single nodes */ + for (temp = root; + temp != (Stream) NULL && temp != bottom; + temp = (Stream) get_downstream(temp)) { - /* if a Join node */ - if (!is_clause(temp)) + /* if a Join node */ + if (!is_clause(temp)) { - if (get_pathptr((Stream)get_downstream(temp)) - == (pathPtr)get_outerjoinpath((JoinPath)get_pathptr(temp))) - whichchild = OUTER; - else whichchild = INNER; - set_groupcost(temp, - xfunc_join_expense((JoinPath)get_pathptr(temp), - whichchild)); - if (primjoin = xfunc_primary_join((JoinPath)get_pathptr(temp))) + if (get_pathptr((Stream) get_downstream(temp)) + == (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(temp))) + whichchild = OUTER; + else + whichchild = INNER; + set_groupcost(temp, + xfunc_join_expense((JoinPath) get_pathptr(temp), + whichchild)); + if (primjoin = xfunc_primary_join((JoinPath) get_pathptr(temp))) { - set_groupsel(temp, - compute_clause_selec(queryInfo, - primjoin, NIL)); + set_groupsel(temp, + compute_clause_selec(queryInfo, + primjoin, NIL)); } - else + else { - set_groupsel(temp,1.0); + set_groupsel(temp, 1.0); } } - else /* a restriction, or 2-ary join pred */ + else +/* a restriction, or 2-ary join pred */ { - set_groupcost(temp, - xfunc_expense(queryInfo, - get_clause(get_cinfo(temp)))); - set_groupsel(temp, - compute_clause_selec(queryInfo, - get_clause(get_cinfo(temp)), - NIL)); + set_groupcost(temp, + xfunc_expense(queryInfo, + get_clause(get_cinfo(temp)))); + set_groupsel(temp, + compute_clause_selec(queryInfo, + get_clause(get_cinfo(temp)), + NIL)); } - set_groupup(temp,false); + set_groupup(temp, false); } - - /* make passes upwards, forming groups */ - do + + /* make passes upwards, forming groups */ + do { - progress = false; - for (temp = (Stream)get_upstream(bottom); - temp != (Stream)NULL; - temp = (Stream)get_upstream(temp)) + progress = false; + for (temp = (Stream) get_upstream(bottom); + temp != (Stream) NULL; + temp = (Stream) get_upstream(temp)) { - /* check for grouping with node upstream */ - if (!get_groupup(temp) && /* not already grouped */ - (parent = (Stream)get_upstream(temp)) != (Stream)NULL && + /* check for grouping with node upstream */ + if (!get_groupup(temp) && /* not already grouped */ + (parent = (Stream) get_upstream(temp)) != (Stream) NULL && /* temp is a join or temp is the top of a group */ - (is_join((Path)get_pathptr(temp)) || - get_downstream(temp) && - get_groupup((Stream)get_downstream(temp))) && - get_grouprank(parent) < get_grouprank(temp)) + (is_join((Path) get_pathptr(temp)) || + get_downstream(temp) && + get_groupup((Stream) get_downstream(temp))) && + get_grouprank(parent) < get_grouprank(temp)) { - progress = true; /* we formed a new group */ - set_groupup(temp,true); - set_groupcost(temp, - get_groupcost(temp) + - get_groupsel(temp) * get_groupcost(parent)); - set_groupsel(temp,get_groupsel(temp) * get_groupsel(parent)); - - /* fix costs and sels of all members of group */ - xfunc_setup_group(temp, bottom); + progress = true;/* we formed a new group */ + set_groupup(temp, true); + set_groupcost(temp, + get_groupcost(temp) + + get_groupsel(temp) * get_groupcost(parent)); + set_groupsel(temp, get_groupsel(temp) * get_groupsel(parent)); + + /* fix costs and sels of all members of group */ + xfunc_setup_group(temp, bottom); } } - } while(progress); + } while (progress); } -/* ------------------- UTILITY FUNCTIONS ------------------------- */ +/* ------------------- UTILITY FUNCTIONS ------------------------- */ /* ** xfunc_free_stream -- ** walk down a stream and pfree it */ -static void xfunc_free_stream(Stream root) +static void +xfunc_free_stream(Stream root) { - Stream cur, next; - - Assert(xfunc_check_stream(root)); - - if (root != (Stream)NULL) - for (cur = root; cur != (Stream)NULL; cur = next) - { - next = (Stream)get_downstream(cur); - pfree(cur); - } + Stream cur, + next; + + Assert(xfunc_check_stream(root)); + + if (root != (Stream) NULL) + for (cur = root; cur != (Stream) NULL; cur = next) + { + next = (Stream) get_downstream(cur); + pfree(cur); + } } /* ** xfunc_add<_clauses - ** find any clauses above current, and insert them into stream as + ** find any clauses above current, and insert them into stream as ** appropriate. Return uppermost clause inserted, or current if none. */ -static Stream xfunc_add_clauses(Stream current) +static Stream +xfunc_add_clauses(Stream current) { - Stream topnode = current; - LispValue temp; - LispValue primjoin; - - /* first add in the local clauses */ - foreach(temp, get_locclauseinfo((Path)get_pathptr(current))) + Stream topnode = current; + LispValue temp; + LispValue primjoin; + + /* first add in the local clauses */ + foreach(temp, get_locclauseinfo((Path) get_pathptr(current))) { - topnode = - xfunc_streaminsert((CInfo)lfirst(temp), topnode, - XFUNC_LOCPRD); + topnode = + xfunc_streaminsert((CInfo) lfirst(temp), topnode, + XFUNC_LOCPRD); } - - /* and add in the join clauses */ - if (IsA(get_pathptr(current),JoinPath)) + + /* and add in the join clauses */ + if (IsA(get_pathptr(current), JoinPath)) { - primjoin = xfunc_primary_join((JoinPath)get_pathptr(current)); - foreach(temp, get_pathclauseinfo((JoinPath)get_pathptr(current))) + primjoin = xfunc_primary_join((JoinPath) get_pathptr(current)); + foreach(temp, get_pathclauseinfo((JoinPath) get_pathptr(current))) { - if (!equal(get_clause((CInfo)lfirst(temp)), primjoin)) - topnode = - xfunc_streaminsert((CInfo)lfirst(temp), topnode, - XFUNC_JOINPRD); + if (!equal(get_clause((CInfo) lfirst(temp)), primjoin)) + topnode = + xfunc_streaminsert((CInfo) lfirst(temp), topnode, + XFUNC_JOINPRD); } } - return(topnode); + return (topnode); } @@ -531,33 +558,36 @@ static Stream xfunc_add_clauses(Stream current) ** find all elements of stream that are grouped with node and are above ** bottom, and set their groupcost and groupsel to be the same as node's. */ -static void xfunc_setup_group(Stream node, Stream bottom) +static void +xfunc_setup_group(Stream node, Stream bottom) { - Stream temp; - - if (node != bottom) - /* traverse downwards */ - for (temp = (Stream)get_downstream(node); - temp != (Stream)NULL && temp != bottom; - temp = (Stream)get_downstream(temp)) - { - if (!get_groupup(temp)) break; - else - { - set_groupcost(temp, get_groupcost(node)); - set_groupsel(temp, get_groupsel(node)); - } - } - - /* traverse upwards */ - for (temp = (Stream)get_upstream(node); temp != (Stream)NULL; - temp = (Stream)get_upstream(temp)) + Stream temp; + + if (node != bottom) + /* traverse downwards */ + for (temp = (Stream) get_downstream(node); + temp != (Stream) NULL && temp != bottom; + temp = (Stream) get_downstream(temp)) + { + if (!get_groupup(temp)) + break; + else + { + set_groupcost(temp, get_groupcost(node)); + set_groupsel(temp, get_groupsel(node)); + } + } + + /* traverse upwards */ + for (temp = (Stream) get_upstream(node); temp != (Stream) NULL; + temp = (Stream) get_upstream(temp)) { - if (!get_groupup((Stream)get_downstream(temp))) break; - else + if (!get_groupup((Stream) get_downstream(temp))) + break; + else { - set_groupcost(temp, get_groupcost(node)); - set_groupsel(temp, get_groupsel(node)); + set_groupcost(temp, get_groupcost(node)); + set_groupsel(temp, get_groupsel(node)); } } } @@ -568,70 +598,75 @@ static void xfunc_setup_group(Stream node, Stream bottom) ** Make a new Stream node to hold clause, and insert it above current. ** Return new node. */ -static Stream +static Stream xfunc_streaminsert(CInfo clauseinfo, - Stream current, - int clausetype) /* XFUNC_LOCPRD or XFUNC_JOINPRD */ + Stream current, + int clausetype) /* XFUNC_LOCPRD or XFUNC_JOINPRD */ { - Stream newstream = RMakeStream(); - set_upstream(newstream, get_upstream(current)); - if (get_upstream(current)) - set_downstream((Stream)(get_upstream(current)), (StreamPtr)newstream); - set_upstream(current, (StreamPtr)newstream); - set_downstream(newstream, (StreamPtr)current); - set_pathptr(newstream, get_pathptr(current)); - set_cinfo(newstream, clauseinfo); - set_clausetype(newstream, clausetype); - return(newstream); + Stream newstream = RMakeStream(); + + set_upstream(newstream, get_upstream(current)); + if (get_upstream(current)) + set_downstream((Stream) (get_upstream(current)), (StreamPtr) newstream); + set_upstream(current, (StreamPtr) newstream); + set_downstream(newstream, (StreamPtr) current); + set_pathptr(newstream, get_pathptr(current)); + set_cinfo(newstream, clauseinfo); + set_clausetype(newstream, clausetype); + return (newstream); } /* ** Given a Stream node, find the number of relids referenced in the pathnode ** associated with the stream node. The number of relids gives a unique - ** ordering on the joins in a stream, which we use to compare the height of + ** ordering on the joins in a stream, which we use to compare the height of ** join nodes. */ -static int xfunc_num_relids(Stream node) +static int +xfunc_num_relids(Stream node) { - if (!node || !IsA(get_pathptr(node),JoinPath)) - return(0); - else return(length - (get_relids(get_parent((JoinPath)get_pathptr(node))))); + if (!node || !IsA(get_pathptr(node), JoinPath)) + return (0); + else + return (length + (get_relids(get_parent((JoinPath) get_pathptr(node))))); } -/* +/* ** xfunc_get_downjoin -- ** Given a stream node, find the next lowest node which points to a ** join predicate or a scan node. */ -static StreamPtr xfunc_get_downjoin(Stream node) +static StreamPtr +xfunc_get_downjoin(Stream node) { - Stream temp; - - if (!is_clause(node)) /* if this is a join */ - node = (Stream)get_downstream(node); - for (temp = node; temp && is_clause(temp); - temp = (Stream)get_downstream(temp)) - /* empty body in for loop */ ; - - return((StreamPtr)temp); + Stream temp; + + if (!is_clause(node)) /* if this is a join */ + node = (Stream) get_downstream(node); + for (temp = node; temp && is_clause(temp); + temp = (Stream) get_downstream(temp)) + /* empty body in for loop */ ; + + return ((StreamPtr) temp); } /* ** xfunc_get_upjoin -- ** same as above, but upwards. */ -static StreamPtr xfunc_get_upjoin(Stream node) +static StreamPtr +xfunc_get_upjoin(Stream node) { - Stream temp; - - if (!is_clause(node)) /* if this is a join */ - node = (Stream)get_upstream(node); - for (temp = node; temp && is_clause(temp); - temp = (Stream)get_upstream(temp)) - /* empty body in for loop */ ; - - return((StreamPtr)temp); + Stream temp; + + if (!is_clause(node)) /* if this is a join */ + node = (Stream) get_upstream(node); + for (temp = node; temp && is_clause(temp); + temp = (Stream) get_upstream(temp)) + /* empty body in for loop */ ; + + return ((StreamPtr) temp); } /* @@ -639,43 +674,46 @@ static StreamPtr xfunc_get_upjoin(Stream node) ** Given a stream, sort by group rank the elements in the stream from the ** node "bottom" up. DESTRUCTIVELY MODIFIES STREAM! Returns new root. */ -static Stream xfunc_stream_qsort(Stream root, Stream bottom) +static Stream +xfunc_stream_qsort(Stream root, Stream bottom) { - int i; - size_t num; - Stream *nodearray, output; - Stream tmp; - - /* find size of list */ - for (num = 0, tmp = root; tmp != bottom; - tmp = (Stream)get_downstream(tmp)) - num ++; - if (num <= 1) return (root); - - /* copy elements of the list into an array */ - nodearray = (Stream *) palloc(num * sizeof(Stream)); - - for (tmp = root, i = 0; tmp != bottom; - tmp = (Stream)get_downstream(tmp), i++) - nodearray[i] = tmp; - - /* sort the array */ - pg_qsort(nodearray, num, sizeof(LispValue), xfunc_stream_compare); - - /* paste together the array elements */ - output = nodearray[num - 1]; - set_upstream(output, (StreamPtr)NULL); - for (i = num - 2; i >= 0; i--) + int i; + size_t num; + Stream *nodearray, + output; + Stream tmp; + + /* find size of list */ + for (num = 0, tmp = root; tmp != bottom; + tmp = (Stream) get_downstream(tmp)) + num++; + if (num <= 1) + return (root); + + /* copy elements of the list into an array */ + nodearray = (Stream *) palloc(num * sizeof(Stream)); + + for (tmp = root, i = 0; tmp != bottom; + tmp = (Stream) get_downstream(tmp), i++) + nodearray[i] = tmp; + + /* sort the array */ + pg_qsort(nodearray, num, sizeof(LispValue), xfunc_stream_compare); + + /* paste together the array elements */ + output = nodearray[num - 1]; + set_upstream(output, (StreamPtr) NULL); + for (i = num - 2; i >= 0; i--) { - set_downstream(nodearray[i+1], (StreamPtr)nodearray[i]); - set_upstream(nodearray[i], (StreamPtr)nodearray[i+1]); + set_downstream(nodearray[i + 1], (StreamPtr) nodearray[i]); + set_upstream(nodearray[i], (StreamPtr) nodearray[i + 1]); } - set_downstream(nodearray[0], (StreamPtr)bottom); - if (bottom) - set_upstream(bottom, (StreamPtr)nodearray[0]); - - Assert(xfunc_check_stream(output)); - return(output); + set_downstream(nodearray[0], (StreamPtr) bottom); + if (bottom) + set_upstream(bottom, (StreamPtr) nodearray[0]); + + Assert(xfunc_check_stream(output)); + return (output); } /* @@ -684,90 +722,102 @@ static Stream xfunc_stream_qsort(Stream root, Stream bottom) ** Compare nodes by group rank. If group ranks are equal, ensure that ** join nodes appear in same order as in plan tree. */ -static int xfunc_stream_compare(void *arg1, void *arg2) +static int +xfunc_stream_compare(void *arg1, void *arg2) { - Stream stream1 = *(Stream *) arg1; - Stream stream2 = *(Stream *) arg2; - Cost rank1, rank2; - - rank1 = get_grouprank(stream1); - rank2 = get_grouprank(stream2); - - if (rank1 > rank2) return(1); - else if (rank1 < rank2) return(-1); - else + Stream stream1 = *(Stream *) arg1; + Stream stream2 = *(Stream *) arg2; + Cost rank1, + rank2; + + rank1 = get_grouprank(stream1); + rank2 = get_grouprank(stream2); + + if (rank1 > rank2) + return (1); + else if (rank1 < rank2) + return (-1); + else { - if (is_clause(stream1) && is_clause(stream2)) - return(0); /* doesn't matter what order if both are restrictions */ - else if (!is_clause(stream1) && !is_clause(stream2)) + if (is_clause(stream1) && is_clause(stream2)) + return (0); /* doesn't matter what order if both are + * restrictions */ + else if (!is_clause(stream1) && !is_clause(stream2)) { - if (xfunc_num_relids(stream1) < xfunc_num_relids(stream2)) - return(-1); - else return(1); + if (xfunc_num_relids(stream1) < xfunc_num_relids(stream2)) + return (-1); + else + return (1); } - else if (is_clause(stream1) && !is_clause(stream2)) + else if (is_clause(stream1) && !is_clause(stream2)) { - if (xfunc_num_relids(stream1) == xfunc_num_relids(stream2)) - /* stream1 is a restriction over stream2 */ - return(1); - else return(-1); + if (xfunc_num_relids(stream1) == xfunc_num_relids(stream2)) + /* stream1 is a restriction over stream2 */ + return (1); + else + return (-1); } - else if (!is_clause(stream1) && is_clause(stream2)) + else if (!is_clause(stream1) && is_clause(stream2)) { - /* stream2 is a restriction over stream1: never push down */ - return(-1); + /* stream2 is a restriction over stream1: never push down */ + return (-1); } } } -/* ------------------ DEBUGGING ROUTINES ---------------------------- */ +/* ------------------ DEBUGGING ROUTINES ---------------------------- */ /* ** Make sure all pointers in stream make sense. Make sure no joins are ** out of order. */ -static bool xfunc_check_stream(Stream node) +static bool +xfunc_check_stream(Stream node) { - Stream temp; - int numrelids, tmp; - - /* set numrelids higher than max */ - if (!is_clause(node)) - numrelids = xfunc_num_relids(node) + 1; - else if (xfunc_get_downjoin(node)) - numrelids = xfunc_num_relids((Stream)xfunc_get_downjoin(node)) + 1; - else numrelids = 1; - - for (temp = node; get_downstream(temp); temp = (Stream)get_downstream(temp)) + Stream temp; + int numrelids, + tmp; + + /* set numrelids higher than max */ + if (!is_clause(node)) + numrelids = xfunc_num_relids(node) + 1; + else if (xfunc_get_downjoin(node)) + numrelids = xfunc_num_relids((Stream) xfunc_get_downjoin(node)) + 1; + else + numrelids = 1; + + for (temp = node; get_downstream(temp); temp = (Stream) get_downstream(temp)) { - if ((Stream)get_upstream((Stream)get_downstream(temp)) != temp) + if ((Stream) get_upstream((Stream) get_downstream(temp)) != temp) { - elog(WARN, "bad pointers in stream"); - return(false); + elog(WARN, "bad pointers in stream"); + return (false); } - if (!is_clause(temp)) + if (!is_clause(temp)) { - if ((tmp = xfunc_num_relids(temp)) >= numrelids) + if ((tmp = xfunc_num_relids(temp)) >= numrelids) { - elog(WARN, "Joins got reordered!"); - return(false); + elog(WARN, "Joins got reordered!"); + return (false); } - numrelids = tmp; + numrelids = tmp; } } - - return(true); + + return (true); } /* ** xfunc_in_stream ** check if node is in stream */ -static bool xfunc_in_stream(Stream node, Stream stream) +static bool +xfunc_in_stream(Stream node, Stream stream) { - Stream temp; - - for (temp = stream; temp; temp = (Stream)get_downstream(temp)) - if (temp == node) return(1); - return(0); + Stream temp; + + for (temp = stream; temp; temp = (Stream) get_downstream(temp)) + if (temp == node) + return (1); + return (0); } diff --git a/src/backend/optimizer/path/prune.c b/src/backend/optimizer/path/prune.c index 0b154e108fa..4f3ae2d15de 100644 --- a/src/backend/optimizer/path/prune.c +++ b/src/backend/optimizer/path/prune.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * prune.c-- - * Routines to prune redundant paths and relations + * Routines to prune redundant paths and relations * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/prune.c,v 1.3 1997/06/10 07:55:47 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/prune.c,v 1.4 1997/09/07 04:43:49 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -24,181 +24,199 @@ #include "utils/elog.h" -static List *prune_joinrel(Rel *rel, List *other_rels); +static List *prune_joinrel(Rel * rel, List * other_rels); -/* +/* * prune-joinrels-- - * Removes any redundant relation entries from a list of rel nodes - * 'rel-list'. - * - * Returns the resulting list. - * + * Removes any redundant relation entries from a list of rel nodes + * 'rel-list'. + * + * Returns the resulting list. + * */ -List *prune_joinrels(List *rel_list) +List * +prune_joinrels(List * rel_list) { - List *temp_list = NIL; - - if (rel_list != NIL) { - temp_list = lcons(lfirst(rel_list), - prune_joinrels(prune_joinrel((Rel*)lfirst(rel_list), - lnext(rel_list)))); - } - return(temp_list); + List *temp_list = NIL; + + if (rel_list != NIL) + { + temp_list = lcons(lfirst(rel_list), + prune_joinrels(prune_joinrel((Rel *) lfirst(rel_list), + lnext(rel_list)))); + } + return (temp_list); } -/* +/* * prune-joinrel-- - * Prunes those relations from 'other-rels' that are redundant with - * 'rel'. A relation is redundant if it is built up of the same - * relations as 'rel'. Paths for the redundant relation are merged into - * the pathlist of 'rel'. - * + * Prunes those relations from 'other-rels' that are redundant with + * 'rel'. A relation is redundant if it is built up of the same + * relations as 'rel'. Paths for the redundant relation are merged into + * the pathlist of 'rel'. + * * Returns a list of non-redundant relations, and sets the pathlist field * of 'rel' appropriately. - * + * */ -static List * -prune_joinrel(Rel *rel, List *other_rels) +static List * +prune_joinrel(Rel * rel, List * other_rels) { - List *i = NIL; - List *t_list = NIL; - List *temp_node = NIL; - Rel *other_rel = (Rel *)NULL; - - foreach(i, other_rels) { - other_rel = (Rel*)lfirst(i); - if(same(rel->relids, other_rel->relids)) { - rel->pathlist = add_pathlist(rel, - rel->pathlist, - other_rel->pathlist); - t_list = nconc(t_list, NIL); /* XXX is this right ? */ - } else { - temp_node = lcons(other_rel, NIL); - t_list = nconc(t_list,temp_node); - } - } - return(t_list); + List *i = NIL; + List *t_list = NIL; + List *temp_node = NIL; + Rel *other_rel = (Rel *) NULL; + + foreach(i, other_rels) + { + other_rel = (Rel *) lfirst(i); + if (same(rel->relids, other_rel->relids)) + { + rel->pathlist = add_pathlist(rel, + rel->pathlist, + other_rel->pathlist); + t_list = nconc(t_list, NIL); /* XXX is this right ? */ + } + else + { + temp_node = lcons(other_rel, NIL); + t_list = nconc(t_list, temp_node); + } + } + return (t_list); } -/* +/* * prune-rel-paths-- - * For each relation entry in 'rel-list' (which corresponds to a join - * relation), set pointers to the unordered path and cheapest paths - * (if the unordered path isn't the cheapest, it is pruned), and - * reset the relation's size field to reflect the join. - * + * For each relation entry in 'rel-list' (which corresponds to a join + * relation), set pointers to the unordered path and cheapest paths + * (if the unordered path isn't the cheapest, it is pruned), and + * reset the relation's size field to reflect the join. + * * Returns nothing of interest. - * + * */ void -prune_rel_paths(List *rel_list) +prune_rel_paths(List * rel_list) { - List *x = NIL; - List *y = NIL; - Path *path = NULL; - Rel *rel = (Rel*)NULL; - JoinPath *cheapest = (JoinPath*)NULL; - - foreach(x, rel_list) { - rel = (Rel*)lfirst(x); - rel->size = 0; - foreach(y, rel->pathlist) { - path = (Path*)lfirst(y); - - if(!path->p_ordering.ord.sortop) { - break; - } + List *x = NIL; + List *y = NIL; + Path *path = NULL; + Rel *rel = (Rel *) NULL; + JoinPath *cheapest = (JoinPath *) NULL; + + foreach(x, rel_list) + { + rel = (Rel *) lfirst(x); + rel->size = 0; + foreach(y, rel->pathlist) + { + path = (Path *) lfirst(y); + + if (!path->p_ordering.ord.sortop) + { + break; + } + } + cheapest = (JoinPath *) prune_rel_path(rel, path); + if (IsA_JoinPath(cheapest)) + { + rel->size = compute_joinrel_size(cheapest); + } + else + elog(WARN, "non JoinPath called"); } - cheapest = (JoinPath*)prune_rel_path(rel, path); - if (IsA_JoinPath(cheapest)) - { - rel->size = compute_joinrel_size(cheapest); - } - else - elog(WARN, "non JoinPath called"); - } } -/* +/* * prune-rel-path-- - * Compares the unordered path for a relation with the cheapest path. If - * the unordered path is not cheapest, it is pruned. - * - * Resets the pointers in 'rel' for unordered and cheapest paths. - * + * Compares the unordered path for a relation with the cheapest path. If + * the unordered path is not cheapest, it is pruned. + * + * Resets the pointers in 'rel' for unordered and cheapest paths. + * * Returns the cheapest path. - * + * */ -Path * -prune_rel_path(Rel *rel, Path *unorderedpath) +Path * +prune_rel_path(Rel * rel, Path * unorderedpath) { - Path *cheapest = set_cheapest(rel, rel->pathlist); - - /* don't prune if not pruneable -- JMH, 11/23/92 */ - if(unorderedpath != cheapest - && rel->pruneable) { - - rel->unorderedpath = (Path *)NULL; - rel->pathlist = lremove(unorderedpath, rel->pathlist); - } else { - rel->unorderedpath = (Path *)unorderedpath; - } - - return(cheapest); + Path *cheapest = set_cheapest(rel, rel->pathlist); + + /* don't prune if not pruneable -- JMH, 11/23/92 */ + if (unorderedpath != cheapest + && rel->pruneable) + { + + rel->unorderedpath = (Path *) NULL; + rel->pathlist = lremove(unorderedpath, rel->pathlist); + } + else + { + rel->unorderedpath = (Path *) unorderedpath; + } + + return (cheapest); } /* * merge-joinrels-- - * Given two lists of rel nodes that are already - * pruned, merge them into one pruned rel node list + * Given two lists of rel nodes that are already + * pruned, merge them into one pruned rel node list * * 'rel-list1' and * 'rel-list2' are the rel node lists * * Returns one pruned rel node list */ -List * -merge_joinrels(List *rel_list1, List *rel_list2) +List * +merge_joinrels(List * rel_list1, List * rel_list2) { - List *xrel = NIL; - - foreach(xrel,rel_list1) { - Rel *rel = (Rel*)lfirst(xrel); - rel_list2 = prune_joinrel(rel,rel_list2); - } - return(append(rel_list1, rel_list2)); + List *xrel = NIL; + + foreach(xrel, rel_list1) + { + Rel *rel = (Rel *) lfirst(xrel); + + rel_list2 = prune_joinrel(rel, rel_list2); + } + return (append(rel_list1, rel_list2)); } /* * prune_oldrels-- - * If all the joininfo's in a rel node are inactive, - * that means that this node has been joined into - * other nodes in all possible ways, therefore - * this node can be discarded. If not, it will cause - * extra complexity of the optimizer. + * If all the joininfo's in a rel node are inactive, + * that means that this node has been joined into + * other nodes in all possible ways, therefore + * this node can be discarded. If not, it will cause + * extra complexity of the optimizer. * * old_rels is a list of rel nodes - * + * * Returns a new list of rel nodes */ -List *prune_oldrels(List *old_rels) +List * +prune_oldrels(List * old_rels) { - Rel *rel; - List *joininfo_list, *xjoininfo; - - if(old_rels == NIL) - return(NIL); - - rel = (Rel*)lfirst(old_rels); - joininfo_list = rel->joininfo; - if(joininfo_list == NIL) - return (lcons(rel, prune_oldrels(lnext(old_rels)))); - - foreach(xjoininfo, joininfo_list) { - JInfo *joininfo = (JInfo*)lfirst(xjoininfo); - if(!joininfo->inactive) - return (lcons(rel, prune_oldrels(lnext(old_rels)))); - } - return(prune_oldrels(lnext(old_rels))); + Rel *rel; + List *joininfo_list, + *xjoininfo; + + if (old_rels == NIL) + return (NIL); + + rel = (Rel *) lfirst(old_rels); + joininfo_list = rel->joininfo; + if (joininfo_list == NIL) + return (lcons(rel, prune_oldrels(lnext(old_rels)))); + + foreach(xjoininfo, joininfo_list) + { + JInfo *joininfo = (JInfo *) lfirst(xjoininfo); + + if (!joininfo->inactive) + return (lcons(rel, prune_oldrels(lnext(old_rels)))); + } + return (prune_oldrels(lnext(old_rels))); } diff --git a/src/backend/optimizer/path/xfunc.c b/src/backend/optimizer/path/xfunc.c index 3e3ee650f94..36135d4a823 100644 --- a/src/backend/optimizer/path/xfunc.c +++ b/src/backend/optimizer/path/xfunc.c @@ -1,21 +1,21 @@ /*------------------------------------------------------------------------- * * xfunc.c-- - * Utility routines to handle expensive function optimization. - * Includes xfunc_trypullup(), which attempts early pullup of predicates - * to allow for maximal pruning. - * + * Utility routines to handle expensive function optimization. + * Includes xfunc_trypullup(), which attempts early pullup of predicates + * to allow for maximal pruning. + * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/xfunc.c,v 1.3 1997/02/14 04:15:39 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/xfunc.c,v 1.4 1997/09/07 04:43:50 momjian Exp $ * *------------------------------------------------------------------------- */ -#include <math.h> /* for MAXFLOAT on most systems */ +#include <math.h> /* for MAXFLOAT on most systems */ -#include <values.h> /* for MAXFLOAT on SunOS */ +#include <values.h> /* for MAXFLOAT on SunOS */ #include <string.h> #include "postgres.h" @@ -40,82 +40,96 @@ #include "lib/lispsort.h" #include "access/heapam.h" #include "tcop/dest.h" -#include "storage/buf_internals.h" /* for NBuffers */ -#include "optimizer/tlist.h" /* for get_expr */ +#include "storage/buf_internals.h" /* for NBuffers */ +#include "optimizer/tlist.h" /* for get_expr */ #define ever ; 1 ; /* local funcs */ -static int xfunc_card_unreferenced(Query *queryInfo, - Expr *clause, Relid referenced); */ +static int +xfunc_card_unreferenced(Query * queryInfo, + Expr * clause, Relid referenced); + +*/ /* ** xfunc_trypullup -- -** Preliminary pullup of predicates, to allow for maximal pruning. +** Preliminary pullup of predicates, to allow for maximal pruning. ** Given a relation, check each of its paths and see if you can ** pullup clauses from its inner and outer. */ -void xfunc_trypullup(Rel rel) +void +xfunc_trypullup(Rel rel) { - LispValue y; /* list ptr */ - CInfo maxcinfo; /* The CInfo to pull up, as calculated by - xfunc_shouldpull() */ - JoinPath curpath; /* current path in list */ - int progress; /* has progress been made this time through? */ - int clausetype; - - do { - progress = false; /* no progress yet in this iteration */ - foreach(y, get_pathlist(rel)) { - curpath = (JoinPath)lfirst(y); - - /* - ** for each operand, attempt to pullup predicates until first - ** failure. - */ - for(ever) { - /* No, the following should NOT be '==' !! */ - if (clausetype = - xfunc_shouldpull((Path)get_innerjoinpath(curpath), - curpath, INNER, &maxcinfo)) { - - xfunc_pullup((Path)get_innerjoinpath(curpath), - curpath, maxcinfo, INNER, clausetype); - progress = true; - }else - break; - } - for(ever) { - - /* No, the following should NOT be '==' !! */ - if (clausetype = - xfunc_shouldpull((Path)get_outerjoinpath(curpath), - curpath, OUTER, &maxcinfo)) { - - xfunc_pullup((Path)get_outerjoinpath(curpath), - curpath, maxcinfo, OUTER, clausetype); - progress = true; - }else - break; - } - - /* - ** make sure the unpruneable flag bubbles up, i.e. - ** if anywhere below us in the path pruneable is false, - ** then pruneable should be false here - */ - if (get_pruneable(get_parent(curpath)) && - (!get_pruneable(get_parent - ((Path)get_innerjoinpath(curpath))) || - !get_pruneable(get_parent((Path) - get_outerjoinpath(curpath))))) { - - set_pruneable(get_parent(curpath),false); - progress = true; - } - } - } while(progress); + LispValue y; /* list ptr */ + CInfo maxcinfo; /* The CInfo to pull up, as calculated by + * xfunc_shouldpull() */ + JoinPath curpath; /* current path in list */ + int progress; /* has progress been made this time + * through? */ + int clausetype; + + do + { + progress = false; /* no progress yet in this iteration */ + foreach(y, get_pathlist(rel)) + { + curpath = (JoinPath) lfirst(y); + + /* + * * for each operand, attempt to pullup predicates until + * first * failure. + */ + for (ever) + { + /* No, the following should NOT be '==' !! */ + if (clausetype = + xfunc_shouldpull((Path) get_innerjoinpath(curpath), + curpath, INNER, &maxcinfo)) + { + + xfunc_pullup((Path) get_innerjoinpath(curpath), + curpath, maxcinfo, INNER, clausetype); + progress = true; + } + else + break; + } + for (ever) + { + + /* No, the following should NOT be '==' !! */ + if (clausetype = + xfunc_shouldpull((Path) get_outerjoinpath(curpath), + curpath, OUTER, &maxcinfo)) + { + + xfunc_pullup((Path) get_outerjoinpath(curpath), + curpath, maxcinfo, OUTER, clausetype); + progress = true; + } + else + break; + } + + /* + * * make sure the unpruneable flag bubbles up, i.e. * if + * anywhere below us in the path pruneable is false, * then + * pruneable should be false here + */ + if (get_pruneable(get_parent(curpath)) && + (!get_pruneable(get_parent + ((Path) get_innerjoinpath(curpath))) || + !get_pruneable(get_parent((Path) + get_outerjoinpath(curpath))))) + { + + set_pruneable(get_parent(curpath), false); + progress = true; + } + } + } while (progress); } /* @@ -128,108 +142,123 @@ void xfunc_trypullup(Rel rel) ** we'd better set the unpruneable flag. -- JMH, 11/11/92 ** ** Returns: 0 if nothing left to pullup - ** XFUNC_LOCPRD if a local predicate is to be pulled up - ** XFUNC_JOINPRD if a secondary join predicate is to be pulled up + ** XFUNC_LOCPRD if a local predicate is to be pulled up + ** XFUNC_JOINPRD if a secondary join predicate is to be pulled up */ -int xfunc_shouldpull(Query* queryInfo, - Path childpath, - JoinPath parentpath, - int whichchild, - CInfo *maxcinfopt) /* Out: pointer to clause to pullup */ +int +xfunc_shouldpull(Query * queryInfo, + Path childpath, + JoinPath parentpath, + int whichchild, + CInfo * maxcinfopt) /* Out: pointer to clause to + * pullup */ { - LispValue clauselist, tmplist; /* lists of clauses */ - CInfo maxcinfo; /* clause to pullup */ - LispValue primjoinclause /* primary join clause */ + LispValue clauselist, + tmplist; /* lists of clauses */ + CInfo maxcinfo; /* clause to pullup */ + LispValue primjoinclause /* primary join clause */ = xfunc_primary_join(parentpath); - Cost tmprank, maxrank = (-1 * MAXFLOAT); /* ranks of clauses */ - Cost joinselec = 0; /* selectivity of the join predicate */ - Cost joincost = 0; /* join cost + primjoinclause cost */ - int retval = XFUNC_LOCPRD; - - clauselist = get_locclauseinfo(childpath); - - if (clauselist != LispNil) { - /* find local predicate with maximum rank */ - for (tmplist = clauselist, - maxcinfo = (CInfo) lfirst(tmplist), - maxrank = xfunc_rank(get_clause(maxcinfo)); - tmplist != LispNil; - tmplist = lnext(tmplist)) { - - if ((tmprank = xfunc_rank(get_clause((CInfo)lfirst(tmplist)))) - > maxrank) { - maxcinfo = (CInfo) lfirst(tmplist); - maxrank = tmprank; - } + Cost tmprank, + maxrank = (-1 * MAXFLOAT); /* ranks of clauses */ + Cost joinselec = 0; /* selectivity of the join + * predicate */ + Cost joincost = 0; /* join cost + primjoinclause cost */ + int retval = XFUNC_LOCPRD; + + clauselist = get_locclauseinfo(childpath); + + if (clauselist != LispNil) + { + /* find local predicate with maximum rank */ + for (tmplist = clauselist, + maxcinfo = (CInfo) lfirst(tmplist), + maxrank = xfunc_rank(get_clause(maxcinfo)); + tmplist != LispNil; + tmplist = lnext(tmplist)) + { + + if ((tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist)))) + > maxrank) + { + maxcinfo = (CInfo) lfirst(tmplist); + maxrank = tmprank; + } + } } - } - - /* - ** If child is a join path, and there are multiple join clauses, - ** see if any join clause has even higher rank than the highest - ** local predicate - */ - if (is_join(childpath) && xfunc_num_join_clauses((JoinPath)childpath) > 1) - for (tmplist = get_pathclauseinfo((JoinPath)childpath); - tmplist != LispNil; - tmplist = lnext(tmplist)) { - - if (tmplist != LispNil && - (tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist)))) - > maxrank) { - maxcinfo = (CInfo) lfirst(tmplist); - maxrank = tmprank; - retval = XFUNC_JOINPRD; - } - } - if (maxrank == (-1 * MAXFLOAT)) /* no expensive clauses */ - return(0); - - /* - ** Pullup over join if clause is higher rank than join, or if - ** join is nested loop and current path is inner child (note that - ** restrictions on the inner of a nested loop don't buy you anything -- - ** you still have to scan the entire inner relation each time). - ** Note that the cost of a secondary join clause is only what's - ** calculated by xfunc_expense(), since the actual joining - ** (i.e. the usual path_cost) is paid for by the primary join clause. - */ - if (primjoinclause != LispNil) { - joinselec = compute_clause_selec(queryInfo, primjoinclause, LispNil); - joincost = xfunc_join_expense(parentpath, whichchild); - - if (XfuncMode == XFUNC_PULLALL || - (XfuncMode != XFUNC_WAIT && - ((joincost != 0 && - (maxrank = xfunc_rank(get_clause(maxcinfo))) > - ((joinselec - 1.0) / joincost)) - || (joincost == 0 && joinselec < 1) - || (!is_join(childpath) - && (whichchild == INNER) - && IsA(parentpath,JoinPath) - && !IsA(parentpath,HashPath) - && !IsA(parentpath,MergePath))))) { - - *maxcinfopt = maxcinfo; - return(retval); - - }else if (maxrank != -(MAXFLOAT)) { - /* - ** we've left an expensive restriction below a join. Since - ** we may pullup this restriction in predmig.c, we'd best - ** set the Rel of this join to be unpruneable - */ - set_pruneable(get_parent(parentpath), false); - /* and fall through */ + + /* + * * If child is a join path, and there are multiple join clauses, * + * see if any join clause has even higher rank than the highest * + * local predicate + */ + if (is_join(childpath) && xfunc_num_join_clauses((JoinPath) childpath) > 1) + for (tmplist = get_pathclauseinfo((JoinPath) childpath); + tmplist != LispNil; + tmplist = lnext(tmplist)) + { + + if (tmplist != LispNil && + (tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist)))) + > maxrank) + { + maxcinfo = (CInfo) lfirst(tmplist); + maxrank = tmprank; + retval = XFUNC_JOINPRD; + } + } + if (maxrank == (-1 * MAXFLOAT)) /* no expensive clauses */ + return (0); + + /* + * * Pullup over join if clause is higher rank than join, or if * join + * is nested loop and current path is inner child (note that * + * restrictions on the inner of a nested loop don't buy you anything + * -- * you still have to scan the entire inner relation each time). * + * Note that the cost of a secondary join clause is only what's * + * calculated by xfunc_expense(), since the actual joining * (i.e. the + * usual path_cost) is paid for by the primary join clause. + */ + if (primjoinclause != LispNil) + { + joinselec = compute_clause_selec(queryInfo, primjoinclause, LispNil); + joincost = xfunc_join_expense(parentpath, whichchild); + + if (XfuncMode == XFUNC_PULLALL || + (XfuncMode != XFUNC_WAIT && + ((joincost != 0 && + (maxrank = xfunc_rank(get_clause(maxcinfo))) > + ((joinselec - 1.0) / joincost)) + || (joincost == 0 && joinselec < 1) + || (!is_join(childpath) + && (whichchild == INNER) + && IsA(parentpath, JoinPath) + && !IsA(parentpath, HashPath) + && !IsA(parentpath, MergePath))))) + { + + *maxcinfopt = maxcinfo; + return (retval); + + } + else if (maxrank != -(MAXFLOAT)) + { + + /* + * * we've left an expensive restriction below a join. Since * + * we may pullup this restriction in predmig.c, we'd best * + * set the Rel of this join to be unpruneable + */ + set_pruneable(get_parent(parentpath), false); + /* and fall through */ + } } - } - return(0); + return (0); } /* ** xfunc_pullup -- - ** move clause from child pathnode to parent pathnode. This operation + ** move clause from child pathnode to parent pathnode. This operation ** makes the child pathnode produce a larger relation than it used to. ** This means that we must construct a new Rel just for the childpath, ** although this Rel will not be added to the list of Rels to be joined up @@ -238,101 +267,111 @@ int xfunc_shouldpull(Query* queryInfo, ** ** Now returns a pointer to the new pulled-up CInfo. -- JMH, 11/18/92 */ -CInfo xfunc_pullup(Query* queryInfo, - Path childpath, - JoinPath parentpath, - CInfo cinfo, /* clause to pull up */ - int whichchild,/* whether child is INNER or OUTER of join */ - int clausetype)/* whether clause to pull is join or local */ +CInfo +xfunc_pullup(Query * queryInfo, + Path childpath, + JoinPath parentpath, + CInfo cinfo, /* clause to pull up */ + int whichchild, /* whether child is INNER or OUTER of join */ + int clausetype) /* whether clause to pull is join or local */ { - Path newkid; - Rel newrel; - Cost pulled_selec; - Cost cost; - CInfo newinfo; - - /* remove clause from childpath */ - newkid = (Path)copyObject((Node)childpath); - if (clausetype == XFUNC_LOCPRD) { - set_locclauseinfo(newkid, - xfunc_LispRemove((LispValue)cinfo, - (List)get_locclauseinfo(newkid))); - }else { - set_pathclauseinfo - ((JoinPath)newkid, - xfunc_LispRemove((LispValue)cinfo, - (List)get_pathclauseinfo((JoinPath)newkid))); - } - - /* - ** give the new child path its own Rel node that reflects the - ** lack of the pulled-up predicate - */ - pulled_selec = compute_clause_selec(queryInfo, - get_clause(cinfo), LispNil); - xfunc_copyrel(get_parent(newkid), &newrel); - set_parent(newkid, newrel); - set_pathlist(newrel, lcons(newkid, NIL)); - set_unorderedpath(newrel, (PathPtr)newkid); - set_cheapestpath(newrel, (PathPtr)newkid); - set_size(newrel, - (Count)((Cost)get_size(get_parent(childpath)) / pulled_selec)); - - /* - ** fix up path cost of newkid. To do this we subtract away all the - ** xfunc_costs of childpath, then recompute the xfunc_costs of newkid - */ - cost = get_path_cost(newkid) - xfunc_get_path_cost(childpath); - Assert(cost >= 0); - set_path_cost(newkid, cost); - cost = get_path_cost(newkid) + xfunc_get_path_cost(newkid); - set_path_cost(newkid, cost); - - /* - ** We copy the cinfo, since it may appear in other plans, and we're going - ** to munge it. -- JMH, 7/22/92 - */ - newinfo = (CInfo)copyObject((Node)cinfo); - - /* - ** Fix all vars in the clause - ** to point to the right varno and varattno in parentpath - */ - xfunc_fixvars(get_clause(newinfo), newrel, whichchild); - - /* add clause to parentpath, and fix up its cost. */ - set_locclauseinfo(parentpath, - lispCons((LispValue)newinfo, - (LispValue)get_locclauseinfo(parentpath))); - /* put new childpath into the path tree */ - if (whichchild == INNER) { - set_innerjoinpath(parentpath, (pathPtr)newkid); - }else { - set_outerjoinpath(parentpath, (pathPtr)newkid); - } - - /* - ** recompute parentpath cost from scratch -- the cost - ** of the join method has changed - */ - cost = xfunc_total_path_cost(parentpath); - set_path_cost(parentpath, cost); - - return(newinfo); + Path newkid; + Rel newrel; + Cost pulled_selec; + Cost cost; + CInfo newinfo; + + /* remove clause from childpath */ + newkid = (Path) copyObject((Node) childpath); + if (clausetype == XFUNC_LOCPRD) + { + set_locclauseinfo(newkid, + xfunc_LispRemove((LispValue) cinfo, + (List) get_locclauseinfo(newkid))); + } + else + { + set_pathclauseinfo + ((JoinPath) newkid, + xfunc_LispRemove((LispValue) cinfo, + (List) get_pathclauseinfo((JoinPath) newkid))); + } + + /* + * * give the new child path its own Rel node that reflects the * lack + * of the pulled-up predicate + */ + pulled_selec = compute_clause_selec(queryInfo, + get_clause(cinfo), LispNil); + xfunc_copyrel(get_parent(newkid), &newrel); + set_parent(newkid, newrel); + set_pathlist(newrel, lcons(newkid, NIL)); + set_unorderedpath(newrel, (PathPtr) newkid); + set_cheapestpath(newrel, (PathPtr) newkid); + set_size(newrel, + (Count) ((Cost) get_size(get_parent(childpath)) / pulled_selec)); + + /* + * * fix up path cost of newkid. To do this we subtract away all the * + * xfunc_costs of childpath, then recompute the xfunc_costs of newkid + */ + cost = get_path_cost(newkid) - xfunc_get_path_cost(childpath); + Assert(cost >= 0); + set_path_cost(newkid, cost); + cost = get_path_cost(newkid) + xfunc_get_path_cost(newkid); + set_path_cost(newkid, cost); + + /* + * * We copy the cinfo, since it may appear in other plans, and we're + * going * to munge it. -- JMH, 7/22/92 + */ + newinfo = (CInfo) copyObject((Node) cinfo); + + /* + * * Fix all vars in the clause * to point to the right varno and + * varattno in parentpath + */ + xfunc_fixvars(get_clause(newinfo), newrel, whichchild); + + /* add clause to parentpath, and fix up its cost. */ + set_locclauseinfo(parentpath, + lispCons((LispValue) newinfo, + (LispValue) get_locclauseinfo(parentpath))); + /* put new childpath into the path tree */ + if (whichchild == INNER) + { + set_innerjoinpath(parentpath, (pathPtr) newkid); + } + else + { + set_outerjoinpath(parentpath, (pathPtr) newkid); + } + + /* + * * recompute parentpath cost from scratch -- the cost * of the join + * method has changed + */ + cost = xfunc_total_path_cost(parentpath); + set_path_cost(parentpath, cost); + + return (newinfo); } /* - ** calculate (selectivity-1)/cost. + ** calculate (selectivity-1)/cost. */ -Cost xfunc_rank(Query *queryInfo,LispValue clause) +Cost +xfunc_rank(Query * queryInfo, LispValue clause) { - Cost selec = compute_clause_selec(queryInfo, clause, LispNil); - Cost cost = xfunc_expense(queryInfo,clause); - - if (cost == 0) - if (selec > 1) return(MAXFLOAT); - else return(-(MAXFLOAT)); - return((selec - 1)/cost); + Cost selec = compute_clause_selec(queryInfo, clause, LispNil); + Cost cost = xfunc_expense(queryInfo, clause); + + if (cost == 0) + if (selec > 1) + return (MAXFLOAT); + else + return (-(MAXFLOAT)); + return ((selec - 1) / cost); } /* @@ -340,91 +379,99 @@ Cost xfunc_rank(Query *queryInfo,LispValue clause) ** by the cardinalities of all the base relations of the query that are *not* ** referenced in the clause. */ -Cost xfunc_expense(Query* queryInfo, clause) - LispValue clause; +Cost +xfunc_expense(Query * queryInfo, clause) +LispValue clause; { - Cost cost = xfunc_local_expense(clause); - - if (cost) + Cost cost = xfunc_local_expense(clause); + + if (cost) { - Count card = xfunc_card_unreferenced(queryInfo, clause, LispNil); - if (card) - cost /= card; + Count card = xfunc_card_unreferenced(queryInfo, clause, LispNil); + + if (card) + cost /= card; } - - return(cost); + + return (cost); } /* ** xfunc_join_expense -- ** Find global expense of a join clause */ -Cost xfunc_join_expense(Query *queryInfo, JoinPath path, int whichchild) +Cost +xfunc_join_expense(Query * queryInfo, JoinPath path, int whichchild) { - LispValue primjoinclause = xfunc_primary_join(path); - - /* - ** the second argument to xfunc_card_unreferenced reflects all the - ** relations involved in the join clause, i.e. all the relids in the Rel - ** of the join clause - */ - Count card = 0; - Cost cost = xfunc_expense_per_tuple(path, whichchild); - - card = xfunc_card_unreferenced(queryInfo, - primjoinclause, - get_relids(get_parent(path))); - if (primjoinclause) - cost += xfunc_local_expense(primjoinclause); - - if (card) cost /= card; - - return(cost); + LispValue primjoinclause = xfunc_primary_join(path); + + /* + * * the second argument to xfunc_card_unreferenced reflects all the * + * relations involved in the join clause, i.e. all the relids in the + * Rel * of the join clause + */ + Count card = 0; + Cost cost = xfunc_expense_per_tuple(path, whichchild); + + card = xfunc_card_unreferenced(queryInfo, + primjoinclause, + get_relids(get_parent(path))); + if (primjoinclause) + cost += xfunc_local_expense(primjoinclause); + + if (card) + cost /= card; + + return (cost); } /* ** Recursively find the per-tuple expense of a clause. See ** xfunc_func_expense for more discussion. */ -Cost xfunc_local_expense(LispValue clause) +Cost +xfunc_local_expense(LispValue clause) { - Cost cost = 0; /* running expense */ - LispValue tmpclause; - - /* First handle the base case */ - if (IsA(clause,Const) || IsA(clause,Var) || IsA(clause,Param)) - return(0); - /* now other stuff */ - else if (IsA(clause,Iter)) - /* Too low. Should multiply by the expected number of iterations. */ - return(xfunc_local_expense(get_iterexpr((Iter)clause))); - else if (IsA(clause,ArrayRef)) - return(xfunc_local_expense(get_refexpr((ArrayRef)clause))); - else if (fast_is_clause(clause)) - return(xfunc_func_expense((LispValue)get_op(clause), - (LispValue)get_opargs(clause))); - else if (fast_is_funcclause(clause)) - return(xfunc_func_expense((LispValue)get_function(clause), - (LispValue)get_funcargs(clause))); - else if (fast_not_clause(clause)) - return(xfunc_local_expense(lsecond(clause))); - else if (fast_or_clause(clause)) { - /* find cost of evaluating each disjunct */ - for (tmpclause = lnext(clause); tmpclause != LispNil; - tmpclause = lnext(tmpclause)) - cost += xfunc_local_expense(lfirst(tmpclause)); - return(cost); - }else { - elog(WARN, "Clause node of undetermined type"); - return(-1); - } + Cost cost = 0; /* running expense */ + LispValue tmpclause; + + /* First handle the base case */ + if (IsA(clause, Const) || IsA(clause, Var) || IsA(clause, Param)) + return (0); + /* now other stuff */ + else if (IsA(clause, Iter)) + /* Too low. Should multiply by the expected number of iterations. */ + return (xfunc_local_expense(get_iterexpr((Iter) clause))); + else if (IsA(clause, ArrayRef)) + return (xfunc_local_expense(get_refexpr((ArrayRef) clause))); + else if (fast_is_clause(clause)) + return (xfunc_func_expense((LispValue) get_op(clause), + (LispValue) get_opargs(clause))); + else if (fast_is_funcclause(clause)) + return (xfunc_func_expense((LispValue) get_function(clause), + (LispValue) get_funcargs(clause))); + else if (fast_not_clause(clause)) + return (xfunc_local_expense(lsecond(clause))); + else if (fast_or_clause(clause)) + { + /* find cost of evaluating each disjunct */ + for (tmpclause = lnext(clause); tmpclause != LispNil; + tmpclause = lnext(tmpclause)) + cost += xfunc_local_expense(lfirst(tmpclause)); + return (cost); + } + else + { + elog(WARN, "Clause node of undetermined type"); + return (-1); + } } /* ** xfunc_func_expense -- ** given a Func or Oper and its args, find its expense. ** Note: in Stonebraker's SIGMOD '91 paper, he uses a more complicated metric - ** than the one here. We can ignore the expected number of tuples for + ** than the one here. We can ignore the expected number of tuples for ** our calculations; we just need the per-tuple expense. But he also ** proposes components to take into account the costs of accessing disk and ** archive. We didn't adopt that scheme here; eventually the vacuum @@ -434,268 +481,323 @@ Cost xfunc_local_expense(LispValue clause) ** accessing secondary or tertiary storage, since we don't have sufficient ** stats to do it right. */ -Cost xfunc_func_expense(LispValue node, LispValue args) +Cost +xfunc_func_expense(LispValue node, LispValue args) { - HeapTuple tupl; /* the pg_proc tuple for each function */ - Form_pg_proc proc; /* a data structure to hold the pg_proc tuple */ - int width = 0; /* byte width of the field referenced by each clause */ - RegProcedure funcid; /* ID of function associate with node */ - Cost cost = 0; /* running expense */ - LispValue tmpclause; - LispValue operand; /* one operand of an operator */ - - if (IsA(node,Oper)) { - /* don't trust the opid in the Oper node. Use the opno. */ - if (!(funcid = get_opcode(get_opno((Oper)node)))) - elog(WARN, "Oper's function is undefined"); - }else { - funcid = get_funcid((Func)node); - } - - /* look up tuple in cache */ - tupl = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid),0,0,0); - if (!HeapTupleIsValid(tupl)) - elog(WARN, "Cache lookup failed for procedure %d", funcid); - proc = (Form_pg_proc) GETSTRUCT(tupl); - - /* - ** if it's a Postquel function, its cost is stored in the - ** associated plan. - */ - if (proc->prolang == SQLlanguageId) { - LispValue tmpplan; - List planlist; - - if (IsA(node,Oper) || get_func_planlist((Func)node) == LispNil) { - Oid *argOidVect; /* vector of argtypes */ - char *pq_src; /* text of PQ function */ - int nargs; /* num args to PQ function */ - QueryTreeList *queryTree_list; /* dummy variable */ - - /* - ** plan the function, storing it in the Func node for later - ** use by the executor. - */ - pq_src = (char *) textout(&(proc->prosrc)); - nargs = proc->pronargs; - if (nargs > 0) - argOidVect = proc->proargtypes; - planlist = (List)pg_plan(pq_src, argOidVect, nargs, - &parseTree_list, None); - if (IsA(node,Func)) - set_func_planlist((Func)node, planlist); - - }else {/* plan has been cached inside the Func node already */ - planlist = get_func_planlist((Func)node); + HeapTuple tupl; /* the pg_proc tuple for each function */ + Form_pg_proc proc; /* a data structure to hold the pg_proc + * tuple */ + int width = 0; /* byte width of the field referenced by + * each clause */ + RegProcedure funcid; /* ID of function associate with node */ + Cost cost = 0; /* running expense */ + LispValue tmpclause; + LispValue operand; /* one operand of an operator */ + + if (IsA(node, Oper)) + { + /* don't trust the opid in the Oper node. Use the opno. */ + if (!(funcid = get_opcode(get_opno((Oper) node)))) + elog(WARN, "Oper's function is undefined"); } - - /* - ** Return the sum of the costs of the plans (the PQ function - ** may have many queries in its body). - */ - foreach(tmpplan, planlist) - cost += get_cost((Plan)lfirst(tmpplan)); - return(cost); - }else { /* it's a C function */ + else + { + funcid = get_funcid((Func) node); + } + + /* look up tuple in cache */ + tupl = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid), 0, 0, 0); + if (!HeapTupleIsValid(tupl)) + elog(WARN, "Cache lookup failed for procedure %d", funcid); + proc = (Form_pg_proc) GETSTRUCT(tupl); + /* - ** find the cost of evaluating the function's arguments - ** and the width of the operands + * * if it's a Postquel function, its cost is stored in the * + * associated plan. */ - for (tmpclause = args; tmpclause != LispNil; - tmpclause = lnext(tmpclause)) { - - if ((operand = lfirst(tmpclause)) != LispNil) { - cost += xfunc_local_expense(operand); - width += xfunc_width(operand); - } + if (proc->prolang == SQLlanguageId) + { + LispValue tmpplan; + List planlist; + + if (IsA(node, Oper) || get_func_planlist((Func) node) == LispNil) + { + Oid *argOidVect; /* vector of argtypes */ + char *pq_src; /* text of PQ function */ + int nargs; /* num args to PQ function */ + QueryTreeList *queryTree_list; /* dummy variable */ + + /* + * * plan the function, storing it in the Func node for later * + * use by the executor. + */ + pq_src = (char *) textout(&(proc->prosrc)); + nargs = proc->pronargs; + if (nargs > 0) + argOidVect = proc->proargtypes; + planlist = (List) pg_plan(pq_src, argOidVect, nargs, + &parseTree_list, None); + if (IsA(node, Func)) + set_func_planlist((Func) node, planlist); + + } + else + { /* plan has been cached inside the Func + * node already */ + planlist = get_func_planlist((Func) node); + } + + /* + * * Return the sum of the costs of the plans (the PQ function * + * may have many queries in its body). + */ + foreach(tmpplan, planlist) + cost += get_cost((Plan) lfirst(tmpplan)); + return (cost); + } + else + { /* it's a C function */ + + /* + * * find the cost of evaluating the function's arguments * and + * the width of the operands + */ + for (tmpclause = args; tmpclause != LispNil; + tmpclause = lnext(tmpclause)) + { + + if ((operand = lfirst(tmpclause)) != LispNil) + { + cost += xfunc_local_expense(operand); + width += xfunc_width(operand); + } + } + + /* + * * when stats become available, add in cost of accessing + * secondary * and tertiary storage here. + */ + return (cost + + (Cost) proc->propercall_cpu + + (Cost) proc->properbyte_cpu * (Cost) proc->probyte_pct / 100.00 * + (Cost) width + + /* + * Pct_of_obj_in_mem DISK_COST * proc->probyte_pct/100.00 * width + * Pct_of_obj_on_disk + ARCH_COST * proc->probyte_pct/100.00 * + * width Pct_of_obj_on_arch + */ + ); } - - /* - ** when stats become available, add in cost of accessing secondary - ** and tertiary storage here. - */ - return(cost + - (Cost)proc->propercall_cpu + - (Cost)proc->properbyte_cpu * (Cost)proc->probyte_pct/100.00 * - (Cost)width - /* - * Pct_of_obj_in_mem - DISK_COST * proc->probyte_pct/100.00 * width - * Pct_of_obj_on_disk + - ARCH_COST * proc->probyte_pct/100.00 * width - * Pct_of_obj_on_arch - */ - ); - } } -/* +/* ** xfunc_width -- ** recursively find the width of a expression */ -int xfunc_width(LispValue clause) +int +xfunc_width(LispValue clause) { - Relation rd; /* Relation Descriptor */ - HeapTuple tupl; /* structure to hold a cached tuple */ - TypeTupleForm type; /* structure to hold a type tuple */ - int retval = 0; - - if (IsA(clause,Const)) { - /* base case: width is the width of this constant */ - retval = get_constlen((Const) clause); - goto exit; - }else if (IsA(clause,ArrayRef)) { - /* base case: width is width of the refelem within the array */ - retval = get_refelemlength((ArrayRef)clause); - goto exit; - }else if (IsA(clause,Var)) { - /* base case: width is width of this attribute */ - tupl = SearchSysCacheTuple(TYPOID, - PointerGetDatum(get_vartype((Var)clause)), - 0,0,0); - if (!HeapTupleIsValid(tupl)) - elog(WARN, "Cache lookup failed for type %d", - get_vartype((Var)clause)); - type = (TypeTupleForm) GETSTRUCT(tupl); - if (get_varattno((Var)clause) == 0) { - /* clause is a tuple. Get its width */ - rd = heap_open(type->typrelid); - retval = xfunc_tuple_width(rd); - heap_close(rd); - }else { - /* attribute is a base type */ - retval = type->typlen; + Relation rd; /* Relation Descriptor */ + HeapTuple tupl; /* structure to hold a cached tuple */ + TypeTupleForm type; /* structure to hold a type tuple */ + int retval = 0; + + if (IsA(clause, Const)) + { + /* base case: width is the width of this constant */ + retval = get_constlen((Const) clause); + goto exit; } - goto exit; - }else if (IsA(clause,Param)) { - if (typeid_get_relid(get_paramtype((Param)clause))) { - /* Param node returns a tuple. Find its width */ - rd = heap_open(typeid_get_relid(get_paramtype((Param)clause))); - retval = xfunc_tuple_width(rd); - heap_close(rd); - }else if (get_param_tlist((Param)clause) != LispNil) { - /* Param node projects a complex type */ - Assert(length(get_param_tlist((Param)clause)) == 1); /* sanity */ - retval = - xfunc_width((LispValue) - get_expr(lfirst(get_param_tlist((Param)clause)))); - }else { - /* Param node returns a base type */ - retval = tlen(get_id_type(get_paramtype((Param)clause))); + else if (IsA(clause, ArrayRef)) + { + /* base case: width is width of the refelem within the array */ + retval = get_refelemlength((ArrayRef) clause); + goto exit; } - goto exit; - }else if (IsA(clause,Iter)) { - /* - ** An Iter returns a setof things, so return the width of a single - ** thing. - ** Note: THIS MAY NOT WORK RIGHT WHEN AGGS GET FIXED, - ** SINCE AGG FUNCTIONS CHEW ON THE WHOLE SETOF THINGS!!!! - ** This whole Iter business is bogus, anyway. - */ - retval = xfunc_width(get_iterexpr((Iter)clause)); - goto exit; - }else if (fast_is_clause(clause)) { - /* - ** get function associated with this Oper, and treat this as - ** a Func - */ - tupl = SearchSysCacheTuple(OPROID, - ObjectIdGetDatum(get_opno((Oper)get_op(clause))), - 0,0,0); - if (!HeapTupleIsValid(tupl)) - elog(WARN, "Cache lookup failed for procedure %d", - get_opno((Oper)get_op(clause))); - return(xfunc_func_width - ((RegProcedure)(((OperatorTupleForm)(GETSTRUCT(tupl)))->oprcode), - (LispValue)get_opargs(clause))); - }else if (fast_is_funcclause(clause)) { - Func func = (Func)get_function(clause); - if (get_func_tlist(func) != LispNil) { - /* this function has a projection on it. Get the length - of the projected attribute */ - Assert(length(get_func_tlist(func)) == 1); /* sanity */ - retval = - xfunc_width((LispValue) - get_expr(lfirst(get_func_tlist(func)))); - goto exit; - }else { - return(xfunc_func_width((RegProcedure)get_funcid(func), - (LispValue)get_funcargs(clause))); + else if (IsA(clause, Var)) + { + /* base case: width is width of this attribute */ + tupl = SearchSysCacheTuple(TYPOID, + PointerGetDatum(get_vartype((Var) clause)), + 0, 0, 0); + if (!HeapTupleIsValid(tupl)) + elog(WARN, "Cache lookup failed for type %d", + get_vartype((Var) clause)); + type = (TypeTupleForm) GETSTRUCT(tupl); + if (get_varattno((Var) clause) == 0) + { + /* clause is a tuple. Get its width */ + rd = heap_open(type->typrelid); + retval = xfunc_tuple_width(rd); + heap_close(rd); + } + else + { + /* attribute is a base type */ + retval = type->typlen; + } + goto exit; + } + else if (IsA(clause, Param)) + { + if (typeid_get_relid(get_paramtype((Param) clause))) + { + /* Param node returns a tuple. Find its width */ + rd = heap_open(typeid_get_relid(get_paramtype((Param) clause))); + retval = xfunc_tuple_width(rd); + heap_close(rd); + } + else if (get_param_tlist((Param) clause) != LispNil) + { + /* Param node projects a complex type */ + Assert(length(get_param_tlist((Param) clause)) == 1); /* sanity */ + retval = + xfunc_width((LispValue) + get_expr(lfirst(get_param_tlist((Param) clause)))); + } + else + { + /* Param node returns a base type */ + retval = tlen(get_id_type(get_paramtype((Param) clause))); + } + goto exit; + } + else if (IsA(clause, Iter)) + { + + /* + * * An Iter returns a setof things, so return the width of a + * single * thing. * Note: THIS MAY NOT WORK RIGHT WHEN AGGS GET + * FIXED, * SINCE AGG FUNCTIONS CHEW ON THE WHOLE SETOF THINGS!!!! * + * This whole Iter business is bogus, anyway. + */ + retval = xfunc_width(get_iterexpr((Iter) clause)); + goto exit; + } + else if (fast_is_clause(clause)) + { + + /* + * * get function associated with this Oper, and treat this as * a + * Func + */ + tupl = SearchSysCacheTuple(OPROID, + ObjectIdGetDatum(get_opno((Oper) get_op(clause))), + 0, 0, 0); + if (!HeapTupleIsValid(tupl)) + elog(WARN, "Cache lookup failed for procedure %d", + get_opno((Oper) get_op(clause))); + return (xfunc_func_width + ((RegProcedure) (((OperatorTupleForm) (GETSTRUCT(tupl)))->oprcode), + (LispValue) get_opargs(clause))); + } + else if (fast_is_funcclause(clause)) + { + Func func = (Func) get_function(clause); + + if (get_func_tlist(func) != LispNil) + { + + /* + * this function has a projection on it. Get the length of + * the projected attribute + */ + Assert(length(get_func_tlist(func)) == 1); /* sanity */ + retval = + xfunc_width((LispValue) + get_expr(lfirst(get_func_tlist(func)))); + goto exit; + } + else + { + return (xfunc_func_width((RegProcedure) get_funcid(func), + (LispValue) get_funcargs(clause))); + } + } + else + { + elog(WARN, "Clause node of undetermined type"); + return (-1); } - }else { - elog(WARN, "Clause node of undetermined type"); - return(-1); - } - - exit: - if (retval == -1) - retval = VARLEN_DEFAULT; - return(retval); + +exit: + if (retval == -1) + retval = VARLEN_DEFAULT; + return (retval); } /* ** xfunc_card_unreferenced: - ** find all relations not referenced in clause, and multiply their - ** cardinalities. Ignore relation of cardinality 0. + ** find all relations not referenced in clause, and multiply their + ** cardinalities. Ignore relation of cardinality 0. ** User may pass in referenced list, if they know it (useful ** for joins). */ -static Count -xfunc_card_unreferenced(Query *queryInfo, - LispValue clause, Relid referenced) +static Count +xfunc_card_unreferenced(Query * queryInfo, + LispValue clause, Relid referenced) { - Relid unreferenced, allrelids = LispNil; - LispValue temp; - - /* find all relids of base relations referenced in query */ - foreach (temp,queryInfo->base_relation_list_) + Relid unreferenced, + allrelids = LispNil; + LispValue temp; + + /* find all relids of base relations referenced in query */ + foreach(temp, queryInfo->base_relation_list_) { - Assert(lnext(get_relids((Rel)lfirst(temp))) == LispNil); - allrelids = lappend(allrelids, - lfirst(get_relids((Rel)lfirst(temp)))); + Assert(lnext(get_relids((Rel) lfirst(temp))) == LispNil); + allrelids = lappend(allrelids, + lfirst(get_relids((Rel) lfirst(temp)))); } - - /* find all relids referenced in query but not in clause */ - if (!referenced) - referenced = xfunc_find_references(clause); - unreferenced = set_difference(allrelids, referenced); - - return(xfunc_card_product(unreferenced)); + + /* find all relids referenced in query but not in clause */ + if (!referenced) + referenced = xfunc_find_references(clause); + unreferenced = set_difference(allrelids, referenced); + + return (xfunc_card_product(unreferenced)); } /* - ** xfunc_card_product + ** xfunc_card_product ** multiple together cardinalities of a list relations. */ -Count xfunc_card_product(Query *queryInfo, Relid relids) +Count +xfunc_card_product(Query * queryInfo, Relid relids) { - LispValue cinfonode; - LispValue temp; - Rel currel; - Cost tuples; - Count retval = 0; - - foreach(temp,relids) { - currel = get_rel(lfirst(temp)); - tuples = get_tuples(currel); - - if (tuples) { /* not of cardinality 0 */ - /* factor in the selectivity of all zero-cost clauses */ - foreach (cinfonode, get_clauseinfo(currel)) { - if (!xfunc_expense(queryInfo,get_clause((CInfo)lfirst(cinfonode)))) - tuples *= - compute_clause_selec(queryInfo, - get_clause((CInfo)lfirst(cinfonode)), - LispNil); - } - - if (retval == 0) retval = tuples; - else retval *= tuples; + LispValue cinfonode; + LispValue temp; + Rel currel; + Cost tuples; + Count retval = 0; + + foreach(temp, relids) + { + currel = get_rel(lfirst(temp)); + tuples = get_tuples(currel); + + if (tuples) + { /* not of cardinality 0 */ + /* factor in the selectivity of all zero-cost clauses */ + foreach(cinfonode, get_clauseinfo(currel)) + { + if (!xfunc_expense(queryInfo, get_clause((CInfo) lfirst(cinfonode)))) + tuples *= + compute_clause_selec(queryInfo, + get_clause((CInfo) lfirst(cinfonode)), + LispNil); + } + + if (retval == 0) + retval = tuples; + else + retval *= tuples; + } } - } - if (retval == 0) retval = 1; /* saves caller from dividing by zero */ - return(retval); + if (retval == 0) + retval = 1; /* saves caller from dividing by zero */ + return (retval); } @@ -703,48 +805,60 @@ Count xfunc_card_product(Query *queryInfo, Relid relids) ** xfunc_find_references: ** Traverse a clause and find all relids referenced in the clause. */ -List xfunc_find_references(LispValue clause) +List +xfunc_find_references(LispValue clause) { - List retval = (List)LispNil; - LispValue tmpclause; - - /* Base cases */ - if (IsA(clause,Var)) - return(lispCons(lfirst(get_varid((Var)clause)), LispNil)); - else if (IsA(clause,Const) || IsA(clause,Param)) - return((List)LispNil); - - /* recursion */ - else if (IsA(clause,Iter)) - /* Too low. Should multiply by the expected number of iterations. maybe */ - return(xfunc_find_references(get_iterexpr((Iter)clause))); - else if (IsA(clause,ArrayRef)) - return(xfunc_find_references(get_refexpr((ArrayRef)clause))); - else if (fast_is_clause(clause)) { - /* string together result of all operands of Oper */ - for (tmpclause = (LispValue)get_opargs(clause); tmpclause != LispNil; - tmpclause = lnext(tmpclause)) - retval = nconc(retval, xfunc_find_references(lfirst(tmpclause))); - return(retval); - }else if (fast_is_funcclause(clause)) { - /* string together result of all args of Func */ - for (tmpclause = (LispValue)get_funcargs(clause); - tmpclause != LispNil; - tmpclause = lnext(tmpclause)) - retval = nconc(retval, xfunc_find_references(lfirst(tmpclause))); - return(retval); - }else if (fast_not_clause(clause)) - return(xfunc_find_references(lsecond(clause))); - else if (fast_or_clause(clause)) { - /* string together result of all operands of OR */ - for (tmpclause = lnext(clause); tmpclause != LispNil; - tmpclause = lnext(tmpclause)) - retval = nconc(retval, xfunc_find_references(lfirst(tmpclause))); - return(retval); - }else { - elog(WARN, "Clause node of undetermined type"); - return((List)LispNil); - } + List retval = (List) LispNil; + LispValue tmpclause; + + /* Base cases */ + if (IsA(clause, Var)) + return (lispCons(lfirst(get_varid((Var) clause)), LispNil)); + else if (IsA(clause, Const) || IsA(clause, Param)) + return ((List) LispNil); + + /* recursion */ + else if (IsA(clause, Iter)) + + /* + * Too low. Should multiply by the expected number of iterations. + * maybe + */ + return (xfunc_find_references(get_iterexpr((Iter) clause))); + else if (IsA(clause, ArrayRef)) + return (xfunc_find_references(get_refexpr((ArrayRef) clause))); + else if (fast_is_clause(clause)) + { + /* string together result of all operands of Oper */ + for (tmpclause = (LispValue) get_opargs(clause); tmpclause != LispNil; + tmpclause = lnext(tmpclause)) + retval = nconc(retval, xfunc_find_references(lfirst(tmpclause))); + return (retval); + } + else if (fast_is_funcclause(clause)) + { + /* string together result of all args of Func */ + for (tmpclause = (LispValue) get_funcargs(clause); + tmpclause != LispNil; + tmpclause = lnext(tmpclause)) + retval = nconc(retval, xfunc_find_references(lfirst(tmpclause))); + return (retval); + } + else if (fast_not_clause(clause)) + return (xfunc_find_references(lsecond(clause))); + else if (fast_or_clause(clause)) + { + /* string together result of all operands of OR */ + for (tmpclause = lnext(clause); tmpclause != LispNil; + tmpclause = lnext(tmpclause)) + retval = nconc(retval, xfunc_find_references(lfirst(tmpclause))); + return (retval); + } + else + { + elog(WARN, "Clause node of undetermined type"); + return ((List) LispNil); + } } /* @@ -753,212 +867,219 @@ List xfunc_find_references(LispValue clause) ** min rank Hash or Merge clause, while for Nested Loop it's the ** min rank pathclause */ -LispValue xfunc_primary_join(JoinPath pathnode) +LispValue +xfunc_primary_join(JoinPath pathnode) { - LispValue joinclauselist = get_pathclauseinfo(pathnode); - CInfo mincinfo; - LispValue tmplist; - LispValue minclause = LispNil; - Cost minrank, tmprank; - - if (IsA(pathnode,MergePath)) + LispValue joinclauselist = get_pathclauseinfo(pathnode); + CInfo mincinfo; + LispValue tmplist; + LispValue minclause = LispNil; + Cost minrank, + tmprank; + + if (IsA(pathnode, MergePath)) { - for(tmplist = get_path_mergeclauses((MergePath)pathnode), - minclause = lfirst(tmplist), - minrank = xfunc_rank(minclause); - tmplist != LispNil; - tmplist = lnext(tmplist)) - if ((tmprank = xfunc_rank(lfirst(tmplist))) - < minrank) - { - minrank = tmprank; - minclause = lfirst(tmplist); - } - return(minclause); + for (tmplist = get_path_mergeclauses((MergePath) pathnode), + minclause = lfirst(tmplist), + minrank = xfunc_rank(minclause); + tmplist != LispNil; + tmplist = lnext(tmplist)) + if ((tmprank = xfunc_rank(lfirst(tmplist))) + < minrank) + { + minrank = tmprank; + minclause = lfirst(tmplist); + } + return (minclause); } - else if (IsA(pathnode,HashPath)) + else if (IsA(pathnode, HashPath)) { - for(tmplist = get_path_hashclauses((HashPath)pathnode), - minclause = lfirst(tmplist), - minrank = xfunc_rank(minclause); - tmplist != LispNil; - tmplist = lnext(tmplist)) - if ((tmprank = xfunc_rank(lfirst(tmplist))) - < minrank) - { - minrank = tmprank; - minclause = lfirst(tmplist); - } - return(minclause); + for (tmplist = get_path_hashclauses((HashPath) pathnode), + minclause = lfirst(tmplist), + minrank = xfunc_rank(minclause); + tmplist != LispNil; + tmplist = lnext(tmplist)) + if ((tmprank = xfunc_rank(lfirst(tmplist))) + < minrank) + { + minrank = tmprank; + minclause = lfirst(tmplist); + } + return (minclause); } - - /* if we drop through, it's nested loop join */ - if (joinclauselist == LispNil) - return(LispNil); - - for(tmplist = joinclauselist, mincinfo = (CInfo) lfirst(joinclauselist), - minrank = xfunc_rank(get_clause((CInfo) lfirst(tmplist))); - tmplist != LispNil; - tmplist = lnext(tmplist)) - if ((tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist)))) - < minrank) - { - minrank = tmprank; - mincinfo = (CInfo) lfirst(tmplist); - } - return((LispValue)get_clause(mincinfo)); + + /* if we drop through, it's nested loop join */ + if (joinclauselist == LispNil) + return (LispNil); + + for (tmplist = joinclauselist, mincinfo = (CInfo) lfirst(joinclauselist), + minrank = xfunc_rank(get_clause((CInfo) lfirst(tmplist))); + tmplist != LispNil; + tmplist = lnext(tmplist)) + if ((tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist)))) + < minrank) + { + minrank = tmprank; + mincinfo = (CInfo) lfirst(tmplist); + } + return ((LispValue) get_clause(mincinfo)); } /* ** xfunc_get_path_cost ** get the expensive function costs of the path */ -Cost xfunc_get_path_cost(Query *queryInfo, Path pathnode) +Cost +xfunc_get_path_cost(Query * queryInfo, Path pathnode) { - Cost cost = 0; - LispValue tmplist; - Cost selec = 1.0; - - /* - ** first add in the expensive local function costs. - ** We ensure that the clauses are sorted by rank, so that we - ** know (via selectivities) the number of tuples that will be checked - ** by each function. If we're not doing any optimization of expensive - ** functions, we don't sort. - */ - if (XfuncMode != XFUNC_OFF) - set_locclauseinfo(pathnode, lisp_qsort(get_locclauseinfo(pathnode), - xfunc_cinfo_compare)); - for(tmplist = get_locclauseinfo(pathnode), selec = 1.0; - tmplist != LispNil; - tmplist = lnext(tmplist)) + Cost cost = 0; + LispValue tmplist; + Cost selec = 1.0; + + /* + * * first add in the expensive local function costs. * We ensure that + * the clauses are sorted by rank, so that we * know (via + * selectivities) the number of tuples that will be checked * by each + * function. If we're not doing any optimization of expensive * + * functions, we don't sort. + */ + if (XfuncMode != XFUNC_OFF) + set_locclauseinfo(pathnode, lisp_qsort(get_locclauseinfo(pathnode), + xfunc_cinfo_compare)); + for (tmplist = get_locclauseinfo(pathnode), selec = 1.0; + tmplist != LispNil; + tmplist = lnext(tmplist)) { - cost += (Cost)(xfunc_local_expense(get_clause((CInfo)lfirst(tmplist))) - * (Cost)get_tuples(get_parent(pathnode)) * selec); - selec *= compute_clause_selec(queryInfo, - get_clause((CInfo)lfirst(tmplist)), - LispNil); + cost += (Cost) (xfunc_local_expense(get_clause((CInfo) lfirst(tmplist))) + * (Cost) get_tuples(get_parent(pathnode)) * selec); + selec *= compute_clause_selec(queryInfo, + get_clause((CInfo) lfirst(tmplist)), + LispNil); } - - /* - ** Now add in any node-specific expensive function costs. - ** Again, we must ensure that the clauses are sorted by rank. - */ - if (IsA(pathnode,JoinPath)) + + /* + * * Now add in any node-specific expensive function costs. * Again, + * we must ensure that the clauses are sorted by rank. + */ + if (IsA(pathnode, JoinPath)) { - if (XfuncMode != XFUNC_OFF) - set_pathclauseinfo((JoinPath)pathnode, lisp_qsort - (get_pathclauseinfo((JoinPath)pathnode), - xfunc_cinfo_compare)); - for(tmplist = get_pathclauseinfo((JoinPath)pathnode), selec = 1.0; - tmplist != LispNil; - tmplist = lnext(tmplist)) + if (XfuncMode != XFUNC_OFF) + set_pathclauseinfo((JoinPath) pathnode, lisp_qsort + (get_pathclauseinfo((JoinPath) pathnode), + xfunc_cinfo_compare)); + for (tmplist = get_pathclauseinfo((JoinPath) pathnode), selec = 1.0; + tmplist != LispNil; + tmplist = lnext(tmplist)) { - cost += (Cost)(xfunc_local_expense(get_clause((CInfo)lfirst(tmplist))) - * (Cost)get_tuples(get_parent(pathnode)) * selec); - selec *= compute_clause_selec(queryInfo, - get_clause((CInfo)lfirst(tmplist)), - LispNil); + cost += (Cost) (xfunc_local_expense(get_clause((CInfo) lfirst(tmplist))) + * (Cost) get_tuples(get_parent(pathnode)) * selec); + selec *= compute_clause_selec(queryInfo, + get_clause((CInfo) lfirst(tmplist)), + LispNil); } } - if (IsA(pathnode,HashPath)) + if (IsA(pathnode, HashPath)) { - if (XfuncMode != XFUNC_OFF) - set_path_hashclauses - ((HashPath)pathnode, - lisp_qsort(get_path_hashclauses((HashPath)pathnode), - xfunc_clause_compare)); - for(tmplist = get_path_hashclauses((HashPath)pathnode), selec = 1.0; - tmplist != LispNil; - tmplist = lnext(tmplist)) + if (XfuncMode != XFUNC_OFF) + set_path_hashclauses + ((HashPath) pathnode, + lisp_qsort(get_path_hashclauses((HashPath) pathnode), + xfunc_clause_compare)); + for (tmplist = get_path_hashclauses((HashPath) pathnode), selec = 1.0; + tmplist != LispNil; + tmplist = lnext(tmplist)) { - cost += (Cost)(xfunc_local_expense(lfirst(tmplist)) - * (Cost)get_tuples(get_parent(pathnode)) * selec); - selec *= compute_clause_selec(queryInfo, - lfirst(tmplist), LispNil); + cost += (Cost) (xfunc_local_expense(lfirst(tmplist)) + * (Cost) get_tuples(get_parent(pathnode)) * selec); + selec *= compute_clause_selec(queryInfo, + lfirst(tmplist), LispNil); } } - if (IsA(pathnode,MergePath)) + if (IsA(pathnode, MergePath)) { - if (XfuncMode != XFUNC_OFF) - set_path_mergeclauses - ((MergePath)pathnode, - lisp_qsort(get_path_mergeclauses((MergePath)pathnode), - xfunc_clause_compare)); - for(tmplist = get_path_mergeclauses((MergePath)pathnode), selec = 1.0; - tmplist != LispNil; - tmplist = lnext(tmplist)) + if (XfuncMode != XFUNC_OFF) + set_path_mergeclauses + ((MergePath) pathnode, + lisp_qsort(get_path_mergeclauses((MergePath) pathnode), + xfunc_clause_compare)); + for (tmplist = get_path_mergeclauses((MergePath) pathnode), selec = 1.0; + tmplist != LispNil; + tmplist = lnext(tmplist)) { - cost += (Cost)(xfunc_local_expense(lfirst(tmplist)) - * (Cost)get_tuples(get_parent(pathnode)) * selec); - selec *= compute_clause_selec(queryInfo, - lfirst(tmplist), LispNil); + cost += (Cost) (xfunc_local_expense(lfirst(tmplist)) + * (Cost) get_tuples(get_parent(pathnode)) * selec); + selec *= compute_clause_selec(queryInfo, + lfirst(tmplist), LispNil); } } - Assert(cost >= 0); - return(cost); + Assert(cost >= 0); + return (cost); } /* - ** Recalculate the cost of a path node. This includes the basic cost of the + ** Recalculate the cost of a path node. This includes the basic cost of the ** node, as well as the cost of its expensive functions. ** We need to do this to the parent after pulling a clause from a child into a ** parent. Thus we should only be calling this function on JoinPaths. */ -Cost xfunc_total_path_cost(JoinPath pathnode) +Cost +xfunc_total_path_cost(JoinPath pathnode) { - Cost cost = xfunc_get_path_cost((Path)pathnode); - - Assert(IsA(pathnode,JoinPath)); - if (IsA(pathnode,MergePath)) + Cost cost = xfunc_get_path_cost((Path) pathnode); + + Assert(IsA(pathnode, JoinPath)); + if (IsA(pathnode, MergePath)) { - MergePath mrgnode = (MergePath)pathnode; - cost += cost_mergesort(get_path_cost((Path)get_outerjoinpath(mrgnode)), - get_path_cost((Path)get_innerjoinpath(mrgnode)), - get_outersortkeys(mrgnode), - get_innersortkeys(mrgnode), - get_tuples(get_parent((Path)get_outerjoinpath - (mrgnode))), - get_tuples(get_parent((Path)get_innerjoinpath - (mrgnode))), - get_width(get_parent((Path)get_outerjoinpath - (mrgnode))), - get_width(get_parent((Path)get_innerjoinpath - (mrgnode)))); - Assert(cost >= 0); - return(cost); + MergePath mrgnode = (MergePath) pathnode; + + cost += cost_mergesort(get_path_cost((Path) get_outerjoinpath(mrgnode)), + get_path_cost((Path) get_innerjoinpath(mrgnode)), + get_outersortkeys(mrgnode), + get_innersortkeys(mrgnode), + get_tuples(get_parent((Path) get_outerjoinpath + (mrgnode))), + get_tuples(get_parent((Path) get_innerjoinpath + (mrgnode))), + get_width(get_parent((Path) get_outerjoinpath + (mrgnode))), + get_width(get_parent((Path) get_innerjoinpath + (mrgnode)))); + Assert(cost >= 0); + return (cost); } - else if (IsA(pathnode,HashPath)) + else if (IsA(pathnode, HashPath)) { - HashPath hashnode = (HashPath)pathnode; - cost += cost_hashjoin(get_path_cost((Path)get_outerjoinpath(hashnode)), - get_path_cost((Path)get_innerjoinpath(hashnode)), - get_outerhashkeys(hashnode), - get_innerhashkeys(hashnode), - get_tuples(get_parent((Path)get_outerjoinpath - (hashnode))), - get_tuples(get_parent((Path)get_innerjoinpath - (hashnode))), - get_width(get_parent((Path)get_outerjoinpath - (hashnode))), - get_width(get_parent((Path)get_innerjoinpath - (hashnode)))); - Assert (cost >= 0); - return(cost); + HashPath hashnode = (HashPath) pathnode; + + cost += cost_hashjoin(get_path_cost((Path) get_outerjoinpath(hashnode)), + get_path_cost((Path) get_innerjoinpath(hashnode)), + get_outerhashkeys(hashnode), + get_innerhashkeys(hashnode), + get_tuples(get_parent((Path) get_outerjoinpath + (hashnode))), + get_tuples(get_parent((Path) get_innerjoinpath + (hashnode))), + get_width(get_parent((Path) get_outerjoinpath + (hashnode))), + get_width(get_parent((Path) get_innerjoinpath + (hashnode)))); + Assert(cost >= 0); + return (cost); } - else /* Nested Loop Join */ + else +/* Nested Loop Join */ { - cost += cost_nestloop(get_path_cost((Path)get_outerjoinpath(pathnode)), - get_path_cost((Path)get_innerjoinpath(pathnode)), - get_tuples(get_parent((Path)get_outerjoinpath - (pathnode))), - get_tuples(get_parent((Path)get_innerjoinpath - (pathnode))), - get_pages(get_parent((Path)get_outerjoinpath - (pathnode))), - IsA(get_innerjoinpath(pathnode),IndexPath)); - Assert(cost >= 0); - return(cost); + cost += cost_nestloop(get_path_cost((Path) get_outerjoinpath(pathnode)), + get_path_cost((Path) get_innerjoinpath(pathnode)), + get_tuples(get_parent((Path) get_outerjoinpath + (pathnode))), + get_tuples(get_parent((Path) get_innerjoinpath + (pathnode))), + get_pages(get_parent((Path) get_outerjoinpath + (pathnode))), + IsA(get_innerjoinpath(pathnode), IndexPath)); + Assert(cost >= 0); + return (cost); } } @@ -967,7 +1088,7 @@ Cost xfunc_total_path_cost(JoinPath pathnode) ** xfunc_expense_per_tuple -- ** return the expense of the join *per-tuple* of the input relation. ** The cost model here is that a join costs - ** k*card(outer)*card(inner) + l*card(outer) + m*card(inner) + n + ** k*card(outer)*card(inner) + l*card(outer) + m*card(inner) + n ** ** We treat the l and m terms by considering them to be like restrictions ** constrained to be right under the join. Thus the cost per inner and @@ -975,138 +1096,146 @@ Cost xfunc_total_path_cost(JoinPath pathnode) ** ** The cost per tuple of outer is k + l/referenced(inner). Cost per tuple ** of inner is k + m/referenced(outer). - ** The constants k, l, m and n depend on the join method. Measures here are + ** The constants k, l, m and n depend on the join method. Measures here are ** based on the costs in costsize.c, with fudging for HashJoin and Sorts to ** make it fit our model (the 'q' in HashJoin results in a ** card(outer)/card(inner) term, and sorting results in a log term. - + */ -Cost xfunc_expense_per_tuple(JoinPath joinnode, int whichchild) +Cost +xfunc_expense_per_tuple(JoinPath joinnode, int whichchild) { - Rel outerrel = get_parent((Path)get_outerjoinpath(joinnode)); - Rel innerrel = get_parent((Path)get_innerjoinpath(joinnode)); - Count outerwidth = get_width(outerrel); - Count outers_per_page = ceil(BLCKSZ/(outerwidth + sizeof(HeapTupleData))); - - if (IsA(joinnode,HashPath)) + Rel outerrel = get_parent((Path) get_outerjoinpath(joinnode)); + Rel innerrel = get_parent((Path) get_innerjoinpath(joinnode)); + Count outerwidth = get_width(outerrel); + Count outers_per_page = ceil(BLCKSZ / (outerwidth + sizeof(HeapTupleData))); + + if (IsA(joinnode, HashPath)) { - if (whichchild == INNER) - return((1 + _CPU_PAGE_WEIGHT_)*outers_per_page/NBuffers); - else - return(((1 + _CPU_PAGE_WEIGHT_)*outers_per_page/NBuffers) - + _CPU_PAGE_WEIGHT_ - / xfunc_card_product(get_relids(innerrel))); + if (whichchild == INNER) + return ((1 + _CPU_PAGE_WEIGHT_) * outers_per_page / NBuffers); + else + return (((1 + _CPU_PAGE_WEIGHT_) * outers_per_page / NBuffers) + + _CPU_PAGE_WEIGHT_ + / xfunc_card_product(get_relids(innerrel))); } - else if (IsA(joinnode,MergePath)) + else if (IsA(joinnode, MergePath)) { - /* assumes sort exists, and costs one (I/O + CPU) per tuple */ - if (whichchild == INNER) - return((2*_CPU_PAGE_WEIGHT_ + 1) - / xfunc_card_product(get_relids(outerrel))); - else - return((2*_CPU_PAGE_WEIGHT_ + 1) - / xfunc_card_product(get_relids(innerrel))); + /* assumes sort exists, and costs one (I/O + CPU) per tuple */ + if (whichchild == INNER) + return ((2 * _CPU_PAGE_WEIGHT_ + 1) + / xfunc_card_product(get_relids(outerrel))); + else + return ((2 * _CPU_PAGE_WEIGHT_ + 1) + / xfunc_card_product(get_relids(innerrel))); } - else /* nestloop */ + else +/* nestloop */ { - Assert(IsA(joinnode,JoinPath)); - return(_CPU_PAGE_WEIGHT_); + Assert(IsA(joinnode, JoinPath)); + return (_CPU_PAGE_WEIGHT_); } } /* ** xfunc_fixvars -- - ** After pulling up a clause, we must walk its expression tree, fixing Var + ** After pulling up a clause, we must walk its expression tree, fixing Var ** nodes to point to the correct varno (either INNER or OUTER, depending - ** on which child the clause was pulled from), and the right varattno in the + ** on which child the clause was pulled from), and the right varattno in the ** target list of the child's former relation. If the target list of the ** child Rel does not contain the attribute we need, we add it. */ -void xfunc_fixvars(LispValue clause, /* clause being pulled up */ - Rel rel, /* rel it's being pulled from */ - int varno) /* whether rel is INNER or OUTER of join */ +void +xfunc_fixvars(LispValue clause, /* clause being pulled up */ + Rel rel, /* rel it's being pulled from */ + int varno) /* whether rel is INNER or OUTER of join */ { - LispValue tmpclause; /* temporary variable */ - TargetEntry *tle; /* tlist member corresponding to var */ - - - if (IsA(clause,Const) || IsA(clause,Param)) return; - else if (IsA(clause,Var)) + LispValue tmpclause; /* temporary variable */ + TargetEntry *tle; /* tlist member corresponding to var */ + + + if (IsA(clause, Const) || IsA(clause, Param)) + return; + else if (IsA(clause, Var)) { - /* here's the meat */ - tle = tlistentry_member((Var)clause, get_targetlist(rel)); - if (tle == LispNil) + /* here's the meat */ + tle = tlistentry_member((Var) clause, get_targetlist(rel)); + if (tle == LispNil) { - /* - ** The attribute we need is not in the target list, - ** so we have to add it. - ** - */ - add_tl_element(rel, (Var)clause); - tle = tlistentry_member((Var)clause, get_targetlist(rel)); + + /* + * * The attribute we need is not in the target list, * so we + * have to add it. * + * + */ + add_tl_element(rel, (Var) clause); + tle = tlistentry_member((Var) clause, get_targetlist(rel)); } - set_varno(((Var)clause), varno); - set_varattno(((Var)clause), get_resno(get_resdom(get_entry(tle)))); + set_varno(((Var) clause), varno); + set_varattno(((Var) clause), get_resno(get_resdom(get_entry(tle)))); } - else if (IsA(clause,Iter)) - xfunc_fixvars(get_iterexpr((Iter)clause), rel, varno); - else if (fast_is_clause(clause)) + else if (IsA(clause, Iter)) + xfunc_fixvars(get_iterexpr((Iter) clause), rel, varno); + else if (fast_is_clause(clause)) { - xfunc_fixvars(lfirst(lnext(clause)), rel, varno); - xfunc_fixvars(lfirst(lnext(lnext(clause))), rel, varno); + xfunc_fixvars(lfirst(lnext(clause)), rel, varno); + xfunc_fixvars(lfirst(lnext(lnext(clause))), rel, varno); } - else if (fast_is_funcclause(clause)) - for (tmpclause = lnext(clause); tmpclause != LispNil; - tmpclause = lnext(tmpclause)) - xfunc_fixvars(lfirst(tmpclause), rel, varno); - else if (fast_not_clause(clause)) - xfunc_fixvars(lsecond(clause), rel, varno); - else if (fast_or_clause(clause)) - for (tmpclause = lnext(clause); tmpclause != LispNil; - tmpclause = lnext(tmpclause)) - xfunc_fixvars(lfirst(tmpclause), rel, varno); - else + else if (fast_is_funcclause(clause)) + for (tmpclause = lnext(clause); tmpclause != LispNil; + tmpclause = lnext(tmpclause)) + xfunc_fixvars(lfirst(tmpclause), rel, varno); + else if (fast_not_clause(clause)) + xfunc_fixvars(lsecond(clause), rel, varno); + else if (fast_or_clause(clause)) + for (tmpclause = lnext(clause); tmpclause != LispNil; + tmpclause = lnext(tmpclause)) + xfunc_fixvars(lfirst(tmpclause), rel, varno); + else { - elog(WARN, "Clause node of undetermined type"); + elog(WARN, "Clause node of undetermined type"); } } /* ** Comparison function for lisp_qsort() on a list of CInfo's. - ** arg1 and arg2 should really be of type (CInfo *). + ** arg1 and arg2 should really be of type (CInfo *). */ -int xfunc_cinfo_compare(void *arg1, void *arg2) +int +xfunc_cinfo_compare(void *arg1, void *arg2) { - CInfo info1 = *(CInfo *) arg1; - CInfo info2 = *(CInfo *) arg2; - - LispValue clause1 = (LispValue) get_clause(info1), - clause2 = (LispValue) get_clause(info2); - - return(xfunc_clause_compare((void *) &clause1, (void *) &clause2)); + CInfo info1 = *(CInfo *) arg1; + CInfo info2 = *(CInfo *) arg2; + + LispValue clause1 = (LispValue) get_clause(info1), + clause2 = (LispValue) get_clause(info2); + + return (xfunc_clause_compare((void *) &clause1, (void *) &clause2)); } /* - ** xfunc_clause_compare: comparison function for lisp_qsort() that compares two + ** xfunc_clause_compare: comparison function for lisp_qsort() that compares two ** clauses based on expense/(1 - selectivity) ** arg1 and arg2 are really pointers to clauses. */ -int xfunc_clause_compare(void *arg1, void *arg2) +int +xfunc_clause_compare(void *arg1, void *arg2) { - LispValue clause1 = *(LispValue *) arg1; - LispValue clause2 = *(LispValue *) arg2; - Cost rank1, /* total xfunc rank of clause1 */ - rank2; /* total xfunc rank of clause2 */ - - rank1 = xfunc_rank(clause1); - rank2 = xfunc_rank(clause2); - - if ( rank1 < rank2) - return(-1); - else if (rank1 == rank2) - return(0); - else return(1); + LispValue clause1 = *(LispValue *) arg1; + LispValue clause2 = *(LispValue *) arg2; + Cost rank1, /* total xfunc rank of clause1 */ + rank2; /* total xfunc rank of clause2 */ + + rank1 = xfunc_rank(clause1); + rank2 = xfunc_rank(clause2); + + if (rank1 < rank2) + return (-1); + else if (rank1 == rank2) + return (0); + else + return (1); } /* @@ -1115,58 +1244,62 @@ int xfunc_clause_compare(void *arg1, void *arg2) ** (this assumes the predicates have been converted to Conjunctive NF) ** Modifies the clause list! */ -void xfunc_disjunct_sort(LispValue clause_list) +void +xfunc_disjunct_sort(LispValue clause_list) { - LispValue temp; - - foreach(temp, clause_list) - if(or_clause(lfirst(temp))) - lnext(lfirst(temp)) = - lisp_qsort(lnext(lfirst(temp)), xfunc_disjunct_compare); + LispValue temp; + + foreach(temp, clause_list) + if (or_clause(lfirst(temp))) + lnext(lfirst(temp)) = + lisp_qsort(lnext(lfirst(temp)), xfunc_disjunct_compare); } /* - ** xfunc_disjunct_compare: comparison function for qsort() that compares two + ** xfunc_disjunct_compare: comparison function for qsort() that compares two ** disjuncts based on cost/selec. ** arg1 and arg2 are really pointers to disjuncts */ -int xfunc_disjunct_compare(Query* queryInfo, void *arg1, void *arg2) +int +xfunc_disjunct_compare(Query * queryInfo, void *arg1, void *arg2) { - LispValue disjunct1 = *(LispValue *) arg1; - LispValue disjunct2 = *(LispValue *) arg2; - Cost cost1, /* total cost of disjunct1 */ - cost2, /* total cost of disjunct2 */ - selec1, - selec2; - Cost rank1, rank2; - - cost1 = xfunc_expense(queryInfo, disjunct1); - cost2 = xfunc_expense(queryInfo, disjunct2); - selec1 = compute_clause_selec(queryInfo, - disjunct1, LispNil); - selec2 = compute_clause_selec(queryInfo, - disjunct2, LispNil); - - if (selec1 == 0) - rank1 = MAXFLOAT; - else if (cost1 == 0) - rank1 = 0; - else - rank1 = cost1/selec1; - - if (selec2 == 0) - rank2 = MAXFLOAT; - else if (cost2 == 0) - rank2 = 0; - else - rank2 = cost2/selec2; - - if ( rank1 < rank2) - return(-1); - else if (rank1 == rank2) - return(0); - else return(1); + LispValue disjunct1 = *(LispValue *) arg1; + LispValue disjunct2 = *(LispValue *) arg2; + Cost cost1, /* total cost of disjunct1 */ + cost2, /* total cost of disjunct2 */ + selec1, + selec2; + Cost rank1, + rank2; + + cost1 = xfunc_expense(queryInfo, disjunct1); + cost2 = xfunc_expense(queryInfo, disjunct2); + selec1 = compute_clause_selec(queryInfo, + disjunct1, LispNil); + selec2 = compute_clause_selec(queryInfo, + disjunct2, LispNil); + + if (selec1 == 0) + rank1 = MAXFLOAT; + else if (cost1 == 0) + rank1 = 0; + else + rank1 = cost1 / selec1; + + if (selec2 == 0) + rank2 = MAXFLOAT; + else if (cost2 == 0) + rank2 = 0; + else + rank2 = cost2 / selec2; + + if (rank1 < rank2) + return (-1); + else if (rank1 == rank2) + return (0); + else + return (1); } /* ------------------------ UTILITY FUNCTIONS ------------------------------- */ @@ -1174,182 +1307,197 @@ int xfunc_disjunct_compare(Query* queryInfo, void *arg1, void *arg2) ** xfunc_func_width -- ** Given a function OID and operands, find the width of the return value. */ -int xfunc_func_width(RegProcedure funcid, LispValue args) +int +xfunc_func_width(RegProcedure funcid, LispValue args) { - Relation rd; /* Relation Descriptor */ - HeapTuple tupl; /* structure to hold a cached tuple */ - Form_pg_proc proc; /* structure to hold the pg_proc tuple */ - TypeTupleForm type; /* structure to hold the pg_type tuple */ - LispValue tmpclause; - int retval; - - /* lookup function and find its return type */ - Assert(RegProcedureIsValid(funcid)); - tupl = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid), 0,0,0); - if (!HeapTupleIsValid(tupl)) - elog(WARN, "Cache lookup failed for procedure %d", funcid); - proc = (Form_pg_proc) GETSTRUCT(tupl); - - /* if function returns a tuple, get the width of that */ - if (typeid_get_relid(proc->prorettype)) + Relation rd; /* Relation Descriptor */ + HeapTuple tupl; /* structure to hold a cached tuple */ + Form_pg_proc proc; /* structure to hold the pg_proc tuple */ + TypeTupleForm type; /* structure to hold the pg_type tuple */ + LispValue tmpclause; + int retval; + + /* lookup function and find its return type */ + Assert(RegProcedureIsValid(funcid)); + tupl = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid), 0, 0, 0); + if (!HeapTupleIsValid(tupl)) + elog(WARN, "Cache lookup failed for procedure %d", funcid); + proc = (Form_pg_proc) GETSTRUCT(tupl); + + /* if function returns a tuple, get the width of that */ + if (typeid_get_relid(proc->prorettype)) { - rd = heap_open(typeid_get_relid(proc->prorettype)); - retval = xfunc_tuple_width(rd); - heap_close(rd); - goto exit; + rd = heap_open(typeid_get_relid(proc->prorettype)); + retval = xfunc_tuple_width(rd); + heap_close(rd); + goto exit; } - else /* function returns a base type */ + else +/* function returns a base type */ { - tupl = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(proc->prorettype), - 0,0,0); - if (!HeapTupleIsValid(tupl)) - elog(WARN, "Cache lookup failed for type %d", proc->prorettype); - type = (TypeTupleForm) GETSTRUCT(tupl); - /* if the type length is known, return that */ - if (type->typlen != -1) + tupl = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(proc->prorettype), + 0, 0, 0); + if (!HeapTupleIsValid(tupl)) + elog(WARN, "Cache lookup failed for type %d", proc->prorettype); + type = (TypeTupleForm) GETSTRUCT(tupl); + /* if the type length is known, return that */ + if (type->typlen != -1) { - retval = type->typlen; - goto exit; + retval = type->typlen; + goto exit; } - else /* estimate the return size */ + else +/* estimate the return size */ { - /* find width of the function's arguments */ - for (tmpclause = args; tmpclause != LispNil; - tmpclause = lnext(tmpclause)) - retval += xfunc_width(lfirst(tmpclause)); - /* multiply by outin_ratio */ - retval = (int)(proc->prooutin_ratio/100.0 * retval); - goto exit; + /* find width of the function's arguments */ + for (tmpclause = args; tmpclause != LispNil; + tmpclause = lnext(tmpclause)) + retval += xfunc_width(lfirst(tmpclause)); + /* multiply by outin_ratio */ + retval = (int) (proc->prooutin_ratio / 100.0 * retval); + goto exit; } } - exit: - return(retval); +exit: + return (retval); } /* ** xfunc_tuple_width -- - ** Return the sum of the lengths of all the attributes of a given relation + ** Return the sum of the lengths of all the attributes of a given relation */ -int xfunc_tuple_width(Relation rd) +int +xfunc_tuple_width(Relation rd) { - int i; - int retval = 0; - TupleDesc tdesc = RelationGetTupleDescriptor(rd); - - for (i = 0; i < tdesc->natts; i++) + int i; + int retval = 0; + TupleDesc tdesc = RelationGetTupleDescriptor(rd); + + for (i = 0; i < tdesc->natts; i++) { - if (tdesc->attrs[i]->attlen != -1) - retval += tdesc->attrs[i]->attlen; - else retval += VARLEN_DEFAULT; + if (tdesc->attrs[i]->attlen != -1) + retval += tdesc->attrs[i]->attlen; + else + retval += VARLEN_DEFAULT; } - - return(retval); + + return (retval); } /* ** xfunc_num_join_clauses -- ** Find the number of join clauses associated with this join path */ -int xfunc_num_join_clauses(JoinPath path) +int +xfunc_num_join_clauses(JoinPath path) { - int num = length(get_pathclauseinfo(path)); - if (IsA(path,MergePath)) - return(num + length(get_path_mergeclauses((MergePath)path))); - else if (IsA(path,HashPath)) - return(num + length(get_path_hashclauses((HashPath)path))); - else return(num); + int num = length(get_pathclauseinfo(path)); + + if (IsA(path, MergePath)) + return (num + length(get_path_mergeclauses((MergePath) path))); + else if (IsA(path, HashPath)) + return (num + length(get_path_hashclauses((HashPath) path))); + else + return (num); } /* ** xfunc_LispRemove -- ** Just like LispRemove, but it whines if the item to be removed ain't there */ -LispValue xfunc_LispRemove(LispValue foo, List bar) +LispValue +xfunc_LispRemove(LispValue foo, List bar) { - LispValue temp = LispNil; - LispValue result = LispNil; - int sanity = false; - - for (temp = bar; !null(temp); temp = lnext(temp)) - if (! equal((Node)(foo),(Node)(lfirst(temp))) ) - { - result = lappend(result,lfirst(temp)); - } - else sanity = true; /* found a matching item to remove! */ - - if (!sanity) - elog(WARN, "xfunc_LispRemove: didn't find a match!"); - - return(result); + LispValue temp = LispNil; + LispValue result = LispNil; + int sanity = false; + + for (temp = bar; !null(temp); temp = lnext(temp)) + if (!equal((Node) (foo), (Node) (lfirst(temp)))) + { + result = lappend(result, lfirst(temp)); + } + else + sanity = true; /* found a matching item to remove! */ + + if (!sanity) + elog(WARN, "xfunc_LispRemove: didn't find a match!"); + + return (result); } #define Node_Copy(a, b, c, d) \ - if (NodeCopy((Node)((a)->d), (Node*)&((b)->d), c) != true) { \ - return false; \ - } + if (NodeCopy((Node)((a)->d), (Node*)&((b)->d), c) != true) { \ + return false; \ + } /* ** xfunc_copyrel -- ** Just like _copyRel, but doesn't copy the paths */ -bool xfunc_copyrel(Rel from, Rel *to) +bool +xfunc_copyrel(Rel from, Rel * to) { - Rel newnode; - Pointer (*alloc)() = palloc; - - /* COPY_CHECKARGS() */ - if (to == NULL) - { - return false; - } - - /* COPY_CHECKNULL() */ - if (from == NULL) + Rel newnode; + + Pointer(*alloc) () = palloc; + + /* COPY_CHECKARGS() */ + if (to == NULL) + { + return false; + } + + /* COPY_CHECKNULL() */ + if (from == NULL) { - (*to) = NULL; - return true; - } - - /* COPY_NEW(c) */ - newnode = (Rel)(*alloc)(classSize(Rel)); - if (newnode == NULL) - { - return false; - } - - /* ---------------- - * copy node superclass fields - * ---------------- - */ - CopyNodeFields((Node)from, (Node)newnode, alloc); - - /* ---------------- - * copy remainder of node - * ---------------- - */ - Node_Copy(from, newnode, alloc, relids); - - newnode->indexed = from->indexed; - newnode->pages = from->pages; - newnode->tuples = from->tuples; - newnode->size = from->size; - newnode->width = from->width; - - Node_Copy(from, newnode, alloc, targetlist); - /* No!!!! Node_Copy(from, newnode, alloc, pathlist); - Node_Copy(from, newnode, alloc, unorderedpath); - Node_Copy(from, newnode, alloc, cheapestpath); */ -#if 0 /* can't use Node_copy now. 2/95 -ay */ - Node_Copy(from, newnode, alloc, classlist); - Node_Copy(from, newnode, alloc, indexkeys); - Node_Copy(from, newnode, alloc, ordering); + (*to) = NULL; + return true; + } + + /* COPY_NEW(c) */ + newnode = (Rel) (*alloc) (classSize(Rel)); + if (newnode == NULL) + { + return false; + } + + /* ---------------- + * copy node superclass fields + * ---------------- + */ + CopyNodeFields((Node) from, (Node) newnode, alloc); + + /* ---------------- + * copy remainder of node + * ---------------- + */ + Node_Copy(from, newnode, alloc, relids); + + newnode->indexed = from->indexed; + newnode->pages = from->pages; + newnode->tuples = from->tuples; + newnode->size = from->size; + newnode->width = from->width; + + Node_Copy(from, newnode, alloc, targetlist); + + /* + * No!!!! Node_Copy(from, newnode, alloc, pathlist); + * Node_Copy(from, newnode, alloc, unorderedpath); Node_Copy(from, + * newnode, alloc, cheapestpath); + */ +#if 0 /* can't use Node_copy now. 2/95 -ay */ + Node_Copy(from, newnode, alloc, classlist); + Node_Copy(from, newnode, alloc, indexkeys); + Node_Copy(from, newnode, alloc, ordering); #endif - Node_Copy(from, newnode, alloc, clauseinfo); - Node_Copy(from, newnode, alloc, joininfo); - Node_Copy(from, newnode, alloc, innerjoin); - Node_Copy(from, newnode, alloc, superrels); - - (*to) = newnode; - return true; + Node_Copy(from, newnode, alloc, clauseinfo); + Node_Copy(from, newnode, alloc, joininfo); + Node_Copy(from, newnode, alloc, innerjoin); + Node_Copy(from, newnode, alloc, superrels); + + (*to) = newnode; + return true; } diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 7637d15f200..bdceec18be3 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * createplan.c-- - * Routines to create the desired plan for processing a query + * Routines to create the desired plan for processing a query * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.11 1997/04/24 15:59:58 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.12 1997/09/07 04:43:57 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -41,766 +41,836 @@ #include "optimizer/internal.h" -#define TEMP_SORT 1 +#define TEMP_SORT 1 #define TEMP_MATERIAL 2 -static List *switch_outer(List *clauses); -static Scan *create_scan_node(Path *best_path, List *tlist); -static Join *create_join_node(JoinPath *best_path, List *tlist); -static SeqScan *create_seqscan_node(Path *best_path, List *tlist, - List *scan_clauses); -static IndexScan *create_indexscan_node(IndexPath *best_path, List *tlist, - List *scan_clauses); -static NestLoop *create_nestloop_node(JoinPath *best_path, List *tlist, - List *clauses, Plan *outer_node, List *outer_tlist, - Plan *inner_node, List *inner_tlist); -static MergeJoin *create_mergejoin_node(MergePath *best_path, List *tlist, - List *clauses, Plan *outer_node, List *outer_tlist, - Plan *inner_node, List *inner_tlist); -static HashJoin *create_hashjoin_node(HashPath *best_path, List *tlist, - List *clauses, Plan *outer_node, List *outer_tlist, - Plan *inner_node, List *inner_tlist); -static Node *fix_indxqual_references(Node *clause, Path *index_path); -static Temp *make_temp(List *tlist, List *keys, Oid *operators, - Plan *plan_node, int temptype); -static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid, - List *indxid, List *indxqual); -static NestLoop *make_nestloop(List *qptlist, List *qpqual, Plan *lefttree, - Plan *righttree); -static HashJoin *make_hashjoin(List *tlist, List *qpqual, - List *hashclauses, Plan *lefttree, Plan *righttree); -static Hash *make_hash(List *tlist, Var *hashkey, Plan *lefttree); -static MergeJoin *make_mergesort(List * tlist, List *qpqual, - List *mergeclauses, Oid opcode, Oid *rightorder, - Oid *leftorder, Plan *righttree, Plan *lefttree); -static Material *make_material(List *tlist, Oid tempid, Plan *lefttree, - int keycount); - -/* +static List *switch_outer(List * clauses); +static Scan *create_scan_node(Path * best_path, List * tlist); +static Join *create_join_node(JoinPath * best_path, List * tlist); +static SeqScan * +create_seqscan_node(Path * best_path, List * tlist, + List * scan_clauses); +static IndexScan * +create_indexscan_node(IndexPath * best_path, List * tlist, + List * scan_clauses); +static NestLoop * +create_nestloop_node(JoinPath * best_path, List * tlist, + List * clauses, Plan * outer_node, List * outer_tlist, + Plan * inner_node, List * inner_tlist); +static MergeJoin * +create_mergejoin_node(MergePath * best_path, List * tlist, + List * clauses, Plan * outer_node, List * outer_tlist, + Plan * inner_node, List * inner_tlist); +static HashJoin * +create_hashjoin_node(HashPath * best_path, List * tlist, + List * clauses, Plan * outer_node, List * outer_tlist, + Plan * inner_node, List * inner_tlist); +static Node *fix_indxqual_references(Node * clause, Path * index_path); +static Temp * +make_temp(List * tlist, List * keys, Oid * operators, + Plan * plan_node, int temptype); +static IndexScan * +make_indexscan(List * qptlist, List * qpqual, Index scanrelid, + List * indxid, List * indxqual); +static NestLoop * +make_nestloop(List * qptlist, List * qpqual, Plan * lefttree, + Plan * righttree); +static HashJoin * +make_hashjoin(List * tlist, List * qpqual, + List * hashclauses, Plan * lefttree, Plan * righttree); +static Hash *make_hash(List * tlist, Var * hashkey, Plan * lefttree); +static MergeJoin * +make_mergesort(List * tlist, List * qpqual, + List * mergeclauses, Oid opcode, Oid * rightorder, + Oid * leftorder, Plan * righttree, Plan * lefttree); +static Material * +make_material(List * tlist, Oid tempid, Plan * lefttree, + int keycount); + +/* * create_plan-- - * Creates the access plan for a query by tracing backwards through the - * desired chain of pathnodes, starting at the node 'best-path'. For - * every pathnode found: - * (1) Create a corresponding plan node containing appropriate id, - * target list, and qualification information. - * (2) Modify ALL clauses so that attributes are referenced using - * relative values. - * (3) Target lists are not modified, but will be in another routine. - * - * best-path is the best access path + * Creates the access plan for a query by tracing backwards through the + * desired chain of pathnodes, starting at the node 'best-path'. For + * every pathnode found: + * (1) Create a corresponding plan node containing appropriate id, + * target list, and qualification information. + * (2) Modify ALL clauses so that attributes are referenced using + * relative values. + * (3) Target lists are not modified, but will be in another routine. + * + * best-path is the best access path * - * Returns the optimal(?) access plan. + * Returns the optimal(?) access plan. */ -Plan * -create_plan(Path *best_path) +Plan * +create_plan(Path * best_path) { - List *tlist; - Plan *plan_node = (Plan*)NULL; - Rel *parent_rel; - int size; - int width; - int pages; - int tuples; - - parent_rel = best_path->parent; - tlist = get_actual_tlist(parent_rel->targetlist); - size = parent_rel->size; - width = parent_rel->width; - pages = parent_rel->pages; - tuples = parent_rel->tuples; - - switch(best_path->pathtype) { - case T_IndexScan : - case T_SeqScan : - plan_node = (Plan*)create_scan_node(best_path, tlist); - break; - case T_HashJoin : - case T_MergeJoin : - case T_NestLoop: - plan_node = (Plan*)create_join_node((JoinPath*)best_path, tlist); - break; - default: - /* do nothing */ - break; - } - - plan_node->plan_size = size; - plan_node->plan_width = width; - if (pages == 0) pages = 1; - plan_node->plan_tupperpage = tuples/pages; - -#if 0 /* fix xfunc */ - /* sort clauses by cost/(1-selectivity) -- JMH 2/26/92 */ - if (XfuncMode != XFUNC_OFF) + List *tlist; + Plan *plan_node = (Plan *) NULL; + Rel *parent_rel; + int size; + int width; + int pages; + int tuples; + + parent_rel = best_path->parent; + tlist = get_actual_tlist(parent_rel->targetlist); + size = parent_rel->size; + width = parent_rel->width; + pages = parent_rel->pages; + tuples = parent_rel->tuples; + + switch (best_path->pathtype) { - set_qpqual((Plan) plan_node, - lisp_qsort( get_qpqual((Plan) plan_node), - xfunc_clause_compare)); - if (XfuncMode != XFUNC_NOR) - /* sort the disjuncts within each clause by cost -- JMH 3/4/92 */ - xfunc_disjunct_sort(plan_node->qpqual); + case T_IndexScan: + case T_SeqScan: + plan_node = (Plan *) create_scan_node(best_path, tlist); + break; + case T_HashJoin: + case T_MergeJoin: + case T_NestLoop: + plan_node = (Plan *) create_join_node((JoinPath *) best_path, tlist); + break; + default: + /* do nothing */ + break; + } + + plan_node->plan_size = size; + plan_node->plan_width = width; + if (pages == 0) + pages = 1; + plan_node->plan_tupperpage = tuples / pages; + +#if 0 /* fix xfunc */ + /* sort clauses by cost/(1-selectivity) -- JMH 2/26/92 */ + if (XfuncMode != XFUNC_OFF) + { + set_qpqual((Plan) plan_node, + lisp_qsort(get_qpqual((Plan) plan_node), + xfunc_clause_compare)); + if (XfuncMode != XFUNC_NOR) + /* sort the disjuncts within each clause by cost -- JMH 3/4/92 */ + xfunc_disjunct_sort(plan_node->qpqual); } #endif - - return(plan_node); + + return (plan_node); } -/* +/* * create_scan_node-- - * Create a scan path for the parent relation of 'best-path'. - * - * tlist is the targetlist for the base relation scanned by 'best-path' - * - * Returns the scan node. + * Create a scan path for the parent relation of 'best-path'. + * + * tlist is the targetlist for the base relation scanned by 'best-path' + * + * Returns the scan node. */ -static Scan * -create_scan_node(Path *best_path, List *tlist) +static Scan * +create_scan_node(Path * best_path, List * tlist) { - Scan *node = NULL ; - List *scan_clauses; - - /* - * Extract the relevant clauses from the parent relation and replace the - * operator OIDs with the corresponding regproc ids. - * - * now that local predicate clauses are copied into paths in - * find_rel_paths() and then (possibly) pulled up in xfunc_trypullup(), - * we get the relevant clauses from the path itself, not its parent - * relation. --- JMH, 6/15/92 - */ - scan_clauses = fix_opids(get_actual_clauses(best_path->locclauseinfo)); - - switch(best_path->pathtype) { - case T_SeqScan : - node = (Scan*)create_seqscan_node(best_path, tlist, scan_clauses); - break; - - case T_IndexScan: - node = (Scan*)create_indexscan_node((IndexPath*)best_path, - tlist, - scan_clauses); - break; - - default : - elog(WARN, "create_scan_node: unknown node type", - best_path->pathtype); - break; - } - - return node; + Scan *node = NULL; + List *scan_clauses; + + /* + * Extract the relevant clauses from the parent relation and replace + * the operator OIDs with the corresponding regproc ids. + * + * now that local predicate clauses are copied into paths in + * find_rel_paths() and then (possibly) pulled up in + * xfunc_trypullup(), we get the relevant clauses from the path + * itself, not its parent relation. --- JMH, 6/15/92 + */ + scan_clauses = fix_opids(get_actual_clauses(best_path->locclauseinfo)); + + switch (best_path->pathtype) + { + case T_SeqScan: + node = (Scan *) create_seqscan_node(best_path, tlist, scan_clauses); + break; + + case T_IndexScan: + node = (Scan *) create_indexscan_node((IndexPath *) best_path, + tlist, + scan_clauses); + break; + + default: + elog(WARN, "create_scan_node: unknown node type", + best_path->pathtype); + break; + } + + return node; } -/* +/* * create_join_node -- - * Create a join path for 'best-path' and(recursively) paths for its - * inner and outer paths. - * - * 'tlist' is the targetlist for the join relation corresponding to - * 'best-path' - * - * Returns the join node. + * Create a join path for 'best-path' and(recursively) paths for its + * inner and outer paths. + * + * 'tlist' is the targetlist for the join relation corresponding to + * 'best-path' + * + * Returns the join node. */ -static Join * -create_join_node(JoinPath *best_path, List *tlist) +static Join * +create_join_node(JoinPath * best_path, List * tlist) { - Plan *outer_node; - List *outer_tlist; - Plan *inner_node; - List *inner_tlist; - List *clauses; - Join *retval = NULL; - - outer_node = create_plan((Path*)best_path->outerjoinpath); - outer_tlist = outer_node->targetlist; - - inner_node = create_plan((Path*)best_path->innerjoinpath); - inner_tlist = inner_node->targetlist; - - clauses = get_actual_clauses(best_path->pathclauseinfo); - - switch(best_path->path.pathtype) { - case T_MergeJoin: - retval = (Join*)create_mergejoin_node((MergePath*)best_path, - tlist, - clauses, - outer_node, - outer_tlist, - inner_node, - inner_tlist); - break; - case T_HashJoin: - retval = (Join*)create_hashjoin_node((HashPath*)best_path, - tlist, - clauses, - outer_node, - outer_tlist, - inner_node, - inner_tlist); - break; - case T_NestLoop: - retval = (Join*)create_nestloop_node((JoinPath*)best_path, - tlist, - clauses, - outer_node, - outer_tlist, - inner_node, - inner_tlist); - break; - default: - /* do nothing */ - elog(WARN, "create_join_node: unknown node type", - best_path->path.pathtype); - } + Plan *outer_node; + List *outer_tlist; + Plan *inner_node; + List *inner_tlist; + List *clauses; + Join *retval = NULL; + + outer_node = create_plan((Path *) best_path->outerjoinpath); + outer_tlist = outer_node->targetlist; + + inner_node = create_plan((Path *) best_path->innerjoinpath); + inner_tlist = inner_node->targetlist; + + clauses = get_actual_clauses(best_path->pathclauseinfo); + + switch (best_path->path.pathtype) + { + case T_MergeJoin: + retval = (Join *) create_mergejoin_node((MergePath *) best_path, + tlist, + clauses, + outer_node, + outer_tlist, + inner_node, + inner_tlist); + break; + case T_HashJoin: + retval = (Join *) create_hashjoin_node((HashPath *) best_path, + tlist, + clauses, + outer_node, + outer_tlist, + inner_node, + inner_tlist); + break; + case T_NestLoop: + retval = (Join *) create_nestloop_node((JoinPath *) best_path, + tlist, + clauses, + outer_node, + outer_tlist, + inner_node, + inner_tlist); + break; + default: + /* do nothing */ + elog(WARN, "create_join_node: unknown node type", + best_path->path.pathtype); + } #if 0 - /* - ** Expensive function pullups may have pulled local predicates - ** into this path node. Put them in the qpqual of the plan node. - ** -- JMH, 6/15/92 - */ - if (get_locclauseinfo(best_path) != NIL) - set_qpqual((Plan)retval, - nconc(get_qpqual((Plan) retval), - fix_opids(get_actual_clauses - (get_locclauseinfo(best_path))))); + + /* + * * Expensive function pullups may have pulled local predicates * + * into this path node. Put them in the qpqual of the plan node. * + * -- JMH, 6/15/92 + */ + if (get_locclauseinfo(best_path) != NIL) + set_qpqual((Plan) retval, + nconc(get_qpqual((Plan) retval), + fix_opids(get_actual_clauses + (get_locclauseinfo(best_path))))); #endif - return(retval); + return (retval); } /***************************************************************************** * - * BASE-RELATION SCAN METHODS + * BASE-RELATION SCAN METHODS * *****************************************************************************/ - -/* + +/* * create_seqscan_node-- - * Returns a seqscan node for the base relation scanned by 'best-path' - * with restriction clauses 'scan-clauses' and targetlist 'tlist'. + * Returns a seqscan node for the base relation scanned by 'best-path' + * with restriction clauses 'scan-clauses' and targetlist 'tlist'. */ static SeqScan * -create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses) +create_seqscan_node(Path * best_path, List * tlist, List * scan_clauses) { - SeqScan *scan_node = (SeqScan*)NULL; - Index scan_relid = -1; - List *temp; - - temp = best_path->parent->relids; - if(temp == NULL) - elog(WARN,"scanrelid is empty"); - else - scan_relid = (Index)lfirsti(temp); /* ??? who takes care of lnext? - ay */ - scan_node = make_seqscan(tlist, - scan_clauses, - scan_relid, - (Plan*)NULL); - - scan_node->plan.cost = best_path->path_cost; - - return(scan_node); + SeqScan *scan_node = (SeqScan *) NULL; + Index scan_relid = -1; + List *temp; + + temp = best_path->parent->relids; + if (temp == NULL) + elog(WARN, "scanrelid is empty"); + else + scan_relid = (Index) lfirsti(temp); /* ??? who takes care of + * lnext? - ay */ + scan_node = make_seqscan(tlist, + scan_clauses, + scan_relid, + (Plan *) NULL); + + scan_node->plan.cost = best_path->path_cost; + + return (scan_node); } -/* +/* * create_indexscan_node-- - * Returns a indexscan node for the base relation scanned by 'best-path' - * with restriction clauses 'scan-clauses' and targetlist 'tlist'. + * Returns a indexscan node for the base relation scanned by 'best-path' + * with restriction clauses 'scan-clauses' and targetlist 'tlist'. */ static IndexScan * -create_indexscan_node(IndexPath *best_path, - List *tlist, - List *scan_clauses) +create_indexscan_node(IndexPath * best_path, + List * tlist, + List * scan_clauses) { - /* - * Extract the(first if conjunct, only if disjunct) clause from the - * clauseinfo list. - */ - Expr *index_clause = (Expr*)NULL; - List *indxqual = NIL; - List *qpqual = NIL; - List *fixed_indxqual = NIL; - List *ixid; - IndexScan *scan_node = (IndexScan*)NULL; - bool lossy = FALSE; - HeapTuple indexTuple; - IndexTupleForm index; - - /* - * If an 'or' clause is to be used with this index, the indxqual - * field will contain a list of the 'or' clause arguments, e.g., the - * clause(OR a b c) will generate: ((a) (b) (c)). Otherwise, the - * indxqual will simply contain one conjunctive qualification: ((a)). - */ - if (best_path->indexqual != NULL) - /* added call to fix_opids, JMH 6/23/92 */ - index_clause = (Expr*) - lfirst(fix_opids(get_actual_clauses(best_path->indexqual))); - - if (or_clause((Node*)index_clause)) { - List *temp = NIL; - - foreach(temp, index_clause->args) - indxqual = lappend(indxqual, lcons(lfirst(temp), NIL)); - } else { - indxqual = lcons(get_actual_clauses(best_path->indexqual), - NIL); - } - - /* check and see if any indices are lossy */ - foreach (ixid, best_path->indexid) { - indexTuple = SearchSysCacheTuple(INDEXRELID, - ObjectIdGetDatum(lfirsti(ixid)), - 0,0,0); - if (!HeapTupleIsValid(indexTuple)) - elog(WARN, "create_plan: index %d not found", - lfirsti(ixid)); - index = (IndexTupleForm)GETSTRUCT(indexTuple); - if (index->indislossy) - lossy = TRUE; - } - - - /* - * The qpqual field contains all restrictions not automatically handled - * by the index. Note that for non-lossy indices, the predicates - * in the indxqual are handled by the index, while for lossy indices - * the indxqual predicates need to be double-checked after the - * index fetches the best-guess tuples. - */ - if(or_clause((Node*)index_clause)) { - qpqual = set_difference(scan_clauses, - lcons(index_clause,NIL)); - - if (lossy) - qpqual = nconc(qpqual, - lcons((List *)copyObject(index_clause),NIL)); - } - else { - qpqual = set_difference(scan_clauses, lfirst(indxqual)); - if (lossy) - qpqual = nconc(qpqual, - (List *)copyObject(lfirst(indxqual))); - } - - fixed_indxqual = - (List*)fix_indxqual_references((Node*)indxqual,(Path*)best_path); - - scan_node = - make_indexscan(tlist, - qpqual, - lfirsti(best_path->path.parent->relids), - best_path->indexid, - fixed_indxqual); - - scan_node->scan.plan.cost = best_path->path.path_cost; - - return(scan_node); + + /* + * Extract the(first if conjunct, only if disjunct) clause from the + * clauseinfo list. + */ + Expr *index_clause = (Expr *) NULL; + List *indxqual = NIL; + List *qpqual = NIL; + List *fixed_indxqual = NIL; + List *ixid; + IndexScan *scan_node = (IndexScan *) NULL; + bool lossy = FALSE; + HeapTuple indexTuple; + IndexTupleForm index; + + /* + * If an 'or' clause is to be used with this index, the indxqual field + * will contain a list of the 'or' clause arguments, e.g., the + * clause(OR a b c) will generate: ((a) (b) (c)). Otherwise, the + * indxqual will simply contain one conjunctive qualification: ((a)). + */ + if (best_path->indexqual != NULL) + /* added call to fix_opids, JMH 6/23/92 */ + index_clause = (Expr *) + lfirst(fix_opids(get_actual_clauses(best_path->indexqual))); + + if (or_clause((Node *) index_clause)) + { + List *temp = NIL; + + foreach(temp, index_clause->args) + indxqual = lappend(indxqual, lcons(lfirst(temp), NIL)); + } + else + { + indxqual = lcons(get_actual_clauses(best_path->indexqual), + NIL); + } + + /* check and see if any indices are lossy */ + foreach(ixid, best_path->indexid) + { + indexTuple = SearchSysCacheTuple(INDEXRELID, + ObjectIdGetDatum(lfirsti(ixid)), + 0, 0, 0); + if (!HeapTupleIsValid(indexTuple)) + elog(WARN, "create_plan: index %d not found", + lfirsti(ixid)); + index = (IndexTupleForm) GETSTRUCT(indexTuple); + if (index->indislossy) + lossy = TRUE; + } + + + /* + * The qpqual field contains all restrictions not automatically + * handled by the index. Note that for non-lossy indices, the + * predicates in the indxqual are handled by the index, while for + * lossy indices the indxqual predicates need to be double-checked + * after the index fetches the best-guess tuples. + */ + if (or_clause((Node *) index_clause)) + { + qpqual = set_difference(scan_clauses, + lcons(index_clause, NIL)); + + if (lossy) + qpqual = nconc(qpqual, + lcons((List *) copyObject(index_clause), NIL)); + } + else + { + qpqual = set_difference(scan_clauses, lfirst(indxqual)); + if (lossy) + qpqual = nconc(qpqual, + (List *) copyObject(lfirst(indxqual))); + } + + fixed_indxqual = + (List *) fix_indxqual_references((Node *) indxqual, (Path *) best_path); + + scan_node = + make_indexscan(tlist, + qpqual, + lfirsti(best_path->path.parent->relids), + best_path->indexid, + fixed_indxqual); + + scan_node->scan.plan.cost = best_path->path.path_cost; + + return (scan_node); } /***************************************************************************** * - * JOIN METHODS + * JOIN METHODS * *****************************************************************************/ static NestLoop * -create_nestloop_node(JoinPath *best_path, - List *tlist, - List *clauses, - Plan *outer_node, - List *outer_tlist, - Plan *inner_node, - List *inner_tlist) +create_nestloop_node(JoinPath * best_path, + List * tlist, + List * clauses, + Plan * outer_node, + List * outer_tlist, + Plan * inner_node, + List * inner_tlist) { - NestLoop *join_node = (NestLoop*)NULL; + NestLoop *join_node = (NestLoop *) NULL; - if (IsA(inner_node,IndexScan)) { - /* An index is being used to reduce the number of tuples scanned in - * the inner relation. There will never be more than one index used - * in the inner scan path, so we need only consider the first set of - * qualifications in indxqual. - * - * But there may be more than one clauses in this "first set" - * in the case of multi-column indices. - vadim 03/18/97 - */ + if (IsA(inner_node, IndexScan)) + { - List *inner_indxqual = lfirst(((IndexScan*)inner_node)->indxqual); - List *inner_qual; - bool found = false; + /* + * An index is being used to reduce the number of tuples scanned + * in the inner relation. There will never be more than one index + * used in the inner scan path, so we need only consider the first + * set of qualifications in indxqual. + * + * But there may be more than one clauses in this "first set" in the + * case of multi-column indices. - vadim 03/18/97 + */ + + List *inner_indxqual = lfirst(((IndexScan *) inner_node)->indxqual); + List *inner_qual; + bool found = false; + + foreach(inner_qual, inner_indxqual) + { + if (!qual_clause_p((Node *) lfirst(inner_qual))) + { + found = true; + break; + } + } - foreach (inner_qual, inner_indxqual) - { - if ( !qual_clause_p ((Node*)lfirst(inner_qual)) ) - { - found = true; - break; - } + /* + * If we have in fact found a join index qualification, remove + * these index clauses from the nestloop's join clauses and reset + * the inner(index) scan's qualification so that the var nodes + * refer to the proper outer join relation attributes. + * + * XXX Re-moving index clauses doesn't work properly: 1. + * fix_indxqual_references may change varattno-s in + * inner_indxqual; 2. clauses may be commuted I havn't time to fix + * it at the moment. - vadim 04/24/97 + */ + if (found) + { + List *new_inner_qual = NIL; + + clauses = set_difference(clauses, inner_indxqual); /* XXX */ + new_inner_qual = + index_outerjoin_references(inner_indxqual, + outer_node->targetlist, + ((Scan *) inner_node)->scanrelid); + ((IndexScan *) inner_node)->indxqual = + lcons(new_inner_qual, NIL); + } } - - /* If we have in fact found a join index qualification, remove these - * index clauses from the nestloop's join clauses and reset the - * inner(index) scan's qualification so that the var nodes refer to - * the proper outer join relation attributes. - * - * XXX Re-moving index clauses doesn't work properly: - * 1. fix_indxqual_references may change varattno-s in - * inner_indxqual; - * 2. clauses may be commuted - * I havn't time to fix it at the moment. - vadim 04/24/97 - */ - if ( found ) + else if (IsA_Join(inner_node)) { - List *new_inner_qual = NIL; - - clauses = set_difference(clauses,inner_indxqual); /* XXX */ - new_inner_qual = - index_outerjoin_references(inner_indxqual, - outer_node->targetlist, - ((Scan*)inner_node)->scanrelid); - ((IndexScan*)inner_node)->indxqual = - lcons(new_inner_qual,NIL); + inner_node = (Plan *) make_temp(inner_tlist, + NIL, + NULL, + inner_node, + TEMP_MATERIAL); } - }else if (IsA_Join(inner_node)) { - inner_node = (Plan*)make_temp(inner_tlist, - NIL, - NULL, - inner_node, - TEMP_MATERIAL); - } - - join_node = make_nestloop(tlist, - join_references(clauses, - outer_tlist, - inner_tlist), - outer_node, - inner_node); - - join_node->join.cost = best_path->path.path_cost; - - return(join_node); + + join_node = make_nestloop(tlist, + join_references(clauses, + outer_tlist, + inner_tlist), + outer_node, + inner_node); + + join_node->join.cost = best_path->path.path_cost; + + return (join_node); } static MergeJoin * -create_mergejoin_node(MergePath *best_path, - List *tlist, - List *clauses, - Plan *outer_node, - List *outer_tlist, - Plan *inner_node, - List *inner_tlist) +create_mergejoin_node(MergePath * best_path, + List * tlist, + List * clauses, + Plan * outer_node, + List * outer_tlist, + Plan * inner_node, + List * inner_tlist) { - List *qpqual, *mergeclauses; - RegProcedure opcode; - Oid *outer_order, *inner_order; - MergeJoin *join_node; - - - /* Separate the mergeclauses from the other join qualification - * clauses and set those clauses to contain references to lower - * attributes. - */ - qpqual = join_references(set_difference(clauses, - best_path->path_mergeclauses), - outer_tlist, - inner_tlist); - - /* Now set the references in the mergeclauses and rearrange them so - * that the outer variable is always on the left. - */ - mergeclauses = switch_outer(join_references(best_path->path_mergeclauses, - outer_tlist, - inner_tlist)); - - opcode = - get_opcode((best_path->jpath.path.p_ordering.ord.merge)->join_operator); - - outer_order = (Oid *)palloc(sizeof(Oid)*2); - outer_order[0] = - (best_path->jpath.path.p_ordering.ord.merge)->left_operator; - outer_order[1] = 0; - - inner_order = (Oid *)palloc(sizeof(Oid)*2); - inner_order[0] = - (best_path->jpath.path.p_ordering.ord.merge)->right_operator; - inner_order[1] = 0; - - /* Create explicit sort paths for the outer and inner join paths if - * necessary. The sort cost was already accounted for in the path. - */ - if (best_path->outersortkeys) { - Temp *sorted_outer_node = make_temp(outer_tlist, - best_path->outersortkeys, - outer_order, - outer_node, - TEMP_SORT); - sorted_outer_node->plan.cost = outer_node->cost; - outer_node = (Plan*)sorted_outer_node; - } - - if (best_path->innersortkeys) { - Temp *sorted_inner_node = make_temp(inner_tlist, - best_path->innersortkeys, - inner_order, - inner_node, - TEMP_SORT); - sorted_inner_node->plan.cost = outer_node->cost; - inner_node = (Plan*)sorted_inner_node; - } - - join_node = make_mergesort(tlist, - qpqual, - mergeclauses, - opcode, - inner_order, - outer_order, - inner_node, - outer_node); - - join_node->join.cost = best_path->jpath.path.path_cost; - - return(join_node); + List *qpqual, + *mergeclauses; + RegProcedure opcode; + Oid *outer_order, + *inner_order; + MergeJoin *join_node; + + + /* + * Separate the mergeclauses from the other join qualification clauses + * and set those clauses to contain references to lower attributes. + */ + qpqual = join_references(set_difference(clauses, + best_path->path_mergeclauses), + outer_tlist, + inner_tlist); + + /* + * Now set the references in the mergeclauses and rearrange them so + * that the outer variable is always on the left. + */ + mergeclauses = switch_outer(join_references(best_path->path_mergeclauses, + outer_tlist, + inner_tlist)); + + opcode = + get_opcode((best_path->jpath.path.p_ordering.ord.merge)->join_operator); + + outer_order = (Oid *) palloc(sizeof(Oid) * 2); + outer_order[0] = + (best_path->jpath.path.p_ordering.ord.merge)->left_operator; + outer_order[1] = 0; + + inner_order = (Oid *) palloc(sizeof(Oid) * 2); + inner_order[0] = + (best_path->jpath.path.p_ordering.ord.merge)->right_operator; + inner_order[1] = 0; + + /* + * Create explicit sort paths for the outer and inner join paths if + * necessary. The sort cost was already accounted for in the path. + */ + if (best_path->outersortkeys) + { + Temp *sorted_outer_node = make_temp(outer_tlist, + best_path->outersortkeys, + outer_order, + outer_node, + TEMP_SORT); + + sorted_outer_node->plan.cost = outer_node->cost; + outer_node = (Plan *) sorted_outer_node; + } + + if (best_path->innersortkeys) + { + Temp *sorted_inner_node = make_temp(inner_tlist, + best_path->innersortkeys, + inner_order, + inner_node, + TEMP_SORT); + + sorted_inner_node->plan.cost = outer_node->cost; + inner_node = (Plan *) sorted_inner_node; + } + + join_node = make_mergesort(tlist, + qpqual, + mergeclauses, + opcode, + inner_order, + outer_order, + inner_node, + outer_node); + + join_node->join.cost = best_path->jpath.path.path_cost; + + return (join_node); } -/* - * create_hashjoin_node-- XXX HASH - * - * Returns a new hashjoin node. - * - * XXX hash join ops are totally bogus -- how the hell do we choose - * these?? at runtime? what about a hash index? +/* + * create_hashjoin_node-- XXX HASH + * + * Returns a new hashjoin node. + * + * XXX hash join ops are totally bogus -- how the hell do we choose + * these?? at runtime? what about a hash index? */ static HashJoin * -create_hashjoin_node(HashPath *best_path, - List *tlist, - List *clauses, - Plan *outer_node, - List *outer_tlist, - Plan *inner_node, - List *inner_tlist) +create_hashjoin_node(HashPath * best_path, + List * tlist, + List * clauses, + Plan * outer_node, + List * outer_tlist, + Plan * inner_node, + List * inner_tlist) { - List *qpqual; - List *hashclauses; - HashJoin *join_node; - Hash *hash_node; - Var *innerhashkey; - - /* Separate the hashclauses from the other join qualification clauses - * and set those clauses to contain references to lower attributes. - */ - qpqual = - join_references(set_difference(clauses, - best_path->path_hashclauses), - outer_tlist, - inner_tlist); - - /* Now set the references in the hashclauses and rearrange them so - * that the outer variable is always on the left. - */ - hashclauses = - switch_outer(join_references(best_path->path_hashclauses, - outer_tlist, - inner_tlist)); - - innerhashkey = get_rightop(lfirst(hashclauses)); - - hash_node = make_hash(inner_tlist, innerhashkey, inner_node); - join_node = make_hashjoin(tlist, - qpqual, - hashclauses, - outer_node, - (Plan*)hash_node); - join_node->join.cost = best_path->jpath.path.path_cost; - - return(join_node); + List *qpqual; + List *hashclauses; + HashJoin *join_node; + Hash *hash_node; + Var *innerhashkey; + + /* + * Separate the hashclauses from the other join qualification clauses + * and set those clauses to contain references to lower attributes. + */ + qpqual = + join_references(set_difference(clauses, + best_path->path_hashclauses), + outer_tlist, + inner_tlist); + + /* + * Now set the references in the hashclauses and rearrange them so + * that the outer variable is always on the left. + */ + hashclauses = + switch_outer(join_references(best_path->path_hashclauses, + outer_tlist, + inner_tlist)); + + innerhashkey = get_rightop(lfirst(hashclauses)); + + hash_node = make_hash(inner_tlist, innerhashkey, inner_node); + join_node = make_hashjoin(tlist, + qpqual, + hashclauses, + outer_node, + (Plan *) hash_node); + join_node->join.cost = best_path->jpath.path.path_cost; + + return (join_node); } /***************************************************************************** * - * SUPPORTING ROUTINES + * SUPPORTING ROUTINES * *****************************************************************************/ -static Node * -fix_indxqual_references(Node *clause, Path *index_path) +static Node * +fix_indxqual_references(Node * clause, Path * index_path) { - Node *newclause; - - if (IsA(clause,Var)) { - if (lfirsti(index_path->parent->relids) == ((Var*)clause)->varno) { - int pos = 0; - int varatt = ((Var*)clause)->varattno; - int *indexkeys = ((IndexPath*)index_path)->indexkeys; - - if (indexkeys) { - while (indexkeys[pos] != 0) { - if(varatt == indexkeys[pos]) { - break; - } - pos++; + Node *newclause; + + if (IsA(clause, Var)) + { + if (lfirsti(index_path->parent->relids) == ((Var *) clause)->varno) + { + int pos = 0; + int varatt = ((Var *) clause)->varattno; + int *indexkeys = ((IndexPath *) index_path)->indexkeys; + + if (indexkeys) + { + while (indexkeys[pos] != 0) + { + if (varatt == indexkeys[pos]) + { + break; + } + pos++; + } + } + newclause = copyObject((Node *) clause); + ((Var *) newclause)->varattno = pos + 1; + return (newclause); + } + else + { + return (clause); } - } - newclause = copyObject((Node*)clause); - ((Var*)newclause)->varattno = pos + 1; - return (newclause); - } else { - return (clause); } - } else if(IsA(clause,Const)) { - return(clause); + else if (IsA(clause, Const)) + { + return (clause); #ifdef INDEXSCAN_PATCH - } else if(IsA(clause,Param)) { - /* Function parameter used as index scan arg. DZ - 27-8-1996 */ - return(clause); + } + else if (IsA(clause, Param)) + { + /* Function parameter used as index scan arg. DZ - 27-8-1996 */ + return (clause); #endif - } else if(is_opclause(clause) && - is_funcclause((Node*)get_leftop((Expr*)clause)) && - ((Func*)((Expr*)get_leftop((Expr*)clause))->oper)->funcisindex){ - Var *newvar = - makeVar((Index)lfirsti(index_path->parent->relids), - 1, /* func indices have one key */ - ((Func*)((Expr*)clause)->oper)->functype, - (Index)lfirsti(index_path->parent->relids), - 0); - - return - ((Node*)make_opclause((Oper*)((Expr*)clause)->oper, - newvar, - get_rightop((Expr*)clause))); - - } else if (IsA(clause,Expr)) { - Expr *expr = (Expr*)clause; - List *new_subclauses = NIL; - Node *subclause = NULL; - List *i = NIL; - - foreach(i, expr->args) { - subclause = lfirst(i); - if(subclause) - new_subclauses = - lappend(new_subclauses, - fix_indxqual_references(subclause, - index_path)); + } + else if (is_opclause(clause) && + is_funcclause((Node *) get_leftop((Expr *) clause)) && + ((Func *) ((Expr *) get_leftop((Expr *) clause))->oper)->funcisindex) + { + Var *newvar = + makeVar((Index) lfirsti(index_path->parent->relids), + 1, /* func indices have one key */ + ((Func *) ((Expr *) clause)->oper)->functype, + (Index) lfirsti(index_path->parent->relids), + 0); + + return + ((Node *) make_opclause((Oper *) ((Expr *) clause)->oper, + newvar, + get_rightop((Expr *) clause))); } - - /* XXX new_subclauses should be a list of the form: - * ( (var var) (var const) ...) ? - */ - if(new_subclauses) { - return (Node*) - make_clause(expr->opType, expr->oper, new_subclauses); - } else { - return(clause); - } - } else { - List *oldclauses = (List*)clause; - List *new_subclauses = NIL; - Node *subclause = NULL; - List *i = NIL; - - foreach(i, oldclauses) { - subclause = lfirst(i); - if(subclause) - new_subclauses = - lappend(new_subclauses, - fix_indxqual_references(subclause, - index_path)); + else if (IsA(clause, Expr)) + { + Expr *expr = (Expr *) clause; + List *new_subclauses = NIL; + Node *subclause = NULL; + List *i = NIL; + + foreach(i, expr->args) + { + subclause = lfirst(i); + if (subclause) + new_subclauses = + lappend(new_subclauses, + fix_indxqual_references(subclause, + index_path)); + + } + + /* + * XXX new_subclauses should be a list of the form: ( (var var) + * (var const) ...) ? + */ + if (new_subclauses) + { + return (Node *) + make_clause(expr->opType, expr->oper, new_subclauses); + } + else + { + return (clause); + } + } + else + { + List *oldclauses = (List *) clause; + List *new_subclauses = NIL; + Node *subclause = NULL; + List *i = NIL; + + foreach(i, oldclauses) + { + subclause = lfirst(i); + if (subclause) + new_subclauses = + lappend(new_subclauses, + fix_indxqual_references(subclause, + index_path)); + + } + /* + * XXX new_subclauses should be a list of the form: ( (var var) + * (var const) ...) ? + */ + if (new_subclauses) + { + return (Node *) new_subclauses; + } + else + { + return (clause); + } } - - /* XXX new_subclauses should be a list of the form: - * ( (var var) (var const) ...) ? - */ - if(new_subclauses) { - return (Node*)new_subclauses; - } else { - return (clause); - } - } } -/* +/* * switch_outer-- - * Given a list of merge clauses, rearranges the elements within the - * clauses so the outer join variable is on the left and the inner is on - * the right. - * - * Returns the rearranged list ? - * - * XXX Shouldn't the operator be commuted?! + * Given a list of merge clauses, rearranges the elements within the + * clauses so the outer join variable is on the left and the inner is on + * the right. + * + * Returns the rearranged list ? + * + * XXX Shouldn't the operator be commuted?! */ -static List * -switch_outer(List *clauses) +static List * +switch_outer(List * clauses) { - List *t_list = NIL; - Expr *temp = NULL; - List *i = NIL; - Expr *clause; - Node *op; - - foreach(i,clauses) { - clause = lfirst(i); - op = (Node*)get_rightop(clause); - if ( IsA (op, ArrayRef) ) - op = ((ArrayRef*)op)->refexpr; - Assert ( IsA (op, Var) ); - if ( var_is_outer ((Var*)op) ) + List *t_list = NIL; + Expr *temp = NULL; + List *i = NIL; + Expr *clause; + Node *op; + + foreach(i, clauses) { - temp = make_clause(clause->opType, clause->oper, - lcons(get_rightop(clause), - lcons(get_leftop(clause), - NIL))); - t_list = lappend(t_list,temp); - } - else - t_list = lappend(t_list,clause); - } - return(t_list); + clause = lfirst(i); + op = (Node *) get_rightop(clause); + if (IsA(op, ArrayRef)) + op = ((ArrayRef *) op)->refexpr; + Assert(IsA(op, Var)); + if (var_is_outer((Var *) op)) + { + temp = make_clause(clause->opType, clause->oper, + lcons(get_rightop(clause), + lcons(get_leftop(clause), + NIL))); + t_list = lappend(t_list, temp); + } + else + t_list = lappend(t_list, clause); + } + return (t_list); } -/* +/* * set-temp-tlist-operators-- - * Sets the key and keyop fields of resdom nodes in a target list. - * - * 'tlist' is the target list - * 'pathkeys' is a list of N keys in the form((key1) (key2)...(keyn)), - * corresponding to vars in the target list that are to - * be sorted or hashed - * 'operators' is the corresponding list of N sort or hash operators - * 'keyno' is the first key number - * XXX - keyno ? doesn't exist - jeff - * - * Returns the modified target list. + * Sets the key and keyop fields of resdom nodes in a target list. + * + * 'tlist' is the target list + * 'pathkeys' is a list of N keys in the form((key1) (key2)...(keyn)), + * corresponding to vars in the target list that are to + * be sorted or hashed + * 'operators' is the corresponding list of N sort or hash operators + * 'keyno' is the first key number + * XXX - keyno ? doesn't exist - jeff + * + * Returns the modified target list. */ -static List * -set_temp_tlist_operators(List *tlist, List *pathkeys, Oid *operators) +static List * +set_temp_tlist_operators(List * tlist, List * pathkeys, Oid * operators) { - Node *keys = NULL; - int keyno = 1; - Resdom *resdom = (Resdom*)NULL ; - List *i = NIL; - - foreach(i, pathkeys) { - keys = lfirst((List*)lfirst(i)); - resdom = tlist_member((Var*)keys, tlist); - if (resdom) { - - /* Order the resdom keys and replace the operator OID for each - * key with the regproc OID. - * - * XXX Note that the optimizer only generates merge joins - * with 1 operator (see create_mergejoin_node) - ay 2/95 - */ - resdom->reskey = keyno; - resdom->reskeyop = get_opcode(operators[0]); + Node *keys = NULL; + int keyno = 1; + Resdom *resdom = (Resdom *) NULL; + List *i = NIL; + + foreach(i, pathkeys) + { + keys = lfirst((List *) lfirst(i)); + resdom = tlist_member((Var *) keys, tlist); + if (resdom) + { + + /* + * Order the resdom keys and replace the operator OID for each + * key with the regproc OID. + * + * XXX Note that the optimizer only generates merge joins with 1 + * operator (see create_mergejoin_node) - ay 2/95 + */ + resdom->reskey = keyno; + resdom->reskeyop = get_opcode(operators[0]); + } + keyno += 1; } - keyno += 1; - } - return(tlist); + return (tlist); } /***************************************************************************** @@ -808,355 +878,362 @@ set_temp_tlist_operators(List *tlist, List *pathkeys, Oid *operators) * *****************************************************************************/ -/* +/* * make_temp-- - * Create plan nodes to sort or materialize relations into temporaries. The - * result returned for a sort will look like (SEQSCAN(SORT(plan-node))) - * or (SEQSCAN(MATERIAL(plan-node))) - * - * 'tlist' is the target list of the scan to be sorted or hashed - * 'keys' is the list of keys which the sort or hash will be done on - * 'operators' is the operators with which the sort or hash is to be done - * (a list of operator OIDs) - * 'plan-node' is the node which yields tuples for the sort - * 'temptype' indicates which operation(sort or hash) to perform + * Create plan nodes to sort or materialize relations into temporaries. The + * result returned for a sort will look like (SEQSCAN(SORT(plan-node))) + * or (SEQSCAN(MATERIAL(plan-node))) + * + * 'tlist' is the target list of the scan to be sorted or hashed + * 'keys' is the list of keys which the sort or hash will be done on + * 'operators' is the operators with which the sort or hash is to be done + * (a list of operator OIDs) + * 'plan-node' is the node which yields tuples for the sort + * 'temptype' indicates which operation(sort or hash) to perform */ -static Temp * -make_temp(List *tlist, - List *keys, - Oid *operators, - Plan *plan_node, - int temptype) +static Temp * +make_temp(List * tlist, + List * keys, + Oid * operators, + Plan * plan_node, + int temptype) { - List *temp_tlist; - Temp *retval = NULL; - - /* Create a new target list for the temporary, with keys set. */ - temp_tlist = set_temp_tlist_operators(new_unsorted_tlist(tlist), - keys, - operators); - switch(temptype) { - case TEMP_SORT : - retval = (Temp*)make_seqscan(tlist, - NIL, - _TEMP_RELATION_ID_, - (Plan*)make_sort(temp_tlist, - _TEMP_RELATION_ID_, - plan_node, - length(keys))); - break; - - case TEMP_MATERIAL : - retval = (Temp*)make_seqscan(tlist, - NIL, - _TEMP_RELATION_ID_, - (Plan*)make_material(temp_tlist, - _TEMP_RELATION_ID_, - plan_node, - length(keys))); - break; - - default: - elog(WARN,"make_temp: unknown temp type %d", temptype); - - } - return(retval); + List *temp_tlist; + Temp *retval = NULL; + + /* Create a new target list for the temporary, with keys set. */ + temp_tlist = set_temp_tlist_operators(new_unsorted_tlist(tlist), + keys, + operators); + switch (temptype) + { + case TEMP_SORT: + retval = (Temp *) make_seqscan(tlist, + NIL, + _TEMP_RELATION_ID_, + (Plan *) make_sort(temp_tlist, + _TEMP_RELATION_ID_, + plan_node, + length(keys))); + break; + + case TEMP_MATERIAL: + retval = (Temp *) make_seqscan(tlist, + NIL, + _TEMP_RELATION_ID_, + (Plan *) make_material(temp_tlist, + _TEMP_RELATION_ID_, + plan_node, + length(keys))); + break; + + default: + elog(WARN, "make_temp: unknown temp type %d", temptype); + + } + return (retval); } -SeqScan * -make_seqscan(List *qptlist, - List *qpqual, - Index scanrelid, - Plan *lefttree) +SeqScan * +make_seqscan(List * qptlist, + List * qpqual, + Index scanrelid, + Plan * lefttree) { - SeqScan *node = makeNode(SeqScan); - Plan *plan = &node->plan; - - plan->cost = 0.0; - plan->state = (EState *)NULL; - plan->targetlist = qptlist; - plan->qual = qpqual; - plan->lefttree = lefttree; - plan->righttree = NULL; - node->scanrelid = scanrelid; - node->scanstate = (CommonScanState *)NULL; - - return(node); + SeqScan *node = makeNode(SeqScan); + Plan *plan = &node->plan; + + plan->cost = 0.0; + plan->state = (EState *) NULL; + plan->targetlist = qptlist; + plan->qual = qpqual; + plan->lefttree = lefttree; + plan->righttree = NULL; + node->scanrelid = scanrelid; + node->scanstate = (CommonScanState *) NULL; + + return (node); } static IndexScan * -make_indexscan(List *qptlist, - List *qpqual, - Index scanrelid, - List *indxid, - List *indxqual) +make_indexscan(List * qptlist, + List * qpqual, + Index scanrelid, + List * indxid, + List * indxqual) { - IndexScan *node = makeNode(IndexScan); - Plan *plan = &node->scan.plan; - - plan->cost = 0.0; - plan->state = (EState *)NULL; - plan->targetlist = qptlist; - plan->qual = qpqual; - plan->lefttree = NULL; - plan->righttree = NULL; - node->scan.scanrelid = scanrelid; - node->indxid = indxid; - node->indxqual = indxqual; - node->scan.scanstate = (CommonScanState *)NULL; - - return(node); + IndexScan *node = makeNode(IndexScan); + Plan *plan = &node->scan.plan; + + plan->cost = 0.0; + plan->state = (EState *) NULL; + plan->targetlist = qptlist; + plan->qual = qpqual; + plan->lefttree = NULL; + plan->righttree = NULL; + node->scan.scanrelid = scanrelid; + node->indxid = indxid; + node->indxqual = indxqual; + node->scan.scanstate = (CommonScanState *) NULL; + + return (node); } static NestLoop * -make_nestloop(List *qptlist, - List *qpqual, - Plan *lefttree, - Plan *righttree) +make_nestloop(List * qptlist, + List * qpqual, + Plan * lefttree, + Plan * righttree) { - NestLoop *node = makeNode(NestLoop); - Plan *plan = &node->join; - - plan->cost = 0.0; - plan->state = (EState *)NULL; - plan->targetlist = qptlist; - plan->qual = qpqual; - plan->lefttree = lefttree; - plan->righttree = righttree; - node->nlstate = (NestLoopState*)NULL; - - return(node); + NestLoop *node = makeNode(NestLoop); + Plan *plan = &node->join; + + plan->cost = 0.0; + plan->state = (EState *) NULL; + plan->targetlist = qptlist; + plan->qual = qpqual; + plan->lefttree = lefttree; + plan->righttree = righttree; + node->nlstate = (NestLoopState *) NULL; + + return (node); } static HashJoin * -make_hashjoin(List *tlist, - List *qpqual, - List *hashclauses, - Plan *lefttree, - Plan *righttree) +make_hashjoin(List * tlist, + List * qpqual, + List * hashclauses, + Plan * lefttree, + Plan * righttree) { - HashJoin *node = makeNode(HashJoin); - Plan *plan = &node->join; - - plan->cost = 0.0; - plan->state = (EState *)NULL; - plan->targetlist = tlist; - plan->qual = qpqual; - plan->lefttree = lefttree; - plan->righttree = righttree; - node->hashclauses = hashclauses; - node->hashjointable = NULL; - node->hashjointablekey = 0; - node->hashjointablesize = 0; - node->hashdone = false; - - return(node); + HashJoin *node = makeNode(HashJoin); + Plan *plan = &node->join; + + plan->cost = 0.0; + plan->state = (EState *) NULL; + plan->targetlist = tlist; + plan->qual = qpqual; + plan->lefttree = lefttree; + plan->righttree = righttree; + node->hashclauses = hashclauses; + node->hashjointable = NULL; + node->hashjointablekey = 0; + node->hashjointablesize = 0; + node->hashdone = false; + + return (node); } -static Hash * -make_hash(List *tlist, Var *hashkey, Plan *lefttree) +static Hash * +make_hash(List * tlist, Var * hashkey, Plan * lefttree) { - Hash *node = makeNode(Hash); - Plan *plan = &node->plan; - - plan->cost = 0.0; - plan->state = (EState *)NULL; - plan->targetlist = tlist; - plan->qual = NULL; - plan->lefttree = lefttree; - plan->righttree = NULL; - node->hashkey = hashkey; - node->hashtable = NULL; - node->hashtablekey = 0; - node->hashtablesize = 0; - - return(node); + Hash *node = makeNode(Hash); + Plan *plan = &node->plan; + + plan->cost = 0.0; + plan->state = (EState *) NULL; + plan->targetlist = tlist; + plan->qual = NULL; + plan->lefttree = lefttree; + plan->righttree = NULL; + node->hashkey = hashkey; + node->hashtable = NULL; + node->hashtablekey = 0; + node->hashtablesize = 0; + + return (node); } static MergeJoin * -make_mergesort(List *tlist, - List *qpqual, - List *mergeclauses, - Oid opcode, - Oid *rightorder, - Oid *leftorder, - Plan *righttree, - Plan *lefttree) +make_mergesort(List * tlist, + List * qpqual, + List * mergeclauses, + Oid opcode, + Oid * rightorder, + Oid * leftorder, + Plan * righttree, + Plan * lefttree) { - MergeJoin *node = makeNode(MergeJoin); - Plan *plan = &node->join; - - plan->cost = 0.0; - plan->state = (EState *)NULL; - plan->targetlist = tlist; - plan->qual = qpqual; - plan->lefttree = lefttree; - plan->righttree = righttree; - node->mergeclauses = mergeclauses; - node->mergesortop = opcode; - node->mergerightorder = rightorder; - node->mergeleftorder = leftorder; - - return(node); + MergeJoin *node = makeNode(MergeJoin); + Plan *plan = &node->join; + + plan->cost = 0.0; + plan->state = (EState *) NULL; + plan->targetlist = tlist; + plan->qual = qpqual; + plan->lefttree = lefttree; + plan->righttree = righttree; + node->mergeclauses = mergeclauses; + node->mergesortop = opcode; + node->mergerightorder = rightorder; + node->mergeleftorder = leftorder; + + return (node); } -Sort * -make_sort(List *tlist, Oid tempid, Plan *lefttree, int keycount) +Sort * +make_sort(List * tlist, Oid tempid, Plan * lefttree, int keycount) { - Sort *node = makeNode(Sort); - Plan *plan = &node->plan; - - plan->cost = 0.0; - plan->state = (EState *)NULL; - plan->targetlist = tlist; - plan->qual = NIL; - plan->lefttree = lefttree; - plan->righttree = NULL; - node->tempid = tempid; - node->keycount = keycount; - - return(node); + Sort *node = makeNode(Sort); + Plan *plan = &node->plan; + + plan->cost = 0.0; + plan->state = (EState *) NULL; + plan->targetlist = tlist; + plan->qual = NIL; + plan->lefttree = lefttree; + plan->righttree = NULL; + node->tempid = tempid; + node->keycount = keycount; + + return (node); } static Material * -make_material(List *tlist, - Oid tempid, - Plan *lefttree, - int keycount) +make_material(List * tlist, + Oid tempid, + Plan * lefttree, + int keycount) { - Material *node = makeNode(Material); - Plan *plan = &node->plan; - - plan->cost = 0.0; - plan->state = (EState *)NULL; - plan->targetlist = tlist; - plan->qual = NIL; - plan->lefttree = lefttree; - plan->righttree = NULL; - node->tempid = tempid; - node->keycount = keycount; - - return(node); + Material *node = makeNode(Material); + Plan *plan = &node->plan; + + plan->cost = 0.0; + plan->state = (EState *) NULL; + plan->targetlist = tlist; + plan->qual = NIL; + plan->lefttree = lefttree; + plan->righttree = NULL; + node->tempid = tempid; + node->keycount = keycount; + + return (node); } -Agg * -make_agg(List *tlist, int nagg, Aggreg **aggs) +Agg * +make_agg(List * tlist, int nagg, Aggreg ** aggs) { - Agg *node = makeNode(Agg); - - node->plan.cost = 0.0; - node->plan.state = (EState*)NULL; - node->plan.qual = NULL; - node->plan.targetlist = tlist; - node->plan.lefttree = (Plan*)NULL; - node->plan.righttree = (Plan*)NULL; - node->numAgg = nagg; - node->aggs = aggs; - - return(node); + Agg *node = makeNode(Agg); + + node->plan.cost = 0.0; + node->plan.state = (EState *) NULL; + node->plan.qual = NULL; + node->plan.targetlist = tlist; + node->plan.lefttree = (Plan *) NULL; + node->plan.righttree = (Plan *) NULL; + node->numAgg = nagg; + node->aggs = aggs; + + return (node); } -Group * -make_group(List *tlist, - bool tuplePerGroup, - int ngrp, - AttrNumber *grpColIdx, - Sort *lefttree) +Group * +make_group(List * tlist, + bool tuplePerGroup, + int ngrp, + AttrNumber * grpColIdx, + Sort * lefttree) { - Group *node = makeNode(Group); - - node->plan.cost = 0.0; - node->plan.state = (EState*)NULL; - node->plan.qual = NULL; - node->plan.targetlist = tlist; - node->plan.lefttree = (Plan*)lefttree; - node->plan.righttree = (Plan*)NULL; - node->tuplePerGroup = tuplePerGroup; - node->numCols = ngrp; - node->grpColIdx = grpColIdx; - - return(node); + Group *node = makeNode(Group); + + node->plan.cost = 0.0; + node->plan.state = (EState *) NULL; + node->plan.qual = NULL; + node->plan.targetlist = tlist; + node->plan.lefttree = (Plan *) lefttree; + node->plan.righttree = (Plan *) NULL; + node->tuplePerGroup = tuplePerGroup; + node->numCols = ngrp; + node->grpColIdx = grpColIdx; + + return (node); } /* - * A unique node always has a SORT node in the lefttree. + * A unique node always has a SORT node in the lefttree. * - * the uniqueAttr argument must be a null-terminated string, - * either the name of the attribute to select unique on + * the uniqueAttr argument must be a null-terminated string, + * either the name of the attribute to select unique on * or "*" */ -Unique * -make_unique(List *tlist, Plan *lefttree, char* uniqueAttr) +Unique * +make_unique(List * tlist, Plan * lefttree, char *uniqueAttr) { - Unique *node = makeNode(Unique); - Plan *plan = &node->plan; - - plan->cost = 0.0; - plan->state = (EState *)NULL; - plan->targetlist = tlist; - plan->qual = NIL; - plan->lefttree = lefttree; - plan->righttree = NULL; - node->tempid = _TEMP_RELATION_ID_; - node->keycount = 0; - if (strcmp(uniqueAttr,"*") == 0) - node->uniqueAttr = NULL; - else - { - node->uniqueAttr=pstrdup(uniqueAttr); - } - return(node); + Unique *node = makeNode(Unique); + Plan *plan = &node->plan; + + plan->cost = 0.0; + plan->state = (EState *) NULL; + plan->targetlist = tlist; + plan->qual = NIL; + plan->lefttree = lefttree; + plan->righttree = NULL; + node->tempid = _TEMP_RELATION_ID_; + node->keycount = 0; + if (strcmp(uniqueAttr, "*") == 0) + node->uniqueAttr = NULL; + else + { + node->uniqueAttr = pstrdup(uniqueAttr); + } + return (node); } -List *generate_fjoin(List *tlist) +List * +generate_fjoin(List * tlist) { #if 0 - List tlistP; - List newTlist = NIL; - List fjoinList = NIL; - int nIters = 0; - - /* - * Break the target list into elements with Iter nodes, - * and those without them. - */ - foreach(tlistP, tlist) { - List tlistElem; - - tlistElem = lfirst(tlistP); - if (IsA(lsecond(tlistElem),Iter)) { - nIters++; - fjoinList = lappend(fjoinList, tlistElem); - } else { - newTlist = lappend(newTlist, tlistElem); + List tlistP; + List newTlist = NIL; + List fjoinList = NIL; + int nIters = 0; + + /* + * Break the target list into elements with Iter nodes, and those + * without them. + */ + foreach(tlistP, tlist) + { + List tlistElem; + + tlistElem = lfirst(tlistP); + if (IsA(lsecond(tlistElem), Iter)) + { + nIters++; + fjoinList = lappend(fjoinList, tlistElem); + } + else + { + newTlist = lappend(newTlist, tlistElem); + } + } + + /* + * if we have an Iter node then we need to flatten. + */ + if (nIters > 0) + { + List *inner; + List *tempList; + Fjoin *fjoinNode; + DatumPtr results = (DatumPtr) palloc(nIters * sizeof(Datum)); + BoolPtr alwaysDone = (BoolPtr) palloc(nIters * sizeof(bool)); + + inner = lfirst(fjoinList); + fjoinList = lnext(fjoinList); + fjoinNode = (Fjoin) MakeFjoin(false, + nIters, + inner, + results, + alwaysDone); + tempList = lcons(fjoinNode, NIL); + tempList = nconc(tempList, fjoinList); + newTlist = lappend(newTlist, tempList); } - } - - /* - * if we have an Iter node then we need to flatten. - */ - if (nIters > 0) { - List *inner; - List *tempList; - Fjoin *fjoinNode; - DatumPtr results = (DatumPtr)palloc(nIters*sizeof(Datum)); - BoolPtr alwaysDone = (BoolPtr)palloc(nIters*sizeof(bool)); - - inner = lfirst(fjoinList); - fjoinList = lnext(fjoinList); - fjoinNode = (Fjoin)MakeFjoin(false, - nIters, - inner, - results, - alwaysDone); - tempList = lcons(fjoinNode, NIL); - tempList = nconc(tempList, fjoinList); - newTlist = lappend(newTlist, tempList); - } - return newTlist; + return newTlist; #endif - return tlist; /* do nothing for now - ay 10/94 */ + return tlist; /* do nothing for now - ay 10/94 */ } diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 35b3969b702..62ff23f207e 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * initsplan.c-- - * Target list, qualification, joininfo initialization routines + * Target list, qualification, joininfo initialization routines * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.5 1997/04/24 16:04:23 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.6 1997/09/07 04:44:00 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -33,370 +33,397 @@ #include "optimizer/clauses.h" #include "optimizer/cost.h" -extern int Quiet; +extern int Quiet; -static void add_clause_to_rels(Query *root, List *clause); -static void add_join_clause_info_to_rels(Query *root, CInfo *clauseinfo, - List *join_relids); -static void add_vars_to_rels(Query *root, List *vars, List *join_relids); +static void add_clause_to_rels(Query * root, List * clause); +static void +add_join_clause_info_to_rels(Query * root, CInfo * clauseinfo, + List * join_relids); +static void add_vars_to_rels(Query * root, List * vars, List * join_relids); -static MergeOrder *mergesortop(Expr *clause); -static Oid hashjoinop(Expr *clause); +static MergeOrder *mergesortop(Expr * clause); +static Oid hashjoinop(Expr * clause); /***************************************************************************** * - * TARGET LISTS + * TARGET LISTS * *****************************************************************************/ -/* +/* * initialize_rel_nodes-- - * Creates rel nodes for every relation mentioned in the target list - * 'tlist' (if a node hasn't already been created) and adds them to - * *query-relation-list*. Creates targetlist entries for each member of - * 'tlist' and adds them to the tlist field of the appropriate rel node. - * - * Returns nothing. + * Creates rel nodes for every relation mentioned in the target list + * 'tlist' (if a node hasn't already been created) and adds them to + * *query-relation-list*. Creates targetlist entries for each member of + * 'tlist' and adds them to the tlist field of the appropriate rel node. + * + * Returns nothing. */ void -initialize_base_rels_list(Query *root, List *tlist) +initialize_base_rels_list(Query * root, List * tlist) { - List *tlist_vars = NIL; - List *l = NIL; - List *tvar = NIL; - - foreach (l, tlist) { - TargetEntry *entry = (TargetEntry *) lfirst(l); - - tlist_vars = append(tlist_vars, pull_var_clause(entry->expr)); - } - - /* now, the target list only contains Var nodes */ - foreach (tvar, tlist_vars) { - Var *var; - Index varno; - Rel *result; - - var = (Var*)lfirst(tvar); - varno = var->varno; - result = get_base_rel(root, varno); - - add_tl_element(result, var); - } + List *tlist_vars = NIL; + List *l = NIL; + List *tvar = NIL; + + foreach(l, tlist) + { + TargetEntry *entry = (TargetEntry *) lfirst(l); + + tlist_vars = append(tlist_vars, pull_var_clause(entry->expr)); + } + + /* now, the target list only contains Var nodes */ + foreach(tvar, tlist_vars) + { + Var *var; + Index varno; + Rel *result; + + var = (Var *) lfirst(tvar); + varno = var->varno; + result = get_base_rel(root, varno); + + add_tl_element(result, var); + } } /* * add_missing_variables_to_base_rels - - * If we have range variable(s) in the FROM clause that does not appear - * in the target list nor qualifications, we add it to the base relation - * list. For instance, "select f.x from foo f, foo f2" is a join of f and - * f2. Note that if we have "select foo.x from foo f", it also gets turned - * into a join. + * If we have range variable(s) in the FROM clause that does not appear + * in the target list nor qualifications, we add it to the base relation + * list. For instance, "select f.x from foo f, foo f2" is a join of f and + * f2. Note that if we have "select foo.x from foo f", it also gets turned + * into a join. */ void -add_missing_vars_to_base_rels(Query *root, List *tlist) +add_missing_vars_to_base_rels(Query * root, List * tlist) { - List *l; - int varno; - - varno = 1; - foreach (l, root->rtable) { - RangeTblEntry *rte = (RangeTblEntry *)lfirst(l); - List *relids; - Rel *result; - Var *var; - - relids = lconsi(varno, NIL); - if (rte->inFromCl && - !rel_member(relids, root->base_relation_list_)) { - - var = makeVar(varno, -2 , 26, varno, -2); - /* add it to base_relation_list_ */ - result = get_base_rel(root, varno); - add_tl_element(result, var); + List *l; + int varno; + + varno = 1; + foreach(l, root->rtable) + { + RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); + List *relids; + Rel *result; + Var *var; + + relids = lconsi(varno, NIL); + if (rte->inFromCl && + !rel_member(relids, root->base_relation_list_)) + { + + var = makeVar(varno, -2, 26, varno, -2); + /* add it to base_relation_list_ */ + result = get_base_rel(root, varno); + add_tl_element(result, var); + } + pfree(relids); + varno++; } - pfree(relids); - varno++; - } - return; + return; } /***************************************************************************** * - * QUALIFICATIONS + * QUALIFICATIONS * *****************************************************************************/ -/* +/* * initialize-qualification-- - * Initializes ClauseInfo and JoinInfo fields of relation entries for all - * relations appearing within clauses. Creates new relation entries if - * necessary, adding them to *query-relation-list*. - * - * Returns nothing of interest. + * Initializes ClauseInfo and JoinInfo fields of relation entries for all + * relations appearing within clauses. Creates new relation entries if + * necessary, adding them to *query-relation-list*. + * + * Returns nothing of interest. */ void -initialize_base_rels_jinfo(Query *root, List *clauses) +initialize_base_rels_jinfo(Query * root, List * clauses) { - List *clause; + List *clause; - foreach (clause, clauses) { - add_clause_to_rels(root, lfirst(clause)); - } - return; + foreach(clause, clauses) + { + add_clause_to_rels(root, lfirst(clause)); + } + return; } -/* +/* * add-clause-to-rels-- - * Add clause information to either the 'ClauseInfo' or 'JoinInfo' field - * of a relation entry(depending on whether or not the clause is a join) - * by creating a new ClauseInfo node and setting appropriate fields - * within the nodes. - * - * Returns nothing of interest. + * Add clause information to either the 'ClauseInfo' or 'JoinInfo' field + * of a relation entry(depending on whether or not the clause is a join) + * by creating a new ClauseInfo node and setting appropriate fields + * within the nodes. + * + * Returns nothing of interest. */ static void -add_clause_to_rels(Query *root, List *clause) +add_clause_to_rels(Query * root, List * clause) { - List *relids; - List *vars; - CInfo *clauseinfo = makeNode(CInfo); + List *relids; + List *vars; + CInfo *clauseinfo = makeNode(CInfo); - /* - * Retrieve all relids and vars contained within the clause. - */ - clause_relids_vars((Node*)clause, &relids, &vars); + /* + * Retrieve all relids and vars contained within the clause. + */ + clause_relids_vars((Node *) clause, &relids, &vars); - clauseinfo->clause = (Expr*)clause; - clauseinfo->notclause = contains_not((Node*)clause); - clauseinfo->selectivity = 0; - clauseinfo->indexids = NIL; - clauseinfo->mergesortorder = (MergeOrder*)NULL; - clauseinfo->hashjoinoperator = (Oid)0; - + clauseinfo->clause = (Expr *) clause; + clauseinfo->notclause = contains_not((Node *) clause); + clauseinfo->selectivity = 0; + clauseinfo->indexids = NIL; + clauseinfo->mergesortorder = (MergeOrder *) NULL; + clauseinfo->hashjoinoperator = (Oid) 0; - if(length(relids) == 1) { - Rel *rel = get_base_rel(root, lfirsti(relids)); - - /* - * There is only one relation participating in 'clause', - * so 'clause' must be a restriction clause. - */ - /* the selectivity of the clause must be computed - regardless of whether it's a restriction or a join clause */ - if (is_funcclause((Node*)clause)) - { + if (length(relids) == 1) + { + Rel *rel = get_base_rel(root, lfirsti(relids)); + /* - * XXX If we have a func clause set selectivity to 1/3, - * really need a true selectivity function. + * There is only one relation participating in 'clause', so + * 'clause' must be a restriction clause. */ - clauseinfo->selectivity = (Cost)0.3333333; - } - else - { - clauseinfo->selectivity = - compute_clause_selec(root, (Node*)clause, - NIL); - } - rel->clauseinfo = lcons(clauseinfo, - rel->clauseinfo); - } else { - /* - * 'clause' is a join clause, since there is more than one - * atom in the relid list. - */ - - if (is_funcclause((Node*)clause)) - { + /* - * XXX If we have a func clause set selectivity to 1/3, - * really need a true selectivity function. + * the selectivity of the clause must be computed regardless of + * whether it's a restriction or a join clause */ - clauseinfo->selectivity = (Cost)0.3333333; - } + if (is_funcclause((Node *) clause)) + { + + /* + * XXX If we have a func clause set selectivity to 1/3, really + * need a true selectivity function. + */ + clauseinfo->selectivity = (Cost) 0.3333333; + } + else + { + clauseinfo->selectivity = + compute_clause_selec(root, (Node *) clause, + NIL); + } + rel->clauseinfo = lcons(clauseinfo, + rel->clauseinfo); + } else - { - clauseinfo->selectivity = - compute_clause_selec(root, (Node*)clause, - NIL); - } - add_join_clause_info_to_rels(root, clauseinfo, relids); - add_vars_to_rels(root,vars, relids); - } + { + + /* + * 'clause' is a join clause, since there is more than one atom in + * the relid list. + */ + + if (is_funcclause((Node *) clause)) + { + + /* + * XXX If we have a func clause set selectivity to 1/3, really + * need a true selectivity function. + */ + clauseinfo->selectivity = (Cost) 0.3333333; + } + else + { + clauseinfo->selectivity = + compute_clause_selec(root, (Node *) clause, + NIL); + } + add_join_clause_info_to_rels(root, clauseinfo, relids); + add_vars_to_rels(root, vars, relids); + } } -/* +/* * add-join-clause-info-to-rels-- - * For every relation participating in a join clause, add 'clauseinfo' to - * the appropriate joininfo node(creating a new one and adding it to the - * appropriate rel node if necessary). - * + * For every relation participating in a join clause, add 'clauseinfo' to + * the appropriate joininfo node(creating a new one and adding it to the + * appropriate rel node if necessary). + * * 'clauseinfo' describes the join clause * 'join-relids' is the list of relations participating in the join clause - * + * * Returns nothing. - * + * */ static void -add_join_clause_info_to_rels(Query *root, CInfo *clauseinfo, List *join_relids) +add_join_clause_info_to_rels(Query * root, CInfo * clauseinfo, List * join_relids) { - List *join_relid; - - foreach (join_relid, join_relids) { - JInfo *joininfo; - List *other_rels = NIL; - List *rel; - - foreach (rel, join_relids) - { - if ( lfirsti(rel) != lfirsti(join_relid) ) - other_rels = lappendi (other_rels, lfirsti(rel)); - } - - joininfo = - find_joininfo_node(get_base_rel(root, lfirsti(join_relid)), - other_rels); - joininfo->jinfoclauseinfo = - lcons(copyObject((void*)clauseinfo), joininfo->jinfoclauseinfo); - - } + List *join_relid; + + foreach(join_relid, join_relids) + { + JInfo *joininfo; + List *other_rels = NIL; + List *rel; + + foreach(rel, join_relids) + { + if (lfirsti(rel) != lfirsti(join_relid)) + other_rels = lappendi(other_rels, lfirsti(rel)); + } + + joininfo = + find_joininfo_node(get_base_rel(root, lfirsti(join_relid)), + other_rels); + joininfo->jinfoclauseinfo = + lcons(copyObject((void *) clauseinfo), joininfo->jinfoclauseinfo); + + } } -/* +/* * add-vars-to-rels-- - * For each variable appearing in a clause, - * (1) If a targetlist entry for the variable is not already present in - * the appropriate relation's target list, add one. - * (2) If a targetlist entry is already present, but the var is part of a - * join clause, add the relids of the join relations to the JoinList - * entry of the targetlist entry. - * - * 'vars' is the list of var nodes - * 'join-relids' is the list of relids appearing in the join clause - * (if this is a join clause) - * - * Returns nothing. + * For each variable appearing in a clause, + * (1) If a targetlist entry for the variable is not already present in + * the appropriate relation's target list, add one. + * (2) If a targetlist entry is already present, but the var is part of a + * join clause, add the relids of the join relations to the JoinList + * entry of the targetlist entry. + * + * 'vars' is the list of var nodes + * 'join-relids' is the list of relids appearing in the join clause + * (if this is a join clause) + * + * Returns nothing. */ static void -add_vars_to_rels(Query *root, List *vars, List *join_relids) +add_vars_to_rels(Query * root, List * vars, List * join_relids) { - Var *var; - List *temp = NIL; - Rel *rel = (Rel*)NULL; - TargetEntry *tlistentry; - - foreach (temp, vars) { - var = (Var*)lfirst(temp); - rel = get_base_rel(root, var->varno); - tlistentry = tlistentry_member(var, rel->targetlist); - if(tlistentry==NULL) - /* add a new entry */ - add_tl_element(rel, var); - } + Var *var; + List *temp = NIL; + Rel *rel = (Rel *) NULL; + TargetEntry *tlistentry; + + foreach(temp, vars) + { + var = (Var *) lfirst(temp); + rel = get_base_rel(root, var->varno); + tlistentry = tlistentry_member(var, rel->targetlist); + if (tlistentry == NULL) + /* add a new entry */ + add_tl_element(rel, var); + } } /***************************************************************************** * - * JOININFO + * JOININFO * *****************************************************************************/ -/* +/* * initialize-join-clause-info-- - * Set the MergeSortable or HashJoinable field for every joininfo node - * (within a rel node) and the MergeSortOrder or HashJoinOp field for - * each clauseinfo node(within a joininfo node) for all relations in a - * query. - * - * Returns nothing. + * Set the MergeSortable or HashJoinable field for every joininfo node + * (within a rel node) and the MergeSortOrder or HashJoinOp field for + * each clauseinfo node(within a joininfo node) for all relations in a + * query. + * + * Returns nothing. */ void -initialize_join_clause_info(List *rel_list) +initialize_join_clause_info(List * rel_list) { - List *x, *y, *z; - Rel *rel; - JInfo *joininfo; - CInfo *clauseinfo; - Expr *clause; - - foreach (x, rel_list) { - rel = (Rel*)lfirst(x); - foreach (y, rel->joininfo) { - joininfo = (JInfo*)lfirst(y); - foreach (z, joininfo->jinfoclauseinfo) { - clauseinfo = (CInfo*)lfirst(z); - clause = clauseinfo->clause; - if(join_clause_p((Node*)clause)) { - MergeOrder *sortop = (MergeOrder*)NULL; - Oid hashop = (Oid)NULL; - - if (_enable_mergesort_) - sortop = mergesortop(clause); - if (_enable_hashjoin_) - hashop = hashjoinop(clause); - - if (sortop) { - clauseinfo->mergesortorder = sortop; - joininfo->mergesortable = true; - } - if (hashop) { - clauseinfo->hashjoinoperator = hashop; - joininfo->hashjoinable = true; - } + List *x, + *y, + *z; + Rel *rel; + JInfo *joininfo; + CInfo *clauseinfo; + Expr *clause; + + foreach(x, rel_list) + { + rel = (Rel *) lfirst(x); + foreach(y, rel->joininfo) + { + joininfo = (JInfo *) lfirst(y); + foreach(z, joininfo->jinfoclauseinfo) + { + clauseinfo = (CInfo *) lfirst(z); + clause = clauseinfo->clause; + if (join_clause_p((Node *) clause)) + { + MergeOrder *sortop = (MergeOrder *) NULL; + Oid hashop = (Oid) NULL; + + if (_enable_mergesort_) + sortop = mergesortop(clause); + if (_enable_hashjoin_) + hashop = hashjoinop(clause); + + if (sortop) + { + clauseinfo->mergesortorder = sortop; + joininfo->mergesortable = true; + } + if (hashop) + { + clauseinfo->hashjoinoperator = hashop; + joininfo->hashjoinable = true; + } + } + } } - } } - } } -/* +/* * mergesortop-- - * Returns the mergesort operator of an operator iff 'clause' is - * mergesortable, i.e., both operands are single vars and the operator is - * a mergesortable operator. + * Returns the mergesort operator of an operator iff 'clause' is + * mergesortable, i.e., both operands are single vars and the operator is + * a mergesortable operator. */ static MergeOrder * -mergesortop(Expr *clause) +mergesortop(Expr * clause) { - Oid leftOp, rightOp; - bool sortable; - - sortable = op_mergesortable(((Oper*)clause->oper)->opno, - (get_leftop(clause))->vartype, - (get_rightop(clause))->vartype, - &leftOp, - &rightOp); - - if (sortable) { - MergeOrder *morder = makeNode(MergeOrder); - - morder->join_operator = ((Oper*)clause->oper)->opno; - morder->left_operator = leftOp; - morder->right_operator = rightOp; - morder->left_type = (get_leftop(clause))->vartype; - morder->right_type = (get_rightop(clause))->vartype; - return (morder); - } else - return(NULL); + Oid leftOp, + rightOp; + bool sortable; + + sortable = op_mergesortable(((Oper *) clause->oper)->opno, + (get_leftop(clause))->vartype, + (get_rightop(clause))->vartype, + &leftOp, + &rightOp); + + if (sortable) + { + MergeOrder *morder = makeNode(MergeOrder); + + morder->join_operator = ((Oper *) clause->oper)->opno; + morder->left_operator = leftOp; + morder->right_operator = rightOp; + morder->left_type = (get_leftop(clause))->vartype; + morder->right_type = (get_rightop(clause))->vartype; + return (morder); + } + else + return (NULL); } -/* +/* * hashjoinop-- - * Returns the hashjoin operator of an operator iff 'clause' is - * hashjoinable, i.e., both operands are single vars and the operator is - * a hashjoinable operator. + * Returns the hashjoin operator of an operator iff 'clause' is + * hashjoinable, i.e., both operands are single vars and the operator is + * a hashjoinable operator. */ -static Oid -hashjoinop(Expr *clause) +static Oid +hashjoinop(Expr * clause) { - return(op_hashjoinable(((Oper*)clause->oper)->opno, - (get_leftop(clause))->vartype, - (get_rightop(clause))->vartype)); + return (op_hashjoinable(((Oper *) clause->oper)->opno, + (get_leftop(clause))->vartype, + (get_rightop(clause))->vartype)); } diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index 7f70d76ac6c..630ed12d2a1 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * planmain.c-- - * Routines to plan a single query + * Routines to plan a single query * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.4 1997/04/29 04:32:50 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.5 1997/09/07 04:44:02 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -38,506 +38,536 @@ #include "utils/mcxt.h" #include "utils/lsyscache.h" -static Plan *subplanner(Query *root, List *flat_tlist, List *qual); -static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan); +static Plan *subplanner(Query * root, List * flat_tlist, List * qual); +static Result *make_result(List * tlist, Node * resconstantqual, Plan * subplan); -static Plan *make_groupPlan(List **tlist, bool tuplePerGroup, - List *groupClause, Plan *subplan); +static Plan * +make_groupPlan(List ** tlist, bool tuplePerGroup, + List * groupClause, Plan * subplan); -/* +/* * query_planner-- - * Routine to create a query plan. It does so by first creating a - * subplan for the topmost level of attributes in the query. Then, - * it modifies all target list and qualifications to consider the next - * level of nesting and creates a plan for this modified query by - * recursively calling itself. The two pieces are then merged together - * by creating a result node that indicates which attributes should - * be placed where and any relation level qualifications to be - * satisfied. - * - * command-type is the query command, e.g., retrieve, delete, etc. - * tlist is the target list of the query - * qual is the qualification of the query - * - * Returns a query plan. + * Routine to create a query plan. It does so by first creating a + * subplan for the topmost level of attributes in the query. Then, + * it modifies all target list and qualifications to consider the next + * level of nesting and creates a plan for this modified query by + * recursively calling itself. The two pieces are then merged together + * by creating a result node that indicates which attributes should + * be placed where and any relation level qualifications to be + * satisfied. + * + * command-type is the query command, e.g., retrieve, delete, etc. + * tlist is the target list of the query + * qual is the qualification of the query + * + * Returns a query plan. */ -Plan * -query_planner(Query *root, - int command_type, - List *tlist, - List *qual) +Plan * +query_planner(Query * root, + int command_type, + List * tlist, + List * qual) { - List *constant_qual = NIL; - List *flattened_tlist = NIL; - List *level_tlist = NIL; - Plan *subplan = (Plan*)NULL; - Agg *aggplan = NULL; - - /* - * A command without a target list or qualification is an error, - * except for "delete foo". - */ - if (tlist==NIL && qual==NULL) { - if (command_type == CMD_DELETE || - /* Total hack here. I don't know how to handle - statements like notify in action bodies. - Notify doesn't return anything but - scans a system table. */ - command_type == CMD_NOTIFY) { - return ((Plan*)make_seqscan(NIL, - NIL, - root->resultRelation, - (Plan*)NULL)); - } else - return((Plan*)NULL); - } - - /* - * Pull out any non-variable qualifications so these can be put in - * the topmost result node. The opids for the remaining - * qualifications will be changed to regprocs later. - */ - qual = pull_constant_clauses(qual, &constant_qual); - fix_opids(constant_qual); - - /* - * Create a target list that consists solely of (resdom var) target - * list entries, i.e., contains no arbitrary expressions. - */ - flattened_tlist = flatten_tlist(tlist); - if (flattened_tlist) { - level_tlist = flattened_tlist; - } else { - /* from old code. the logic is beyond me. - ay 2/95 */ - level_tlist = tlist; - } - - /* - * A query may have a non-variable target list and a non-variable - * qualification only under certain conditions: - * - the query creates all-new tuples, or - * - the query is a replace (a scan must still be done in this case). - */ - if (flattened_tlist==NULL && qual==NULL) { - - switch (command_type) { - case CMD_SELECT: - case CMD_INSERT: - return ((Plan*)make_result(tlist, - (Node*)constant_qual, - (Plan*)NULL)); - break; - - case CMD_DELETE: - case CMD_UPDATE: - { - SeqScan *scan = make_seqscan(tlist, - (List *)NULL, - root->resultRelation, - (Plan*)NULL); - if (constant_qual!=NULL) { - return ((Plan*)make_result(tlist, - (Node*)constant_qual, - (Plan*)scan)); - } else { - return ((Plan*)scan); - } - } - break; - - default: - return ((Plan*)NULL); + List *constant_qual = NIL; + List *flattened_tlist = NIL; + List *level_tlist = NIL; + Plan *subplan = (Plan *) NULL; + Agg *aggplan = NULL; + + /* + * A command without a target list or qualification is an error, + * except for "delete foo". + */ + if (tlist == NIL && qual == NULL) + { + if (command_type == CMD_DELETE || + + /* + * Total hack here. I don't know how to handle statements like + * notify in action bodies. Notify doesn't return anything but + * scans a system table. + */ + command_type == CMD_NOTIFY) + { + return ((Plan *) make_seqscan(NIL, + NIL, + root->resultRelation, + (Plan *) NULL)); + } + else + return ((Plan *) NULL); + } + + /* + * Pull out any non-variable qualifications so these can be put in the + * topmost result node. The opids for the remaining qualifications + * will be changed to regprocs later. + */ + qual = pull_constant_clauses(qual, &constant_qual); + fix_opids(constant_qual); + + /* + * Create a target list that consists solely of (resdom var) target + * list entries, i.e., contains no arbitrary expressions. + */ + flattened_tlist = flatten_tlist(tlist); + if (flattened_tlist) + { + level_tlist = flattened_tlist; + } + else + { + /* from old code. the logic is beyond me. - ay 2/95 */ + level_tlist = tlist; } - } - - /* - * Find the subplan (access path) and destructively modify the - * target list of the newly created subplan to contain the appropriate - * join references. - */ - subplan = subplanner(root, level_tlist, qual); - - set_tlist_references(subplan); - - /* - * If we have a GROUP BY clause, insert a group node (with the appropriate - * sort node.) - */ - if (root->groupClause != NULL) { - bool tuplePerGroup; /* - * decide whether how many tuples per group the Group node needs - * to return. (Needs only one tuple per group if no aggregate is - * present. Otherwise, need every tuple from the group to do the - * aggregation.) + * A query may have a non-variable target list and a non-variable + * qualification only under certain conditions: - the query creates + * all-new tuples, or - the query is a replace (a scan must still be + * done in this case). */ - tuplePerGroup = ( root->qry_aggs ) ? TRUE : FALSE; - - subplan = - make_groupPlan(&tlist, tuplePerGroup, root->groupClause, subplan); - - } - - /* - * If aggregate is present, insert the agg node - */ - if ( root->qry_aggs ) - { - aggplan = make_agg(tlist, root->qry_numAgg, root->qry_aggs); - aggplan->plan.lefttree = subplan; + if (flattened_tlist == NULL && qual == NULL) + { + + switch (command_type) + { + case CMD_SELECT: + case CMD_INSERT: + return ((Plan *) make_result(tlist, + (Node *) constant_qual, + (Plan *) NULL)); + break; + + case CMD_DELETE: + case CMD_UPDATE: + { + SeqScan *scan = make_seqscan(tlist, + (List *) NULL, + root->resultRelation, + (Plan *) NULL); + + if (constant_qual != NULL) + { + return ((Plan *) make_result(tlist, + (Node *) constant_qual, + (Plan *) scan)); + } + else + { + return ((Plan *) scan); + } + } + break; + + default: + return ((Plan *) NULL); + } + } + /* - * set the varno/attno entries to the appropriate references to - * the result tuple of the subplans. (We need to set those in the - * array of aggreg's in the Agg node also. Even though they're - * pointers, after a few dozen's of copying, they're not the same as - * those in the target list.) + * Find the subplan (access path) and destructively modify the target + * list of the newly created subplan to contain the appropriate join + * references. */ - set_agg_tlist_references (aggplan); - set_agg_agglist_references (aggplan); - - subplan = (Plan*)aggplan; - - tlist = aggplan->plan.targetlist; - } - - /* - * Build a result node linking the plan if we have constant quals - */ - if (constant_qual) { - Plan *plan; - - plan = (Plan*)make_result(tlist, - (Node*)constant_qual, - subplan); + subplan = subplanner(root, level_tlist, qual); + + set_tlist_references(subplan); + /* - * Change all varno's of the Result's node target list. + * If we have a GROUP BY clause, insert a group node (with the + * appropriate sort node.) */ - set_result_tlist_references((Result*)plan); - - return (plan); - } - - /* - * fix up the flattened target list of the plan root node so that - * expressions are evaluated. this forces expression evaluations - * that may involve expensive function calls to be delayed to - * the very last stage of query execution. this could be bad. - * but it is joey's responsibility to optimally push these - * expressions down the plan tree. -- Wei - * - * But now nothing to do if there are GroupBy and/or Aggregates: - * 1. make_groupPlan fixes tlist; 2. flatten_tlist_vars does nothing - * with aggregates fixing only other entries (i.e. - GroupBy-ed and - * so fixed by make_groupPlan). - vadim 04/05/97 - */ - if ( root->groupClause == NULL && aggplan == NULL ) - { - subplan->targetlist = flatten_tlist_vars(tlist, - subplan->targetlist); - } - - /* - * Destructively modify the query plan's targetlist to add fjoin - * lists to flatten functions that return sets of base types - */ - subplan->targetlist = generate_fjoin(subplan->targetlist); - - return (subplan); + if (root->groupClause != NULL) + { + bool tuplePerGroup; + + /* + * decide whether how many tuples per group the Group node needs + * to return. (Needs only one tuple per group if no aggregate is + * present. Otherwise, need every tuple from the group to do the + * aggregation.) + */ + tuplePerGroup = (root->qry_aggs) ? TRUE : FALSE; + + subplan = + make_groupPlan(&tlist, tuplePerGroup, root->groupClause, subplan); + + } + + /* + * If aggregate is present, insert the agg node + */ + if (root->qry_aggs) + { + aggplan = make_agg(tlist, root->qry_numAgg, root->qry_aggs); + aggplan->plan.lefttree = subplan; + + /* + * set the varno/attno entries to the appropriate references to + * the result tuple of the subplans. (We need to set those in the + * array of aggreg's in the Agg node also. Even though they're + * pointers, after a few dozen's of copying, they're not the same + * as those in the target list.) + */ + set_agg_tlist_references(aggplan); + set_agg_agglist_references(aggplan); + + subplan = (Plan *) aggplan; + + tlist = aggplan->plan.targetlist; + } + + /* + * Build a result node linking the plan if we have constant quals + */ + if (constant_qual) + { + Plan *plan; + + plan = (Plan *) make_result(tlist, + (Node *) constant_qual, + subplan); + + /* + * Change all varno's of the Result's node target list. + */ + set_result_tlist_references((Result *) plan); + + return (plan); + } + + /* + * fix up the flattened target list of the plan root node so that + * expressions are evaluated. this forces expression evaluations that + * may involve expensive function calls to be delayed to the very last + * stage of query execution. this could be bad. but it is joey's + * responsibility to optimally push these expressions down the plan + * tree. -- Wei + * + * But now nothing to do if there are GroupBy and/or Aggregates: 1. + * make_groupPlan fixes tlist; 2. flatten_tlist_vars does nothing with + * aggregates fixing only other entries (i.e. - GroupBy-ed and so + * fixed by make_groupPlan). - vadim 04/05/97 + */ + if (root->groupClause == NULL && aggplan == NULL) + { + subplan->targetlist = flatten_tlist_vars(tlist, + subplan->targetlist); + } + + /* + * Destructively modify the query plan's targetlist to add fjoin lists + * to flatten functions that return sets of base types + */ + subplan->targetlist = generate_fjoin(subplan->targetlist); + + return (subplan); } -/* +/* * subplanner - * - * Subplanner creates an entire plan consisting of joins and scans - * for processing a single level of attributes. - * - * flat-tlist is the flattened target list - * qual is the qualification to be satisfied - * - * Returns a subplan. - * + * + * Subplanner creates an entire plan consisting of joins and scans + * for processing a single level of attributes. + * + * flat-tlist is the flattened target list + * qual is the qualification to be satisfied + * + * Returns a subplan. + * */ -static Plan * -subplanner(Query *root, - List *flat_tlist, - List *qual) +static Plan * +subplanner(Query * root, + List * flat_tlist, + List * qual) { - Rel *final_relation; - List *final_relation_list; - - /* Initialize the targetlist and qualification, adding entries to - * *query-relation-list* as relation references are found (e.g., in the - * qualification, the targetlist, etc.) - */ - root->base_relation_list_ = NIL; - root->join_relation_list_ = NIL; - initialize_base_rels_list(root, flat_tlist); - initialize_base_rels_jinfo(root, qual); - add_missing_vars_to_base_rels(root, flat_tlist); - - /* Find all possible scan and join paths. - * Mark all the clauses and relations that can be processed using special - * join methods, then do the exhaustive path search. - */ - initialize_join_clause_info(root->base_relation_list_); - final_relation_list = find_paths(root, - root->base_relation_list_); - - if (final_relation_list) - final_relation = (Rel*)lfirst (final_relation_list); - else - final_relation = (Rel*)NIL; - -#if 0 /* fix xfunc */ - /* - * Perform Predicate Migration on each path, to optimize and correctly - * assess the cost of each before choosing the cheapest one. - * -- JMH, 11/16/92 - * - * Needn't do so if the top rel is pruneable: that means there's no - * expensive functions left to pull up. -- JMH, 11/22/92 - */ - if (XfuncMode != XFUNC_OFF && XfuncMode != XFUNC_NOPM && - XfuncMode != XFUNC_NOPULL && !final_relation->pruneable) + Rel *final_relation; + List *final_relation_list; + + /* + * Initialize the targetlist and qualification, adding entries to + * *query-relation-list* as relation references are found (e.g., in + * the qualification, the targetlist, etc.) + */ + root->base_relation_list_ = NIL; + root->join_relation_list_ = NIL; + initialize_base_rels_list(root, flat_tlist); + initialize_base_rels_jinfo(root, qual); + add_missing_vars_to_base_rels(root, flat_tlist); + + /* + * Find all possible scan and join paths. Mark all the clauses and + * relations that can be processed using special join methods, then do + * the exhaustive path search. + */ + initialize_join_clause_info(root->base_relation_list_); + final_relation_list = find_paths(root, + root->base_relation_list_); + + if (final_relation_list) + final_relation = (Rel *) lfirst(final_relation_list); + else + final_relation = (Rel *) NIL; + +#if 0 /* fix xfunc */ + + /* + * Perform Predicate Migration on each path, to optimize and correctly + * assess the cost of each before choosing the cheapest one. -- JMH, + * 11/16/92 + * + * Needn't do so if the top rel is pruneable: that means there's no + * expensive functions left to pull up. -- JMH, 11/22/92 + */ + if (XfuncMode != XFUNC_OFF && XfuncMode != XFUNC_NOPM && + XfuncMode != XFUNC_NOPULL && !final_relation->pruneable) { - List *pathnode; - foreach(pathnode, final_relation->pathlist) + List *pathnode; + + foreach(pathnode, final_relation->pathlist) { - if (xfunc_do_predmig((Path*)lfirst(pathnode))) - set_cheapest(final_relation, final_relation->pathlist); + if (xfunc_do_predmig((Path *) lfirst(pathnode))) + set_cheapest(final_relation, final_relation->pathlist); } } #endif - - /* - * Determine the cheapest path and create a subplan corresponding to it. - */ - if (final_relation) { - return (create_plan ((Path*)final_relation->cheapestpath)); - }else { - elog(NOTICE, "final relation is nil"); - return(create_plan ((Path*)NULL)); - } - + + /* + * Determine the cheapest path and create a subplan corresponding to + * it. + */ + if (final_relation) + { + return (create_plan((Path *) final_relation->cheapestpath)); + } + else + { + elog(NOTICE, "final relation is nil"); + return (create_plan((Path *) NULL)); + } + } /***************************************************************************** * *****************************************************************************/ -static Result * -make_result(List *tlist, - Node *resconstantqual, - Plan *subplan) +static Result * +make_result(List * tlist, + Node * resconstantqual, + Plan * subplan) { - Result *node = makeNode(Result); - Plan *plan = &node->plan; - - tlist = generate_fjoin(tlist); - plan->cost = 0.0; - plan->state = (EState *)NULL; - plan->targetlist = tlist; - plan->lefttree = subplan; - plan->righttree = NULL; - node->resconstantqual = resconstantqual; - node->resstate = NULL; - - return(node); -} + Result *node = makeNode(Result); + Plan *plan = &node->plan; + + tlist = generate_fjoin(tlist); + plan->cost = 0.0; + plan->state = (EState *) NULL; + plan->targetlist = tlist; + plan->lefttree = subplan; + plan->righttree = NULL; + node->resconstantqual = resconstantqual; + node->resstate = NULL; + + return (node); +} /***************************************************************************** * *****************************************************************************/ -static Plan * -make_groupPlan(List **tlist, - bool tuplePerGroup, - List *groupClause, - Plan *subplan) +static Plan * +make_groupPlan(List ** tlist, + bool tuplePerGroup, + List * groupClause, + Plan * subplan) { - List *sort_tlist; - List *sl, *gl; - List *glc = listCopy (groupClause); - List *otles = NIL; /* list of removed non-GroupBy entries */ - List *otlvars = NIL; /* list of var in them */ - int otlvcnt; - Sort *sortplan; - Group *grpplan; - int numCols; - AttrNumber *grpColIdx; - int keyno = 1; - int last_resno = 1; - - numCols = length(groupClause); - grpColIdx = (AttrNumber *)palloc(sizeof(AttrNumber)*numCols); - - sort_tlist = new_unsorted_tlist(*tlist); /* it's copy */ - - /* - * Make template TL for subplan, Sort & Group: - * 1. If there are aggregates (tuplePerGroup is true) then take - * away non-GroupBy entries and re-set resno-s accordantly. - * 2. Make grpColIdx - * - * Note: we assume that TLEs in *tlist are ordered in accordance - * with their resdom->resno. - */ - foreach (sl, sort_tlist) - { - Resdom *resdom = NULL; - TargetEntry *te = (TargetEntry *) lfirst (sl); - - foreach (gl, glc) - { - GroupClause *grpcl = (GroupClause*)lfirst(gl); - - if ( grpcl->entry->resdom->resno == te->resdom->resno ) - { - - resdom = te->resdom; - resdom->reskey = keyno; - resdom->reskeyop = get_opcode (grpcl->grpOpoid); - resdom->resno = last_resno; /* re-set */ - grpColIdx[keyno-1] = last_resno++; - keyno++; - glc = lremove (lfirst (gl), glc); /* TLE found for it */ - break; - } - } - /* - * Non-GroupBy entry: remove it from Group/Sort TL if there are - * aggregates in query - it will be evaluated by Aggregate plan + List *sort_tlist; + List *sl, + *gl; + List *glc = listCopy(groupClause); + List *otles = NIL;/* list of removed non-GroupBy entries */ + List *otlvars = NIL; /* list of var in them */ + int otlvcnt; + Sort *sortplan; + Group *grpplan; + int numCols; + AttrNumber *grpColIdx; + int keyno = 1; + int last_resno = 1; + + numCols = length(groupClause); + grpColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols); + + sort_tlist = new_unsorted_tlist(*tlist); /* it's copy */ + + /* + * Make template TL for subplan, Sort & Group: 1. If there are + * aggregates (tuplePerGroup is true) then take away non-GroupBy + * entries and re-set resno-s accordantly. 2. Make grpColIdx + * + * Note: we assume that TLEs in *tlist are ordered in accordance with + * their resdom->resno. */ - if ( resdom == NULL ) + foreach(sl, sort_tlist) { - if ( tuplePerGroup ) - { - otlvars = nconc (otlvars, pull_var_clause (te->expr)); - otles = lcons (te, otles); - sort_tlist = lremove (te, sort_tlist); - } - else - te->resdom->resno = last_resno++; + Resdom *resdom = NULL; + TargetEntry *te = (TargetEntry *) lfirst(sl); + + foreach(gl, glc) + { + GroupClause *grpcl = (GroupClause *) lfirst(gl); + + if (grpcl->entry->resdom->resno == te->resdom->resno) + { + + resdom = te->resdom; + resdom->reskey = keyno; + resdom->reskeyop = get_opcode(grpcl->grpOpoid); + resdom->resno = last_resno; /* re-set */ + grpColIdx[keyno - 1] = last_resno++; + keyno++; + glc = lremove(lfirst(gl), glc); /* TLE found for it */ + break; + } + } + + /* + * Non-GroupBy entry: remove it from Group/Sort TL if there are + * aggregates in query - it will be evaluated by Aggregate plan + */ + if (resdom == NULL) + { + if (tuplePerGroup) + { + otlvars = nconc(otlvars, pull_var_clause(te->expr)); + otles = lcons(te, otles); + sort_tlist = lremove(te, sort_tlist); + } + else + te->resdom->resno = last_resno++; + } } - } - - if ( length (glc) != 0 ) - { - elog(WARN, "group attribute disappeared from target list"); - } - - /* - * If non-GroupBy entries were removed from TL - we are to add Vars for - * them to the end of TL if there are no such Vars in TL already. - */ - - otlvcnt = length (otlvars); - foreach (gl, otlvars) - { - Var *v = (Var*)lfirst (gl); - - if ( tlist_member (v, sort_tlist) == NULL ) + + if (length(glc) != 0) { - sort_tlist = lappend (sort_tlist, - create_tl_element (v, last_resno)); - last_resno++; + elog(WARN, "group attribute disappeared from target list"); } - else /* already in TL */ - otlvcnt--; - } - /* Now otlvcnt is number of Vars added in TL for non-GroupBy entries */ - - /* Make TL for subplan: substitute Vars from subplan TL into new TL */ - sl = flatten_tlist_vars (sort_tlist, subplan->targetlist); - - subplan->targetlist = new_unsorted_tlist (sl); /* there */ - - /* - * Make Sort/Group TL : - * 1. make Var nodes (with varno = 1 and varnoold = -1) for all - * functions, 'couse they will be evaluated by subplan; - * 2. for real Vars: set varno = 1 and varattno to its resno in subplan - */ - foreach (sl, sort_tlist) - { - TargetEntry *te = (TargetEntry *) lfirst (sl); - Resdom *resdom = te->resdom; - Node *expr = te->expr; - - if ( IsA (expr, Var) ) - { -#if 0 /* subplanVar->resdom->resno expected to be = te->resdom->resno */ - TargetEntry *subplanVar; - - subplanVar = match_varid ((Var*)expr, subplan->targetlist); - ((Var*)expr)->varattno = subplanVar->resdom->resno; + + /* + * If non-GroupBy entries were removed from TL - we are to add Vars + * for them to the end of TL if there are no such Vars in TL already. + */ + + otlvcnt = length(otlvars); + foreach(gl, otlvars) + { + Var *v = (Var *) lfirst(gl); + + if (tlist_member(v, sort_tlist) == NULL) + { + sort_tlist = lappend(sort_tlist, + create_tl_element(v, last_resno)); + last_resno++; + } + else +/* already in TL */ + otlvcnt--; + } + /* Now otlvcnt is number of Vars added in TL for non-GroupBy entries */ + + /* Make TL for subplan: substitute Vars from subplan TL into new TL */ + sl = flatten_tlist_vars(sort_tlist, subplan->targetlist); + + subplan->targetlist = new_unsorted_tlist(sl); /* there */ + + /* + * Make Sort/Group TL : 1. make Var nodes (with varno = 1 and varnoold + * = -1) for all functions, 'couse they will be evaluated by subplan; + * 2. for real Vars: set varno = 1 and varattno to its resno in + * subplan + */ + foreach(sl, sort_tlist) + { + TargetEntry *te = (TargetEntry *) lfirst(sl); + Resdom *resdom = te->resdom; + Node *expr = te->expr; + + if (IsA(expr, Var)) + { +#if 0 /* subplanVar->resdom->resno expected to + * be = te->resdom->resno */ + TargetEntry *subplanVar; + + subplanVar = match_varid((Var *) expr, subplan->targetlist); + ((Var *) expr)->varattno = subplanVar->resdom->resno; #endif - ((Var*)expr)->varattno = te->resdom->resno; - ((Var*)expr)->varno = 1; - } - else - te->expr = (Node*) makeVar (1, resdom->resno, - resdom->restype, - -1, resdom->resno); - } - - sortplan = make_sort(sort_tlist, - _TEMP_RELATION_ID_, - subplan, - numCols); - sortplan->plan.cost = subplan->cost; /* XXX assume no cost */ - - /* - * make the Group node - */ - sort_tlist = copyObject (sort_tlist); - grpplan = make_group(sort_tlist, tuplePerGroup, numCols, - grpColIdx, sortplan); - - /* - * Make TL for parent: "restore" non-GroupBy entries (if they - * were removed) and set resno-s of others accordantly. - */ - sl = sort_tlist; - sort_tlist = NIL; /* to be new parent TL */ - foreach (gl, *tlist) - { - List *temp = NIL; - TargetEntry *te = (TargetEntry *) lfirst (gl); - - foreach (temp, otles) /* Is it removed non-GroupBy entry ? */ - { - TargetEntry *ote = (TargetEntry *) lfirst (temp); - - if ( ote->resdom->resno == te->resdom->resno ) - { - otles = lremove (ote, otles); - break; - } - } - if ( temp == NIL ) /* It's "our" TLE - we're to return */ - { /* it from Sort/Group plans */ - TargetEntry *my = (TargetEntry *) lfirst (sl); /* get it */ - - sl = sl->next; /* prepare for the next "our" */ - my = copyObject (my); - my->resdom->resno = te->resdom->resno; /* order of parent TL */ - sort_tlist = lappend (sort_tlist, my); - continue; + ((Var *) expr)->varattno = te->resdom->resno; + ((Var *) expr)->varno = 1; + } + else + te->expr = (Node *) makeVar(1, resdom->resno, + resdom->restype, + -1, resdom->resno); } - /* else - it's TLE of an non-GroupBy entry */ - sort_tlist = lappend (sort_tlist, copyObject(te)); - } - /* - * Pure non-GroupBy entries Vars were at the end of Group' TL. - * They shouldn't appear in parent TL, all others shouldn't - * disappear. - */ - Assert ( otlvcnt == length (sl) ); - Assert ( length (otles) == 0 ); - - *tlist = sort_tlist; - - return (Plan*)grpplan; + + sortplan = make_sort(sort_tlist, + _TEMP_RELATION_ID_, + subplan, + numCols); + sortplan->plan.cost = subplan->cost; /* XXX assume no cost */ + + /* + * make the Group node + */ + sort_tlist = copyObject(sort_tlist); + grpplan = make_group(sort_tlist, tuplePerGroup, numCols, + grpColIdx, sortplan); + + /* + * Make TL for parent: "restore" non-GroupBy entries (if they were + * removed) and set resno-s of others accordantly. + */ + sl = sort_tlist; + sort_tlist = NIL; /* to be new parent TL */ + foreach(gl, *tlist) + { + List *temp = NIL; + TargetEntry *te = (TargetEntry *) lfirst(gl); + + foreach(temp, otles) /* Is it removed non-GroupBy entry ? */ + { + TargetEntry *ote = (TargetEntry *) lfirst(temp); + + if (ote->resdom->resno == te->resdom->resno) + { + otles = lremove(ote, otles); + break; + } + } + if (temp == NIL) /* It's "our" TLE - we're to return */ + { /* it from Sort/Group plans */ + TargetEntry *my = (TargetEntry *) lfirst(sl); /* get it */ + + sl = sl->next; /* prepare for the next "our" */ + my = copyObject(my); + my->resdom->resno = te->resdom->resno; /* order of parent TL */ + sort_tlist = lappend(sort_tlist, my); + continue; + } + /* else - it's TLE of an non-GroupBy entry */ + sort_tlist = lappend(sort_tlist, copyObject(te)); + } + + /* + * Pure non-GroupBy entries Vars were at the end of Group' TL. They + * shouldn't appear in parent TL, all others shouldn't disappear. + */ + Assert(otlvcnt == length(sl)); + Assert(length(otles) == 0); + + *tlist = sort_tlist; + + return (Plan *) grpplan; } diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 5a6b78384b6..43441a3b7ff 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * planner.c-- - * The query optimizer external interface. + * The query optimizer external interface. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.6 1997/09/05 20:20:48 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.7 1997/09/07 04:44:03 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -28,7 +28,7 @@ #include "optimizer/internal.h" #include "optimizer/planner.h" -#include "optimizer/plancat.h" +#include "optimizer/plancat.h" #include "optimizer/prep.h" #include "optimizer/planmain.h" #include "optimizer/paths.h" @@ -47,215 +47,225 @@ #include "executor/executor.h" -static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode); -static Plan *init_query_planner(Query *parse); -static Existential *make_existential(Plan *left, Plan *right); +static Plan *make_sortplan(List * tlist, List * sortcls, Plan * plannode); +static Plan *init_query_planner(Query * parse); +static Existential *make_existential(Plan * left, Plan * right); /***************************************************************************** * - * Query optimizer entry point - * + * Query optimizer entry point + * *****************************************************************************/ -/* +/* * planner-- - * Main query optimizer routine. - * - * Invokes the planner on union queries if there are any left, - * recursing if necessary to get them all, then processes normal plans. - * + * Main query optimizer routine. + * + * Invokes the planner on union queries if there are any left, + * recursing if necessary to get them all, then processes normal plans. + * * Returns a query plan. - * + * */ -Plan* -planner(Query *parse) +Plan * +planner(Query * parse) { - List *tlist = parse->targetList; - List *rangetable = parse->rtable; - char* uniqueflag = parse->uniqueFlag; - List *sortclause = parse->sortClause; - Plan *special_plans = (Plan*)NULL; - - Plan *result_plan = (Plan*) NULL; - - int rt_index; - - /* - * plan inheritance - */ - rt_index = first_matching_rt_entry(rangetable, INHERITS_FLAG); - if (rt_index != -1) { - special_plans = (Plan *)plan_union_queries((Index)rt_index, - parse, - INHERITS_FLAG); - } - - /* - * plan archive queries - */ - rt_index = first_matching_rt_entry(rangetable, ARCHIVE_FLAG); - if (rt_index != -1) { - special_plans = (Plan *)plan_union_queries((Index)rt_index, - parse, - ARCHIVE_FLAG); - } - - if (special_plans) - result_plan = special_plans; - else - result_plan = init_query_planner(parse); /* regular plans */ - - /* - * For now, before we hand back the plan, check to see if there - * is a user-specified sort that needs to be done. Eventually, this - * will be moved into the guts of the planner s.t. user specified - * sorts will be considered as part of the planning process. - * Since we can only make use of user-specified sorts in - * special cases, we can do the optimization step later. - */ - - if (uniqueflag) { - Plan *sortplan = make_sortplan(tlist, sortclause, result_plan); - - return((Plan*)make_unique(tlist,sortplan,uniqueflag)); - } else { - if (sortclause) - return(make_sortplan(tlist,sortclause,result_plan)); - else - return((Plan*)result_plan); - } + List *tlist = parse->targetList; + List *rangetable = parse->rtable; + char *uniqueflag = parse->uniqueFlag; + List *sortclause = parse->sortClause; + Plan *special_plans = (Plan *) NULL; + + Plan *result_plan = (Plan *) NULL; + + int rt_index; + + /* + * plan inheritance + */ + rt_index = first_matching_rt_entry(rangetable, INHERITS_FLAG); + if (rt_index != -1) + { + special_plans = (Plan *) plan_union_queries((Index) rt_index, + parse, + INHERITS_FLAG); + } + + /* + * plan archive queries + */ + rt_index = first_matching_rt_entry(rangetable, ARCHIVE_FLAG); + if (rt_index != -1) + { + special_plans = (Plan *) plan_union_queries((Index) rt_index, + parse, + ARCHIVE_FLAG); + } + + if (special_plans) + result_plan = special_plans; + else + result_plan = init_query_planner(parse); /* regular plans */ + + /* + * For now, before we hand back the plan, check to see if there is a + * user-specified sort that needs to be done. Eventually, this will + * be moved into the guts of the planner s.t. user specified sorts + * will be considered as part of the planning process. Since we can + * only make use of user-specified sorts in special cases, we can do + * the optimization step later. + */ + + if (uniqueflag) + { + Plan *sortplan = make_sortplan(tlist, sortclause, result_plan); + + return ((Plan *) make_unique(tlist, sortplan, uniqueflag)); + } + else + { + if (sortclause) + return (make_sortplan(tlist, sortclause, result_plan)); + else + return ((Plan *) result_plan); + } } /* * make_sortplan-- - * Returns a sortplan which is basically a SORT node attached to the - * top of the plan returned from the planner. It also adds the - * cost of sorting into the plan. - * + * Returns a sortplan which is basically a SORT node attached to the + * top of the plan returned from the planner. It also adds the + * cost of sorting into the plan. + * * sortkeys: ( resdom1 resdom2 resdom3 ...) * sortops: (sortop1 sortop2 sortop3 ...) */ -static Plan * -make_sortplan(List *tlist, List *sortcls, Plan *plannode) +static Plan * +make_sortplan(List * tlist, List * sortcls, Plan * plannode) { - Plan *sortplan = (Plan*)NULL; - List *temp_tlist = NIL; - List *i = NIL; - Resdom *resnode = (Resdom*)NULL; - Resdom *resdom = (Resdom*)NULL; - int keyno =1; - - /* First make a copy of the tlist so that we don't corrupt the - * the original . - */ - - temp_tlist = new_unsorted_tlist(tlist); - - foreach (i, sortcls) { - SortClause *sortcl = (SortClause*)lfirst(i); - - resnode = sortcl->resdom; - resdom = tlist_resdom(temp_tlist, resnode); - - /* Order the resdom keys and replace the operator OID for each - * key with the regproc OID. + Plan *sortplan = (Plan *) NULL; + List *temp_tlist = NIL; + List *i = NIL; + Resdom *resnode = (Resdom *) NULL; + Resdom *resdom = (Resdom *) NULL; + int keyno = 1; + + /* + * First make a copy of the tlist so that we don't corrupt the the + * original . + */ + + temp_tlist = new_unsorted_tlist(tlist); + + foreach(i, sortcls) + { + SortClause *sortcl = (SortClause *) lfirst(i); + + resnode = sortcl->resdom; + resdom = tlist_resdom(temp_tlist, resnode); + + /* + * Order the resdom keys and replace the operator OID for each key + * with the regproc OID. + */ + resdom->reskey = keyno; + resdom->reskeyop = get_opcode(sortcl->opoid); + keyno += 1; + } + + sortplan = (Plan *) make_sort(temp_tlist, + _TEMP_RELATION_ID_, + (Plan *) plannode, + length(sortcls)); + + /* + * XXX Assuming that an internal sort has no. cost. This is wrong, but + * given that at this point, we don't know the no. of tuples returned, + * etc, we can't do better than to add a constant cost. This will be + * fixed once we move the sort further into the planner, but for now + * ... functionality.... */ - resdom->reskey = keyno; - resdom->reskeyop = get_opcode(sortcl->opoid); - keyno += 1; - } - - sortplan = (Plan*)make_sort(temp_tlist, - _TEMP_RELATION_ID_, - (Plan*)plannode, - length(sortcls)); - - /* - * XXX Assuming that an internal sort has no. cost. - * This is wrong, but given that at this point, we don't - * know the no. of tuples returned, etc, we can't do - * better than to add a constant cost. - * This will be fixed once we move the sort further into the planner, - * but for now ... functionality.... - */ - - sortplan->cost = plannode->cost; - - return(sortplan); + + sortplan->cost = plannode->cost; + + return (sortplan); } -/* +/* * init-query-planner-- - * Deals with all non-union preprocessing, including existential - * qualifications and CNFifying the qualifications. - * + * Deals with all non-union preprocessing, including existential + * qualifications and CNFifying the qualifications. + * * Returns a query plan. * MODIFIES: tlist,qual - * + * */ -static Plan * -init_query_planner(Query *root) +static Plan * +init_query_planner(Query * root) { - List *primary_qual; - List *existential_qual; - Existential *exist_plan; - List *tlist = root->targetList; - - tlist = preprocess_targetlist(tlist, - root->commandType, - root->resultRelation, - root->rtable); - - primary_qual = - preprocess_qualification((Expr*)root->qual, - tlist, - &existential_qual); - - if(existential_qual==NULL) { - return(query_planner(root, - root->commandType, - tlist, - primary_qual)); - } else { - int temp = root->commandType; - Plan *existential_plan; - - root->commandType = CMD_SELECT; - existential_plan = query_planner(root, - temp, - NIL, - existential_qual); - - exist_plan = make_existential(existential_plan, - query_planner(root, - root->commandType, - tlist, - primary_qual)); - return((Plan*)exist_plan); - } + List *primary_qual; + List *existential_qual; + Existential *exist_plan; + List *tlist = root->targetList; + + tlist = preprocess_targetlist(tlist, + root->commandType, + root->resultRelation, + root->rtable); + + primary_qual = + preprocess_qualification((Expr *) root->qual, + tlist, + &existential_qual); + + if (existential_qual == NULL) + { + return (query_planner(root, + root->commandType, + tlist, + primary_qual)); + } + else + { + int temp = root->commandType; + Plan *existential_plan; + + root->commandType = CMD_SELECT; + existential_plan = query_planner(root, + temp, + NIL, + existential_qual); + + exist_plan = make_existential(existential_plan, + query_planner(root, + root->commandType, + tlist, + primary_qual)); + return ((Plan *) exist_plan); + } } -/* +/* * make_existential-- - * Instantiates an existential plan node and fills in - * the left and right subtree slots. + * Instantiates an existential plan node and fills in + * the left and right subtree slots. */ static Existential * -make_existential(Plan *left, Plan *right) +make_existential(Plan * left, Plan * right) { - Existential *node = makeNode(Existential); + Existential *node = makeNode(Existential); - node->lefttree = left; - node->righttree = left; - return(node); + node->lefttree = left; + node->righttree = left; + return (node); } /* * pg_checkretval() -- check return value of a list of sql parse - * trees. + * trees. * * The return value of a sql function is the value returned by * the final query in the function. We do some ad-hoc define-time @@ -263,145 +273,152 @@ make_existential(Plan *left, Plan *right) * type he claims. */ void -pg_checkretval(Oid rettype, QueryTreeList *queryTreeList) +pg_checkretval(Oid rettype, QueryTreeList * queryTreeList) { - Query *parse; - List *tlist; - List *rt; - int cmd; - Type typ; - Resdom *resnode; - Relation reln; - Oid relid; - Oid tletype; - int relnatts; - int i; - - /* find the final query */ - parse = queryTreeList->qtrees[queryTreeList->len - 1]; - - /* - * test 1: if the last query is a utility invocation, then there - * had better not be a return value declared. - */ - if (parse->commandType == CMD_UTILITY) { + Query *parse; + List *tlist; + List *rt; + int cmd; + Type typ; + Resdom *resnode; + Relation reln; + Oid relid; + Oid tletype; + int relnatts; + int i; + + /* find the final query */ + parse = queryTreeList->qtrees[queryTreeList->len - 1]; + + /* + * test 1: if the last query is a utility invocation, then there had + * better not be a return value declared. + */ + if (parse->commandType == CMD_UTILITY) + { + if (rettype == InvalidOid) + return; + else + elog(WARN, "return type mismatch in function decl: final query is a catalog utility"); + } + + /* okay, it's an ordinary query */ + tlist = parse->targetList; + rt = parse->rtable; + cmd = parse->commandType; + + /* + * test 2: if the function is declared to return no value, then the + * final query had better not be a retrieve. + */ if (rettype == InvalidOid) - return; - else - elog(WARN, "return type mismatch in function decl: final query is a catalog utility"); - } - - /* okay, it's an ordinary query */ - tlist = parse->targetList; - rt = parse->rtable; - cmd = parse->commandType; - - /* - * test 2: if the function is declared to return no value, then the - * final query had better not be a retrieve. - */ - if (rettype == InvalidOid) { - if (cmd == CMD_SELECT) - elog(WARN, - "function declared with no return type, but final query is a retrieve"); - else - return; - } - - /* by here, the function is declared to return some type */ - if ((typ = (Type)get_id_type(rettype)) == NULL) - elog(WARN, "can't find return type %d for function\n", rettype); - - /* - * test 3: if the function is declared to return a value, then the - * final query had better be a retrieve. - */ - if (cmd != CMD_SELECT) - elog(WARN, "function declared to return type %s, but final query is not a retrieve", tname(typ)); - - /* - * test 4: for base type returns, the target list should have exactly - * one entry, and its type should agree with what the user declared. - */ - - if (get_typrelid(typ) == InvalidOid) { - if (exec_tlist_length(tlist) > 1) - elog(WARN, "function declared to return %s returns multiple values in final retrieve", tname(typ)); - - resnode = (Resdom*) ((TargetEntry*)lfirst(tlist))->resdom; - if (resnode->restype != rettype) - elog(WARN, "return type mismatch in function: declared to return %s, returns %s", tname(typ), tname(get_id_type(resnode->restype))); - - /* by here, base return types match */ - return; - } - - /* - * If the target list is of length 1, and the type of the varnode - * in the target list is the same as the declared return type, this - * is okay. This can happen, for example, where the body of the - * function is 'retrieve (x = func2())', where func2 has the same - * return type as the function that's calling it. - */ - if (exec_tlist_length(tlist) == 1) { - resnode = (Resdom*) ((TargetEntry*)lfirst(tlist))->resdom; - if (resnode->restype == rettype) - return; - } - - /* - * By here, the procedure returns a (set of) tuples. This part of - * the typechecking is a hack. We look up the relation that is - * the declared return type, and be sure that attributes 1 .. n - * in the target list match the declared types. - */ - reln = heap_open(get_typrelid(typ)); - - if (!RelationIsValid(reln)) - elog(WARN, "cannot open relation relid %d", get_typrelid(typ)); - - relid = reln->rd_id; - relnatts = reln->rd_rel->relnatts; - - if (exec_tlist_length(tlist) != relnatts) - elog(WARN, "function declared to return type %s does not retrieve (%s.*)", tname(typ), tname(typ)); - - /* expect attributes 1 .. n in order */ - for (i = 1; i <= relnatts; i++) { - TargetEntry *tle = lfirst(tlist); - Node *thenode = tle->expr; - - tlist = lnext(tlist); - tletype = exprType(thenode); - -#if 0 /* fix me */ - /* this is tedious */ - if (IsA(thenode,Var)) - tletype = (Oid) ((Var*)thenode)->vartype; - else if (IsA(thenode,Const)) - tletype = (Oid) ((Const*)thenode)->consttype; - else if (IsA(thenode,Param)) - tletype = (Oid) ((Param*)thenode)->paramtype; - else if (IsA(thenode,Expr)) - tletype = Expr; - else if (IsA(thenode,LispList)) { - thenode = lfirst(thenode); - if (IsA(thenode,Oper)) - tletype = (Oid) get_opresulttype((Oper*)thenode); - else if (IsA(thenode,Func)) - tletype = (Oid) get_functype((Func*)thenode); - else - elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ)); - } else - elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ)); + { + if (cmd == CMD_SELECT) + elog(WARN, + "function declared with no return type, but final query is a retrieve"); + else + return; + } + + /* by here, the function is declared to return some type */ + if ((typ = (Type) get_id_type(rettype)) == NULL) + elog(WARN, "can't find return type %d for function\n", rettype); + + /* + * test 3: if the function is declared to return a value, then the + * final query had better be a retrieve. + */ + if (cmd != CMD_SELECT) + elog(WARN, "function declared to return type %s, but final query is not a retrieve", tname(typ)); + + /* + * test 4: for base type returns, the target list should have exactly + * one entry, and its type should agree with what the user declared. + */ + + if (get_typrelid(typ) == InvalidOid) + { + if (exec_tlist_length(tlist) > 1) + elog(WARN, "function declared to return %s returns multiple values in final retrieve", tname(typ)); + + resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom; + if (resnode->restype != rettype) + elog(WARN, "return type mismatch in function: declared to return %s, returns %s", tname(typ), tname(get_id_type(resnode->restype))); + + /* by here, base return types match */ + return; + } + + /* + * If the target list is of length 1, and the type of the varnode in + * the target list is the same as the declared return type, this is + * okay. This can happen, for example, where the body of the function + * is 'retrieve (x = func2())', where func2 has the same return type + * as the function that's calling it. + */ + if (exec_tlist_length(tlist) == 1) + { + resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom; + if (resnode->restype == rettype) + return; + } + + /* + * By here, the procedure returns a (set of) tuples. This part of the + * typechecking is a hack. We look up the relation that is the + * declared return type, and be sure that attributes 1 .. n in the + * target list match the declared types. + */ + reln = heap_open(get_typrelid(typ)); + + if (!RelationIsValid(reln)) + elog(WARN, "cannot open relation relid %d", get_typrelid(typ)); + + relid = reln->rd_id; + relnatts = reln->rd_rel->relnatts; + + if (exec_tlist_length(tlist) != relnatts) + elog(WARN, "function declared to return type %s does not retrieve (%s.*)", tname(typ), tname(typ)); + + /* expect attributes 1 .. n in order */ + for (i = 1; i <= relnatts; i++) + { + TargetEntry *tle = lfirst(tlist); + Node *thenode = tle->expr; + + tlist = lnext(tlist); + tletype = exprType(thenode); + +#if 0 /* fix me */ + /* this is tedious */ + if (IsA(thenode, Var)) + tletype = (Oid) ((Var *) thenode)->vartype; + else if (IsA(thenode, Const)) + tletype = (Oid) ((Const *) thenode)->consttype; + else if (IsA(thenode, Param)) + tletype = (Oid) ((Param *) thenode)->paramtype; + else if (IsA(thenode, Expr)) + tletype = Expr; + else if (IsA(thenode, LispList)) + { + thenode = lfirst(thenode); + if (IsA(thenode, Oper)) + tletype = (Oid) get_opresulttype((Oper *) thenode); + else if (IsA(thenode, Func)) + tletype = (Oid) get_functype((Func *) thenode); + else + elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ)); + } + else + elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ)); #endif - /* reach right in there, why don't you? */ - if (tletype != reln->rd_att->attrs[i-1]->atttypid) - elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ)); - } + /* reach right in there, why don't you? */ + if (tletype != reln->rd_att->attrs[i - 1]->atttypid) + elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ)); + } - heap_close(reln); + heap_close(reln); - /* success */ - return; + /* success */ + return; } diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 4527837e9d4..19cee246a58 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * setrefs.c-- - * Routines to change varno/attno entries to contain references + * Routines to change varno/attno entries to contain references * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.4 1997/06/12 17:26:15 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.5 1997/09/07 04:44:05 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -33,419 +33,468 @@ #include "optimizer/var.h" #include "optimizer/tlist.h" -static void set_join_tlist_references(Join *join); -static void set_tempscan_tlist_references(SeqScan *tempscan); -static void set_temp_tlist_references(Temp *temp); -static List *replace_clause_joinvar_refs(Expr *clause, - List *outer_tlist, List *inner_tlist); -static List *replace_subclause_joinvar_refs(List *clauses, - List *outer_tlist, List *inner_tlist); -static Var *replace_joinvar_refs(Var *var, List *outer_tlist, List *inner_tlist); -static List *tlist_temp_references(Oid tempid, List *tlist); -static void replace_result_clause(List *clause, List *subplanTargetList); -static bool OperandIsInner(Node *opnd, int inner_relid); -static void replace_agg_clause(Node *expr, List *targetlist); +static void set_join_tlist_references(Join * join); +static void set_tempscan_tlist_references(SeqScan * tempscan); +static void set_temp_tlist_references(Temp * temp); +static List * +replace_clause_joinvar_refs(Expr * clause, + List * outer_tlist, List * inner_tlist); +static List * +replace_subclause_joinvar_refs(List * clauses, + List * outer_tlist, List * inner_tlist); +static Var *replace_joinvar_refs(Var * var, List * outer_tlist, List * inner_tlist); +static List *tlist_temp_references(Oid tempid, List * tlist); +static void replace_result_clause(List * clause, List * subplanTargetList); +static bool OperandIsInner(Node * opnd, int inner_relid); +static void replace_agg_clause(Node * expr, List * targetlist); /***************************************************************************** - * - * SUBPLAN REFERENCES - * + * + * SUBPLAN REFERENCES + * *****************************************************************************/ -/* +/* * set-tlist-references-- - * Modifies the target list of nodes in a plan to reference target lists - * at lower levels. - * + * Modifies the target list of nodes in a plan to reference target lists + * at lower levels. + * * 'plan' is the plan whose target list and children's target lists will - * be modified - * + * be modified + * * Returns nothing of interest, but modifies internal fields of nodes. - * + * */ void -set_tlist_references(Plan *plan) +set_tlist_references(Plan * plan) { - if(plan==NULL) - return; - - if (IsA_Join(plan)) { - set_join_tlist_references((Join*)plan); - } else if (IsA(plan,SeqScan) && plan->lefttree && - IsA_Temp(plan->lefttree)) { - set_tempscan_tlist_references((SeqScan*)plan); - } else if (IsA(plan,Sort)) { - set_temp_tlist_references ((Temp*)plan); - } else if (IsA(plan,Result)) { - set_result_tlist_references((Result*)plan); - } else if (IsA(plan,Hash)) { - set_tlist_references(plan->lefttree); - } else if (IsA(plan,Choose)) { - List *x; - foreach (x, ((Choose*)plan)->chooseplanlist) { - set_tlist_references((Plan*)lfirst(x)); - } - } + if (plan == NULL) + return; + + if (IsA_Join(plan)) + { + set_join_tlist_references((Join *) plan); + } + else if (IsA(plan, SeqScan) && plan->lefttree && + IsA_Temp(plan->lefttree)) + { + set_tempscan_tlist_references((SeqScan *) plan); + } + else if (IsA(plan, Sort)) + { + set_temp_tlist_references((Temp *) plan); + } + else if (IsA(plan, Result)) + { + set_result_tlist_references((Result *) plan); + } + else if (IsA(plan, Hash)) + { + set_tlist_references(plan->lefttree); + } + else if (IsA(plan, Choose)) + { + List *x; + + foreach(x, ((Choose *) plan)->chooseplanlist) + { + set_tlist_references((Plan *) lfirst(x)); + } + } } -/* +/* * set-join-tlist-references-- - * Modifies the target list of a join node by setting the varnos and - * varattnos to reference the target list of the outer and inner join - * relations. - * - * Creates a target list for a join node to contain references by setting - * varno values to OUTER or INNER and setting attno values to the - * result domain number of either the corresponding outer or inner join - * tuple. - * + * Modifies the target list of a join node by setting the varnos and + * varattnos to reference the target list of the outer and inner join + * relations. + * + * Creates a target list for a join node to contain references by setting + * varno values to OUTER or INNER and setting attno values to the + * result domain number of either the corresponding outer or inner join + * tuple. + * * 'join' is a join plan node - * + * * Returns nothing of interest, but modifies internal fields of nodes. - * + * */ static void -set_join_tlist_references(Join *join) +set_join_tlist_references(Join * join) { - Plan *outer = ((Plan*)join)->lefttree; - Plan *inner = ((Plan*)join)->righttree; - List *new_join_targetlist = NIL; - TargetEntry *temp = (TargetEntry *)NULL; - List *entry = NIL; - List *inner_tlist = NULL; - List *outer_tlist = NULL; - TargetEntry *xtl = (TargetEntry *)NULL; - List *qptlist = ((Plan*)join)->targetlist; - - foreach(entry, qptlist) { - List *joinvar; - - xtl = (TargetEntry *)lfirst(entry); - inner_tlist = ((inner==NULL) ? NIL : inner->targetlist); - outer_tlist = ((outer==NULL) ? NIL : outer->targetlist); - joinvar = replace_clause_joinvar_refs((Expr*)get_expr(xtl), - outer_tlist, - inner_tlist); - - temp = MakeTLE(xtl->resdom, (Node*)joinvar); - new_join_targetlist = lappend(new_join_targetlist,temp); - } - - ((Plan*)join)->targetlist = new_join_targetlist; - if (outer!=NULL) - set_tlist_references(outer); - if (inner!=NULL) - set_tlist_references(inner); + Plan *outer = ((Plan *) join)->lefttree; + Plan *inner = ((Plan *) join)->righttree; + List *new_join_targetlist = NIL; + TargetEntry *temp = (TargetEntry *) NULL; + List *entry = NIL; + List *inner_tlist = NULL; + List *outer_tlist = NULL; + TargetEntry *xtl = (TargetEntry *) NULL; + List *qptlist = ((Plan *) join)->targetlist; + + foreach(entry, qptlist) + { + List *joinvar; + + xtl = (TargetEntry *) lfirst(entry); + inner_tlist = ((inner == NULL) ? NIL : inner->targetlist); + outer_tlist = ((outer == NULL) ? NIL : outer->targetlist); + joinvar = replace_clause_joinvar_refs((Expr *) get_expr(xtl), + outer_tlist, + inner_tlist); + + temp = MakeTLE(xtl->resdom, (Node *) joinvar); + new_join_targetlist = lappend(new_join_targetlist, temp); + } + + ((Plan *) join)->targetlist = new_join_targetlist; + if (outer != NULL) + set_tlist_references(outer); + if (inner != NULL) + set_tlist_references(inner); } -/* +/* * set-tempscan-tlist-references-- - * Modifies the target list of a node that scans a temp relation (i.e., a - * sort or hash node) so that the varnos refer to the child temporary. - * + * Modifies the target list of a node that scans a temp relation (i.e., a + * sort or hash node) so that the varnos refer to the child temporary. + * * 'tempscan' is a seqscan node - * + * * Returns nothing of interest, but modifies internal fields of nodes. - * + * */ static void -set_tempscan_tlist_references(SeqScan *tempscan) +set_tempscan_tlist_references(SeqScan * tempscan) { - Temp *temp = (Temp*)((Plan*)tempscan)->lefttree; + Temp *temp = (Temp *) ((Plan *) tempscan)->lefttree; - ((Plan*)tempscan)->targetlist = - tlist_temp_references(temp->tempid, - ((Plan*)tempscan)->targetlist); - set_temp_tlist_references(temp); + ((Plan *) tempscan)->targetlist = + tlist_temp_references(temp->tempid, + ((Plan *) tempscan)->targetlist); + set_temp_tlist_references(temp); } -/* +/* * set-temp-tlist-references-- - * The temp's vars are made consistent with (actually, identical to) the - * modified version of the target list of the node from which temp node - * receives its tuples. - * + * The temp's vars are made consistent with (actually, identical to) the + * modified version of the target list of the node from which temp node + * receives its tuples. + * * 'temp' is a temp (e.g., sort, hash) plan node - * + * * Returns nothing of interest, but modifies internal fields of nodes. - * + * */ static void -set_temp_tlist_references(Temp *temp) +set_temp_tlist_references(Temp * temp) { - Plan *source = ((Plan*)temp)->lefttree; - - if (source!=NULL) { - set_tlist_references(source); - ((Plan*)temp)->targetlist = - copy_vars(((Plan*)temp)->targetlist , - (source)->targetlist); - } else { - elog(WARN, "calling set_temp_tlist_references with empty lefttree"); - } + Plan *source = ((Plan *) temp)->lefttree; + + if (source != NULL) + { + set_tlist_references(source); + ((Plan *) temp)->targetlist = + copy_vars(((Plan *) temp)->targetlist, + (source)->targetlist); + } + else + { + elog(WARN, "calling set_temp_tlist_references with empty lefttree"); + } } -/* +/* * join-references-- - * Creates a new set of join clauses by replacing the varno/varattno - * values of variables in the clauses to reference target list values - * from the outer and inner join relation target lists. - * + * Creates a new set of join clauses by replacing the varno/varattno + * values of variables in the clauses to reference target list values + * from the outer and inner join relation target lists. + * * 'clauses' is the list of join clauses * 'outer-tlist' is the target list of the outer join relation * 'inner-tlist' is the target list of the inner join relation - * + * * Returns the new join clauses. - * + * */ -List * -join_references(List *clauses, - List *outer_tlist, - List *inner_tlist) +List * +join_references(List * clauses, + List * outer_tlist, + List * inner_tlist) { - return (replace_subclause_joinvar_refs(clauses, - outer_tlist, - inner_tlist)); + return (replace_subclause_joinvar_refs(clauses, + outer_tlist, + inner_tlist)); } -/* +/* * index-outerjoin-references-- - * Given a list of join clauses, replace the operand corresponding to the - * outer relation in the join with references to the corresponding target - * list element in 'outer-tlist' (the outer is rather obscurely - * identified as the side that doesn't contain a var whose varno equals - * 'inner-relid'). - * - * As a side effect, the operator is replaced by the regproc id. - * + * Given a list of join clauses, replace the operand corresponding to the + * outer relation in the join with references to the corresponding target + * list element in 'outer-tlist' (the outer is rather obscurely + * identified as the side that doesn't contain a var whose varno equals + * 'inner-relid'). + * + * As a side effect, the operator is replaced by the regproc id. + * * 'inner-indxqual' is the list of join clauses (so-called because they * are used as qualifications for the inner (inbex) scan of a nestloop) - * + * * Returns the new list of clauses. - * + * */ -List * -index_outerjoin_references(List *inner_indxqual, - List *outer_tlist, - Index inner_relid) +List * +index_outerjoin_references(List * inner_indxqual, + List * outer_tlist, + Index inner_relid) { - List *t_list = NIL; - Expr *temp = NULL; - List *t_clause = NIL; - Expr *clause = NULL; + List *t_list = NIL; + Expr *temp = NULL; + List *t_clause = NIL; + Expr *clause = NULL; - foreach (t_clause,inner_indxqual) { - clause = lfirst(t_clause); - /* - * if inner scan on the right. - */ - if (OperandIsInner((Node*)get_rightop(clause), inner_relid)) { - Var *joinvar = (Var*) - replace_clause_joinvar_refs((Expr*)get_leftop(clause), - outer_tlist, - NIL); - temp = make_opclause(replace_opid((Oper*)((Expr*)clause)->oper), - joinvar, - get_rightop(clause)); - t_list = lappend(t_list,temp); - } else { - /* inner scan on left */ - Var *joinvar = (Var*) - replace_clause_joinvar_refs((Expr*)get_rightop(clause), - outer_tlist, - NIL); - temp = make_opclause(replace_opid((Oper*)((Expr*)clause)->oper), - get_leftop(clause), - joinvar); - t_list = lappend(t_list,temp); - } - - } - return(t_list); + foreach(t_clause, inner_indxqual) + { + clause = lfirst(t_clause); + + /* + * if inner scan on the right. + */ + if (OperandIsInner((Node *) get_rightop(clause), inner_relid)) + { + Var *joinvar = (Var *) + replace_clause_joinvar_refs((Expr *) get_leftop(clause), + outer_tlist, + NIL); + + temp = make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper), + joinvar, + get_rightop(clause)); + t_list = lappend(t_list, temp); + } + else + { + /* inner scan on left */ + Var *joinvar = (Var *) + replace_clause_joinvar_refs((Expr *) get_rightop(clause), + outer_tlist, + NIL); + + temp = make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper), + get_leftop(clause), + joinvar); + t_list = lappend(t_list, temp); + } + + } + return (t_list); } -/* +/* * replace-clause-joinvar-refs * replace-subclause-joinvar-refs * replace-joinvar-refs - * - * Replaces all variables within a join clause with a new var node - * whose varno/varattno fields contain a reference to a target list - * element from either the outer or inner join relation. - * + * + * Replaces all variables within a join clause with a new var node + * whose varno/varattno fields contain a reference to a target list + * element from either the outer or inner join relation. + * * 'clause' is the join clause * 'outer-tlist' is the target list of the outer join relation * 'inner-tlist' is the target list of the inner join relation - * + * * Returns the new join clause. - * + * */ -static List * -replace_clause_joinvar_refs(Expr *clause, - List *outer_tlist, - List *inner_tlist) +static List * +replace_clause_joinvar_refs(Expr * clause, + List * outer_tlist, + List * inner_tlist) { - List *temp = NULL; + List *temp = NULL; - if(IsA (clause,Var)) { - temp = (List*)replace_joinvar_refs((Var*)clause, - outer_tlist,inner_tlist); - if(temp) - return(temp); - else - if (clause != NULL) - return((List*)clause); - else - return(NIL); - } else if (single_node((Node*)clause)) { - return ((List*)clause); - } else if (or_clause((Node*)clause)) { - List *orclause = - replace_subclause_joinvar_refs(((Expr*)clause)->args, - outer_tlist, - inner_tlist); - return ((List*)make_orclause(orclause)); - } else if (IsA(clause,ArrayRef)) { - ArrayRef *aref = (ArrayRef *)clause; - - temp = replace_subclause_joinvar_refs(aref->refupperindexpr, - outer_tlist, - inner_tlist); - aref->refupperindexpr = (List*)temp; - temp = replace_subclause_joinvar_refs(aref->reflowerindexpr, - outer_tlist, - inner_tlist); - aref->reflowerindexpr = (List*)temp; - temp = replace_clause_joinvar_refs((Expr*)aref->refexpr, - outer_tlist, - inner_tlist); - aref->refexpr = (Node*)temp; + if (IsA(clause, Var)) + { + temp = (List *) replace_joinvar_refs((Var *) clause, + outer_tlist, inner_tlist); + if (temp) + return (temp); + else if (clause != NULL) + return ((List *) clause); + else + return (NIL); + } + else if (single_node((Node *) clause)) + { + return ((List *) clause); + } + else if (or_clause((Node *) clause)) + { + List *orclause = + replace_subclause_joinvar_refs(((Expr *) clause)->args, + outer_tlist, + inner_tlist); - /* - * no need to set refassgnexpr. we only set that in the - * target list on replaces, and this is an array reference - * in the qualification. if we got this far, it's 0x0 in - * the ArrayRef structure 'clause'. - */ + return ((List *) make_orclause(orclause)); + } + else if (IsA(clause, ArrayRef)) + { + ArrayRef *aref = (ArrayRef *) clause; + + temp = replace_subclause_joinvar_refs(aref->refupperindexpr, + outer_tlist, + inner_tlist); + aref->refupperindexpr = (List *) temp; + temp = replace_subclause_joinvar_refs(aref->reflowerindexpr, + outer_tlist, + inner_tlist); + aref->reflowerindexpr = (List *) temp; + temp = replace_clause_joinvar_refs((Expr *) aref->refexpr, + outer_tlist, + inner_tlist); + aref->refexpr = (Node *) temp; + + /* + * no need to set refassgnexpr. we only set that in the target + * list on replaces, and this is an array reference in the + * qualification. if we got this far, it's 0x0 in the ArrayRef + * structure 'clause'. + */ + + return ((List *) clause); + } + else if (is_funcclause((Node *) clause)) + { + List *funcclause = + replace_subclause_joinvar_refs(((Expr *) clause)->args, + outer_tlist, + inner_tlist); + + return ((List *) make_funcclause((Func *) ((Expr *) clause)->oper, + funcclause)); + } + else if (not_clause((Node *) clause)) + { + List *notclause = + replace_clause_joinvar_refs(get_notclausearg(clause), + outer_tlist, + inner_tlist); - return((List*)clause); - } else if (is_funcclause((Node*)clause)) { - List *funcclause = - replace_subclause_joinvar_refs(((Expr*)clause)->args, - outer_tlist, - inner_tlist); - return ((List*)make_funcclause((Func*)((Expr*)clause)->oper, - funcclause)); - } else if (not_clause((Node*)clause)) { - List *notclause = - replace_clause_joinvar_refs(get_notclausearg(clause), - outer_tlist, - inner_tlist); - return ((List*)make_notclause((Expr*)notclause)); - } else if (is_opclause((Node*)clause)) { - Var *leftvar = - (Var*)replace_clause_joinvar_refs((Expr*)get_leftop(clause), - outer_tlist, - inner_tlist); - Var *rightvar = - (Var*)replace_clause_joinvar_refs((Expr*)get_rightop(clause), - outer_tlist, - inner_tlist); - return ((List*)make_opclause(replace_opid((Oper*)((Expr*)clause)->oper), - leftvar, - rightvar)); - } - /* shouldn't reach here */ - return NULL; + return ((List *) make_notclause((Expr *) notclause)); + } + else if (is_opclause((Node *) clause)) + { + Var *leftvar = + (Var *) replace_clause_joinvar_refs((Expr *) get_leftop(clause), + outer_tlist, + inner_tlist); + Var *rightvar = + (Var *) replace_clause_joinvar_refs((Expr *) get_rightop(clause), + outer_tlist, + inner_tlist); + + return ((List *) make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper), + leftvar, + rightvar)); + } + /* shouldn't reach here */ + return NULL; } -static List * -replace_subclause_joinvar_refs(List *clauses, - List *outer_tlist, - List *inner_tlist) +static List * +replace_subclause_joinvar_refs(List * clauses, + List * outer_tlist, + List * inner_tlist) { - List *t_list = NIL; - List *temp = NIL; - List *clause = NIL; - - foreach (clause,clauses) { - temp = replace_clause_joinvar_refs(lfirst(clause), - outer_tlist, - inner_tlist); - t_list = lappend(t_list,temp); - } - return(t_list); + List *t_list = NIL; + List *temp = NIL; + List *clause = NIL; + + foreach(clause, clauses) + { + temp = replace_clause_joinvar_refs(lfirst(clause), + outer_tlist, + inner_tlist); + t_list = lappend(t_list, temp); + } + return (t_list); } -static Var * -replace_joinvar_refs(Var *var, List *outer_tlist, List *inner_tlist) +static Var * +replace_joinvar_refs(Var * var, List * outer_tlist, List * inner_tlist) { - Resdom *outer_resdom =(Resdom*)NULL; - - outer_resdom= tlist_member(var,outer_tlist); - - if (outer_resdom!=NULL && IsA (outer_resdom,Resdom) ) { - return (makeVar (OUTER, - outer_resdom->resno, - var->vartype, - var->varnoold, - var->varoattno)); - } else { - Resdom *inner_resdom; - inner_resdom = tlist_member(var,inner_tlist); - if ( inner_resdom!=NULL && IsA (inner_resdom,Resdom) ) { - return (makeVar (INNER, - inner_resdom->resno, - var->vartype, - var->varnoold, - var->varoattno)); - } - } - return (Var*)NULL; + Resdom *outer_resdom = (Resdom *) NULL; + + outer_resdom = tlist_member(var, outer_tlist); + + if (outer_resdom != NULL && IsA(outer_resdom, Resdom)) + { + return (makeVar(OUTER, + outer_resdom->resno, + var->vartype, + var->varnoold, + var->varoattno)); + } + else + { + Resdom *inner_resdom; + + inner_resdom = tlist_member(var, inner_tlist); + if (inner_resdom != NULL && IsA(inner_resdom, Resdom)) + { + return (makeVar(INNER, + inner_resdom->resno, + var->vartype, + var->varnoold, + var->varoattno)); + } + } + return (Var *) NULL; } -/* +/* * tlist-temp-references-- - * Creates a new target list for a node that scans a temp relation, - * setting the varnos to the id of the temp relation and setting varids - * if necessary (varids are only needed if this is a targetlist internal - * to the tree, in which case the targetlist entry always contains a var - * node, so we can just copy it from the temp). - * + * Creates a new target list for a node that scans a temp relation, + * setting the varnos to the id of the temp relation and setting varids + * if necessary (varids are only needed if this is a targetlist internal + * to the tree, in which case the targetlist entry always contains a var + * node, so we can just copy it from the temp). + * * 'tempid' is the id of the temp relation * 'tlist' is the target list to be modified - * + * * Returns new target list - * + * */ -static List * -tlist_temp_references(Oid tempid, - List *tlist) +static List * +tlist_temp_references(Oid tempid, + List * tlist) { - List *t_list = NIL; - TargetEntry *temp = (TargetEntry *)NULL; - TargetEntry *xtl = NULL; - List *entry; - - foreach (entry, tlist) { - AttrNumber oattno; - - xtl = lfirst(entry); - if (IsA(get_expr(xtl), Var)) - oattno = ((Var*)xtl->expr)->varoattno; - else - oattno = 0; - - temp = MakeTLE(xtl->resdom, - (Node*)makeVar(tempid, - xtl->resdom->resno, - xtl->resdom->restype, - tempid, - oattno)); - - t_list = lappend(t_list,temp); - } - return(t_list); + List *t_list = NIL; + TargetEntry *temp = (TargetEntry *) NULL; + TargetEntry *xtl = NULL; + List *entry; + + foreach(entry, tlist) + { + AttrNumber oattno; + + xtl = lfirst(entry); + if (IsA(get_expr(xtl), Var)) + oattno = ((Var *) xtl->expr)->varoattno; + else + oattno = 0; + + temp = MakeTLE(xtl->resdom, + (Node *) makeVar(tempid, + xtl->resdom->resno, + xtl->resdom->restype, + tempid, + oattno)); + + t_list = lappend(t_list, temp); + } + return (t_list); } /*--------------------------------------------------------- @@ -456,45 +505,49 @@ tlist_temp_references(Oid tempid, * addresses the tuples returned by its left tree subplan. * * NOTE: - * 1) we ignore the right tree! (in the current implementation - * it is always nil - * 2) this routine will probably *NOT* work with nested dot - * fields.... + * 1) we ignore the right tree! (in the current implementation + * it is always nil + * 2) this routine will probably *NOT* work with nested dot + * fields.... */ void -set_result_tlist_references(Result *resultNode) +set_result_tlist_references(Result * resultNode) { - Plan *subplan; - List *resultTargetList; - List *subplanTargetList; - List *t; - TargetEntry *entry; - Expr *expr; - - resultTargetList= ((Plan*)resultNode)->targetlist; - - /* - * NOTE: we only consider the left tree subplan. - * This is usually a seq scan. - */ - subplan = ((Plan*)resultNode)->lefttree; - if (subplan != NULL) { - subplanTargetList = subplan->targetlist; - } else { - subplanTargetList = NIL; - } - - /* - * now for traverse all the entris of the target list. - * These should be of the form (Resdom_Node Expression). - * For every expression clause, call "replace_result_clause()" - * to appropriatelly change all the Var nodes. - */ - foreach (t, resultTargetList) { - entry = (TargetEntry *)lfirst(t); - expr = (Expr*) get_expr(entry); - replace_result_clause((List*)expr, subplanTargetList); - } + Plan *subplan; + List *resultTargetList; + List *subplanTargetList; + List *t; + TargetEntry *entry; + Expr *expr; + + resultTargetList = ((Plan *) resultNode)->targetlist; + + /* + * NOTE: we only consider the left tree subplan. This is usually a seq + * scan. + */ + subplan = ((Plan *) resultNode)->lefttree; + if (subplan != NULL) + { + subplanTargetList = subplan->targetlist; + } + else + { + subplanTargetList = NIL; + } + + /* + * now for traverse all the entris of the target list. These should be + * of the form (Resdom_Node Expression). For every expression clause, + * call "replace_result_clause()" to appropriatelly change all the Var + * nodes. + */ + foreach(t, resultTargetList) + { + entry = (TargetEntry *) lfirst(t); + expr = (Expr *) get_expr(entry); + replace_result_clause((List *) expr, subplanTargetList); + } } /*--------------------------------------------------------- @@ -504,100 +557,121 @@ set_result_tlist_references(Result *resultNode) * This routine is called from set_result_tlist_references(). * and modifies the expressions of the target list of a Result * node so that all Var nodes reference the target list of its subplan. - * + * */ static void -replace_result_clause(List *clause, - List *subplanTargetList) /* target list of the - subplan */ +replace_result_clause(List * clause, + List * subplanTargetList) /* target list of the + * subplan */ { - List *t; - List *subClause; - TargetEntry *subplanVar; + List *t; + List *subClause; + TargetEntry *subplanVar; - if (IsA(clause,Var)) { - /* - * Ha! A Var node! - */ - subplanVar = match_varid((Var*)clause, subplanTargetList); - /* - * Change the varno & varattno fields of the - * var node. - * - */ - ((Var*)clause)->varno = (Index)OUTER; - ((Var*)clause)->varattno = subplanVar->resdom->resno; - } else if (is_funcclause((Node*)clause)) { - /* - * This is a function. Recursively call this routine - * for its arguments... - */ - subClause = ((Expr*)clause)->args; - foreach (t, subClause) { - replace_result_clause(lfirst(t),subplanTargetList); - } - } else if (IsA(clause,ArrayRef)) { - ArrayRef *aref = (ArrayRef *)clause; - /* - * This is an arrayref. Recursively call this routine - * for its expression and its index expression... - */ - subClause = aref->refupperindexpr; - foreach (t, subClause) { - replace_result_clause(lfirst(t),subplanTargetList); - } - subClause = aref->reflowerindexpr; - foreach (t, subClause) { - replace_result_clause(lfirst(t),subplanTargetList); - } - replace_result_clause((List*)aref->refexpr, - subplanTargetList); - replace_result_clause((List*)aref->refassgnexpr, - subplanTargetList); - } else if (is_opclause((Node*)clause)) { - /* - * This is an operator. Recursively call this routine - * for both its left and right operands - */ - subClause = (List*)get_leftop((Expr*)clause); - replace_result_clause(subClause,subplanTargetList); - subClause = (List*)get_rightop((Expr*)clause); - replace_result_clause(subClause,subplanTargetList); - } else if (IsA(clause,Param) || IsA(clause,Const)) { - /* do nothing! */ - } else { - /* - * Ooops! we can not handle that! - */ - elog(WARN,"replace_result_clause: Can not handle this tlist!\n"); - } + if (IsA(clause, Var)) + { + + /* + * Ha! A Var node! + */ + subplanVar = match_varid((Var *) clause, subplanTargetList); + + /* + * Change the varno & varattno fields of the var node. + * + */ + ((Var *) clause)->varno = (Index) OUTER; + ((Var *) clause)->varattno = subplanVar->resdom->resno; + } + else if (is_funcclause((Node *) clause)) + { + + /* + * This is a function. Recursively call this routine for its + * arguments... + */ + subClause = ((Expr *) clause)->args; + foreach(t, subClause) + { + replace_result_clause(lfirst(t), subplanTargetList); + } + } + else if (IsA(clause, ArrayRef)) + { + ArrayRef *aref = (ArrayRef *) clause; + + /* + * This is an arrayref. Recursively call this routine for its + * expression and its index expression... + */ + subClause = aref->refupperindexpr; + foreach(t, subClause) + { + replace_result_clause(lfirst(t), subplanTargetList); + } + subClause = aref->reflowerindexpr; + foreach(t, subClause) + { + replace_result_clause(lfirst(t), subplanTargetList); + } + replace_result_clause((List *) aref->refexpr, + subplanTargetList); + replace_result_clause((List *) aref->refassgnexpr, + subplanTargetList); + } + else if (is_opclause((Node *) clause)) + { + + /* + * This is an operator. Recursively call this routine for both its + * left and right operands + */ + subClause = (List *) get_leftop((Expr *) clause); + replace_result_clause(subClause, subplanTargetList); + subClause = (List *) get_rightop((Expr *) clause); + replace_result_clause(subClause, subplanTargetList); + } + else if (IsA(clause, Param) || IsA(clause, Const)) + { + /* do nothing! */ + } + else + { + + /* + * Ooops! we can not handle that! + */ + elog(WARN, "replace_result_clause: Can not handle this tlist!\n"); + } } static -bool OperandIsInner(Node *opnd, int inner_relid) +bool +OperandIsInner(Node * opnd, int inner_relid) { - /* - * Can be the inner scan if its a varnode or a function and the - * inner_relid is equal to the varnode's var number or in the - * case of a function the first argument's var number (all args - * in a functional index are from the same relation). - */ - if ( IsA (opnd,Var) && - (inner_relid == ((Var*)opnd)->varno) ) + + /* + * Can be the inner scan if its a varnode or a function and the + * inner_relid is equal to the varnode's var number or in the case of + * a function the first argument's var number (all args in a + * functional index are from the same relation). + */ + if (IsA(opnd, Var) && + (inner_relid == ((Var *) opnd)->varno)) { - return true; + return true; } - if (is_funcclause(opnd)) + if (is_funcclause(opnd)) { - List *firstArg = lfirst(((Expr*)opnd)->args); + List *firstArg = lfirst(((Expr *) opnd)->args); - if ( IsA (firstArg,Var) && - (inner_relid == ((Var*)firstArg)->varno) ) + if (IsA(firstArg, Var) && + (inner_relid == ((Var *) firstArg)->varno)) { - return true; + return true; } } - return false; + return false; } /***************************************************************************** @@ -607,105 +681,125 @@ bool OperandIsInner(Node *opnd, int inner_relid) /*--------------------------------------------------------- * * set_agg_tlist_references - - * changes the target list of an Agg node so that it points to - * the tuples returned by its left tree subplan. + * changes the target list of an Agg node so that it points to + * the tuples returned by its left tree subplan. * */ void -set_agg_tlist_references(Agg *aggNode) +set_agg_tlist_references(Agg * aggNode) { - List *aggTargetList; - List *subplanTargetList; - List *tl; + List *aggTargetList; + List *subplanTargetList; + List *tl; - aggTargetList = aggNode->plan.targetlist; - subplanTargetList = aggNode->plan.lefttree->targetlist; + aggTargetList = aggNode->plan.targetlist; + subplanTargetList = aggNode->plan.lefttree->targetlist; - foreach (tl, aggTargetList) { - TargetEntry *tle = lfirst(tl); + foreach(tl, aggTargetList) + { + TargetEntry *tle = lfirst(tl); - replace_agg_clause(tle->expr, subplanTargetList); - } + replace_agg_clause(tle->expr, subplanTargetList); + } } void -set_agg_agglist_references(Agg *aggNode) +set_agg_agglist_references(Agg * aggNode) { - List *subplanTargetList; - Aggreg **aggs; - int i; + List *subplanTargetList; + Aggreg **aggs; + int i; - aggs = aggNode->aggs; - subplanTargetList = aggNode->plan.lefttree->targetlist; + aggs = aggNode->aggs; + subplanTargetList = aggNode->plan.lefttree->targetlist; - for (i = 0; i < aggNode->numAgg; i++) { - replace_agg_clause(aggs[i]->target, subplanTargetList); - } + for (i = 0; i < aggNode->numAgg; i++) + { + replace_agg_clause(aggs[i]->target, subplanTargetList); + } } static void -replace_agg_clause(Node *clause, List *subplanTargetList) +replace_agg_clause(Node * clause, List * subplanTargetList) { - List *t; - TargetEntry *subplanVar; + List *t; + TargetEntry *subplanVar; - if (IsA(clause,Var)) { - /* - * Ha! A Var node! - */ - subplanVar = match_varid((Var*)clause, subplanTargetList); - /* - * Change the varno & varattno fields of the - * var node. - * - */ - ((Var*)clause)->varattno = subplanVar->resdom->resno; - } else if (is_funcclause(clause)) { - /* - * This is a function. Recursively call this routine - * for its arguments... - */ - foreach (t, ((Expr*)clause)->args) { - replace_agg_clause(lfirst(t), subplanTargetList); - } - } else if (IsA(clause,Aggreg)) { - replace_agg_clause(((Aggreg*)clause)->target, subplanTargetList); - } else if (IsA(clause,ArrayRef)) { - ArrayRef *aref = (ArrayRef *)clause; + if (IsA(clause, Var)) + { - /* - * This is an arrayref. Recursively call this routine - * for its expression and its index expression... - */ - foreach (t, aref->refupperindexpr) { - replace_agg_clause(lfirst(t),subplanTargetList); + /* + * Ha! A Var node! + */ + subplanVar = match_varid((Var *) clause, subplanTargetList); + + /* + * Change the varno & varattno fields of the var node. + * + */ + ((Var *) clause)->varattno = subplanVar->resdom->resno; + } + else if (is_funcclause(clause)) + { + + /* + * This is a function. Recursively call this routine for its + * arguments... + */ + foreach(t, ((Expr *) clause)->args) + { + replace_agg_clause(lfirst(t), subplanTargetList); + } } - foreach (t, aref->reflowerindexpr) { - replace_agg_clause(lfirst(t),subplanTargetList); + else if (IsA(clause, Aggreg)) + { + replace_agg_clause(((Aggreg *) clause)->target, subplanTargetList); } - replace_agg_clause(aref->refexpr, subplanTargetList); - replace_agg_clause(aref->refassgnexpr, subplanTargetList); - } else if (is_opclause(clause)) { - /* - * This is an operator. Recursively call this routine - * for both its left and right operands - */ - Node *left = (Node*)get_leftop((Expr*)clause); - Node *right = (Node*)get_rightop((Expr*)clause); - - if ( left != (Node*) NULL ) - replace_agg_clause(left, subplanTargetList); - if ( right != (Node*) NULL ) - replace_agg_clause(right, subplanTargetList); - } else if (IsA(clause,Param) || IsA(clause,Const)) { - /* do nothing! */ - } else { - /* - * Ooops! we can not handle that! - */ - elog(WARN,"replace_agg_clause: Can not handle this tlist!\n"); - } + else if (IsA(clause, ArrayRef)) + { + ArrayRef *aref = (ArrayRef *) clause; -} + /* + * This is an arrayref. Recursively call this routine for its + * expression and its index expression... + */ + foreach(t, aref->refupperindexpr) + { + replace_agg_clause(lfirst(t), subplanTargetList); + } + foreach(t, aref->reflowerindexpr) + { + replace_agg_clause(lfirst(t), subplanTargetList); + } + replace_agg_clause(aref->refexpr, subplanTargetList); + replace_agg_clause(aref->refassgnexpr, subplanTargetList); + } + else if (is_opclause(clause)) + { + + /* + * This is an operator. Recursively call this routine for both its + * left and right operands + */ + Node *left = (Node *) get_leftop((Expr *) clause); + Node *right = (Node *) get_rightop((Expr *) clause); + + if (left != (Node *) NULL) + replace_agg_clause(left, subplanTargetList); + if (right != (Node *) NULL) + replace_agg_clause(right, subplanTargetList); + } + else if (IsA(clause, Param) || IsA(clause, Const)) + { + /* do nothing! */ + } + else + { + /* + * Ooops! we can not handle that! + */ + elog(WARN, "replace_agg_clause: Can not handle this tlist!\n"); + } +} diff --git a/src/backend/optimizer/prep/archive.c b/src/backend/optimizer/prep/archive.c index 0303eca70f1..bbc797234ac 100644 --- a/src/backend/optimizer/prep/archive.c +++ b/src/backend/optimizer/prep/archive.c @@ -1,18 +1,18 @@ /*------------------------------------------------------------------------- * * archive.c-- - * Support for planning scans on archived relations + * Support for planning scans on archived relations * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/Attic/archive.c,v 1.1.1.1 1996/07/09 06:21:38 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/Attic/archive.c,v 1.2 1997/09/07 04:44:09 momjian Exp $ * *------------------------------------------------------------------------- */ -#include <stdio.h> /* for sprintf() */ -#include <sys/types.h> /* for u_int in relcache.h */ +#include <stdio.h> /* for sprintf() */ +#include <sys/types.h> /* for u_int in relcache.h */ #include "postgres.h" #include "utils/rel.h" @@ -26,41 +26,44 @@ #include "commands/creatinh.h" void -plan_archive(List *rt) +plan_archive(List * rt) { - List *rtitem; - RangeTblEntry *rte; - TimeRange *trange; - Relation r; - Oid reloid; + List *rtitem; + RangeTblEntry *rte; + TimeRange *trange; + Relation r; + Oid reloid; - foreach(rtitem, rt) { - rte = lfirst(rtitem); - trange = rte->timeRange; - if (trange) { - reloid = rte->relid; - r = RelationIdGetRelation(reloid); - if (r->rd_rel->relarch != 'n') { - rte->archive = true; - } + foreach(rtitem, rt) + { + rte = lfirst(rtitem); + trange = rte->timeRange; + if (trange) + { + reloid = rte->relid; + r = RelationIdGetRelation(reloid); + if (r->rd_rel->relarch != 'n') + { + rte->archive = true; + } + } } - } } /* - * find_archive_rels -- Given a particular relid, find the archive - * relation's relid. + * find_archive_rels -- Given a particular relid, find the archive + * relation's relid. */ -List * +List * find_archive_rels(Oid relid) { - Relation arel; - char *arelName; + Relation arel; + char *arelName; - arelName = MakeArchiveName(relid); - arel = RelationNameGetRelation(arelName); - pfree(arelName); + arelName = MakeArchiveName(relid); + arel = RelationNameGetRelation(arelName); + pfree(arelName); - return lconsi(arel->rd_id, lconsi(relid, NIL)); + return lconsi(arel->rd_id, lconsi(relid, NIL)); } diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c index 148f9638089..eac1eafa44f 100644 --- a/src/backend/optimizer/prep/prepqual.c +++ b/src/backend/optimizer/prep/prepqual.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * prepqual.c-- - * Routines for preprocessing the parse tree qualification + * Routines for preprocessing the parse tree qualification * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.3 1997/08/20 14:53:30 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.4 1997/09/07 04:44:10 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -24,531 +24,608 @@ #include "utils/lsyscache.h" -static Expr *pull_args(Expr *qual); -static List *pull_ors(List *orlist); -static List *pull_ands(List *andlist); -static Expr *find_nots(Expr *qual); -static Expr *push_nots(Expr *qual); -static Expr *normalize(Expr *qual); -static List *or_normalize(List *orlist); -static List *distribute_args(List *item, List *args); -static List *qualcleanup(Expr *qual); -static List *remove_ands(Expr *qual); -static List *remove_duplicates(List *list); - -/* +static Expr *pull_args(Expr * qual); +static List *pull_ors(List * orlist); +static List *pull_ands(List * andlist); +static Expr *find_nots(Expr * qual); +static Expr *push_nots(Expr * qual); +static Expr *normalize(Expr * qual); +static List *or_normalize(List * orlist); +static List *distribute_args(List * item, List * args); +static List *qualcleanup(Expr * qual); +static List *remove_ands(Expr * qual); +static List *remove_duplicates(List * list); + +/* * preprocess-qualification-- - * Driver routine for modifying the parse tree qualification. - * + * Driver routine for modifying the parse tree qualification. + * * Returns the new base qualification and the existential qualification * in existentialQualPtr. - * - * XXX right now, update_clauses() does nothing so - * preprocess-qualification simply converts the qual in conjunctive - * normal form (see cnfify() below ) + * + * XXX right now, update_clauses() does nothing so + * preprocess-qualification simply converts the qual in conjunctive + * normal form (see cnfify() below ) */ -List * -preprocess_qualification(Expr *qual, List *tlist, List **existentialQualPtr) +List * +preprocess_qualification(Expr * qual, List * tlist, List ** existentialQualPtr) { - List *cnf_qual = cnfify(qual, true); + List *cnf_qual = cnfify(qual, true); + /* - List *existential_qual = - update_clauses(intCons(_query_result_relation_, - update_relations(tlist)), - cnf_qual, - _query_command_type_); - if (existential_qual) { - *existentialQualPtr = existential_qual; - return set_difference(cnf_qual, existential_qual); - } else { + List *existential_qual = + update_clauses(intCons(_query_result_relation_, + update_relations(tlist)), + cnf_qual, + _query_command_type_); + if (existential_qual) { + *existentialQualPtr = existential_qual; + return set_difference(cnf_qual, existential_qual); + } else { + *existentialQualPtr = NIL; + return cnf_qual; + } +*/ + /* update_clauses() is not working right now */ *existentialQualPtr = NIL; return cnf_qual; - } -*/ - /* update_clauses() is not working right now */ - *existentialQualPtr = NIL; - return cnf_qual; } /***************************************************************************** * - * CNF CONVERSION ROUTINES - * - * NOTES: - * The basic algorithms for normalizing the qualification are taken - * from ingres/source/qrymod/norml.c - * - * Remember that the initial qualification may consist of ARBITRARY - * combinations of clauses. In addition, before this routine is called, - * the qualification will contain explicit "AND"s. - * + * CNF CONVERSION ROUTINES + * + * NOTES: + * The basic algorithms for normalizing the qualification are taken + * from ingres/source/qrymod/norml.c + * + * Remember that the initial qualification may consist of ARBITRARY + * combinations of clauses. In addition, before this routine is called, + * the qualification will contain explicit "AND"s. + * *****************************************************************************/ -/* +/* * cnfify-- - * Convert a qualification to conjunctive normal form by applying - * successive normalizations. - * + * Convert a qualification to conjunctive normal form by applying + * successive normalizations. + * * Returns the modified qualification with an extra level of nesting. * * If 'removeAndFlag' is true then it removes the explicit ANDs. * * NOTE: this routine is called by the planner (removeAndFlag = true) - * and from the rule manager (removeAndFlag = false). + * and from the rule manager (removeAndFlag = false). * */ -List * -cnfify(Expr *qual, bool removeAndFlag) +List * +cnfify(Expr * qual, bool removeAndFlag) { - Expr *newqual = NULL; - - if (qual != NULL) { - newqual = find_nots(pull_args(qual)); - newqual = normalize(pull_args(newqual)); - newqual = (Expr*)qualcleanup(pull_args(newqual)); - newqual = pull_args(newqual);; - - if (removeAndFlag) { - if(and_clause((Node*)newqual)) - newqual=(Expr*)remove_ands(newqual); - else - newqual=(Expr*)remove_ands(make_andclause(lcons(newqual,NIL))); - } - } - else if (qual!=NULL) - newqual = (Expr*)lcons(qual, NIL); - - return (List*)(newqual); + Expr *newqual = NULL; + + if (qual != NULL) + { + newqual = find_nots(pull_args(qual)); + newqual = normalize(pull_args(newqual)); + newqual = (Expr *) qualcleanup(pull_args(newqual)); + newqual = pull_args(newqual);; + + if (removeAndFlag) + { + if (and_clause((Node *) newqual)) + newqual = (Expr *) remove_ands(newqual); + else + newqual = (Expr *) remove_ands(make_andclause(lcons(newqual, NIL))); + } + } + else if (qual != NULL) + newqual = (Expr *) lcons(qual, NIL); + + return (List *) (newqual); } -/* +/* * pull-args-- - * Given a qualification, eliminate nested 'and' and 'or' clauses. - * + * Given a qualification, eliminate nested 'and' and 'or' clauses. + * * Returns the modified qualification. - * + * */ -static Expr * -pull_args(Expr *qual) +static Expr * +pull_args(Expr * qual) { - if (qual==NULL) - return (NULL); - - if (is_opclause((Node*)qual)) { - return(make_clause(qual->opType, qual->oper, - lcons(pull_args((Expr*)get_leftop(qual)), - lcons(pull_args((Expr*)get_rightop(qual)), - NIL)))); - } else if (and_clause((Node*)qual)) { - List *temp = NIL; - List *t_list = NIL; - - foreach (temp, qual->args) - t_list = lappend (t_list, pull_args(lfirst(temp))); - return (make_andclause (pull_ands (t_list))); - }else if (or_clause((Node*)qual)) { - List *temp = NIL; - List *t_list = NIL; - - foreach (temp, qual->args) - t_list = lappend (t_list, pull_args(lfirst(temp))); - return (make_orclause (pull_ors (t_list))); - } else if (not_clause((Node*)qual)) { - return (make_notclause (pull_args (get_notclausearg (qual)))); - } else { - return (qual); - } + if (qual == NULL) + return (NULL); + + if (is_opclause((Node *) qual)) + { + return (make_clause(qual->opType, qual->oper, + lcons(pull_args((Expr *) get_leftop(qual)), + lcons(pull_args((Expr *) get_rightop(qual)), + NIL)))); + } + else if (and_clause((Node *) qual)) + { + List *temp = NIL; + List *t_list = NIL; + + foreach(temp, qual->args) + t_list = lappend(t_list, pull_args(lfirst(temp))); + return (make_andclause(pull_ands(t_list))); + } + else if (or_clause((Node *) qual)) + { + List *temp = NIL; + List *t_list = NIL; + + foreach(temp, qual->args) + t_list = lappend(t_list, pull_args(lfirst(temp))); + return (make_orclause(pull_ors(t_list))); + } + else if (not_clause((Node *) qual)) + { + return (make_notclause(pull_args(get_notclausearg(qual)))); + } + else + { + return (qual); + } } -/* +/* * pull-ors-- - * Pull the arguments of an 'or' clause nested within another 'or' - * clause up into the argument list of the parent. - * + * Pull the arguments of an 'or' clause nested within another 'or' + * clause up into the argument list of the parent. + * * Returns the modified list. */ -static List * -pull_ors(List *orlist) +static List * +pull_ors(List * orlist) { - if (orlist==NIL) - return (NIL); + if (orlist == NIL) + return (NIL); - if (or_clause(lfirst(orlist))) { - List *args = ((Expr*)lfirst(orlist))->args; - return (pull_ors(nconc(copyObject((Node*)args), - copyObject((Node*)lnext(orlist))))); - } else { - return (lcons(lfirst(orlist), pull_ors(lnext(orlist)))); - } + if (or_clause(lfirst(orlist))) + { + List *args = ((Expr *) lfirst(orlist))->args; + + return (pull_ors(nconc(copyObject((Node *) args), + copyObject((Node *) lnext(orlist))))); + } + else + { + return (lcons(lfirst(orlist), pull_ors(lnext(orlist)))); + } } -/* +/* * pull-ands-- - * Pull the arguments of an 'and' clause nested within another 'and' - * clause up into the argument list of the parent. - * + * Pull the arguments of an 'and' clause nested within another 'and' + * clause up into the argument list of the parent. + * * Returns the modified list. */ -static List * -pull_ands(List *andlist) +static List * +pull_ands(List * andlist) { - if (andlist==NIL) - return (NIL); + if (andlist == NIL) + return (NIL); + + if (and_clause(lfirst(andlist))) + { + List *args = ((Expr *) lfirst(andlist))->args; - if (and_clause (lfirst(andlist))) { - List *args = ((Expr*)lfirst(andlist))->args; - return (pull_ands(nconc(copyObject((Node*)args), - copyObject((Node*)lnext(andlist))))); - } else { - return (lcons(lfirst(andlist), pull_ands(lnext(andlist)))); - } + return (pull_ands(nconc(copyObject((Node *) args), + copyObject((Node *) lnext(andlist))))); + } + else + { + return (lcons(lfirst(andlist), pull_ands(lnext(andlist)))); + } } -/* +/* * find-nots-- - * Traverse the qualification, looking for 'not's to take care of. - * For 'not' clauses, remove the 'not' and push it down to the clauses' - * descendants. - * For all other clause types, simply recurse. - * + * Traverse the qualification, looking for 'not's to take care of. + * For 'not' clauses, remove the 'not' and push it down to the clauses' + * descendants. + * For all other clause types, simply recurse. + * * Returns the modified qualification. - * + * */ -static Expr * -find_nots(Expr *qual) +static Expr * +find_nots(Expr * qual) { - if (qual==NULL) - return (NULL); - - if (is_opclause((Node*)qual)) { - return (make_clause(qual->opType, qual->oper, - lcons(find_nots((Expr*)get_leftop(qual)), - lcons(find_nots((Expr*)get_rightop(qual)), - NIL)))); - } else if (and_clause ((Node*)qual)) { - List *temp = NIL; - List *t_list = NIL; - - foreach (temp, qual->args) { - t_list = lappend(t_list,find_nots(lfirst(temp))); - } - - return (make_andclause(t_list)); - } else if (or_clause((Node*)qual)) { - List *temp = NIL; - List *t_list = NIL; - - foreach (temp, qual->args) { - t_list = lappend(t_list,find_nots(lfirst(temp))); - } - return (make_orclause (t_list)); - } else if (not_clause((Node*)qual)) - return (push_nots(get_notclausearg (qual))); - else - return (qual); + if (qual == NULL) + return (NULL); + + if (is_opclause((Node *) qual)) + { + return (make_clause(qual->opType, qual->oper, + lcons(find_nots((Expr *) get_leftop(qual)), + lcons(find_nots((Expr *) get_rightop(qual)), + NIL)))); + } + else if (and_clause((Node *) qual)) + { + List *temp = NIL; + List *t_list = NIL; + + foreach(temp, qual->args) + { + t_list = lappend(t_list, find_nots(lfirst(temp))); + } + + return (make_andclause(t_list)); + } + else if (or_clause((Node *) qual)) + { + List *temp = NIL; + List *t_list = NIL; + + foreach(temp, qual->args) + { + t_list = lappend(t_list, find_nots(lfirst(temp))); + } + return (make_orclause(t_list)); + } + else if (not_clause((Node *) qual)) + return (push_nots(get_notclausearg(qual))); + else + return (qual); } -/* +/* * push-nots-- - * Negate the descendants of a 'not' clause. - * + * Negate the descendants of a 'not' clause. + * * Returns the modified qualification. - * + * */ -static Expr * -push_nots(Expr *qual) +static Expr * +push_nots(Expr * qual) { - if (qual==NULL) - return (NULL); - - /* - * Negate an operator clause if possible: - * ("NOT" (< A B)) => (> A B) - * Otherwise, retain the clause as it is (the 'not' can't be pushed - * down any farther). - */ - if (is_opclause((Node*)qual)) { - Oper *oper = (Oper*)((Expr*)qual)->oper; - Oid negator = get_negator(oper->opno); - - if(negator) { - Oper *op = (Oper*) makeOper(negator, - InvalidOid, - oper->opresulttype, - 0, NULL); - op->op_fcache = (FunctionCache *) NULL; - return - (make_opclause(op, get_leftop(qual), get_rightop(qual))); - } else { - return (make_notclause(qual)); - } - } else if (and_clause((Node*)qual)) { - /* Apply DeMorgan's Laws: - * ("NOT" ("AND" A B)) => ("OR" ("NOT" A) ("NOT" B)) - * ("NOT" ("OR" A B)) => ("AND" ("NOT" A) ("NOT" B)) - * i.e., continue negating down through the clause's descendants. - */ - List *temp = NIL; - List *t_list = NIL; - - foreach(temp, qual->args) { - t_list = lappend(t_list,push_nots(lfirst(temp))); - } - return (make_orclause (t_list)); - } else if (or_clause((Node*)qual)) { - List *temp = NIL; - List *t_list = NIL; - - foreach(temp, qual->args) { - t_list = lappend(t_list,push_nots(lfirst(temp))); - } - return (make_andclause (t_list)); - } else if (not_clause((Node*)qual)) - /* Another 'not' cancels this 'not', so eliminate the 'not' and - * stop negating this branch. - */ - return (find_nots (get_notclausearg (qual))); - else - /* We don't know how to negate anything else, place a 'not' at this - * level. + if (qual == NULL) + return (NULL); + + /* + * Negate an operator clause if possible: ("NOT" (< A B)) => (> A B) + * Otherwise, retain the clause as it is (the 'not' can't be pushed + * down any farther). */ - return (make_notclause (qual)); + if (is_opclause((Node *) qual)) + { + Oper *oper = (Oper *) ((Expr *) qual)->oper; + Oid negator = get_negator(oper->opno); + + if (negator) + { + Oper *op = (Oper *) makeOper(negator, + InvalidOid, + oper->opresulttype, + 0, NULL); + + op->op_fcache = (FunctionCache *) NULL; + return + (make_opclause(op, get_leftop(qual), get_rightop(qual))); + } + else + { + return (make_notclause(qual)); + } + } + else if (and_clause((Node *) qual)) + { + + /* + * Apply DeMorgan's Laws: ("NOT" ("AND" A B)) => ("OR" ("NOT" A) + * ("NOT" B)) ("NOT" ("OR" A B)) => ("AND" ("NOT" A) ("NOT" B)) + * i.e., continue negating down through the clause's descendants. + */ + List *temp = NIL; + List *t_list = NIL; + + foreach(temp, qual->args) + { + t_list = lappend(t_list, push_nots(lfirst(temp))); + } + return (make_orclause(t_list)); + } + else if (or_clause((Node *) qual)) + { + List *temp = NIL; + List *t_list = NIL; + + foreach(temp, qual->args) + { + t_list = lappend(t_list, push_nots(lfirst(temp))); + } + return (make_andclause(t_list)); + } + else if (not_clause((Node *) qual)) + + /* + * Another 'not' cancels this 'not', so eliminate the 'not' and + * stop negating this branch. + */ + return (find_nots(get_notclausearg(qual))); + else + + /* + * We don't know how to negate anything else, place a 'not' at + * this level. + */ + return (make_notclause(qual)); } -/* +/* * normalize-- - * Given a qualification tree with the 'not's pushed down, convert it - * to a tree in CNF by repeatedly applying the rule: - * ("OR" A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C)) - * bottom-up. - * Note that 'or' clauses will always be turned into 'and' clauses. - * + * Given a qualification tree with the 'not's pushed down, convert it + * to a tree in CNF by repeatedly applying the rule: + * ("OR" A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C)) + * bottom-up. + * Note that 'or' clauses will always be turned into 'and' clauses. + * * Returns the modified qualification. - * + * */ -static Expr * -normalize(Expr *qual) +static Expr * +normalize(Expr * qual) { - if (qual==NULL) - return (NULL); - - if (is_opclause((Node*)qual)) { - Expr *expr = (Expr*)qual; - return (make_clause(expr->opType, expr->oper, - lcons(normalize((Expr*)get_leftop(qual)), - lcons(normalize((Expr*)get_rightop(qual)), - NIL)))); - } else if (and_clause((Node*)qual)) { - List *temp = NIL; - List *t_list = NIL; - - foreach (temp, qual->args) { - t_list = lappend(t_list,normalize(lfirst(temp))); - } - return (make_andclause (t_list)); - } else if (or_clause((Node*)qual)) { - /* XXX - let form, maybe incorrect */ - List *orlist = NIL; - List *temp = NIL; - bool has_andclause = FALSE; - - foreach(temp, qual->args) { - orlist = lappend(orlist,normalize(lfirst(temp))); - } - foreach (temp, orlist) { - if (and_clause (lfirst(temp))) { - has_andclause = TRUE; - break; - } - } - if (has_andclause == TRUE) - return (make_andclause(or_normalize(orlist))); - else - return (make_orclause(orlist)); - - } else if (not_clause((Node*)qual)) - return (make_notclause (normalize (get_notclausearg (qual)))); - else - return (qual); + if (qual == NULL) + return (NULL); + + if (is_opclause((Node *) qual)) + { + Expr *expr = (Expr *) qual; + + return (make_clause(expr->opType, expr->oper, + lcons(normalize((Expr *) get_leftop(qual)), + lcons(normalize((Expr *) get_rightop(qual)), + NIL)))); + } + else if (and_clause((Node *) qual)) + { + List *temp = NIL; + List *t_list = NIL; + + foreach(temp, qual->args) + { + t_list = lappend(t_list, normalize(lfirst(temp))); + } + return (make_andclause(t_list)); + } + else if (or_clause((Node *) qual)) + { + /* XXX - let form, maybe incorrect */ + List *orlist = NIL; + List *temp = NIL; + bool has_andclause = FALSE; + + foreach(temp, qual->args) + { + orlist = lappend(orlist, normalize(lfirst(temp))); + } + foreach(temp, orlist) + { + if (and_clause(lfirst(temp))) + { + has_andclause = TRUE; + break; + } + } + if (has_andclause == TRUE) + return (make_andclause(or_normalize(orlist))); + else + return (make_orclause(orlist)); + + } + else if (not_clause((Node *) qual)) + return (make_notclause(normalize(get_notclausearg(qual)))); + else + return (qual); } -/* +/* * or-normalize-- - * Given a list of exprs which are 'or'ed together, distribute any - * 'and' clauses. - * + * Given a list of exprs which are 'or'ed together, distribute any + * 'and' clauses. + * * Returns the modified list. - * + * */ -static List * -or_normalize(List *orlist) +static List * +or_normalize(List * orlist) { - List *distributable = NIL; - List *new_orlist = NIL; - List *temp = NIL; - - if (orlist==NIL) - return NIL; - - foreach(temp, orlist) { - if (and_clause(lfirst(temp))) - distributable = lfirst(temp); - } - if (distributable) - new_orlist = LispRemove(distributable,orlist); - - if(new_orlist) { - return - (or_normalize(lcons(distribute_args(lfirst(new_orlist), - ((Expr*)distributable)->args), - lnext(new_orlist)))); - }else { - return (orlist); - } + List *distributable = NIL; + List *new_orlist = NIL; + List *temp = NIL; + + if (orlist == NIL) + return NIL; + + foreach(temp, orlist) + { + if (and_clause(lfirst(temp))) + distributable = lfirst(temp); + } + if (distributable) + new_orlist = LispRemove(distributable, orlist); + + if (new_orlist) + { + return + (or_normalize(lcons(distribute_args(lfirst(new_orlist), + ((Expr *) distributable)->args), + lnext(new_orlist)))); + } + else + { + return (orlist); + } } -/* +/* * distribute-args-- - * Create new 'or' clauses by or'ing 'item' with each element of 'args'. - * E.g.: (distribute-args A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C)) - * + * Create new 'or' clauses by or'ing 'item' with each element of 'args'. + * E.g.: (distribute-args A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C)) + * * Returns an 'and' clause. - * + * */ -static List * -distribute_args(List *item, List *args) +static List * +distribute_args(List * item, List * args) { - List *or_list = NIL; - List *n_list = NIL; - List *temp = NIL; - List *t_list = NIL; - - if (args==NULL) - return (item); - - foreach (temp,args) { - n_list = or_normalize(pull_ors(lcons(item, - lcons(lfirst(temp),NIL)))); - or_list = (List*)make_orclause(n_list); - t_list = lappend(t_list,or_list); - } - return ((List*)make_andclause(t_list)); + List *or_list = NIL; + List *n_list = NIL; + List *temp = NIL; + List *t_list = NIL; + + if (args == NULL) + return (item); + + foreach(temp, args) + { + n_list = or_normalize(pull_ors(lcons(item, + lcons(lfirst(temp), NIL)))); + or_list = (List *) make_orclause(n_list); + t_list = lappend(t_list, or_list); + } + return ((List *) make_andclause(t_list)); } -/* +/* * qualcleanup-- - * Fix up a qualification by removing duplicate entries (left over from - * normalization), and by removing 'and' and 'or' clauses which have only - * one valid expr (e.g., ("AND" A) => A). - * + * Fix up a qualification by removing duplicate entries (left over from + * normalization), and by removing 'and' and 'or' clauses which have only + * one valid expr (e.g., ("AND" A) => A). + * * Returns the modified qualfication. - * + * */ -static List * -qualcleanup(Expr *qual) +static List * +qualcleanup(Expr * qual) { - if (qual==NULL) - return (NIL); - - if (is_opclause((Node*)qual)) { - return ((List*)make_clause(qual->opType, qual->oper, - lcons(qualcleanup((Expr*)get_leftop(qual)), - lcons(qualcleanup((Expr*)get_rightop(qual)), - NIL)))); - } else if (and_clause((Node*)qual)) { - List *temp = NIL; - List *t_list = NIL; - List *new_and_args = NIL; - - foreach(temp, qual->args) - t_list = lappend(t_list,qualcleanup(lfirst(temp))); - - new_and_args = remove_duplicates(t_list); - - if(length (new_and_args) > 1) - return ((List*)make_andclause(new_and_args)); - else - return (lfirst(new_and_args)); - } - else if (or_clause((Node*)qual)) { - List *temp = NIL; - List *t_list = NIL; - List *new_or_args = NIL; - - foreach (temp, qual->args) - t_list = lappend(t_list,qualcleanup(lfirst(temp))); - - new_or_args = remove_duplicates(t_list); - - - if(length (new_or_args) > 1) - return ((List*)make_orclause (new_or_args)); - else - return (lfirst (new_or_args)); - } else if (not_clause((Node*)qual)) - return ((List*)make_notclause((Expr*)qualcleanup((Expr*)get_notclausearg(qual)))); - - else - return ((List*)qual); + if (qual == NULL) + return (NIL); + + if (is_opclause((Node *) qual)) + { + return ((List *) make_clause(qual->opType, qual->oper, + lcons(qualcleanup((Expr *) get_leftop(qual)), + lcons(qualcleanup((Expr *) get_rightop(qual)), + NIL)))); + } + else if (and_clause((Node *) qual)) + { + List *temp = NIL; + List *t_list = NIL; + List *new_and_args = NIL; + + foreach(temp, qual->args) + t_list = lappend(t_list, qualcleanup(lfirst(temp))); + + new_and_args = remove_duplicates(t_list); + + if (length(new_and_args) > 1) + return ((List *) make_andclause(new_and_args)); + else + return (lfirst(new_and_args)); + } + else if (or_clause((Node *) qual)) + { + List *temp = NIL; + List *t_list = NIL; + List *new_or_args = NIL; + + foreach(temp, qual->args) + t_list = lappend(t_list, qualcleanup(lfirst(temp))); + + new_or_args = remove_duplicates(t_list); + + + if (length(new_or_args) > 1) + return ((List *) make_orclause(new_or_args)); + else + return (lfirst(new_or_args)); + } + else if (not_clause((Node *) qual)) + return ((List *) make_notclause((Expr *) qualcleanup((Expr *) get_notclausearg(qual)))); + + else + return ((List *) qual); } -/* +/* * remove-ands-- - * Remove the explicit "AND"s from the qualification: - * ("AND" A B) => (A B) - * + * Remove the explicit "AND"s from the qualification: + * ("AND" A B) => (A B) + * * RETURNS : qual * MODIFIES: qual */ -static List * -remove_ands(Expr *qual) +static List * +remove_ands(Expr * qual) { - List *t_list = NIL; - - if (qual==NULL) - return (NIL); - if (is_opclause((Node*)qual)) { - return ((List*)make_clause(qual->opType, qual->oper, - lcons(remove_ands((Expr*)get_leftop(qual)), - lcons(remove_ands((Expr*)get_rightop(qual)), - NIL)))); - } else if (and_clause((Node*)qual)) { - List *temp = NIL; - foreach (temp, qual->args) - t_list = lappend(t_list,remove_ands(lfirst(temp))); - return(t_list); - } else if (or_clause((Node*)qual)) { - List *temp = NIL; - foreach (temp, qual->args) - t_list = lappend(t_list,remove_ands(lfirst(temp))); - return ((List*)make_orclause((List*)t_list)); - } else if (not_clause((Node*)qual)) { - return ((List*)make_notclause((Expr*)remove_ands((Expr*)get_notclausearg (qual)))); - } else { - return ((List*)qual); - } + List *t_list = NIL; + + if (qual == NULL) + return (NIL); + if (is_opclause((Node *) qual)) + { + return ((List *) make_clause(qual->opType, qual->oper, + lcons(remove_ands((Expr *) get_leftop(qual)), + lcons(remove_ands((Expr *) get_rightop(qual)), + NIL)))); + } + else if (and_clause((Node *) qual)) + { + List *temp = NIL; + + foreach(temp, qual->args) + t_list = lappend(t_list, remove_ands(lfirst(temp))); + return (t_list); + } + else if (or_clause((Node *) qual)) + { + List *temp = NIL; + + foreach(temp, qual->args) + t_list = lappend(t_list, remove_ands(lfirst(temp))); + return ((List *) make_orclause((List *) t_list)); + } + else if (not_clause((Node *) qual)) + { + return ((List *) make_notclause((Expr *) remove_ands((Expr *) get_notclausearg(qual)))); + } + else + { + return ((List *) qual); + } } /***************************************************************************** * - * EXISTENTIAL QUALIFICATIONS + * EXISTENTIAL QUALIFICATIONS * *****************************************************************************/ -/* +/* * update-relations-- - * Returns the range table indices (i.e., varnos) for all relations which - * are referenced in the target list. - * + * Returns the range table indices (i.e., varnos) for all relations which + * are referenced in the target list. + * */ -#ifdef NOT_USED -static List * -update_relations(List *tlist) +#ifdef NOT_USED +static List * +update_relations(List * tlist) { - return(NIL); + return (NIL); } + #endif /***************************************************************************** @@ -557,28 +634,31 @@ update_relations(List *tlist) * *****************************************************************************/ -static List * -remove_duplicates(List *list) +static List * +remove_duplicates(List * list) { - List *i; - List *j; - List *result = NIL; - bool there_exists_duplicate = false; - - if (length(list) == 1) - return(list); - - foreach (i, list) { - if (i != NIL) { - foreach (j, lnext(i)) { - if (equal(lfirst(i), lfirst(j))) - there_exists_duplicate = true; - } - if (!there_exists_duplicate) - result = lappend(result, lfirst(i)); - - there_exists_duplicate = false; - } - } - return(result); + List *i; + List *j; + List *result = NIL; + bool there_exists_duplicate = false; + + if (length(list) == 1) + return (list); + + foreach(i, list) + { + if (i != NIL) + { + foreach(j, lnext(i)) + { + if (equal(lfirst(i), lfirst(j))) + there_exists_duplicate = true; + } + if (!there_exists_duplicate) + result = lappend(result, lfirst(i)); + + there_exists_duplicate = false; + } + } + return (result); } diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index d57755ac064..8b94fb4cbba 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * preptlist.c-- - * Routines to preprocess the parse tree target list + * Routines to preprocess the parse tree target list * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.2 1997/01/22 01:42:38 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.3 1997/09/07 04:44:13 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -25,7 +25,7 @@ #include "utils/lsyscache.h" #include "utils/palloc.h" -#include "parser/parsetree.h" /* for getrelid() */ +#include "parser/parsetree.h" /* for getrelid() */ #include "parser/catalog_utils.h" #include "optimizer/internal.h" @@ -33,291 +33,315 @@ #include "optimizer/clauses.h" #include "optimizer/tlist.h" -static List *expand_targetlist(List *tlist, Oid relid, int command_type, - Index result_relation); -static List *replace_matching_resname(List *new_tlist, - List *old_tlist); -static List *new_relation_targetlist(Oid relid, Index rt_index, - NodeTag node_type); - +static List * +expand_targetlist(List * tlist, Oid relid, int command_type, + Index result_relation); +static List * +replace_matching_resname(List * new_tlist, + List * old_tlist); +static List * +new_relation_targetlist(Oid relid, Index rt_index, + NodeTag node_type); -/* + +/* * preprocess-targetlist-- - * Driver for preprocessing the parse tree targetlist. - * - * 1. Deal with appends and replaces by filling missing attributes - * in the target list. - * 2. Reset operator OIDs to the appropriate regproc ids. - * - * Returns the new targetlist. + * Driver for preprocessing the parse tree targetlist. + * + * 1. Deal with appends and replaces by filling missing attributes + * in the target list. + * 2. Reset operator OIDs to the appropriate regproc ids. + * + * Returns the new targetlist. */ -List * -preprocess_targetlist(List *tlist, - int command_type, - Index result_relation, - List *range_table) +List * +preprocess_targetlist(List * tlist, + int command_type, + Index result_relation, + List * range_table) { - List *expanded_tlist = NIL; - Oid relid = InvalidOid; - List *t_list = NIL; - List *temp = NIL; - - if (result_relation>=1 && command_type != CMD_SELECT) { - relid = getrelid(result_relation, range_table); - } - - /* - * for heap_formtuple to work, the targetlist must match the exact - * order of the attributes. We also need to fill in the missing - * attributes here. -ay 10/94 - */ - expanded_tlist = - expand_targetlist(tlist, relid, command_type, result_relation); - - /* XXX should the fix-opids be this early?? */ - /* was mapCAR */ - foreach (temp,expanded_tlist) { - TargetEntry *tle = lfirst(temp); - if (tle->expr) - fix_opid(tle->expr); - } - t_list = copyObject(expanded_tlist); - - /* ------------------ - * for "replace" or "delete" queries, add ctid of the result - * relation into the target list so that the ctid can get - * propogate through the execution and in the end ExecReplace() - * will find the right tuple to replace or delete. This - * extra field will be removed in ExecReplace(). - * For convinient, we append this extra field to the end of - * the target list. - * ------------------ - */ - if (command_type == CMD_UPDATE || command_type == CMD_DELETE) { - TargetEntry *ctid; - Resdom *resdom; - Var *var; - - resdom = makeResdom(length(t_list) + 1, - 27, - 6, - "ctid", - 0, - 0, - 1); - - var = makeVar(result_relation, -1, 27, result_relation, -1); - - ctid = makeNode(TargetEntry); - ctid->resdom = resdom; - ctid->expr = (Node *)var; - t_list = lappend(t_list, ctid); - } - - return(t_list); + List *expanded_tlist = NIL; + Oid relid = InvalidOid; + List *t_list = NIL; + List *temp = NIL; + + if (result_relation >= 1 && command_type != CMD_SELECT) + { + relid = getrelid(result_relation, range_table); + } + + /* + * for heap_formtuple to work, the targetlist must match the exact + * order of the attributes. We also need to fill in the missing + * attributes here. -ay 10/94 + */ + expanded_tlist = + expand_targetlist(tlist, relid, command_type, result_relation); + + /* XXX should the fix-opids be this early?? */ + /* was mapCAR */ + foreach(temp, expanded_tlist) + { + TargetEntry *tle = lfirst(temp); + + if (tle->expr) + fix_opid(tle->expr); + } + t_list = copyObject(expanded_tlist); + + /* ------------------ + * for "replace" or "delete" queries, add ctid of the result + * relation into the target list so that the ctid can get + * propogate through the execution and in the end ExecReplace() + * will find the right tuple to replace or delete. This + * extra field will be removed in ExecReplace(). + * For convinient, we append this extra field to the end of + * the target list. + * ------------------ + */ + if (command_type == CMD_UPDATE || command_type == CMD_DELETE) + { + TargetEntry *ctid; + Resdom *resdom; + Var *var; + + resdom = makeResdom(length(t_list) + 1, + 27, + 6, + "ctid", + 0, + 0, + 1); + + var = makeVar(result_relation, -1, 27, result_relation, -1); + + ctid = makeNode(TargetEntry); + ctid->resdom = resdom; + ctid->expr = (Node *) var; + t_list = lappend(t_list, ctid); + } + + return (t_list); } /***************************************************************************** * - * TARGETLIST EXPANSION + * TARGETLIST EXPANSION * *****************************************************************************/ -/* +/* * expand-targetlist-- - * Given a target list as generated by the parser and a result relation, - * add targetlist entries for the attributes which have not been used. - * - * XXX This code is only supposed to work with unnested relations. - * - * 'tlist' is the original target list - * 'relid' is the relid of the result relation - * 'command' is the update command - * + * Given a target list as generated by the parser and a result relation, + * add targetlist entries for the attributes which have not been used. + * + * XXX This code is only supposed to work with unnested relations. + * + * 'tlist' is the original target list + * 'relid' is the relid of the result relation + * 'command' is the update command + * * Returns the expanded target list, sorted in resno order. */ -static List * -expand_targetlist(List *tlist, - Oid relid, - int command_type, - Index result_relation) +static List * +expand_targetlist(List * tlist, + Oid relid, + int command_type, + Index result_relation) { - NodeTag node_type = T_Invalid; - - switch (command_type) { - case CMD_INSERT: - node_type = (NodeTag)T_Const; - break; - case CMD_UPDATE: - node_type = (NodeTag)T_Var; - break; - } - - if(node_type != T_Invalid) { - List *ntlist = new_relation_targetlist(relid, - result_relation, - node_type); - - return (replace_matching_resname(ntlist, tlist)); - } else { - return (tlist); - } - + NodeTag node_type = T_Invalid; + + switch (command_type) + { + case CMD_INSERT: + node_type = (NodeTag) T_Const; + break; + case CMD_UPDATE: + node_type = (NodeTag) T_Var; + break; + } + + if (node_type != T_Invalid) + { + List *ntlist = new_relation_targetlist(relid, + result_relation, + node_type); + + return (replace_matching_resname(ntlist, tlist)); + } + else + { + return (tlist); + } + } -static List * -replace_matching_resname(List *new_tlist, List *old_tlist) +static List * +replace_matching_resname(List * new_tlist, List * old_tlist) { - List *temp, *i; - List *t_list = NIL; - - foreach (i,new_tlist) { - TargetEntry *new_tle = (TargetEntry *)lfirst(i); - TargetEntry *matching_old_tl = NULL; - - foreach (temp, old_tlist) { - TargetEntry *old_tle = (TargetEntry *)lfirst(temp); - - old_tle = lfirst(temp); - if (!strcmp(old_tle->resdom->resname, - new_tle->resdom->resname)) { - matching_old_tl = old_tle; - break; - } + List *temp, + *i; + List *t_list = NIL; + + foreach(i, new_tlist) + { + TargetEntry *new_tle = (TargetEntry *) lfirst(i); + TargetEntry *matching_old_tl = NULL; + + foreach(temp, old_tlist) + { + TargetEntry *old_tle = (TargetEntry *) lfirst(temp); + + old_tle = lfirst(temp); + if (!strcmp(old_tle->resdom->resname, + new_tle->resdom->resname)) + { + matching_old_tl = old_tle; + break; + } + } + + if (matching_old_tl) + { + matching_old_tl->resdom->resno = + new_tle->resdom->resno; + t_list = lappend(t_list, matching_old_tl); + } + else + { + t_list = lappend(t_list, new_tle); + } } - - if(matching_old_tl) { - matching_old_tl->resdom->resno = - new_tle->resdom->resno; - t_list = lappend(t_list, matching_old_tl); - } - else { - t_list = lappend(t_list, new_tle); - } - } - - /* - * It is possible that 'old_tlist' has some negative - * attributes (i.e. negative resnos). This only happens - * if this is a replace/append command and we explicitly - * specify a system attribute. Of course this is not a very good - * idea if this is a user query, but on the other hand the rule - * manager uses this mechanism to replace rule locks. - * - * So, copy all these entries to the end of the target list - * and set their 'resjunk' value to 1 to show that these are - * special attributes and have to be treated specially by the - * executor! - */ - foreach (temp, old_tlist) { - TargetEntry *old_tle, *new_tl; - Resdom *newresno; - - old_tle = lfirst(temp); - if (old_tle->resdom->resno < 0) { - newresno = (Resdom*) copyObject((Node*)old_tle->resdom); - newresno->resno = length(t_list) +1; - newresno->resjunk = 1; - new_tl = MakeTLE(newresno, old_tle->expr); - t_list = lappend(t_list, new_tl); + + /* + * It is possible that 'old_tlist' has some negative attributes (i.e. + * negative resnos). This only happens if this is a replace/append + * command and we explicitly specify a system attribute. Of course + * this is not a very good idea if this is a user query, but on the + * other hand the rule manager uses this mechanism to replace rule + * locks. + * + * So, copy all these entries to the end of the target list and set their + * 'resjunk' value to 1 to show that these are special attributes and + * have to be treated specially by the executor! + */ + foreach(temp, old_tlist) + { + TargetEntry *old_tle, + *new_tl; + Resdom *newresno; + + old_tle = lfirst(temp); + if (old_tle->resdom->resno < 0) + { + newresno = (Resdom *) copyObject((Node *) old_tle->resdom); + newresno->resno = length(t_list) + 1; + newresno->resjunk = 1; + new_tl = MakeTLE(newresno, old_tle->expr); + t_list = lappend(t_list, new_tl); + } } - } - return (t_list); + return (t_list); } -/* +/* * new-relation-targetlist-- - * Generate a targetlist for the relation with relation OID 'relid' - * and rangetable index 'rt-index'. - * - * Returns the new targetlist. + * Generate a targetlist for the relation with relation OID 'relid' + * and rangetable index 'rt-index'. + * + * Returns the new targetlist. */ -static List * +static List * new_relation_targetlist(Oid relid, Index rt_index, NodeTag node_type) { - AttrNumber attno; - List *t_list = NIL; - char *attname; - Oid atttype = 0; - int16 typlen = 0; - bool attisset = false; -/* Oid type_id; */ -/* type_id = RelationIdGetTypeId(relid); */ - - for(attno=1; attno <= get_relnatts(relid); attno++) { - attname = get_attname(/*type_id,*/ relid, attno); - atttype = get_atttype(/*type_id,*/ relid, attno); - /* - * Since this is an append or replace, the size of any set - * attribute is the size of the OID used to represent it. - */ - attisset = get_attisset(/* type_id,*/ relid, attname); - if (attisset) { - typlen = tlen(type("oid")); - } else { - typlen = get_typlen(atttype); - } - - switch (node_type) { - case T_Const: - { - struct varlena *typedefault = get_typdefault(atttype); - int temp = 0; - Const *temp2 = (Const*)NULL; - TargetEntry *temp3 = (TargetEntry *)NULL; - - if (typedefault==NULL) - temp = 0; - else - temp = typlen; - - temp2 = makeConst (atttype, - temp, - (Datum)typedefault, - (typedefault == (struct varlena *)NULL), - /* XXX this is bullshit */ - false, - false, /* not a set */ - false); - - temp3 = MakeTLE (makeResdom(attno, - atttype, - typlen, - attname, - 0, - (Oid)0, - 0), - (Node*)temp2); - t_list = lappend(t_list,temp3); - break; - } - case T_Var: - { - Var *temp_var = (Var*)NULL; - TargetEntry *temp_list = NULL; - - temp_var = - makeVar(rt_index, attno, atttype, rt_index, attno); - - temp_list = MakeTLE(makeResdom(attno, - atttype, - typlen, - attname, - 0, - (Oid)0, - 0), - (Node*)temp_var); - t_list = lappend(t_list,temp_list); - break; - } - default: /* do nothing */ - break; - } - } + AttrNumber attno; + List *t_list = NIL; + char *attname; + Oid atttype = 0; + int16 typlen = 0; + bool attisset = false; - return(t_list); -} +/* Oid type_id; */ +/* type_id = RelationIdGetTypeId(relid); */ + + for (attno = 1; attno <= get_relnatts(relid); attno++) + { + attname = get_attname( /* type_id, */ relid, attno); + atttype = get_atttype( /* type_id, */ relid, attno); + + /* + * Since this is an append or replace, the size of any set + * attribute is the size of the OID used to represent it. + */ + attisset = get_attisset( /* type_id, */ relid, attname); + if (attisset) + { + typlen = tlen(type("oid")); + } + else + { + typlen = get_typlen(atttype); + } + switch (node_type) + { + case T_Const: + { + struct varlena *typedefault = get_typdefault(atttype); + int temp = 0; + Const *temp2 = (Const *) NULL; + TargetEntry *temp3 = (TargetEntry *) NULL; + if (typedefault == NULL) + temp = 0; + else + temp = typlen; + + temp2 = makeConst(atttype, + temp, + (Datum) typedefault, + (typedefault == (struct varlena *) NULL), + /* XXX this is bullshit */ + false, + false, /* not a set */ + false); + + temp3 = MakeTLE(makeResdom(attno, + atttype, + typlen, + attname, + 0, + (Oid) 0, + 0), + (Node *) temp2); + t_list = lappend(t_list, temp3); + break; + } + case T_Var: + { + Var *temp_var = (Var *) NULL; + TargetEntry *temp_list = NULL; + + temp_var = + makeVar(rt_index, attno, atttype, rt_index, attno); + + temp_list = MakeTLE(makeResdom(attno, + atttype, + typlen, + attname, + 0, + (Oid) 0, + 0), + (Node *) temp_var); + t_list = lappend(t_list, temp_list); + break; + } + default: /* do nothing */ + break; + } + } + + return (t_list); +} diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 3142f37c07a..9bf282f8cc3 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * prepunion.c-- - * Routines to plan archive, inheritance, union, and version queries + * Routines to plan archive, inheritance, union, and version queries * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.3 1997/01/10 20:18:12 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.4 1997/09/07 04:44:14 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -34,370 +34,396 @@ #include "optimizer/planner.h" #include "optimizer/prep.h" -static List *plan_union_query(List *relids, Index rt_index, - RangeTblEntry *rt_entry, Query *parse, UnionFlag flag, - List **union_rtentriesPtr); -static RangeTblEntry *new_rangetable_entry(Oid new_relid, - RangeTblEntry *old_entry); -static Query *subst_rangetable(Query *root, Index index, - RangeTblEntry *new_entry); -static void fix_parsetree_attnums(Index rt_index, Oid old_relid, - Oid new_relid, Query *parsetree); -static Append *make_append(List *unionplans, Index rt_index, - List *union_rt_entries, List *tlist); +static List * +plan_union_query(List * relids, Index rt_index, + RangeTblEntry * rt_entry, Query * parse, UnionFlag flag, + List ** union_rtentriesPtr); +static RangeTblEntry * +new_rangetable_entry(Oid new_relid, + RangeTblEntry * old_entry); +static Query * +subst_rangetable(Query * root, Index index, + RangeTblEntry * new_entry); +static void +fix_parsetree_attnums(Index rt_index, Oid old_relid, + Oid new_relid, Query * parsetree); +static Append * +make_append(List * unionplans, Index rt_index, + List * union_rt_entries, List * tlist); -/* +/* * find-all-inheritors - - * Returns a list of relids corresponding to relations that inherit - * attributes from any relations listed in either of the argument relid - * lists. + * Returns a list of relids corresponding to relations that inherit + * attributes from any relations listed in either of the argument relid + * lists. */ -List * -find_all_inheritors(List *unexamined_relids, - List *examined_relids) +List * +find_all_inheritors(List * unexamined_relids, + List * examined_relids) { - List *new_inheritors = NIL; - List *new_examined_relids = NIL; - List *new_unexamined_relids = NIL; - - /* Find all relations which inherit from members of - * 'unexamined-relids' and store them in 'new-inheritors'. - */ - List *rels = NIL; - List *newrels = NIL; - - foreach(rels,unexamined_relids) { - newrels = (List*)LispUnioni(find_inheritance_children(lfirsti(rels)), - newrels); - } - new_inheritors = newrels; - - new_examined_relids = (List*)LispUnioni(examined_relids,unexamined_relids); - new_unexamined_relids = set_differencei(new_inheritors, - new_examined_relids); - - if (new_unexamined_relids==NULL) { - return(new_examined_relids); - } else { - return (find_all_inheritors (new_unexamined_relids, - new_examined_relids)); - } + List *new_inheritors = NIL; + List *new_examined_relids = NIL; + List *new_unexamined_relids = NIL; + + /* + * Find all relations which inherit from members of + * 'unexamined-relids' and store them in 'new-inheritors'. + */ + List *rels = NIL; + List *newrels = NIL; + + foreach(rels, unexamined_relids) + { + newrels = (List *) LispUnioni(find_inheritance_children(lfirsti(rels)), + newrels); + } + new_inheritors = newrels; + + new_examined_relids = (List *) LispUnioni(examined_relids, unexamined_relids); + new_unexamined_relids = set_differencei(new_inheritors, + new_examined_relids); + + if (new_unexamined_relids == NULL) + { + return (new_examined_relids); + } + else + { + return (find_all_inheritors(new_unexamined_relids, + new_examined_relids)); + } } -/* +/* * first-matching-rt-entry - - * Given a rangetable, find the first rangetable entry that represents - * the appropriate special case. - * - * Returns a rangetable index., Returns -1 if no matches + * Given a rangetable, find the first rangetable entry that represents + * the appropriate special case. + * + * Returns a rangetable index., Returns -1 if no matches */ int -first_matching_rt_entry (List *rangetable, UnionFlag flag) +first_matching_rt_entry(List * rangetable, UnionFlag flag) { - int count = 0; - List *temp = NIL; + int count = 0; + List *temp = NIL; - foreach(temp, rangetable) { - RangeTblEntry *rt_entry = lfirst(temp); - - switch(flag) { - case INHERITS_FLAG: - if (rt_entry->inh) - return count+1; - break; - case ARCHIVE_FLAG: - if (rt_entry->archive) - return count+1; - break; - default: - break; + foreach(temp, rangetable) + { + RangeTblEntry *rt_entry = lfirst(temp); + + switch (flag) + { + case INHERITS_FLAG: + if (rt_entry->inh) + return count + 1; + break; + case ARCHIVE_FLAG: + if (rt_entry->archive) + return count + 1; + break; + default: + break; + } + count++; } - count++; - } - - return(-1); + + return (-1); } -/* +/* * plan-union-queries-- - * - * Plans the queries for a given parent relation. - * + * + * Plans the queries for a given parent relation. + * * Returns a list containing a list of plans and a list of rangetable * entries to be inserted into an APPEND node. * XXX - what exactly does this mean, look for make_append */ -Append * +Append * plan_union_queries(Index rt_index, - Query *parse, - UnionFlag flag) + Query * parse, + UnionFlag flag) { - List *rangetable = parse->rtable; - RangeTblEntry *rt_entry = rt_fetch(rt_index,rangetable); - List *union_relids = NIL; - List *union_plans = NIL; - List *union_rt_entries = NIL; - - switch (flag) { - case INHERITS_FLAG: - union_relids = - find_all_inheritors(lconsi(rt_entry->relid, - NIL), - NIL); - break; - -#if 0 - case UNION_FLAG: + List *rangetable = parse->rtable; + RangeTblEntry *rt_entry = rt_fetch(rt_index, rangetable); + List *union_relids = NIL; + List *union_plans = NIL; + List *union_rt_entries = NIL; + + switch (flag) { - Index rt_index = 0; - union_plans = handleunion(root,rangetable,tlist,qual); - return (make_append (union_plans, - rt_index, rangetable, - ((Plan*)lfirst(union_plans))->targetlist )); - } - break; + case INHERITS_FLAG: + union_relids = + find_all_inheritors(lconsi(rt_entry->relid, + NIL), + NIL); + break; + +#if 0 + case UNION_FLAG: + { + Index rt_index = 0; + + union_plans = handleunion(root, rangetable, tlist, qual); + return (make_append(union_plans, + rt_index, rangetable, + ((Plan *) lfirst(union_plans))->targetlist)); + } + break; #endif - - case VERSION_FLAG: - union_relids = VersionGetParents(rt_entry->relid); - break; - - case ARCHIVE_FLAG: - union_relids = find_archive_rels(rt_entry->relid); - break; - - default: - /* do nothing */ - break; - } - - /* - * Remove the flag for this relation, since we're about to handle it - * (do it before recursing!). - * XXX destructive parse tree change - */ - switch(flag) { - case INHERITS_FLAG: - rt_fetch(rt_index,rangetable)->inh = false; - break; - case ARCHIVE_FLAG: - rt_fetch(rt_index,rangetable)->archive = false; - break; - default: - break; - } - - /* XXX - can't find any reason to sort union-relids - * as paul did, so we're leaving it out for now - * (maybe forever) - jeff & lp - * - * [maybe so. btw, jeff & lp did the lisp conversion, according to Paul. - * -- ay 10/94.] - */ - union_plans = plan_union_query(union_relids, rt_index, rt_entry, - parse, flag, &union_rt_entries); - - return (make_append(union_plans, - rt_index, - union_rt_entries, - ((Plan*)lfirst(union_plans))->targetlist)); + + case VERSION_FLAG: + union_relids = VersionGetParents(rt_entry->relid); + break; + + case ARCHIVE_FLAG: + union_relids = find_archive_rels(rt_entry->relid); + break; + + default: + /* do nothing */ + break; + } + + /* + * Remove the flag for this relation, since we're about to handle it + * (do it before recursing!). XXX destructive parse tree change + */ + switch (flag) + { + case INHERITS_FLAG: + rt_fetch(rt_index, rangetable)->inh = false; + break; + case ARCHIVE_FLAG: + rt_fetch(rt_index, rangetable)->archive = false; + break; + default: + break; + } + + /* + * XXX - can't find any reason to sort union-relids as paul did, so + * we're leaving it out for now (maybe forever) - jeff & lp + * + * [maybe so. btw, jeff & lp did the lisp conversion, according to Paul. + * -- ay 10/94.] + */ + union_plans = plan_union_query(union_relids, rt_index, rt_entry, + parse, flag, &union_rt_entries); + + return (make_append(union_plans, + rt_index, + union_rt_entries, + ((Plan *) lfirst(union_plans))->targetlist)); } -/* +/* * plan-union-query-- - * Returns a list of plans for 'relids' and a list of range table entries - * in union_rtentries. + * Returns a list of plans for 'relids' and a list of range table entries + * in union_rtentries. */ -static List * -plan_union_query(List *relids, - Index rt_index, - RangeTblEntry *rt_entry, - Query *root, - UnionFlag flag, - List **union_rtentriesPtr) +static List * +plan_union_query(List * relids, + Index rt_index, + RangeTblEntry * rt_entry, + Query * root, + UnionFlag flag, + List ** union_rtentriesPtr) { - List *i; - List *union_plans = NIL; - List *union_rtentries = NIL; - - foreach (i, relids) { - int relid = lfirsti(i); - RangeTblEntry *new_rt_entry = new_rangetable_entry(relid, - rt_entry); - Query *new_root = subst_rangetable(root, - rt_index, - new_rt_entry); - - /* reset the uniqueflag and sortclause in parse tree root, so that - * sorting will only be done once after append - */ -/* new_root->uniqueFlag = false; */ - new_root->uniqueFlag = NULL; - new_root->sortClause = NULL; - if (flag == ARCHIVE_FLAG) { - /* - * the entire union query uses the same (most recent) schema. - * to do otherwise would require either ragged tuples or careful - * archiving and interpretation of pg_attribute... - */ - } else { - fix_parsetree_attnums(rt_index, - rt_entry->relid, - relid, - new_root); - } + List *i; + List *union_plans = NIL; + List *union_rtentries = NIL; - union_plans = lappend(union_plans, planner(new_root)); - union_rtentries = lappend(union_rtentries, new_rt_entry); - } + foreach(i, relids) + { + int relid = lfirsti(i); + RangeTblEntry *new_rt_entry = new_rangetable_entry(relid, + rt_entry); + Query *new_root = subst_rangetable(root, + rt_index, + new_rt_entry); + + /* + * reset the uniqueflag and sortclause in parse tree root, so that + * sorting will only be done once after append + */ +/* new_root->uniqueFlag = false; */ + new_root->uniqueFlag = NULL; + new_root->sortClause = NULL; + if (flag == ARCHIVE_FLAG) + { + + /* + * the entire union query uses the same (most recent) schema. + * to do otherwise would require either ragged tuples or + * careful archiving and interpretation of pg_attribute... + */ + } + else + { + fix_parsetree_attnums(rt_index, + rt_entry->relid, + relid, + new_root); + } + + union_plans = lappend(union_plans, planner(new_root)); + union_rtentries = lappend(union_rtentries, new_rt_entry); + } - *union_rtentriesPtr = union_rtentries; - return(union_plans); + *union_rtentriesPtr = union_rtentries; + return (union_plans); } -/* +/* * new-rangetable-entry - - * Replaces the name and relid of 'old-entry' with the values for - * 'new-relid'. - * - * Returns a copy of 'old-entry' with the parameters substituted. + * Replaces the name and relid of 'old-entry' with the values for + * 'new-relid'. + * + * Returns a copy of 'old-entry' with the parameters substituted. */ static RangeTblEntry * -new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry) +new_rangetable_entry(Oid new_relid, RangeTblEntry * old_entry) { - RangeTblEntry *new_entry = copyObject(old_entry); + RangeTblEntry *new_entry = copyObject(old_entry); - /* ??? someone tell me what the following is doing! - ay 11/94 */ - if (!strcmp(new_entry->refname, "*CURRENT*") || - !strcmp(new_entry->refname, "*NEW*")) - new_entry->refname = get_rel_name(new_relid); - else - new_entry->relname = get_rel_name(new_relid); + /* ??? someone tell me what the following is doing! - ay 11/94 */ + if (!strcmp(new_entry->refname, "*CURRENT*") || + !strcmp(new_entry->refname, "*NEW*")) + new_entry->refname = get_rel_name(new_relid); + else + new_entry->relname = get_rel_name(new_relid); - new_entry->relid = new_relid; - return(new_entry); + new_entry->relid = new_relid; + return (new_entry); } -/* +/* * subst-rangetable-- - * Replaces the 'index'th rangetable entry in 'root' with 'new-entry'. - * + * Replaces the 'index'th rangetable entry in 'root' with 'new-entry'. + * * Returns a new copy of 'root'. */ -static Query * -subst_rangetable(Query *root, Index index, RangeTblEntry *new_entry) +static Query * +subst_rangetable(Query * root, Index index, RangeTblEntry * new_entry) { - Query *new_root = copyObject(root); - List *temp = NIL; - int i = 0; + Query *new_root = copyObject(root); + List *temp = NIL; + int i = 0; - for(temp = new_root->rtable,i =1; i < index; temp =lnext(temp),i++) - ; - lfirst(temp) = new_entry; + for (temp = new_root->rtable, i = 1; i < index; temp = lnext(temp), i++) + ; + lfirst(temp) = new_entry; - return (new_root); + return (new_root); } static void fix_parsetree_attnums_nodes(Index rt_index, - Oid old_relid, - Oid new_relid, - Node *node) + Oid old_relid, + Oid new_relid, + Node * node) { - if (node==NULL) - return; - - switch(nodeTag(node)) { - case T_TargetEntry: - { - TargetEntry *tle = (TargetEntry *)node; - - fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid, - tle->expr); - } - break; - case T_Expr: - { - Expr *expr = (Expr *)node; - fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid, - (Node*)expr->args); - } - break; - case T_Var: - { - Var *var = (Var *)node; - Oid old_typeid, new_typeid; - -/* old_typeid = RelationIdGetTypeId(old_relid);*/ -/* new_typeid = RelationIdGetTypeId(new_relid);*/ - old_typeid = old_relid; - new_typeid = new_relid; - - if (var->varno == rt_index && var->varattno != 0) { - var->varattno = - get_attnum(new_typeid, - get_attname(old_typeid, var->varattno)); - } - } - break; - case T_List: + if (node == NULL) + return; + + switch (nodeTag(node)) { - List *l; - foreach(l, (List*)node) { - fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid, - (Node*)lfirst(l)); - } + case T_TargetEntry: + { + TargetEntry *tle = (TargetEntry *) node; + + fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid, + tle->expr); + } + break; + case T_Expr: + { + Expr *expr = (Expr *) node; + + fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid, + (Node *) expr->args); + } + break; + case T_Var: + { + Var *var = (Var *) node; + Oid old_typeid, + new_typeid; + +/* old_typeid = RelationIdGetTypeId(old_relid);*/ +/* new_typeid = RelationIdGetTypeId(new_relid);*/ + old_typeid = old_relid; + new_typeid = new_relid; + + if (var->varno == rt_index && var->varattno != 0) + { + var->varattno = + get_attnum(new_typeid, + get_attname(old_typeid, var->varattno)); + } + } + break; + case T_List: + { + List *l; + + foreach(l, (List *) node) + { + fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid, + (Node *) lfirst(l)); + } + } + break; + default: + break; } - break; - default: - break; - } } - -/* + +/* * fix-parsetree-attnums-- - * Replaces attribute numbers from the relation represented by - * 'old-relid' in 'parsetree' with the attribute numbers from - * 'new-relid'. - * + * Replaces attribute numbers from the relation represented by + * 'old-relid' in 'parsetree' with the attribute numbers from + * 'new-relid'. + * * Returns the destructively-modified parsetree. - * + * */ static void fix_parsetree_attnums(Index rt_index, - Oid old_relid, - Oid new_relid, - Query *parsetree) + Oid old_relid, + Oid new_relid, + Query * parsetree) { - if (old_relid == new_relid) - return; + if (old_relid == new_relid) + return; - fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid, - (Node*)parsetree->targetList); - fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid, - parsetree->qual); + fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid, + (Node *) parsetree->targetList); + fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid, + parsetree->qual); } -static Append * -make_append(List *unionplans, - Index rt_index, - List *union_rt_entries, - List *tlist) +static Append * +make_append(List * unionplans, + Index rt_index, + List * union_rt_entries, + List * tlist) { - Append *node = makeNode(Append); - - node->unionplans = unionplans; - node->unionrelid = rt_index; - node->unionrtentries = union_rt_entries; - node->plan.cost = 0.0; - node->plan.state = (EState*)NULL; - node->plan.targetlist = tlist; - node->plan.qual = NIL; - node->plan.lefttree = (Plan*)NULL; - node->plan.righttree = (Plan*)NULL; - - return(node); + Append *node = makeNode(Append); + + node->unionplans = unionplans; + node->unionrelid = rt_index; + node->unionrtentries = union_rt_entries; + node->plan.cost = 0.0; + node->plan.state = (EState *) NULL; + node->plan.targetlist = tlist; + node->plan.qual = NIL; + node->plan.lefttree = (Plan *) NULL; + node->plan.righttree = (Plan *) NULL; + + return (node); } diff --git a/src/backend/optimizer/util/clauseinfo.c b/src/backend/optimizer/util/clauseinfo.c index 2d648eb3605..e5fd2b7e5bb 100644 --- a/src/backend/optimizer/util/clauseinfo.c +++ b/src/backend/optimizer/util/clauseinfo.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * clauseinfo.c-- - * ClauseInfo node manipulation routines. + * ClauseInfo node manipulation routines. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/clauseinfo.c,v 1.3 1996/07/31 18:47:06 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/clauseinfo.c,v 1.4 1997/09/07 04:44:17 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -20,167 +20,172 @@ #include "optimizer/clauses.h" #include "optimizer/clauseinfo.h" -/* +/* * valid-or-clause-- - * + * * Returns t iff the clauseinfo node contains a 'normal' 'or' clause. - * + * */ bool -valid_or_clause(CInfo *clauseinfo) +valid_or_clause(CInfo * clauseinfo) { - if (clauseinfo != NULL && - !single_node((Node*)clauseinfo->clause) && - !clauseinfo->notclause && - or_clause((Node*)clauseinfo->clause)) - return(true); - else - return(false); + if (clauseinfo != NULL && + !single_node((Node *) clauseinfo->clause) && + !clauseinfo->notclause && + or_clause((Node *) clauseinfo->clause)) + return (true); + else + return (false); } -/* +/* * get-actual-clauses-- - * + * * Returns a list containing the clauses from 'clauseinfo-list'. - * + * */ -List * -get_actual_clauses(List *clauseinfo_list) +List * +get_actual_clauses(List * clauseinfo_list) { - List *temp = NIL; - List *result = NIL; - CInfo *clause = (CInfo *)NULL; - - foreach(temp,clauseinfo_list) { - clause = (CInfo *)lfirst(temp); - result = lappend(result,clause->clause); - } - return(result); + List *temp = NIL; + List *result = NIL; + CInfo *clause = (CInfo *) NULL; + + foreach(temp, clauseinfo_list) + { + clause = (CInfo *) lfirst(temp); + result = lappend(result, clause->clause); + } + return (result); } -/* +/* * XXX NOTE: - * The following routines must return their contents in the same order - * (e.g., the first clause's info should be first, and so on) or else - * get_index_sel() won't work. - * + * The following routines must return their contents in the same order + * (e.g., the first clause's info should be first, and so on) or else + * get_index_sel() won't work. + * */ -/* +/* * get_relattvals-- - * For each member of a list of clauseinfo nodes to be used with an - * index, create a vectori-long specifying: - * the attnos, - * the values of the clause constants, and - * flags indicating the type and location of the constant within - * each clause. - * Each clause is of the form (op var some_type_of_constant), thus the - * flag indicating whether the constant is on the left or right should - * always be *SELEC-CONSTANT-RIGHT*. - * + * For each member of a list of clauseinfo nodes to be used with an + * index, create a vectori-long specifying: + * the attnos, + * the values of the clause constants, and + * flags indicating the type and location of the constant within + * each clause. + * Each clause is of the form (op var some_type_of_constant), thus the + * flag indicating whether the constant is on the left or right should + * always be *SELEC-CONSTANT-RIGHT*. + * * 'clauseinfo-list' is a list of clauseinfo nodes - * + * * Returns a list of vectori-longs. - * + * */ void -get_relattvals(List *clauseinfo_list, - List **attnos, - List **values, - List **flags) +get_relattvals(List * clauseinfo_list, + List ** attnos, + List ** values, + List ** flags) { - List *result1 = NIL; - List *result2 = NIL; - List *result3 = NIL; - CInfo *temp = (CInfo *)NULL; - List *i = NIL; - - foreach (i,clauseinfo_list) { - int dummy; - AttrNumber attno; - Datum constval; - int flag; - - temp = (CInfo *)lfirst(i); - get_relattval((Node*)temp->clause, &dummy, &attno, &constval, &flag); - result1 = lappendi(result1, (int)attno); - result2 = lappendi(result2, constval); - result3 = lappendi(result3, flag); - } + List *result1 = NIL; + List *result2 = NIL; + List *result3 = NIL; + CInfo *temp = (CInfo *) NULL; + List *i = NIL; + + foreach(i, clauseinfo_list) + { + int dummy; + AttrNumber attno; + Datum constval; + int flag; + + temp = (CInfo *) lfirst(i); + get_relattval((Node *) temp->clause, &dummy, &attno, &constval, &flag); + result1 = lappendi(result1, (int) attno); + result2 = lappendi(result2, constval); + result3 = lappendi(result3, flag); + } - *attnos = result1; - *values = result2; - *flags = result3; - return; + *attnos = result1; + *values = result2; + *flags = result3; + return; } -/* +/* * get_joinvars -- - * Given a list of join clauseinfo nodes to be used with the index - * of an inner join relation, return three lists consisting of: - * the attributes corresponding to the inner join relation - * the value of the inner var clause (always "") - * whether the attribute appears on the left or right side of - * the operator. - * + * Given a list of join clauseinfo nodes to be used with the index + * of an inner join relation, return three lists consisting of: + * the attributes corresponding to the inner join relation + * the value of the inner var clause (always "") + * whether the attribute appears on the left or right side of + * the operator. + * * 'relid' is the inner join relation * 'clauseinfo-list' is a list of qualification clauses to be used with - * 'rel' - * + * 'rel' + * */ void get_joinvars(Oid relid, - List *clauseinfo_list, - List **attnos, - List **values, - List **flags) + List * clauseinfo_list, + List ** attnos, + List ** values, + List ** flags) { - List *result1 = NIL; - List *result2 = NIL; - List *result3 = NIL; - List *temp; - - foreach(temp, clauseinfo_list) { - CInfo *clauseinfo = lfirst(temp); - Expr *clause = clauseinfo->clause; - - if( IsA (get_leftop(clause),Var) && - (relid == (get_leftop(clause))->varno)) { - result1 = lappendi(result1, (int4)(get_leftop(clause))->varattno); - result2 = lappend(result2, ""); - result3 = lappendi(result3, _SELEC_CONSTANT_RIGHT_); - } else { - result1 = lappendi(result1, (int4)(get_rightop(clause))->varattno); - result2 = lappend(result2, ""); - result3 = lappendi(result3, _SELEC_CONSTANT_LEFT_); + List *result1 = NIL; + List *result2 = NIL; + List *result3 = NIL; + List *temp; + + foreach(temp, clauseinfo_list) + { + CInfo *clauseinfo = lfirst(temp); + Expr *clause = clauseinfo->clause; + + if (IsA(get_leftop(clause), Var) && + (relid == (get_leftop(clause))->varno)) + { + result1 = lappendi(result1, (int4) (get_leftop(clause))->varattno); + result2 = lappend(result2, ""); + result3 = lappendi(result3, _SELEC_CONSTANT_RIGHT_); + } + else + { + result1 = lappendi(result1, (int4) (get_rightop(clause))->varattno); + result2 = lappend(result2, ""); + result3 = lappendi(result3, _SELEC_CONSTANT_LEFT_); + } } - } - *attnos = result1; - *values = result2; - *flags = result3; - return; + *attnos = result1; + *values = result2; + *flags = result3; + return; } -/* +/* * get_opnos-- - * Create and return a list containing the clause operators of each member - * of a list of clauseinfo nodes to be used with an index. - * + * Create and return a list containing the clause operators of each member + * of a list of clauseinfo nodes to be used with an index. + * */ -List * -get_opnos(List *clauseinfo_list) +List * +get_opnos(List * clauseinfo_list) { - CInfo *temp = (CInfo *)NULL; - List *result = NIL; - List *i = NIL; - - foreach(i,clauseinfo_list) { - temp = (CInfo *)lfirst(i); - result = - lappendi(result, - (((Oper*)temp->clause->oper)->opno)); - } - return(result); + CInfo *temp = (CInfo *) NULL; + List *result = NIL; + List *i = NIL; + + foreach(i, clauseinfo_list) + { + temp = (CInfo *) lfirst(i); + result = + lappendi(result, + (((Oper *) temp->clause->oper)->opno)); + } + return (result); } - - diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 153c11f9f42..03e0856ef09 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -1,17 +1,17 @@ /*------------------------------------------------------------------------- * * clauses.c-- - * routines to manipulate qualification clauses + * routines to manipulate qualification clauses * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.7 1997/08/19 21:31:54 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.8 1997/09/07 04:44:20 momjian Exp $ * * HISTORY - * AUTHOR DATE MAJOR EVENT - * Andrew Yu Nov 3, 1994 clause.c and clauses.c combined + * AUTHOR DATE MAJOR EVENT + * Andrew Yu Nov 3, 1994 clause.c and clauses.c combined * *------------------------------------------------------------------------- */ @@ -34,533 +34,556 @@ #include "optimizer/internal.h" #include "optimizer/var.h" -static bool agg_clause(Node *clause); +static bool agg_clause(Node * clause); -Expr * -make_clause(int type, Node *oper, List *args) +Expr * +make_clause(int type, Node * oper, List * args) { - if (type == AND_EXPR || type == OR_EXPR || type == NOT_EXPR || - type == OP_EXPR || type == FUNC_EXPR) { - Expr *expr = makeNode(Expr); - - /* - * assume type checking already done and we don't need the type of - * the expr any more. - */ - expr->typeOid = InvalidOid; - expr->opType = type; - expr->oper = oper; /* ignored for AND, OR, NOT */ - expr->args = args; - return expr; - }else { - /* will this ever happen? translated from lispy C code - ay 10/94 */ - return((Expr*)args); - } + if (type == AND_EXPR || type == OR_EXPR || type == NOT_EXPR || + type == OP_EXPR || type == FUNC_EXPR) + { + Expr *expr = makeNode(Expr); + + /* + * assume type checking already done and we don't need the type of + * the expr any more. + */ + expr->typeOid = InvalidOid; + expr->opType = type; + expr->oper = oper; /* ignored for AND, OR, NOT */ + expr->args = args; + return expr; + } + else + { + /* will this ever happen? translated from lispy C code - ay 10/94 */ + return ((Expr *) args); + } } /***************************************************************************** - * OPERATOR clause functions + * OPERATOR clause functions *****************************************************************************/ -/* +/* * is_opclause-- - * + * * Returns t iff the clause is an operator clause: - * (op expr expr) or (op expr). + * (op expr expr) or (op expr). * * [historical note: is_clause has the exact functionality and is used - * throughout the code. They're renamed to is_opclause for clarity. - * - ay 10/94.] + * throughout the code. They're renamed to is_opclause for clarity. + * - ay 10/94.] */ bool -is_opclause(Node *clause) +is_opclause(Node * clause) { - return - (clause!=NULL && - nodeTag(clause)==T_Expr && ((Expr*)clause)->opType==OP_EXPR); + return + (clause != NULL && + nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == OP_EXPR); } -/* +/* * make_opclause-- - * Creates a clause given its operator left operand and right - * operand (if it is non-null). - * + * Creates a clause given its operator left operand and right + * operand (if it is non-null). + * */ -Expr * -make_opclause(Oper *op, Var *leftop, Var *rightop) +Expr * +make_opclause(Oper * op, Var * leftop, Var * rightop) { - Expr *expr = makeNode(Expr); + Expr *expr = makeNode(Expr); - expr->typeOid = InvalidOid; /* assume type checking done */ - expr->opType = OP_EXPR; - expr->oper = (Node*)op; - expr->args = makeList(leftop, rightop, -1); - return expr; + expr->typeOid = InvalidOid; /* assume type checking done */ + expr->opType = OP_EXPR; + expr->oper = (Node *) op; + expr->args = makeList(leftop, rightop, -1); + return expr; } -/* +/* * get_leftop-- - * + * * Returns the left operand of a clause of the form (op expr expr) - * or (op expr) - * NB: it is assumed (for now) that all expr must be Var nodes + * or (op expr) + * NB: it is assumed (for now) that all expr must be Var nodes */ -Var * -get_leftop(Expr *clause) +Var * +get_leftop(Expr * clause) { - if (clause->args!=NULL) - return(lfirst(clause->args)); - else - return NULL; + if (clause->args != NULL) + return (lfirst(clause->args)); + else + return NULL; } -/* +/* * get_rightop - * + * * Returns the right operand in a clause of the form (op expr expr). - * + * */ -Var * -get_rightop(Expr *clause) +Var * +get_rightop(Expr * clause) { - if (clause->args!=NULL && lnext(clause->args)!=NULL) - return (lfirst(lnext(clause->args))); - else - return NULL; + if (clause->args != NULL && lnext(clause->args) != NULL) + return (lfirst(lnext(clause->args))); + else + return NULL; } /***************************************************************************** - * AGG clause functions + * AGG clause functions *****************************************************************************/ -static bool -agg_clause(Node *clause) +static bool +agg_clause(Node * clause) { - return - (clause!=NULL && nodeTag(clause)==T_Aggreg); + return + (clause != NULL && nodeTag(clause) == T_Aggreg); } /***************************************************************************** - * FUNC clause functions + * FUNC clause functions *****************************************************************************/ -/* +/* * is_funcclause-- - * + * * Returns t iff the clause is a function clause: (func { expr }). - * + * */ bool -is_funcclause(Node *clause) +is_funcclause(Node * clause) { - return - (clause!=NULL && - nodeTag(clause)==T_Expr && ((Expr*)clause)->opType==FUNC_EXPR); + return + (clause != NULL && + nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == FUNC_EXPR); } -/* +/* * make_funcclause-- - * + * * Creates a function clause given the FUNC node and the functional * arguments. - * + * */ -Expr * -make_funcclause(Func *func, List *funcargs) +Expr * +make_funcclause(Func * func, List * funcargs) { - Expr *expr = makeNode(Expr); + Expr *expr = makeNode(Expr); - expr->typeOid = InvalidOid; /* assume type checking done */ - expr->opType = FUNC_EXPR; - expr->oper = (Node*)func; - expr->args = funcargs; - return expr; + expr->typeOid = InvalidOid; /* assume type checking done */ + expr->opType = FUNC_EXPR; + expr->oper = (Node *) func; + expr->args = funcargs; + return expr; } /***************************************************************************** - * OR clause functions + * OR clause functions *****************************************************************************/ -/* +/* * or_clause-- - * + * * Returns t iff the clause is an 'or' clause: (OR { expr }). - * + * */ bool -or_clause(Node *clause) +or_clause(Node * clause) { - return - (clause!=NULL && - nodeTag(clause)==T_Expr && ((Expr*)clause)->opType==OR_EXPR); + return + (clause != NULL && + nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == OR_EXPR); } -/* +/* * make_orclause-- - * + * * Creates an 'or' clause given a list of its subclauses. - * + * */ -Expr * -make_orclause(List *orclauses) +Expr * +make_orclause(List * orclauses) { - Expr *expr = makeNode(Expr); + Expr *expr = makeNode(Expr); - expr->typeOid = InvalidOid; /* assume type checking done */ - expr->opType = OR_EXPR; - expr->oper = NULL; - expr->args = orclauses; - return expr; + expr->typeOid = InvalidOid; /* assume type checking done */ + expr->opType = OR_EXPR; + expr->oper = NULL; + expr->args = orclauses; + return expr; } /***************************************************************************** - * NOT clause functions + * NOT clause functions *****************************************************************************/ -/* +/* * not_clause-- - * + * * Returns t iff this is a 'not' clause: (NOT expr). - * + * */ bool -not_clause(Node *clause) +not_clause(Node * clause) { - return - (clause!=NULL && - nodeTag(clause)==T_Expr && ((Expr*)clause)->opType == NOT_EXPR); + return + (clause != NULL && + nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == NOT_EXPR); } -/* +/* * make_notclause-- - * + * * Create a 'not' clause given the expression to be negated. - * + * */ -Expr * -make_notclause(Expr *notclause) +Expr * +make_notclause(Expr * notclause) { - Expr *expr = makeNode(Expr); + Expr *expr = makeNode(Expr); - expr->typeOid = InvalidOid; /* assume type checking done */ - expr->opType = NOT_EXPR; - expr->oper = NULL; - expr->args = lcons(notclause, NIL); - return expr; + expr->typeOid = InvalidOid; /* assume type checking done */ + expr->opType = NOT_EXPR; + expr->oper = NULL; + expr->args = lcons(notclause, NIL); + return expr; } -/* +/* * get_notclausearg-- - * + * * Retrieve the clause within a 'not' clause - * + * */ -Expr * -get_notclausearg(Expr *notclause) +Expr * +get_notclausearg(Expr * notclause) { - return(lfirst(notclause->args)); + return (lfirst(notclause->args)); } /***************************************************************************** - * AND clause functions + * AND clause functions *****************************************************************************/ -/* +/* * and_clause-- - * + * * Returns t iff its argument is an 'and' clause: (AND { expr }). - * + * */ bool -and_clause(Node *clause) +and_clause(Node * clause) { - return - (clause!=NULL && - nodeTag(clause)==T_Expr && ((Expr*)clause)->opType == AND_EXPR); + return + (clause != NULL && + nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == AND_EXPR); } -/* + +/* * make_andclause-- - * + * * Create an 'and' clause given its arguments in a list. - * + * */ -Expr * -make_andclause(List *andclauses) +Expr * +make_andclause(List * andclauses) { - Expr *expr = makeNode(Expr); + Expr *expr = makeNode(Expr); - expr->typeOid = InvalidOid; /* assume type checking done */ - expr->opType = AND_EXPR; - expr->oper = NULL; - expr->args = andclauses; - return expr; + expr->typeOid = InvalidOid; /* assume type checking done */ + expr->opType = AND_EXPR; + expr->oper = NULL; + expr->args = andclauses; + return expr; } /***************************************************************************** - * * - * * - * * + * * + * * + * * *****************************************************************************/ -/* +/* * pull-constant-clauses-- - * Scans through a list of qualifications and find those that - * contain no variables. - * + * Scans through a list of qualifications and find those that + * contain no variables. + * * Returns a list of the constant clauses in constantQual and the remaining * quals as the return value. - * + * */ -List * -pull_constant_clauses(List *quals, List **constantQual) +List * +pull_constant_clauses(List * quals, List ** constantQual) { - List *q; - List *constqual=NIL; - List *restqual=NIL; - - foreach(q, quals) { - if (!contain_var_clause(lfirst(q))) { - constqual = lcons(lfirst(q), constqual); - }else { - restqual = lcons(lfirst(q), restqual); + List *q; + List *constqual = NIL; + List *restqual = NIL; + + foreach(q, quals) + { + if (!contain_var_clause(lfirst(q))) + { + constqual = lcons(lfirst(q), constqual); + } + else + { + restqual = lcons(lfirst(q), restqual); + } } - } - freeList(quals); - *constantQual = constqual; - return restqual; + freeList(quals); + *constantQual = constqual; + return restqual; } -/* +/* * clause-relids-vars-- - * Retrieves relids and vars appearing within a clause. - * Returns ((relid1 relid2 ... relidn) (var1 var2 ... varm)) where - * vars appear in the clause this is done by recursively searching - * through the left and right operands of a clause. - * + * Retrieves relids and vars appearing within a clause. + * Returns ((relid1 relid2 ... relidn) (var1 var2 ... varm)) where + * vars appear in the clause this is done by recursively searching + * through the left and right operands of a clause. + * * Returns the list of relids and vars. - * + * * XXX take the nreverse's out later - * + * */ void -clause_relids_vars(Node *clause, List **relids, List **vars) +clause_relids_vars(Node * clause, List ** relids, List ** vars) { - List *clvars = pull_var_clause(clause); - List *var_list = NIL; - List *varno_list = NIL; - List *i = NIL; + List *clvars = pull_var_clause(clause); + List *var_list = NIL; + List *varno_list = NIL; + List *i = NIL; - foreach (i, clvars) { - Var *var = (Var *)lfirst(i); - List *vi; - - if (!intMember(var->varno, varno_list)) { - varno_list = lappendi(varno_list, var->varno); - } - foreach (vi, var_list) + foreach(i, clvars) { - Var *in_list = (Var *)lfirst(vi); - - if ( in_list->varno == var->varno && - in_list->varattno == var->varattno ) - break; + Var *var = (Var *) lfirst(i); + List *vi; + + if (!intMember(var->varno, varno_list)) + { + varno_list = lappendi(varno_list, var->varno); + } + foreach(vi, var_list) + { + Var *in_list = (Var *) lfirst(vi); + + if (in_list->varno == var->varno && + in_list->varattno == var->varattno) + break; + } + if (vi == NIL) + var_list = lappend(var_list, var); } - if ( vi == NIL ) - var_list = lappend(var_list, var); - } - *relids = varno_list; - *vars = var_list; - return; + *relids = varno_list; + *vars = var_list; + return; } -/* +/* * NumRelids-- - * (formerly clause-relids) - * + * (formerly clause-relids) + * * Returns the number of different relations referenced in 'clause'. */ int -NumRelids(Node *clause) +NumRelids(Node * clause) { - List *vars = pull_var_clause(clause); - List *i = NIL; - List *var_list = NIL; + List *vars = pull_var_clause(clause); + List *i = NIL; + List *var_list = NIL; - foreach (i, vars) { - Var *var = (Var *)lfirst(i); + foreach(i, vars) + { + Var *var = (Var *) lfirst(i); - if (!intMember(var->varno, var_list)) { - var_list = lconsi(var->varno, var_list); + if (!intMember(var->varno, var_list)) + { + var_list = lconsi(var->varno, var_list); + } } - } - return(length(var_list)); + return (length(var_list)); } -/* +/* * contains-not-- * * Returns t iff the clause is a 'not' clause or if any of the * subclauses within an 'or' clause contain 'not's. - * + * */ bool -contains_not(Node *clause) +contains_not(Node * clause) { - if (single_node(clause)) - return (false); - - if (not_clause(clause)) - return (true); + if (single_node(clause)) + return (false); - if (or_clause(clause)) { - List *a; - foreach(a, ((Expr*)clause)->args) { - if (contains_not(lfirst(a))) + if (not_clause(clause)) return (true); + + if (or_clause(clause)) + { + List *a; + + foreach(a, ((Expr *) clause)->args) + { + if (contains_not(lfirst(a))) + return (true); + } } - } - - return(false); + + return (false); } -/* +/* * join-clause-p-- - * + * * Returns t iff 'clause' is a valid join clause. - * + * */ bool -join_clause_p(Node *clause) +join_clause_p(Node * clause) { - Node *leftop, *rightop; + Node *leftop, + *rightop; - if (!is_opclause(clause)) - return false; + if (!is_opclause(clause)) + return false; - leftop = (Node*)get_leftop((Expr*)clause); - rightop = (Node*)get_rightop((Expr*)clause); + leftop = (Node *) get_leftop((Expr *) clause); + rightop = (Node *) get_rightop((Expr *) clause); - /* - * One side of the clause (i.e. left or right operands) - * must either be a var node ... - */ - if (IsA(leftop,Var) || IsA(rightop,Var)) - return true; + /* + * One side of the clause (i.e. left or right operands) must either be + * a var node ... + */ + if (IsA(leftop, Var) || IsA(rightop, Var)) + return true; - /* - * ... or a func node. - */ - if (is_funcclause(leftop) || is_funcclause(rightop)) - return(true); + /* + * ... or a func node. + */ + if (is_funcclause(leftop) || is_funcclause(rightop)) + return (true); - return(false); + return (false); } -/* +/* * qual-clause-p-- - * + * * Returns t iff 'clause' is a valid qualification clause. - * + * */ bool -qual_clause_p(Node *clause) +qual_clause_p(Node * clause) { - if (!is_opclause(clause)) - return false; + if (!is_opclause(clause)) + return false; - if (IsA (get_leftop((Expr*)clause),Var) && - IsA (get_rightop((Expr*)clause),Const)) + if (IsA(get_leftop((Expr *) clause), Var) && + IsA(get_rightop((Expr *) clause), Const)) { - return(true); + return (true); } - else if (IsA (get_rightop((Expr*)clause),Var) && - IsA (get_leftop((Expr*)clause),Const)) + else if (IsA(get_rightop((Expr *) clause), Var) && + IsA(get_leftop((Expr *) clause), Const)) { - return(true); + return (true); } - return(false); + return (false); } -/* +/* * fix-opid-- - * Calculate the opfid from the opno... - * + * Calculate the opfid from the opno... + * * Returns nothing. - * + * */ void -fix_opid(Node *clause) +fix_opid(Node * clause) { - if (clause==NULL || single_node(clause)) { - ; - } - else if (or_clause (clause)) { - fix_opids(((Expr*)clause)->args); - } - else if (is_funcclause (clause)) { - fix_opids(((Expr*)clause)->args); - } - else if (IsA(clause,ArrayRef)) { - ArrayRef *aref = (ArrayRef *)clause; - - fix_opids(aref->refupperindexpr); - fix_opids(aref->reflowerindexpr); - fix_opid(aref->refexpr); - fix_opid(aref->refassgnexpr); - } - else if (not_clause(clause)) { - fix_opid((Node*)get_notclausearg((Expr*)clause)); - } - else if (is_opclause (clause)) { - replace_opid((Oper*)((Expr*)clause)->oper); - fix_opid((Node*)get_leftop((Expr*)clause)); - fix_opid((Node*)get_rightop((Expr*)clause)); - } - else if (agg_clause (clause)) { - fix_opid (((Aggreg*)clause)->target); - } + if (clause == NULL || single_node(clause)) + { + ; + } + else if (or_clause(clause)) + { + fix_opids(((Expr *) clause)->args); + } + else if (is_funcclause(clause)) + { + fix_opids(((Expr *) clause)->args); + } + else if (IsA(clause, ArrayRef)) + { + ArrayRef *aref = (ArrayRef *) clause; + + fix_opids(aref->refupperindexpr); + fix_opids(aref->reflowerindexpr); + fix_opid(aref->refexpr); + fix_opid(aref->refassgnexpr); + } + else if (not_clause(clause)) + { + fix_opid((Node *) get_notclausearg((Expr *) clause)); + } + else if (is_opclause(clause)) + { + replace_opid((Oper *) ((Expr *) clause)->oper); + fix_opid((Node *) get_leftop((Expr *) clause)); + fix_opid((Node *) get_rightop((Expr *) clause)); + } + else if (agg_clause(clause)) + { + fix_opid(((Aggreg *) clause)->target); + } } -/* +/* * fix-opids-- - * Calculate the opfid from the opno for all the clauses... - * + * Calculate the opfid from the opno for all the clauses... + * * Returns its argument. - * + * */ -List * -fix_opids(List *clauses) +List * +fix_opids(List * clauses) { - List *clause; + List *clause; - foreach(clause, clauses) - fix_opid(lfirst(clause)); + foreach(clause, clauses) + fix_opid(lfirst(clause)); - return(clauses); + return (clauses); } -/* +/* * get_relattval-- - * For a non-join clause, returns a list consisting of the - * relid, - * attno, - * value of the CONST node (if any), and a - * flag indicating whether the value appears on the left or right - * of the operator and whether the value varied. + * For a non-join clause, returns a list consisting of the + * relid, + * attno, + * value of the CONST node (if any), and a + * flag indicating whether the value appears on the left or right + * of the operator and whether the value varied. * * OLD OBSOLETE COMMENT FOLLOWS: - * If 'clause' is not of the format (op var node) or (op node var), - * or if the var refers to a nested attribute, then -1's are returned for - * everything but the value a blank string "" (pointer to \0) is - * returned for the value if it is unknown or null. + * If 'clause' is not of the format (op var node) or (op node var), + * or if the var refers to a nested attribute, then -1's are returned for + * everything but the value a blank string "" (pointer to \0) is + * returned for the value if it is unknown or null. * END OF OLD OBSOLETE COMMENT. * NEW COMMENT: * when defining rules one of the attibutes of the operator can @@ -569,198 +592,223 @@ fix_opids(List *clauses) * this routine used to return "" as value, which made 'compute_selec' * to bomb (because it was expecting a lisp integer and got back a lisp * string). Now the code returns a plain old good "lispInteger(0)". - * + * */ void -get_relattval(Node *clause, - int *relid, - AttrNumber *attno, - Datum *constval, - int *flag) +get_relattval(Node * clause, + int *relid, + AttrNumber * attno, + Datum * constval, + int *flag) { - Var *left = get_leftop((Expr*)clause); - Var *right = get_rightop((Expr*)clause); - - if(is_opclause(clause) && IsA(left,Var) && - IsA(right,Const)) { - - if(right!=NULL) { - - *relid = left->varno; - *attno = left->varattno; - *constval = ((Const *)right)->constvalue; - *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_); - - } else { - - *relid = left->varno; - *attno = left->varattno; - *constval = 0; - *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_NOT_CONSTANT_); - - } + Var *left = get_leftop((Expr *) clause); + Var *right = get_rightop((Expr *) clause); + + if (is_opclause(clause) && IsA(left, Var) && + IsA(right, Const)) + { + + if (right != NULL) + { + + *relid = left->varno; + *attno = left->varattno; + *constval = ((Const *) right)->constvalue; + *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_); + + } + else + { + + *relid = left->varno; + *attno = left->varattno; + *constval = 0; + *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_NOT_CONSTANT_); + + } #ifdef INDEXSCAN_PATCH - } else if (is_opclause(clause) && IsA(left,Var) && IsA(right,Param)) { - /* Function parameter used as index scan arg. DZ - 27-8-1996 */ - *relid = left->varno; - *attno = left->varattno; - *constval = 0; - *flag = (_SELEC_NOT_CONSTANT_); + } + else if (is_opclause(clause) && IsA(left, Var) && IsA(right, Param)) + { + /* Function parameter used as index scan arg. DZ - 27-8-1996 */ + *relid = left->varno; + *attno = left->varattno; + *constval = 0; + *flag = (_SELEC_NOT_CONSTANT_); #endif - }else if (is_opclause(clause) && - is_funcclause((Node*)left) && - IsA(right,Const)) { - List *args = ((Expr*)left)->args; + } + else if (is_opclause(clause) && + is_funcclause((Node *) left) && + IsA(right, Const)) + { + List *args = ((Expr *) left)->args; + + + *relid = ((Var *) lfirst(args))->varno; + *attno = InvalidAttrNumber; + *constval = ((Const *) right)->constvalue; + *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_); + + /* + * XXX both of these func clause handling if's seem wrong to me. + * they assume that the first argument is the Var. It could not + * handle (for example) f(1, emp.name). I think I may have been + * assuming no constants in functional index scans when I + * implemented this originally (still currently true). -mer 10 Aug + * 1992 + */ + } + else if (is_opclause(clause) && + is_funcclause((Node *) right) && + IsA(left, Const)) + { + List *args = ((Expr *) right)->args; + *relid = ((Var *) lfirst(args))->varno; + *attno = InvalidAttrNumber; + *constval = ((Const *) left)->constvalue; + *flag = (_SELEC_IS_CONSTANT_); - *relid = ((Var*)lfirst(args))->varno; - *attno = InvalidAttrNumber; - *constval = ((Const*)right)->constvalue; - *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_); - - /* - * XXX both of these func clause handling if's seem wrong to me. - * they assume that the first argument is the Var. It could - * not handle (for example) f(1, emp.name). I think I may have - * been assuming no constants in functional index scans when I - * implemented this originally (still currently true). - * -mer 10 Aug 1992 - */ - } else if (is_opclause(clause) && - is_funcclause((Node*)right) && - IsA(left,Const)) { - List *args = ((Expr*)right)->args; - - *relid = ((Var*)lfirst(args))->varno; - *attno = InvalidAttrNumber; - *constval = ((Const*)left)->constvalue; - *flag = ( _SELEC_IS_CONSTANT_); - - } else if (is_opclause (clause) && IsA (right,Var) && - IsA (left,Const)) { - if (left!=NULL) { - - *relid = right->varno; - *attno = right->varattno; - *constval = ((Const*)left)->constvalue; - *flag = (_SELEC_IS_CONSTANT_); - } else { - - *relid = right->varno; - *attno = right->varattno; - *constval = 0; - *flag = (_SELEC_NOT_CONSTANT_); - } + } + else if (is_opclause(clause) && IsA(right, Var) && + IsA(left, Const)) + { + if (left != NULL) + { + + *relid = right->varno; + *attno = right->varattno; + *constval = ((Const *) left)->constvalue; + *flag = (_SELEC_IS_CONSTANT_); + } + else + { + + *relid = right->varno; + *attno = right->varattno; + *constval = 0; + *flag = (_SELEC_NOT_CONSTANT_); + } #ifdef INDEXSCAN_PATCH - } else if (is_opclause(clause) && IsA(right,Var) && IsA(left,Param)) { - /* ...And here... - vadim 01/22/97 */ - *relid = right->varno; - *attno = right->varattno; - *constval = 0; - *flag = (_SELEC_NOT_CONSTANT_); + } + else if (is_opclause(clause) && IsA(right, Var) && IsA(left, Param)) + { + /* ...And here... - vadim 01/22/97 */ + *relid = right->varno; + *attno = right->varattno; + *constval = 0; + *flag = (_SELEC_NOT_CONSTANT_); #endif - } else { - /* One or more of the operands are expressions - * (e.g., oper clauses) - */ - *relid = _SELEC_VALUE_UNKNOWN_; - *attno = _SELEC_VALUE_UNKNOWN_; - *constval = 0; - *flag = (_SELEC_NOT_CONSTANT_); - } + } + else + { + + /* + * One or more of the operands are expressions (e.g., oper + * clauses) + */ + *relid = _SELEC_VALUE_UNKNOWN_; + *attno = _SELEC_VALUE_UNKNOWN_; + *constval = 0; + *flag = (_SELEC_NOT_CONSTANT_); + } } -/* +/* * get_relsatts-- - * - * Returns a list - * ( relid1 attno1 relid2 attno2 ) - * for a joinclause. - * + * + * Returns a list + * ( relid1 attno1 relid2 attno2 ) + * for a joinclause. + * * If the clause is not of the form (op var var) or if any of the vars * refer to nested attributes, then -1's are returned. - * + * */ void -get_rels_atts(Node *clause, - int *relid1, - AttrNumber *attno1, - int *relid2, - AttrNumber *attno2) +get_rels_atts(Node * clause, + int *relid1, + AttrNumber * attno1, + int *relid2, + AttrNumber * attno2) { - Var *left = get_leftop((Expr*)clause); - Var *right = get_rightop((Expr*)clause); - bool var_left = (IsA(left,Var)); - bool var_right = (IsA(right,Var)); - bool varexpr_left = (bool)((IsA(left,Func) || IsA (left,Oper)) && - contain_var_clause((Node*)left)); - bool varexpr_right = (bool)(( IsA(right,Func) || IsA (right,Oper)) && - contain_var_clause((Node*)right)); - - if (is_opclause(clause)) { - if(var_left && var_right) { - - *relid1 = left->varno; - *attno1 = left->varoattno; - *relid2 = right->varno; - *attno2 = right->varoattno; - return; - } else if (var_left && varexpr_right ) { - - *relid1 = left->varno; - *attno1 = left->varoattno; - *relid2 = _SELEC_VALUE_UNKNOWN_; - *attno2 = _SELEC_VALUE_UNKNOWN_; - return; - } else if (varexpr_left && var_right) { - - *relid1 = _SELEC_VALUE_UNKNOWN_; - *attno1 = _SELEC_VALUE_UNKNOWN_; - *relid2 = right->varno; - *attno2 = right->varoattno; - return; + Var *left = get_leftop((Expr *) clause); + Var *right = get_rightop((Expr *) clause); + bool var_left = (IsA(left, Var)); + bool var_right = (IsA(right, Var)); + bool varexpr_left = (bool) ((IsA(left, Func) || IsA(left, Oper)) && + contain_var_clause((Node *) left)); + bool varexpr_right = (bool) ((IsA(right, Func) || IsA(right, Oper)) && + contain_var_clause((Node *) right)); + + if (is_opclause(clause)) + { + if (var_left && var_right) + { + + *relid1 = left->varno; + *attno1 = left->varoattno; + *relid2 = right->varno; + *attno2 = right->varoattno; + return; + } + else if (var_left && varexpr_right) + { + + *relid1 = left->varno; + *attno1 = left->varoattno; + *relid2 = _SELEC_VALUE_UNKNOWN_; + *attno2 = _SELEC_VALUE_UNKNOWN_; + return; + } + else if (varexpr_left && var_right) + { + + *relid1 = _SELEC_VALUE_UNKNOWN_; + *attno1 = _SELEC_VALUE_UNKNOWN_; + *relid2 = right->varno; + *attno2 = right->varoattno; + return; + } } - } - *relid1 = _SELEC_VALUE_UNKNOWN_; - *attno1 = _SELEC_VALUE_UNKNOWN_; - *relid2 = _SELEC_VALUE_UNKNOWN_; - *attno2 = _SELEC_VALUE_UNKNOWN_; - return; + *relid1 = _SELEC_VALUE_UNKNOWN_; + *attno1 = _SELEC_VALUE_UNKNOWN_; + *relid2 = _SELEC_VALUE_UNKNOWN_; + *attno2 = _SELEC_VALUE_UNKNOWN_; + return; } void -CommuteClause(Node *clause) +CommuteClause(Node * clause) { - Node *temp; - Oper *commu; - OperatorTupleForm commuTup; - HeapTuple heapTup; + Node *temp; + Oper *commu; + OperatorTupleForm commuTup; + HeapTuple heapTup; - if (!is_opclause(clause)) - return; + if (!is_opclause(clause)) + return; - heapTup = (HeapTuple) - get_operator_tuple(get_commutator(((Oper*)((Expr*)clause)->oper)->opno)); + heapTup = (HeapTuple) + get_operator_tuple(get_commutator(((Oper *) ((Expr *) clause)->oper)->opno)); - if (heapTup == (HeapTuple)NULL) - return; + if (heapTup == (HeapTuple) NULL) + return; - commuTup = (OperatorTupleForm)GETSTRUCT(heapTup); - - commu = makeOper(heapTup->t_oid, - InvalidOid, - commuTup->oprresult, - ((Oper*)((Expr*)clause)->oper)->opsize, - NULL); - - /* - * reform the clause -> (operator func/var constant) - */ - ((Expr*)clause)->oper = (Node*)commu; - temp = lfirst(((Expr*)clause)->args); - lfirst(((Expr*)clause)->args) = lsecond(((Expr*)clause)->args); - lsecond(((Expr*)clause)->args) = temp; -} + commuTup = (OperatorTupleForm) GETSTRUCT(heapTup); + commu = makeOper(heapTup->t_oid, + InvalidOid, + commuTup->oprresult, + ((Oper *) ((Expr *) clause)->oper)->opsize, + NULL); + /* + * reform the clause -> (operator func/var constant) + */ + ((Expr *) clause)->oper = (Node *) commu; + temp = lfirst(((Expr *) clause)->args); + lfirst(((Expr *) clause)->args) = lsecond(((Expr *) clause)->args); + lsecond(((Expr *) clause)->args) = temp; +} diff --git a/src/backend/optimizer/util/indexnode.c b/src/backend/optimizer/util/indexnode.c index 8e9237e6845..e6a1902f8b9 100644 --- a/src/backend/optimizer/util/indexnode.c +++ b/src/backend/optimizer/util/indexnode.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * indexnode.c-- - * Routines to find all indices on a relation + * Routines to find all indices on a relation * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/indexnode.c,v 1.2 1996/10/31 10:59:37 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/indexnode.c,v 1.3 1997/09/07 04:44:22 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -21,74 +21,77 @@ #include "optimizer/internal.h" #include "optimizer/plancat.h" -#include "optimizer/pathnode.h" /* where the decls go */ +#include "optimizer/pathnode.h" /* where the decls go */ -static List *find_secondary_index(Query *root, Oid relid); +static List *find_secondary_index(Query * root, Oid relid); -/* +/* * find-relation-indices-- - * Returns a list of index nodes containing appropriate information for - * each (secondary) index defined on a relation. - * + * Returns a list of index nodes containing appropriate information for + * each (secondary) index defined on a relation. + * */ -List * -find_relation_indices(Query *root, Rel *rel) +List * +find_relation_indices(Query * root, Rel * rel) { - if (rel->indexed) { - return (find_secondary_index(root, lfirsti(rel->relids))); - } else { - return (NIL); - } + if (rel->indexed) + { + return (find_secondary_index(root, lfirsti(rel->relids))); + } + else + { + return (NIL); + } } -/* +/* * find-secondary-index-- - * Creates a list of index path nodes containing information for each - * secondary index defined on a relation by searching through the index - * catalog. - * + * Creates a list of index path nodes containing information for each + * secondary index defined on a relation by searching through the index + * catalog. + * * 'relid' is the OID of the relation for which indices are being located - * + * * Returns a list of new index nodes. - * + * */ -static List * -find_secondary_index(Query *root, Oid relid) +static List * +find_secondary_index(Query * root, Oid relid) { - IdxInfoRetval indexinfo; - List *indexes = NIL; - bool first = TRUE; + IdxInfoRetval indexinfo; + List *indexes = NIL; + bool first = TRUE; - while (index_info(root, first, relid,&indexinfo)) { - Rel *indexnode = makeNode(Rel); + while (index_info(root, first, relid, &indexinfo)) + { + Rel *indexnode = makeNode(Rel); - indexnode->relids = lconsi(indexinfo.relid,NIL); - indexnode->relam = indexinfo.relam; - indexnode->pages = indexinfo.pages; - indexnode->tuples = indexinfo.tuples; - indexnode->indexkeys = indexinfo.indexkeys; - indexnode->ordering = indexinfo.orderOprs; - indexnode->classlist = indexinfo.classlist; - indexnode->indproc= indexinfo.indproc; - indexnode->indpred = (List*)indexinfo.indpred; - - indexnode->indexed= false; /* not indexed itself */ - indexnode->size = 0; - indexnode->width= 0; - indexnode->targetlist= NIL; - indexnode->pathlist= NIL; - indexnode->unorderedpath= NULL; - indexnode->cheapestpath= NULL; - indexnode->pruneable= true; - indexnode->clauseinfo= NIL; - indexnode->joininfo= NIL; - indexnode->innerjoin= NIL; + indexnode->relids = lconsi(indexinfo.relid, NIL); + indexnode->relam = indexinfo.relam; + indexnode->pages = indexinfo.pages; + indexnode->tuples = indexinfo.tuples; + indexnode->indexkeys = indexinfo.indexkeys; + indexnode->ordering = indexinfo.orderOprs; + indexnode->classlist = indexinfo.classlist; + indexnode->indproc = indexinfo.indproc; + indexnode->indpred = (List *) indexinfo.indpred; - indexes = lcons(indexnode, indexes); - first = FALSE; - } + indexnode->indexed = false; /* not indexed itself */ + indexnode->size = 0; + indexnode->width = 0; + indexnode->targetlist = NIL; + indexnode->pathlist = NIL; + indexnode->unorderedpath = NULL; + indexnode->cheapestpath = NULL; + indexnode->pruneable = true; + indexnode->clauseinfo = NIL; + indexnode->joininfo = NIL; + indexnode->innerjoin = NIL; - return indexes; -} + indexes = lcons(indexnode, indexes); + first = FALSE; + } + return indexes; +} diff --git a/src/backend/optimizer/util/internal.c b/src/backend/optimizer/util/internal.c index 8b2dfd43bcb..d1af2062fce 100644 --- a/src/backend/optimizer/util/internal.c +++ b/src/backend/optimizer/util/internal.c @@ -1,24 +1,24 @@ /*------------------------------------------------------------------------- * * internal.c-- - * Definitions required throughout the query optimizer. + * Definitions required throughout the query optimizer. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/internal.c,v 1.3 1997/08/20 14:53:37 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/internal.c,v 1.4 1997/09/07 04:44:24 momjian Exp $ * *------------------------------------------------------------------------- */ -/* - * ---------- SHARED MACROS - * - * Macros common to modules for creating, accessing, and modifying - * query tree and query plan components. - * Shared with the executor. - * +/* + * ---------- SHARED MACROS + * + * Macros common to modules for creating, accessing, and modifying + * query tree and query plan components. + * Shared with the executor. + * */ #include <sys/types.h> @@ -31,32 +31,30 @@ #include "nodes/primnodes.h" #include "utils/palloc.h" -#ifdef NOT_USED +#ifdef NOT_USED /***************************************************************************** * *****************************************************************************/ /* the following should probably be moved elsewhere -ay */ -TargetEntry * -MakeTLE(Resdom *resdom, Node *expr) +TargetEntry * +MakeTLE(Resdom * resdom, Node * expr) { - TargetEntry *rt = makeNode(TargetEntry); - rt->resdom = resdom; - rt->expr = expr; - return rt; + TargetEntry *rt = makeNode(TargetEntry); + + rt->resdom = resdom; + rt->expr = expr; + return rt; } -Var * -get_expr(TargetEntry *tle) +Var * +get_expr(TargetEntry * tle) { - Assert(tle!=NULL); - Assert(tle->expr!=NULL); + Assert(tle != NULL); + Assert(tle->expr != NULL); - return ((Var *)tle->expr); + return ((Var *) tle->expr); } -#endif /* 0 */ - - - +#endif /* 0 */ diff --git a/src/backend/optimizer/util/joininfo.c b/src/backend/optimizer/util/joininfo.c index a4fd6913752..cf206d80094 100644 --- a/src/backend/optimizer/util/joininfo.c +++ b/src/backend/optimizer/util/joininfo.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * joininfo.c-- - * JoinInfo node manipulation routines + * JoinInfo node manipulation routines * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/joininfo.c,v 1.2 1996/11/10 03:01:00 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/joininfo.c,v 1.3 1997/09/07 04:44:27 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -21,88 +21,96 @@ #include "optimizer/clauses.h" -/* +/* * joininfo-member-- - * Determines whether a node has already been created for a join - * between a set of join relations and the relation described by - * 'joininfo-list'. - * + * Determines whether a node has already been created for a join + * between a set of join relations and the relation described by + * 'joininfo-list'. + * * 'join-relids' is a list of relids corresponding to the join relation - * 'joininfo-list' is the list of joininfo nodes against which this is - * checked - * + * 'joininfo-list' is the list of joininfo nodes against which this is + * checked + * * Returns the corresponding node in 'joininfo-list' if such a node * exists. - * + * */ -JInfo * -joininfo_member(List *join_relids, List *joininfo_list) +JInfo * +joininfo_member(List * join_relids, List * joininfo_list) { - List *i = NIL; - List *other_rels = NIL; + List *i = NIL; + List *other_rels = NIL; - foreach(i,joininfo_list) { - other_rels = lfirst(i); - if(same(join_relids, ((JInfo*)other_rels)->otherrels)) - return((JInfo*)other_rels); - } - return((JInfo*)NULL); + foreach(i, joininfo_list) + { + other_rels = lfirst(i); + if (same(join_relids, ((JInfo *) other_rels)->otherrels)) + return ((JInfo *) other_rels); + } + return ((JInfo *) NULL); } -/* +/* * find-joininfo-node-- - * Find the joininfo node within a relation entry corresponding - * to a join between 'this_rel' and the relations in 'join-relids'. A - * new node is created and added to the relation entry's joininfo - * field if the desired one can't be found. - * + * Find the joininfo node within a relation entry corresponding + * to a join between 'this_rel' and the relations in 'join-relids'. A + * new node is created and added to the relation entry's joininfo + * field if the desired one can't be found. + * * Returns a joininfo node. - * + * */ -JInfo * -find_joininfo_node(Rel *this_rel, List *join_relids) +JInfo * +find_joininfo_node(Rel * this_rel, List * join_relids) { - JInfo *joininfo = joininfo_member(join_relids, - this_rel->joininfo); - if( joininfo == NULL ) { - joininfo = makeNode(JInfo); - joininfo->otherrels = join_relids; - joininfo->jinfoclauseinfo = NIL; - joininfo->mergesortable = false; - joininfo->hashjoinable = false; - joininfo->inactive = false; - this_rel->joininfo = lcons(joininfo, this_rel->joininfo); - } - return(joininfo); + JInfo *joininfo = joininfo_member(join_relids, + this_rel->joininfo); + + if (joininfo == NULL) + { + joininfo = makeNode(JInfo); + joininfo->otherrels = join_relids; + joininfo->jinfoclauseinfo = NIL; + joininfo->mergesortable = false; + joininfo->hashjoinable = false; + joininfo->inactive = false; + this_rel->joininfo = lcons(joininfo, this_rel->joininfo); + } + return (joininfo); } -/* +/* * other-join-clause-var-- - * Determines whether a var node is contained within a joinclause - * of the form(op var var). - * + * Determines whether a var node is contained within a joinclause + * of the form(op var var). + * * Returns the other var node in the joinclause if it is, nil if not. - * + * */ -Var * -other_join_clause_var(Var *var, Expr *clause) +Var * +other_join_clause_var(Var * var, Expr * clause) { - Var *retval; - Var *l, *r; + Var *retval; + Var *l, + *r; - retval = (Var*) NULL; + retval = (Var *) NULL; - if( var != NULL && join_clause_p((Node*)clause)) { - l = (Var *) get_leftop(clause); - r = (Var *) get_rightop(clause); + if (var != NULL && join_clause_p((Node *) clause)) + { + l = (Var *) get_leftop(clause); + r = (Var *) get_rightop(clause); - if(var_equal(var, l)) { - retval = r; - } else if(var_equal(var, r)) { - retval = l; - } - } + if (var_equal(var, l)) + { + retval = r; + } + else if (var_equal(var, r)) + { + retval = l; + } + } - return(retval); + return (retval); } diff --git a/src/backend/optimizer/util/keys.c b/src/backend/optimizer/util/keys.c index 4296deb7e98..0c3a3569eb5 100644 --- a/src/backend/optimizer/util/keys.c +++ b/src/backend/optimizer/util/keys.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * keys.c-- - * Key manipulation routines + * Key manipulation routines * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/keys.c,v 1.2 1997/08/19 21:32:03 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/keys.c,v 1.3 1997/09/07 04:44:28 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -22,173 +22,180 @@ #include "optimizer/tlist.h" -static Expr *matching2_tlvar(int var, List *tlist, bool (*test)()); -static bool equal_indexkey_var(int index_key, Var *var); +static Expr *matching2_tlvar(int var, List * tlist, bool(*test) ()); +static bool equal_indexkey_var(int index_key, Var * var); -/* +/* * 1. index key - * one of: - * attnum - * (attnum arrayindex) + * one of: + * attnum + * (attnum arrayindex) * 2. path key - * (subkey1 ... subkeyN) - * where subkeyI is a var node - * note that the 'Keys field is a list of these + * (subkey1 ... subkeyN) + * where subkeyI is a var node + * note that the 'Keys field is a list of these * 3. join key - * (outer-subkey inner-subkey) - * where each subkey is a var node + * (outer-subkey inner-subkey) + * where each subkey is a var node * 4. sort key - * one of: - * SortKey node - * number - * nil - * (may also refer to the 'SortKey field of a SortKey node, - * which looks exactly like an index key) - * + * one of: + * SortKey node + * number + * nil + * (may also refer to the 'SortKey field of a SortKey node, + * which looks exactly like an index key) + * */ -/* +/* * match-indexkey-operand-- - * Returns t iff an index key 'index-key' matches the given clause - * operand. - * + * Returns t iff an index key 'index-key' matches the given clause + * operand. + * */ bool -match_indexkey_operand(int indexkey, Var *operand, Rel *rel) +match_indexkey_operand(int indexkey, Var * operand, Rel * rel) { - if (IsA (operand,Var) && - (lfirsti(rel->relids) == operand->varno) && - equal_indexkey_var(indexkey,operand)) - return(true); - else - return(false); + if (IsA(operand, Var) && + (lfirsti(rel->relids) == operand->varno) && + equal_indexkey_var(indexkey, operand)) + return (true); + else + return (false); } -/* +/* * equal_indexkey_var-- - * Returns t iff an index key 'index-key' matches the corresponding - * fields of var node 'var'. - * + * Returns t iff an index key 'index-key' matches the corresponding + * fields of var node 'var'. + * */ -static bool -equal_indexkey_var(int index_key, Var *var) +static bool +equal_indexkey_var(int index_key, Var * var) { - if (index_key == var->varattno) - return(true); - else - return(false); + if (index_key == var->varattno) + return (true); + else + return (false); } -/* +/* * extract-subkey-- - * Returns the subkey in a join key corresponding to the outer or inner - * lelation. - * + * Returns the subkey in a join key corresponding to the outer or inner + * lelation. + * */ -Var * -extract_subkey(JoinKey *jk, int which_subkey) +Var * +extract_subkey(JoinKey * jk, int which_subkey) { - Var *retval; - - switch (which_subkey) { - case OUTER: - retval = jk->outer; - break; - case INNER: - retval = jk->inner; - break; - default: /* do nothing */ - elog(DEBUG,"extract_subkey with neither INNER or OUTER"); - retval = NULL; - } - return(retval); + Var *retval; + + switch (which_subkey) + { + case OUTER: + retval = jk->outer; + break; + case INNER: + retval = jk->inner; + break; + default: /* do nothing */ + elog(DEBUG, "extract_subkey with neither INNER or OUTER"); + retval = NULL; + } + return (retval); } -/* +/* * samekeys-- - * Returns t iff two sets of path keys are equivalent. They are - * equivalent if the first subkey (var node) within each sublist of - * list 'keys1' is contained within the corresponding sublist of 'keys2'. - * - * XXX It isn't necessary to check that each sublist exactly contain - * the same elements because if the routine that built these - * sublists together is correct, having one element in common - * implies having all elements in common. - * + * Returns t iff two sets of path keys are equivalent. They are + * equivalent if the first subkey (var node) within each sublist of + * list 'keys1' is contained within the corresponding sublist of 'keys2'. + * + * XXX It isn't necessary to check that each sublist exactly contain + * the same elements because if the routine that built these + * sublists together is correct, having one element in common + * implies having all elements in common. + * */ bool -samekeys(List *keys1, List *keys2) +samekeys(List * keys1, List * keys2) { - bool allmember = true; - List *key1, *key2; - - for(key1=keys1,key2=keys2 ; key1 != NIL && key2 !=NIL ; - key1=lnext(key1), key2=lnext(key2)) - if (!member(lfirst(key1), lfirst(key2))) - allmember = false; - - if ( (length (keys2) >= length (keys1)) && allmember) - return(true); - else - return(false); + bool allmember = true; + List *key1, + *key2; + + for (key1 = keys1, key2 = keys2; key1 != NIL && key2 != NIL; + key1 = lnext(key1), key2 = lnext(key2)) + if (!member(lfirst(key1), lfirst(key2))) + allmember = false; + + if ((length(keys2) >= length(keys1)) && allmember) + return (true); + else + return (false); } -/* +/* * collect-index-pathkeys-- - * Creates a list of subkeys by retrieving var nodes corresponding to - * each index key in 'index-keys' from the relation's target list - * 'tlist'. If the key is not in the target list, the key is irrelevant - * and is thrown away. The returned subkey list is of the form: - * ((var1) (var2) ... (varn)) - * + * Creates a list of subkeys by retrieving var nodes corresponding to + * each index key in 'index-keys' from the relation's target list + * 'tlist'. If the key is not in the target list, the key is irrelevant + * and is thrown away. The returned subkey list is of the form: + * ((var1) (var2) ... (varn)) + * * 'index-keys' is a list of index keys * 'tlist' is a relation target list - * + * * Returns the list of cons'd subkeys. - * + * */ /* This function is identical to matching_tlvar and tlistentry_member. * They should be merged. */ -static Expr * -matching2_tlvar(int var, List *tlist, bool (*test)()) +static Expr * +matching2_tlvar(int var, List * tlist, bool(*test) ()) { - TargetEntry *tlentry = NULL; - - if (var) { - List *temp; - foreach (temp,tlist) { - if ((*test)(var, get_expr(lfirst(temp)))) { - tlentry = lfirst(temp); - break; - } + TargetEntry *tlentry = NULL; + + if (var) + { + List *temp; + + foreach(temp, tlist) + { + if ((*test) (var, get_expr(lfirst(temp)))) + { + tlentry = lfirst(temp); + break; + } + } } - } - if (tlentry) - return((Expr*)get_expr(tlentry)); - else - return((Expr*)NULL); + if (tlentry) + return ((Expr *) get_expr(tlentry)); + else + return ((Expr *) NULL); } -List * -collect_index_pathkeys(int *index_keys, List *tlist) +List * +collect_index_pathkeys(int *index_keys, List * tlist) { - List *retval = NIL; - - Assert (index_keys != NULL); - - while(index_keys[0] != 0) { - Expr *mvar; - mvar = matching2_tlvar(index_keys[0], - tlist, - equal_indexkey_var); - if (mvar) - retval = nconc(retval,lcons(lcons(mvar,NIL), - NIL)); - index_keys++; - } - return(retval); -} + List *retval = NIL; + + Assert(index_keys != NULL); + + while (index_keys[0] != 0) + { + Expr *mvar; + mvar = matching2_tlvar(index_keys[0], + tlist, + equal_indexkey_var); + if (mvar) + retval = nconc(retval, lcons(lcons(mvar, NIL), + NIL)); + index_keys++; + } + return (retval); +} diff --git a/src/backend/optimizer/util/ordering.c b/src/backend/optimizer/util/ordering.c index 40699e81e0b..504d48bdce5 100644 --- a/src/backend/optimizer/util/ordering.c +++ b/src/backend/optimizer/util/ordering.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * ordering.c-- - * Routines to manipulate and compare merge and path orderings + * Routines to manipulate and compare merge and path orderings * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/ordering.c,v 1.3 1997/08/19 21:32:06 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/ordering.c,v 1.4 1997/09/07 04:44:30 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -18,81 +18,88 @@ #include "optimizer/internal.h" #include "optimizer/ordering.h" -static bool equal_sortops_order(Oid *ordering1, Oid *ordering2); +static bool equal_sortops_order(Oid * ordering1, Oid * ordering2); -/* +/* * equal-path-path-ordering-- - * Returns t iff two path orderings are equal. - * + * Returns t iff two path orderings are equal. + * */ bool -equal_path_path_ordering(PathOrder *path_ordering1, - PathOrder *path_ordering2) +equal_path_path_ordering(PathOrder * path_ordering1, + PathOrder * path_ordering2) { - if (path_ordering1 == path_ordering2) - return true; - - if (!path_ordering1 || !path_ordering2) - return false; - - if (path_ordering1->ordtype == MERGE_ORDER && - path_ordering2->ordtype == MERGE_ORDER) { - - return equal(path_ordering1->ord.merge, path_ordering2->ord.merge); - - } else if (path_ordering1->ordtype == SORTOP_ORDER && - path_ordering2->ordtype == SORTOP_ORDER) { - - return - (equal_sortops_order(path_ordering1->ord.sortop, - path_ordering2->ord.sortop)); - } else if (path_ordering1->ordtype == MERGE_ORDER && - path_ordering2->ordtype == SORTOP_ORDER) { - - return (path_ordering2->ord.sortop && - (path_ordering1->ord.merge->left_operator == - path_ordering2->ord.sortop[0])); - } else { - - return (path_ordering1->ord.sortop && - (path_ordering1->ord.sortop[0] == - path_ordering2->ord.merge->left_operator)); - } + if (path_ordering1 == path_ordering2) + return true; + + if (!path_ordering1 || !path_ordering2) + return false; + + if (path_ordering1->ordtype == MERGE_ORDER && + path_ordering2->ordtype == MERGE_ORDER) + { + + return equal(path_ordering1->ord.merge, path_ordering2->ord.merge); + + } + else if (path_ordering1->ordtype == SORTOP_ORDER && + path_ordering2->ordtype == SORTOP_ORDER) + { + + return + (equal_sortops_order(path_ordering1->ord.sortop, + path_ordering2->ord.sortop)); + } + else if (path_ordering1->ordtype == MERGE_ORDER && + path_ordering2->ordtype == SORTOP_ORDER) + { + + return (path_ordering2->ord.sortop && + (path_ordering1->ord.merge->left_operator == + path_ordering2->ord.sortop[0])); + } + else + { + + return (path_ordering1->ord.sortop && + (path_ordering1->ord.sortop[0] == + path_ordering2->ord.merge->left_operator)); + } } -/* +/* * equal-path-merge-ordering-- - * Returns t iff a path ordering is usable for ordering a merge join. + * Returns t iff a path ordering is usable for ordering a merge join. * * XXX Presently, this means that the first sortop of the path matches - * either of the merge sortops. Is there a "right" and "wrong" - * sortop to match? - * + * either of the merge sortops. Is there a "right" and "wrong" + * sortop to match? + * */ bool -equal_path_merge_ordering(Oid *path_ordering, - MergeOrder *merge_ordering) +equal_path_merge_ordering(Oid * path_ordering, + MergeOrder * merge_ordering) { - if (path_ordering == NULL || merge_ordering == NULL) - return(false); - - if (path_ordering[0] == merge_ordering->left_operator || - path_ordering[0] == merge_ordering->right_operator) - return(true); - else - return(false); + if (path_ordering == NULL || merge_ordering == NULL) + return (false); + + if (path_ordering[0] == merge_ordering->left_operator || + path_ordering[0] == merge_ordering->right_operator) + return (true); + else + return (false); } -/* +/* * equal-merge-merge-ordering-- - * Returns t iff two merge orderings are equal. - * + * Returns t iff two merge orderings are equal. + * */ bool -equal_merge_merge_ordering(MergeOrder *merge_ordering1, - MergeOrder *merge_ordering2) +equal_merge_merge_ordering(MergeOrder * merge_ordering1, + MergeOrder * merge_ordering2) { - return (equal(merge_ordering1, merge_ordering2)); + return (equal(merge_ordering1, merge_ordering2)); } /***************************************************************************** @@ -101,21 +108,22 @@ equal_merge_merge_ordering(MergeOrder *merge_ordering1, /* * equal_sort_ops_order - - * Returns true iff the sort operators are in the same order. + * Returns true iff the sort operators are in the same order. */ -static bool -equal_sortops_order(Oid *ordering1, Oid *ordering2) +static bool +equal_sortops_order(Oid * ordering1, Oid * ordering2) { - int i = 0; - - if (ordering1 == NULL || ordering2 == NULL) - return (ordering1==ordering2); - - while (ordering1[i]!=0 && ordering2[i]!=0) { - if (ordering1[i] != ordering2[i]) - break; - i++; - } - - return (ordering1[i]==0 && ordering2[i]==0); + int i = 0; + + if (ordering1 == NULL || ordering2 == NULL) + return (ordering1 == ordering2); + + while (ordering1[i] != 0 && ordering2[i] != 0) + { + if (ordering1[i] != ordering2[i]) + break; + i++; + } + + return (ordering1[i] == 0 && ordering2[i] == 0); } diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index d79788b0e6e..6b37d2f36d4 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * pathnode.c-- - * Routines to manipulate pathlists and create path nodes + * Routines to manipulate pathlists and create path nodes * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.3 1997/09/05 18:10:36 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.4 1997/09/07 04:44:30 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -27,418 +27,459 @@ #include "optimizer/xfunc.h" #include "optimizer/ordering.h" -#include "parser/parsetree.h" /* for getrelid() */ +#include "parser/parsetree.h" /* for getrelid() */ -static Path *better_path(Path *new_path, List *unique_paths, bool *noOther); +static Path *better_path(Path * new_path, List * unique_paths, bool * noOther); /***************************************************************************** - * MISC. PATH UTILITIES + * MISC. PATH UTILITIES *****************************************************************************/ -/* +/* * path-is-cheaper-- - * Returns t iff 'path1' is cheaper than 'path2'. - * + * Returns t iff 'path1' is cheaper than 'path2'. + * */ bool -path_is_cheaper(Path *path1, Path *path2) +path_is_cheaper(Path * path1, Path * path2) { - Cost cost1 = path1->path_cost; - Cost cost2 = path2->path_cost; + Cost cost1 = path1->path_cost; + Cost cost2 = path2->path_cost; - return((bool)(cost1 < cost2)); + return ((bool) (cost1 < cost2)); } -/* +/* * set_cheapest-- - * Finds the minimum cost path from among a relation's paths. - * + * 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 + * + * Returns and sets the relation entry field with the pathnode that * is minimum. - * + * */ -Path * -set_cheapest(Rel *parent_rel, List *pathlist) +Path * +set_cheapest(Rel * parent_rel, List * pathlist) { - List *p; - Path *cheapest_so_far; + List *p; + Path *cheapest_so_far; - Assert(pathlist!=NIL); - Assert(IsA(parent_rel,Rel)); + Assert(pathlist != NIL); + Assert(IsA(parent_rel, Rel)); - cheapest_so_far = (Path*)lfirst(pathlist); + cheapest_so_far = (Path *) lfirst(pathlist); - foreach (p, lnext(pathlist)) { - Path *path = (Path*)lfirst(p); + foreach(p, lnext(pathlist)) + { + Path *path = (Path *) lfirst(p); - if (path_is_cheaper(path, cheapest_so_far)) { - cheapest_so_far = path; + if (path_is_cheaper(path, cheapest_so_far)) + { + cheapest_so_far = path; + } } - } - parent_rel->cheapestpath = cheapest_so_far; + parent_rel->cheapestpath = cheapest_so_far; - return(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. - * + * 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(Rel *parent_rel, List *unique_paths, List *new_paths) +List * +add_pathlist(Rel * parent_rel, List * unique_paths, List * new_paths) { - List *x; - Path *new_path; - Path *old_path; - bool noOther; - - foreach (x, new_paths) { - new_path = (Path*)lfirst(x); - if (member(new_path, unique_paths)) - continue; - old_path = better_path(new_path,unique_paths,&noOther); - - if (noOther) { - /* 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)); + List *x; + Path *new_path; + Path *old_path; + bool noOther; + + foreach(x, new_paths) + { + new_path = (Path *) lfirst(x); + if (member(new_path, unique_paths)) + continue; + old_path = better_path(new_path, unique_paths, &noOther); + + if (noOther) + { + /* 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); + 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. - * + * 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 - * + * 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 *noOther) +static Path * +better_path(Path * new_path, List * unique_paths, bool * noOther) { - Path *old_path = (Path*)NULL; - Path *path = (Path*)NULL; - List *temp = NIL; - Path *retval = NULL; - - /* XXX - added the following two lines which weren't int - * the lisp planner, but otherwise, doesn't seem to work - * for the case where new_path is 'nil - */ - foreach (temp,unique_paths) { - path = (Path*) lfirst(temp); - - if ((equal_path_path_ordering(&new_path->p_ordering, - &path->p_ordering) && - samekeys(new_path->keys, path->keys))) { - old_path = path; - break; + Path *old_path = (Path *) NULL; + Path *path = (Path *) NULL; + List *temp = NIL; + Path *retval = NULL; + + /* + * XXX - added the following two lines which weren't int the lisp + * planner, but otherwise, doesn't seem to work for the case where + * new_path is 'nil + */ + foreach(temp, unique_paths) + { + path = (Path *) lfirst(temp); + + if ((equal_path_path_ordering(&new_path->p_ordering, + &path->p_ordering) && + samekeys(new_path->keys, path->keys))) + { + old_path = path; + break; + } } - } - - if (old_path==NULL) { - *noOther = true; - } else { - *noOther = false; - if (path_is_cheaper(new_path,old_path)) { - retval = old_path; + + if (old_path == NULL) + { + *noOther = true; + } + else + { + *noOther = false; + if (path_is_cheaper(new_path, old_path)) + { + retval = old_path; + } } - } - - return(retval); + + return (retval); } /***************************************************************************** - * PATH NODE CREATION ROUTINES + * PATH NODE CREATION ROUTINES *****************************************************************************/ -/* +/* * create_seqscan_path-- - * Creates a path corresponding to a sequential scan, returning the - * pathnode. - * + * Creates a path corresponding to a sequential scan, returning the + * pathnode. + * */ -Path * -create_seqscan_path(Rel *rel) +Path * +create_seqscan_path(Rel * rel) { - int relid=0; - - Path *pathnode = makeNode(Path); - - pathnode->pathtype = T_SeqScan; - pathnode->parent = rel; - pathnode->path_cost = 0.0; - pathnode->p_ordering.ordtype = SORTOP_ORDER; - pathnode->p_ordering.ord.sortop = NULL; - pathnode->keys = NIL; - /* copy clauseinfo list into path for expensive function processing - * -- JMH, 7/7/92 - */ - pathnode->locclauseinfo= - (List*)copyObject((Node*)rel->clauseinfo); - - 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 */ + int relid = 0; + + Path *pathnode = makeNode(Path); + + pathnode->pathtype = T_SeqScan; + pathnode->parent = rel; + pathnode->path_cost = 0.0; + pathnode->p_ordering.ordtype = SORTOP_ORDER; + pathnode->p_ordering.ord.sortop = NULL; + pathnode->keys = NIL; + + /* + * copy clauseinfo list into path for expensive function processing -- + * JMH, 7/7/92 + */ + pathnode->locclauseinfo = + (List *) copyObject((Node *) rel->clauseinfo); + + 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 */ #if 0 - if (XfuncMode != XFUNC_OFF) { - pathnode->path_cost += - xfunc_get_path_cost(pathnode); - } + if (XfuncMode != XFUNC_OFF) + { + pathnode->path_cost += + xfunc_get_path_cost(pathnode); + } #endif - return (pathnode); + return (pathnode); } -/* +/* * create_index_path-- - * Creates a single path node for an index scan. - * + * 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. - * + * considered because of its sort order. + * * Returns the new path node. - * + * */ -IndexPath * -create_index_path(Query *root, - Rel *rel, - Rel *index, - List *restriction_clauses, - bool is_join_scan) +IndexPath * +create_index_path(Query * root, + Rel * rel, + Rel * index, + List * restriction_clauses, + bool is_join_scan) { - IndexPath *pathnode = makeNode(IndexPath); - - pathnode->path.pathtype = T_IndexScan; - pathnode->path.parent = rel; - pathnode->path.p_ordering.ordtype = SORTOP_ORDER; - pathnode->path.p_ordering.ord.sortop = index->ordering; - - pathnode->indexid = index->relids; - pathnode->indexkeys = index->indexkeys; - pathnode->indexqual = NIL; - - /* copy clauseinfo list into path for expensive function processing - * -- JMH, 7/7/92 - */ - pathnode->path.locclauseinfo = - set_difference((List*) copyObject((Node*)rel->clauseinfo), - (List*) restriction_clauses); - - /* - * The index must have an ordering for the path to have (ordering) keys, - * and vice versa. - */ - if (pathnode->path.p_ordering.ord.sortop) { - pathnode->path.keys = collect_index_pathkeys(index->indexkeys, - rel->targetlist); + IndexPath *pathnode = makeNode(IndexPath); + + pathnode->path.pathtype = T_IndexScan; + pathnode->path.parent = rel; + pathnode->path.p_ordering.ordtype = SORTOP_ORDER; + pathnode->path.p_ordering.ord.sortop = index->ordering; + + pathnode->indexid = index->relids; + pathnode->indexkeys = index->indexkeys; + pathnode->indexqual = NIL; + /* - * Check that the keys haven't 'disappeared', since they may - * no longer be in the target list (i.e., index keys that are not - * relevant to the scan are not applied to the scan path node, - * so if no index keys were found, we can't order the path). + * copy clauseinfo list into path for expensive function processing -- + * JMH, 7/7/92 */ - if (pathnode->path.keys==NULL) { - pathnode->path.p_ordering.ord.sortop = NULL; - } - } else { - pathnode->path.keys = NULL; - } + pathnode->path.locclauseinfo = + set_difference((List *) copyObject((Node *) rel->clauseinfo), + (List *) restriction_clauses); - if (is_join_scan || restriction_clauses==NULL) { /* - * Indices used for joins or sorting result nodes don't - * restrict the result at all, they simply order it, - * so compute the scan cost - * accordingly -- use a selectivity of 1.0. + * The index must have an ordering for the path to have (ordering) + * keys, and vice versa. */ -/* is the statement above really true? what about IndexScan as the + if (pathnode->path.p_ordering.ord.sortop) + { + pathnode->path.keys = collect_index_pathkeys(index->indexkeys, + rel->targetlist); + + /* + * Check that the keys haven't 'disappeared', since they may no + * longer be in the target list (i.e., index keys that are not + * relevant to the scan are not applied to the scan path node, so + * if no index keys were found, we can't order the path). + */ + if (pathnode->path.keys == NULL) + { + pathnode->path.p_ordering.ord.sortop = NULL; + } + } + else + { + pathnode->path.keys = NULL; + } + + if (is_join_scan || restriction_clauses == NULL) + { + + /* + * Indices used for joins or sorting result nodes don't restrict + * the result at all, they simply order it, so compute the scan + * cost accordingly -- use a selectivity of 1.0. + */ +/* is the statement above really true? what about IndexScan as the inner of a join? */ - pathnode->path.path_cost = - cost_index (lfirsti(index->relids), - index->pages, - 1.0, - rel->pages, - rel->tuples, - index->pages, - index->tuples, - false); - /* add in expensive functions cost! -- JMH, 7/7/92 */ + pathnode->path.path_cost = + cost_index(lfirsti(index->relids), + index->pages, + 1.0, + rel->pages, + rel->tuples, + index->pages, + index->tuples, + false); + /* add in expensive functions cost! -- JMH, 7/7/92 */ #if 0 - if (XfuncMode != XFUNC_OFF) { - pathnode->path_cost = - (pathnode->path_cost + - xfunc_get_path_cost((Path*)pathnode)); - } + if (XfuncMode != XFUNC_OFF) + { + pathnode->path_cost = + (pathnode->path_cost + + xfunc_get_path_cost((Path *) pathnode)); + } #endif - } else { - /* - * Compute scan cost for the case when 'index' is used with a - * restriction clause. - */ - List *attnos; - List *values; - List *flags; - float npages; - float selec; - Cost clausesel; - - get_relattvals(restriction_clauses, - &attnos, - &values, - &flags); - index_selectivity(lfirsti(index->relids), - index->classlist, - get_opnos(restriction_clauses), - getrelid(lfirsti(rel->relids), - root->rtable), - attnos, - values, - flags, - length(restriction_clauses), - &npages, - &selec); - /* each clause gets an equal selectivity */ - clausesel = - pow(selec, - 1.0 / (double) length(restriction_clauses)); - - pathnode->indexqual = restriction_clauses; - pathnode->path.path_cost = - cost_index (lfirsti(index->relids), - (int)npages, - selec, - rel->pages, - rel->tuples, - index->pages, - index->tuples, - false); + } + else + { + + /* + * Compute scan cost for the case when 'index' is used with a + * restriction clause. + */ + List *attnos; + List *values; + List *flags; + float npages; + float selec; + Cost clausesel; + + get_relattvals(restriction_clauses, + &attnos, + &values, + &flags); + index_selectivity(lfirsti(index->relids), + index->classlist, + get_opnos(restriction_clauses), + getrelid(lfirsti(rel->relids), + root->rtable), + attnos, + values, + flags, + length(restriction_clauses), + &npages, + &selec); + /* each clause gets an equal selectivity */ + clausesel = + pow(selec, + 1.0 / (double) length(restriction_clauses)); + + pathnode->indexqual = restriction_clauses; + pathnode->path.path_cost = + cost_index(lfirsti(index->relids), + (int) npages, + selec, + rel->pages, + rel->tuples, + index->pages, + index->tuples, + false); #if 0 - /* add in expensive functions cost! -- JMH, 7/7/92 */ - if (XfuncMode != XFUNC_OFF) { - pathnode->path_cost += - xfunc_get_path_cost((Path*)pathnode); - } + /* add in expensive functions cost! -- JMH, 7/7/92 */ + if (XfuncMode != XFUNC_OFF) + { + pathnode->path_cost += + xfunc_get_path_cost((Path *) pathnode); + } #endif - /* Set selectivities of clauses used with index to the selectivity - * of this index, subdividing the selectivity equally over each of - * the clauses. - */ - /* XXX Can this divide the selectivities in a better way? */ - set_clause_selectivities(restriction_clauses, clausesel); - } - return(pathnode); + /* + * Set selectivities of clauses used with index to the selectivity + * of this index, subdividing the selectivity equally over each of + * the clauses. + */ + + /* XXX Can this divide the selectivities in a better way? */ + set_clause_selectivities(restriction_clauses, clausesel); + } + return (pathnode); } -/* +/* * create_nestloop_path-- - * Creates a pathnode corresponding to a nestloop join between two - * relations. - * + * Creates a pathnode corresponding to a nestloop join between two + * relations. + * * 'joinrel' is the join relation. * 'outer_rel' is the outer join relation * 'outer_path' is the outer join path. * 'inner_path' is the inner join path. * 'keys' are the keys of the path - * + * * Returns the resulting path node. - * + * */ -JoinPath * -create_nestloop_path(Rel *joinrel, - Rel *outer_rel, - Path *outer_path, - Path *inner_path, - List *keys) +JoinPath * +create_nestloop_path(Rel * joinrel, + Rel * outer_rel, + Path * outer_path, + Path * inner_path, + List * keys) { - JoinPath *pathnode = makeNode(JoinPath); - - pathnode->path.pathtype = T_NestLoop; - pathnode->path.parent = joinrel; - pathnode->outerjoinpath = outer_path; - pathnode->innerjoinpath = inner_path; - pathnode->pathclauseinfo = joinrel->clauseinfo; - pathnode->path.keys = keys; - pathnode->path.joinid = NIL; - pathnode->path.outerjoincost = (Cost)0.0; - pathnode->path.locclauseinfo = NIL; - - if (keys) { - pathnode->path.p_ordering.ordtype = - outer_path->p_ordering.ordtype; - if (outer_path->p_ordering.ordtype == SORTOP_ORDER) { - pathnode->path.p_ordering.ord.sortop = - outer_path->p_ordering.ord.sortop; - } else { - pathnode->path.p_ordering.ord.merge = - outer_path->p_ordering.ord.merge; + JoinPath *pathnode = makeNode(JoinPath); + + pathnode->path.pathtype = T_NestLoop; + pathnode->path.parent = joinrel; + pathnode->outerjoinpath = outer_path; + pathnode->innerjoinpath = inner_path; + pathnode->pathclauseinfo = joinrel->clauseinfo; + pathnode->path.keys = keys; + pathnode->path.joinid = NIL; + pathnode->path.outerjoincost = (Cost) 0.0; + pathnode->path.locclauseinfo = NIL; + + if (keys) + { + pathnode->path.p_ordering.ordtype = + outer_path->p_ordering.ordtype; + if (outer_path->p_ordering.ordtype == SORTOP_ORDER) + { + pathnode->path.p_ordering.ord.sortop = + outer_path->p_ordering.ord.sortop; + } + else + { + pathnode->path.p_ordering.ord.merge = + outer_path->p_ordering.ord.merge; + } } - } else { - pathnode->path.p_ordering.ordtype = SORTOP_ORDER; - pathnode->path.p_ordering.ord.sortop = NULL; - } - - pathnode->path.path_cost = - cost_nestloop(outer_path->path_cost, - inner_path->path_cost, - outer_rel->size, - inner_path->parent->size, - page_size(outer_rel->size, - outer_rel->width), - IsA(inner_path,IndexPath)); - /* add in expensive function costs -- JMH 7/7/92 */ + else + { + pathnode->path.p_ordering.ordtype = SORTOP_ORDER; + pathnode->path.p_ordering.ord.sortop = NULL; + } + + pathnode->path.path_cost = + cost_nestloop(outer_path->path_cost, + inner_path->path_cost, + outer_rel->size, + inner_path->parent->size, + page_size(outer_rel->size, + outer_rel->width), + IsA(inner_path, IndexPath)); + /* add in expensive function costs -- JMH 7/7/92 */ #if 0 - if (XfuncMode != XFUNC_OFF) { - pathnode->path_cost += xfunc_get_path_cost((Path*)pathnode); - } + if (XfuncMode != XFUNC_OFF) + { + pathnode->path_cost += xfunc_get_path_cost((Path *) pathnode); + } #endif - return(pathnode); + return (pathnode); } -/* +/* * create_mergesort_path-- - * Creates a pathnode corresponding to a mergesort join between - * two relations - * + * Creates a pathnode corresponding to a mergesort join between + * two relations + * * 'joinrel' is the join relation * 'outersize' is the number of tuples in the outer relation * 'innersize' is the number of tuples in the inner relation @@ -451,59 +492,60 @@ create_nestloop_path(Rel *joinrel, * 'mergeclauses' are the applicable join/restriction clauses * 'outersortkeys' are the sort varkeys for the outer relation * 'innersortkeys' are the sort varkeys for the inner relation - * + * */ -MergePath * -create_mergesort_path(Rel *joinrel, - int outersize, - int innersize, - int outerwidth, - int innerwidth, - Path *outer_path, - Path *inner_path, - List *keys, - MergeOrder *order, - List *mergeclauses, - List *outersortkeys, - List *innersortkeys) +MergePath * +create_mergesort_path(Rel * joinrel, + int outersize, + int innersize, + int outerwidth, + int innerwidth, + Path * outer_path, + Path * inner_path, + List * keys, + MergeOrder * order, + List * mergeclauses, + List * outersortkeys, + List * innersortkeys) { - MergePath *pathnode = makeNode(MergePath); - - pathnode->jpath.path.pathtype = T_MergeJoin; - pathnode->jpath.path.parent = joinrel; - pathnode->jpath.outerjoinpath = outer_path; - pathnode->jpath.innerjoinpath = inner_path; - pathnode->jpath.pathclauseinfo = joinrel->clauseinfo; - pathnode->jpath.path.keys = keys; - pathnode->jpath.path.p_ordering.ordtype = MERGE_ORDER; - pathnode->jpath.path.p_ordering.ord.merge = order; - pathnode->path_mergeclauses = mergeclauses; - pathnode->jpath.path.locclauseinfo = NIL; - pathnode->outersortkeys = outersortkeys; - pathnode->innersortkeys = innersortkeys; - pathnode->jpath.path.path_cost = - cost_mergesort(outer_path->path_cost, - inner_path->path_cost, - outersortkeys, - innersortkeys, - outersize, - innersize, - outerwidth, - innerwidth); - /* add in expensive function costs -- JMH 7/7/92 */ + MergePath *pathnode = makeNode(MergePath); + + pathnode->jpath.path.pathtype = T_MergeJoin; + pathnode->jpath.path.parent = joinrel; + pathnode->jpath.outerjoinpath = outer_path; + pathnode->jpath.innerjoinpath = inner_path; + pathnode->jpath.pathclauseinfo = joinrel->clauseinfo; + pathnode->jpath.path.keys = keys; + pathnode->jpath.path.p_ordering.ordtype = MERGE_ORDER; + pathnode->jpath.path.p_ordering.ord.merge = order; + pathnode->path_mergeclauses = mergeclauses; + pathnode->jpath.path.locclauseinfo = NIL; + pathnode->outersortkeys = outersortkeys; + pathnode->innersortkeys = innersortkeys; + pathnode->jpath.path.path_cost = + cost_mergesort(outer_path->path_cost, + inner_path->path_cost, + outersortkeys, + innersortkeys, + outersize, + innersize, + outerwidth, + innerwidth); + /* add in expensive function costs -- JMH 7/7/92 */ #if 0 - if (XfuncMode != XFUNC_OFF) { - pathnode->path_cost += - xfunc_get_path_cost((Path*)pathnode); - } + if (XfuncMode != XFUNC_OFF) + { + pathnode->path_cost += + xfunc_get_path_cost((Path *) pathnode); + } #endif - return(pathnode); + return (pathnode); } -/* - * create_hashjoin_path-- XXX HASH - * Creates a pathnode corresponding to a hash join between two relations. - * +/* + * create_hashjoin_path-- XXX HASH + * Creates a pathnode corresponding to a hash join between two relations. + * * 'joinrel' is the join relation * 'outersize' is the number of tuples in the outer relation * 'innersize' is the number of tuples in the inner relation @@ -516,52 +558,53 @@ create_mergesort_path(Rel *joinrel, * 'hashclauses' are the applicable join/restriction clauses * 'outerkeys' are the sort varkeys for the outer relation * 'innerkeys' are the sort varkeys for the inner relation - * + * */ -HashPath * -create_hashjoin_path(Rel *joinrel, - int outersize, - int innersize, - int outerwidth, - int innerwidth, - Path *outer_path, - Path *inner_path, - List *keys, - Oid operator, - List *hashclauses, - List *outerkeys, - List *innerkeys) +HashPath * +create_hashjoin_path(Rel * joinrel, + int outersize, + int innersize, + int outerwidth, + int innerwidth, + Path * outer_path, + Path * inner_path, + List * keys, + Oid operator, + List * hashclauses, + List * outerkeys, + List * innerkeys) { - HashPath *pathnode = makeNode(HashPath); - - pathnode->jpath.path.pathtype = T_HashJoin; - pathnode->jpath.path.parent = joinrel; - pathnode->jpath.outerjoinpath = outer_path; - pathnode->jpath.innerjoinpath = inner_path; - pathnode->jpath.pathclauseinfo = joinrel->clauseinfo; - pathnode->jpath.path.locclauseinfo = NIL; - pathnode->jpath.path.keys = keys; - pathnode->jpath.path.p_ordering.ordtype = SORTOP_ORDER; - pathnode->jpath.path.p_ordering.ord.sortop = NULL; - pathnode->jpath.path.outerjoincost = (Cost)0.0; - pathnode->jpath.path.joinid = (Relid)NULL; - /* pathnode->hashjoinoperator = operator; */ - pathnode->path_hashclauses = hashclauses; - pathnode->outerhashkeys = outerkeys; - pathnode->innerhashkeys = innerkeys; - pathnode->jpath.path.path_cost = - cost_hashjoin(outer_path->path_cost, - inner_path->path_cost, - outerkeys, - innerkeys, - outersize,innersize, - outerwidth,innerwidth); - /* add in expensive function costs -- JMH 7/7/92 */ + HashPath *pathnode = makeNode(HashPath); + + pathnode->jpath.path.pathtype = T_HashJoin; + pathnode->jpath.path.parent = joinrel; + pathnode->jpath.outerjoinpath = outer_path; + pathnode->jpath.innerjoinpath = inner_path; + pathnode->jpath.pathclauseinfo = joinrel->clauseinfo; + pathnode->jpath.path.locclauseinfo = NIL; + pathnode->jpath.path.keys = keys; + pathnode->jpath.path.p_ordering.ordtype = SORTOP_ORDER; + pathnode->jpath.path.p_ordering.ord.sortop = NULL; + pathnode->jpath.path.outerjoincost = (Cost) 0.0; + pathnode->jpath.path.joinid = (Relid) NULL; + /* pathnode->hashjoinoperator = operator; */ + pathnode->path_hashclauses = hashclauses; + pathnode->outerhashkeys = outerkeys; + pathnode->innerhashkeys = innerkeys; + pathnode->jpath.path.path_cost = + cost_hashjoin(outer_path->path_cost, + inner_path->path_cost, + outerkeys, + innerkeys, + outersize, innersize, + outerwidth, innerwidth); + /* add in expensive function costs -- JMH 7/7/92 */ #if 0 - if (XfuncMode != XFUNC_OFF) { - pathnode->path_cost += - xfunc_get_path_cost((Path*)pathnode); - } + if (XfuncMode != XFUNC_OFF) + { + pathnode->path_cost += + xfunc_get_path_cost((Path *) pathnode); + } #endif - return(pathnode); + return (pathnode); } diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index abe764aa4e0..0e88a72c4eb 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -1,14 +1,14 @@ /*------------------------------------------------------------------------- * * plancat.c-- - * routines for accessing the system catalogs + * routines for accessing the system catalogs * * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.6 1997/04/24 16:07:14 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.7 1997/09/07 04:44:31 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -26,7 +26,7 @@ #include "catalog/pg_inherits.h" #include "catalog/pg_version.h" -#include "parser/parsetree.h" /* for getrelid() */ +#include "parser/parsetree.h" /* for getrelid() */ #include "fmgr.h" #include "optimizer/internal.h" @@ -34,193 +34,203 @@ #include "utils/syscache.h" #ifndef HAVE_MEMMOVE -# include <regex/utils.h> +#include <regex/utils.h> #else -# include <string.h> +#include <string.h> #endif -static void IndexSelectivity(Oid indexrelid, Oid indrelid, int32 nIndexKeys, - Oid AccessMethodOperatorClasses[], Oid operatorObjectIds[], +static void +IndexSelectivity(Oid indexrelid, Oid indrelid, int32 nIndexKeys, + Oid AccessMethodOperatorClasses[], Oid operatorObjectIds[], int32 varAttributeNumbers[], char *constValues[], int32 constFlags[], - float *idxPages, float *idxSelec); + float *idxPages, float *idxSelec); /* * relation-info - - * Retrieves catalog information for a given relation. Given the oid of - * the relation, return the following information: - * whether the relation has secondary indices - * number of pages - * number of tuples + * Retrieves catalog information for a given relation. Given the oid of + * the relation, return the following information: + * whether the relation has secondary indices + * number of pages + * number of tuples */ void -relation_info(Query *root, Index relid, - bool *hasindex, int *pages, int *tuples) +relation_info(Query * root, Index relid, + bool * hasindex, int *pages, int *tuples) { - HeapTuple relationTuple; - Form_pg_class relation; - Oid relationObjectId; - - relationObjectId = getrelid(relid, root->rtable); - relationTuple = SearchSysCacheTuple(RELOID, - ObjectIdGetDatum(relationObjectId), - 0,0,0); - if (HeapTupleIsValid(relationTuple)) { - relation = (Form_pg_class)GETSTRUCT(relationTuple); - - *hasindex = (relation->relhasindex) ? TRUE : FALSE; - *pages = relation->relpages; - *tuples = relation->reltuples; - } else { - elog(WARN, "RelationCatalogInformation: Relation %d not found", - relationObjectId); - } - - return; + HeapTuple relationTuple; + Form_pg_class relation; + Oid relationObjectId; + + relationObjectId = getrelid(relid, root->rtable); + relationTuple = SearchSysCacheTuple(RELOID, + ObjectIdGetDatum(relationObjectId), + 0, 0, 0); + if (HeapTupleIsValid(relationTuple)) + { + relation = (Form_pg_class) GETSTRUCT(relationTuple); + + *hasindex = (relation->relhasindex) ? TRUE : FALSE; + *pages = relation->relpages; + *tuples = relation->reltuples; + } + else + { + elog(WARN, "RelationCatalogInformation: Relation %d not found", + relationObjectId); + } + + return; } -/* +/* * index-info-- - * Retrieves catalog information on an index on a given relation. - * - * The index relation is opened on the first invocation. The current - * retrieves the next index relation within the catalog that has not - * already been retrieved by a previous call. The index catalog - * is closed when no more indices for 'relid' can be found. - * - * 'first' is 1 if this is the first call - * + * Retrieves catalog information on an index on a given relation. + * + * The index relation is opened on the first invocation. The current + * retrieves the next index relation within the catalog that has not + * already been retrieved by a previous call. The index catalog + * is closed when no more indices for 'relid' can be found. + * + * 'first' is 1 if this is the first call + * * Returns true if successful and false otherwise. Index info is returned * via the transient data structure 'info'. - * + * */ bool -index_info(Query *root, bool first, int relid, IdxInfoRetval *info) +index_info(Query * root, bool first, int relid, IdxInfoRetval * info) { - register i; - HeapTuple indexTuple, amopTuple; - IndexTupleForm index; - Relation indexRelation; - uint16 amstrategy; - Oid relam; - Oid indrelid; - - static Relation relation = (Relation) NULL; - static HeapScanDesc scan = (HeapScanDesc) NULL; - static ScanKeyData indexKey; - - - /* find the oid of the indexed relation */ - indrelid = getrelid(relid, root->rtable); - - memset(info, 0, sizeof(IdxInfoRetval)); - - /* - * the maximum number of elements in each of the following arrays is - * 8. We allocate one more for a terminating 0 to indicate the end - * of the array. - */ - info->indexkeys = (int *)palloc(sizeof(int)*9); - memset(info->indexkeys, 0, sizeof(int)*9); - info->orderOprs = (Oid *)palloc(sizeof(Oid)*9); - memset(info->orderOprs, 0, sizeof(Oid)*9); - info->classlist = (Oid *)palloc(sizeof(Oid)*9); - memset(info->classlist, 0, sizeof(Oid)*9); - - /* Find an index on the given relation */ - if (first) { - if (RelationIsValid(relation)) - heap_close(relation); - if (HeapScanIsValid(scan)) - heap_endscan(scan); - - ScanKeyEntryInitialize(&indexKey, 0, - Anum_pg_index_indrelid, - F_OIDEQ, - ObjectIdGetDatum(indrelid)); - - relation = heap_openr(IndexRelationName); - scan = heap_beginscan(relation, 0, NowTimeQual, - 1, &indexKey); - } - if (!HeapScanIsValid(scan)) - elog(WARN, "index_info: scan not started"); - indexTuple = heap_getnext(scan, 0, (Buffer *) NULL); - if (!HeapTupleIsValid(indexTuple)) { - heap_endscan(scan); - heap_close(relation); - scan = (HeapScanDesc) NULL; - relation = (Relation) NULL; - return(0); - } - - /* Extract info from the index tuple */ - index = (IndexTupleForm)GETSTRUCT(indexTuple); - info->relid = index->indexrelid; /* index relation */ - for (i = 0; i < 8; i++) - info->indexkeys[i] = index->indkey[i]; - for (i = 0; i < 8; i++) - info->classlist[i] = index->indclass[i]; - - info->indproc = index->indproc; /* functional index ?? */ - - /* partial index ?? */ - if (VARSIZE(&index->indpred) != 0) { + register i; + HeapTuple indexTuple, + amopTuple; + IndexTupleForm index; + Relation indexRelation; + uint16 amstrategy; + Oid relam; + Oid indrelid; + + static Relation relation = (Relation) NULL; + static HeapScanDesc scan = (HeapScanDesc) NULL; + static ScanKeyData indexKey; + + + /* find the oid of the indexed relation */ + indrelid = getrelid(relid, root->rtable); + + memset(info, 0, sizeof(IdxInfoRetval)); + /* - * The memory allocated here for the predicate (in lispReadString) - * only needs to stay around until it's used in find_index_paths, - * which is all within a command, so the automatic pfree at end - * of transaction should be ok. + * the maximum number of elements in each of the following arrays is + * 8. We allocate one more for a terminating 0 to indicate the end of + * the array. */ - char *predString; + info->indexkeys = (int *) palloc(sizeof(int) * 9); + memset(info->indexkeys, 0, sizeof(int) * 9); + info->orderOprs = (Oid *) palloc(sizeof(Oid) * 9); + memset(info->orderOprs, 0, sizeof(Oid) * 9); + info->classlist = (Oid *) palloc(sizeof(Oid) * 9); + memset(info->classlist, 0, sizeof(Oid) * 9); + + /* Find an index on the given relation */ + if (first) + { + if (RelationIsValid(relation)) + heap_close(relation); + if (HeapScanIsValid(scan)) + heap_endscan(scan); + + ScanKeyEntryInitialize(&indexKey, 0, + Anum_pg_index_indrelid, + F_OIDEQ, + ObjectIdGetDatum(indrelid)); + + relation = heap_openr(IndexRelationName); + scan = heap_beginscan(relation, 0, NowTimeQual, + 1, &indexKey); + } + if (!HeapScanIsValid(scan)) + elog(WARN, "index_info: scan not started"); + indexTuple = heap_getnext(scan, 0, (Buffer *) NULL); + if (!HeapTupleIsValid(indexTuple)) + { + heap_endscan(scan); + heap_close(relation); + scan = (HeapScanDesc) NULL; + relation = (Relation) NULL; + return (0); + } + + /* Extract info from the index tuple */ + index = (IndexTupleForm) GETSTRUCT(indexTuple); + info->relid = index->indexrelid; /* index relation */ + for (i = 0; i < 8; i++) + info->indexkeys[i] = index->indkey[i]; + for (i = 0; i < 8; i++) + info->classlist[i] = index->indclass[i]; - predString = fmgr(F_TEXTOUT, &index->indpred); - info->indpred = (Node*)stringToNode(predString); - pfree(predString); - } + info->indproc = index->indproc; /* functional index ?? */ - /* Extract info from the relation descriptor for the index */ - indexRelation = index_open(index->indexrelid); + /* partial index ?? */ + if (VARSIZE(&index->indpred) != 0) + { + + /* + * The memory allocated here for the predicate (in lispReadString) + * only needs to stay around until it's used in find_index_paths, + * which is all within a command, so the automatic pfree at end of + * transaction should be ok. + */ + char *predString; + + predString = fmgr(F_TEXTOUT, &index->indpred); + info->indpred = (Node *) stringToNode(predString); + pfree(predString); + } + + /* Extract info from the relation descriptor for the index */ + indexRelation = index_open(index->indexrelid); #ifdef notdef - /* XXX should iterate through strategies -- but how? use #1 for now */ - amstrategy = indexRelation->rd_am->amstrategies; -#endif /* notdef */ - amstrategy = 1; - relam = indexRelation->rd_rel->relam; - info->relam = relam; - info->pages = indexRelation->rd_rel->relpages; - info->tuples = indexRelation->rd_rel->reltuples; - heap_close(indexRelation); - - /* - * Find the index ordering keys - * - * Must use indclass to know when to stop looking since with - * functional indices there could be several keys (args) for - * one opclass. -mer 27 Sept 1991 - */ - for (i = 0; i < 8 && index->indclass[i]; ++i) { - amopTuple = SearchSysCacheTuple(AMOPSTRATEGY, - ObjectIdGetDatum(relam), - ObjectIdGetDatum(index->indclass[i]), - UInt16GetDatum(amstrategy), - 0); - if (!HeapTupleIsValid(amopTuple)) - elog(WARN, "index_info: no amop %d %d %d", - relam, index->indclass[i], amstrategy); - info->orderOprs[i] = - ((Form_pg_amop)GETSTRUCT(amopTuple))->amopopr; - } - return(TRUE); + /* XXX should iterate through strategies -- but how? use #1 for now */ + amstrategy = indexRelation->rd_am->amstrategies; +#endif /* notdef */ + amstrategy = 1; + relam = indexRelation->rd_rel->relam; + info->relam = relam; + info->pages = indexRelation->rd_rel->relpages; + info->tuples = indexRelation->rd_rel->reltuples; + heap_close(indexRelation); + + /* + * Find the index ordering keys + * + * Must use indclass to know when to stop looking since with functional + * indices there could be several keys (args) for one opclass. -mer 27 + * Sept 1991 + */ + for (i = 0; i < 8 && index->indclass[i]; ++i) + { + amopTuple = SearchSysCacheTuple(AMOPSTRATEGY, + ObjectIdGetDatum(relam), + ObjectIdGetDatum(index->indclass[i]), + UInt16GetDatum(amstrategy), + 0); + if (!HeapTupleIsValid(amopTuple)) + elog(WARN, "index_info: no amop %d %d %d", + relam, index->indclass[i], amstrategy); + info->orderOprs[i] = + ((Form_pg_amop) GETSTRUCT(amopTuple))->amopopr; + } + return (TRUE); } -/* +/* * index-selectivity-- - * - * Call util/plancat.c:IndexSelectivity with the indicated arguments. - * + * + * Call util/plancat.c:IndexSelectivity with the indicated arguments. + * * 'indid' is the index OID * 'classes' is a list of index key classes * 'opnos' is a list of index key operator OIDs @@ -229,153 +239,162 @@ index_info(Query *root, bool first, int relid, IdxInfoRetval *info) * 'values' is a list of the values of the clause's constants * 'flags' is a list of fixnums which describe the constants * 'nkeys' is the number of index keys - * + * * Returns two floats: index pages and index selectivity in 'idxPages' and - * 'idxSelec'. - * + * 'idxSelec'. + * */ void index_selectivity(Oid indid, - Oid *classes, - List *opnos, - Oid relid, - List *attnos, - List *values, - List *flags, - int32 nkeys, - float *idxPages, - float *idxSelec) + Oid * classes, + List * opnos, + Oid relid, + List * attnos, + List * values, + List * flags, + int32 nkeys, + float *idxPages, + float *idxSelec) { - Oid *opno_array; - int *attno_array, *flag_array; - char **value_array; - int i = 0; - List *xopno, *xattno, *value, *flag; + Oid *opno_array; + int *attno_array, + *flag_array; + char **value_array; + int i = 0; + List *xopno, + *xattno, + *value, + *flag; + + if (length(opnos) != nkeys || length(attnos) != nkeys || + length(values) != nkeys || length(flags) != nkeys) + { + + *idxPages = 0.0; + *idxSelec = 1.0; + return; + } - if (length(opnos)!=nkeys || length(attnos)!=nkeys || - length(values)!=nkeys || length(flags)!=nkeys) { + opno_array = (Oid *) palloc(nkeys * sizeof(Oid)); + attno_array = (int *) palloc(nkeys * sizeof(int32)); + value_array = (char **) palloc(nkeys * sizeof(char *)); + flag_array = (int *) palloc(nkeys * sizeof(int32)); - *idxPages = 0.0; - *idxSelec = 1.0; + i = 0; + foreach(xopno, opnos) + { + opno_array[i++] = lfirsti(xopno); + } + + i = 0; + foreach(xattno, attnos) + { + attno_array[i++] = lfirsti(xattno); + } + + i = 0; + foreach(value, values) + { + value_array[i++] = (char *) lfirst(value); + } + + i = 0; + foreach(flag, flags) + { + flag_array[i++] = lfirsti(flag); + } + + IndexSelectivity(indid, + relid, + nkeys, + classes, /* not used */ + opno_array, + attno_array, + value_array, + flag_array, + idxPages, + idxSelec); return; - } - - opno_array = (Oid *)palloc(nkeys*sizeof(Oid)); - attno_array = (int *)palloc(nkeys*sizeof(int32)); - value_array = (char **)palloc(nkeys*sizeof(char *)); - flag_array = (int *)palloc(nkeys*sizeof(int32)); - - i = 0; - foreach(xopno, opnos) { - opno_array[i++] = lfirsti(xopno); - } - - i = 0; - foreach(xattno,attnos) { - attno_array[i++] = lfirsti(xattno); - } - - i = 0; - foreach(value, values) { - value_array[i++] = (char *)lfirst(value); - } - - i = 0; - foreach(flag,flags) { - flag_array[i++] = lfirsti(flag); - } - - IndexSelectivity(indid, - relid, - nkeys, - classes, /* not used */ - opno_array, - attno_array, - value_array, - flag_array, - idxPages, - idxSelec); - return; } /* * restriction_selectivity in lisp system.-- * - * NOTE: The routine is now merged with RestrictionClauseSelectivity - * as defined in plancat.c + * NOTE: The routine is now merged with RestrictionClauseSelectivity + * as defined in plancat.c * * Returns the selectivity of a specified operator. * This code executes registered procedures stored in the * operator relation, by calling the function manager. * * XXX The assumption in the selectivity procedures is that if the - * relation OIDs or attribute numbers are -1, then the clause - * isn't of the form (op var const). + * relation OIDs or attribute numbers are -1, then the clause + * isn't of the form (op var const). */ Cost restriction_selectivity(Oid functionObjectId, - Oid operatorObjectId, - Oid relationObjectId, - AttrNumber attributeNumber, - char *constValue, - int32 constFlag) + Oid operatorObjectId, + Oid relationObjectId, + AttrNumber attributeNumber, + char *constValue, + int32 constFlag) { - float64 result; - - result = (float64) fmgr(functionObjectId, - (char *) operatorObjectId, - (char *) relationObjectId, - (char *) (int)attributeNumber, - (char *) constValue, - (char *) constFlag, - NULL); - if (!PointerIsValid(result)) - elog(WARN, "RestrictionClauseSelectivity: bad pointer"); - - if (*result < 0.0 || *result > 1.0) - elog(WARN, "RestrictionClauseSelectivity: bad value %lf", - *result); - - return ((Cost)*result); + float64 result; + + result = (float64) fmgr(functionObjectId, + (char *) operatorObjectId, + (char *) relationObjectId, + (char *) (int) attributeNumber, + (char *) constValue, + (char *) constFlag, + NULL); + if (!PointerIsValid(result)) + elog(WARN, "RestrictionClauseSelectivity: bad pointer"); + + if (*result < 0.0 || *result > 1.0) + elog(WARN, "RestrictionClauseSelectivity: bad value %lf", + *result); + + return ((Cost) * result); } /* * join_selectivity-- - * Similarly, this routine is merged with JoinClauseSelectivity in - * plancat.c + * Similarly, this routine is merged with JoinClauseSelectivity in + * plancat.c * - * Returns the selectivity of an operator, given the join clause - * information. + * Returns the selectivity of an operator, given the join clause + * information. * * XXX The assumption in the selectivity procedures is that if the - * relation OIDs or attribute numbers are -1, then the clause - * isn't of the form (op var var). + * relation OIDs or attribute numbers are -1, then the clause + * isn't of the form (op var var). */ Cost -join_selectivity (Oid functionObjectId, - Oid operatorObjectId, - Oid relationObjectId1, - AttrNumber attributeNumber1, - Oid relationObjectId2, - AttrNumber attributeNumber2) +join_selectivity(Oid functionObjectId, + Oid operatorObjectId, + Oid relationObjectId1, + AttrNumber attributeNumber1, + Oid relationObjectId2, + AttrNumber attributeNumber2) { - float64 result; - - result = (float64) fmgr(functionObjectId, - (char *) operatorObjectId, - (char *) relationObjectId1, - (char *) (int)attributeNumber1, - (char *) relationObjectId2, - (char *) (int)attributeNumber2, - NULL); - if (!PointerIsValid(result)) - elog(WARN, "JoinClauseSelectivity: bad pointer"); - - if (*result < 0.0 || *result > 1.0) - elog(WARN, "JoinClauseSelectivity: bad value %lf", - *result); - - return((Cost)*result); + float64 result; + + result = (float64) fmgr(functionObjectId, + (char *) operatorObjectId, + (char *) relationObjectId1, + (char *) (int) attributeNumber1, + (char *) relationObjectId2, + (char *) (int) attributeNumber2, + NULL); + if (!PointerIsValid(result)) + elog(WARN, "JoinClauseSelectivity: bad pointer"); + + if (*result < 0.0 || *result > 1.0) + elog(WARN, "JoinClauseSelectivity: bad value %lf", + *result); + + return ((Cost) * result); } /* @@ -384,33 +403,34 @@ join_selectivity (Oid functionObjectId, * Returns a LISP list containing the OIDs of all relations which * inherits from the relation with OID 'inhparent'. */ -List * +List * find_inheritance_children(Oid inhparent) { - static ScanKeyData key[1] = { - { 0, Anum_pg_inherits_inhparent, F_OIDEQ } - }; - - HeapTuple inheritsTuple; - Relation relation; - HeapScanDesc scan; - List *list = NIL; - Oid inhrelid; - - fmgr_info(F_OIDEQ, &key[0].sk_func, &key[0].sk_nargs); - - key[0].sk_argument = ObjectIdGetDatum((Oid)inhparent); - relation = heap_openr(InheritsRelationName); - scan = heap_beginscan(relation, 0, NowTimeQual, 1, key); - while (HeapTupleIsValid(inheritsTuple = - heap_getnext(scan, 0, - (Buffer *) NULL))) { - inhrelid = ((InheritsTupleForm)GETSTRUCT(inheritsTuple))->inhrel; - list = lappendi(list, inhrelid); - } - heap_endscan(scan); - heap_close(relation); - return(list); + static ScanKeyData key[1] = { + {0, Anum_pg_inherits_inhparent, F_OIDEQ} + }; + + HeapTuple inheritsTuple; + Relation relation; + HeapScanDesc scan; + List *list = NIL; + Oid inhrelid; + + fmgr_info(F_OIDEQ, &key[0].sk_func, &key[0].sk_nargs); + + key[0].sk_argument = ObjectIdGetDatum((Oid) inhparent); + relation = heap_openr(InheritsRelationName); + scan = heap_beginscan(relation, 0, NowTimeQual, 1, key); + while (HeapTupleIsValid(inheritsTuple = + heap_getnext(scan, 0, + (Buffer *) NULL))) + { + inhrelid = ((InheritsTupleForm) GETSTRUCT(inheritsTuple))->inhrel; + list = lappendi(list, inhrelid); + } + heap_endscan(scan); + heap_close(relation); + return (list); } /* @@ -419,39 +439,40 @@ find_inheritance_children(Oid inhparent) * Returns a LISP list containing the OIDs of all relations which are * base relations of the relation with OID 'verrelid'. */ -List * +List * VersionGetParents(Oid verrelid) { - static ScanKeyData key[1] = { - { 0, Anum_pg_version_verrelid, F_OIDEQ } - }; - - HeapTuple versionTuple; - Relation relation; - HeapScanDesc scan; - Oid verbaseid; - List *list= NIL; - - fmgr_info(F_OIDEQ, &key[0].sk_func, &key[0].sk_nargs); - relation = heap_openr(VersionRelationName); - key[0].sk_argument = ObjectIdGetDatum(verrelid); - scan = heap_beginscan(relation, 0, NowTimeQual, 1, key); - for (;;) { - versionTuple = heap_getnext(scan, 0, - (Buffer *) NULL); - if (!HeapTupleIsValid(versionTuple)) - break; - verbaseid = ((VersionTupleForm) - GETSTRUCT(versionTuple))->verbaseid; - - list = lconsi(verbaseid, list); - - key[0].sk_argument = ObjectIdGetDatum(verbaseid); - heap_rescan(scan, 0, key); - } - heap_endscan(scan); - heap_close(relation); - return(list); + static ScanKeyData key[1] = { + {0, Anum_pg_version_verrelid, F_OIDEQ} + }; + + HeapTuple versionTuple; + Relation relation; + HeapScanDesc scan; + Oid verbaseid; + List *list = NIL; + + fmgr_info(F_OIDEQ, &key[0].sk_func, &key[0].sk_nargs); + relation = heap_openr(VersionRelationName); + key[0].sk_argument = ObjectIdGetDatum(verrelid); + scan = heap_beginscan(relation, 0, NowTimeQual, 1, key); + for (;;) + { + versionTuple = heap_getnext(scan, 0, + (Buffer *) NULL); + if (!HeapTupleIsValid(versionTuple)) + break; + verbaseid = ((VersionTupleForm) + GETSTRUCT(versionTuple))->verbaseid; + + list = lconsi(verbaseid, list); + + key[0].sk_argument = ObjectIdGetDatum(verbaseid); + heap_rescan(scan, 0, key); + } + heap_endscan(scan); + heap_close(relation); + return (list); } /***************************************************************************** @@ -461,14 +482,14 @@ VersionGetParents(Oid verrelid) /* * IdexSelectivity-- * - * Retrieves the 'amopnpages' and 'amopselect' parameters for each - * AM operator when a given index (specified by 'indexrelid') is used. - * These two parameters are returned by copying them to into an array of - * floats. + * Retrieves the 'amopnpages' and 'amopselect' parameters for each + * AM operator when a given index (specified by 'indexrelid') is used. + * These two parameters are returned by copying them to into an array of + * floats. * - * Assumption: the attribute numbers and operator ObjectIds are in order - * WRT to each other (otherwise, you have no way of knowing which - * AM operator class or attribute number corresponds to which operator. + * Assumption: the attribute numbers and operator ObjectIds are in order + * WRT to each other (otherwise, you have no way of knowing which + * AM operator class or attribute number corresponds to which operator. * * 'varAttributeNumbers' contains attribute numbers for variables * 'constValues' contains the constant values @@ -481,144 +502,154 @@ VersionGetParents(Oid verrelid) */ static void IndexSelectivity(Oid indexrelid, - Oid indrelid, - int32 nIndexKeys, - Oid AccessMethodOperatorClasses[], /* XXX not used? */ - Oid operatorObjectIds[], - int32 varAttributeNumbers[], - char *constValues[], - int32 constFlags[], - float *idxPages, - float *idxSelec) + Oid indrelid, + int32 nIndexKeys, + Oid AccessMethodOperatorClasses[], /* XXX not used? */ + Oid operatorObjectIds[], + int32 varAttributeNumbers[], + char *constValues[], + int32 constFlags[], + float *idxPages, + float *idxSelec) { - register i, n; - HeapTuple indexTuple, amopTuple, indRel; - IndexTupleForm index; - Form_pg_amop amop; - Oid indclass; - float64data npages, select; - float64 amopnpages, amopselect; - Oid relam; - bool nphack = false; - float64data fattr_select = 1.0; - - indRel = SearchSysCacheTuple(RELOID, - ObjectIdGetDatum(indexrelid), - 0,0,0); - if (!HeapTupleIsValid(indRel)) - elog(WARN, "IndexSelectivity: index %d not found", - indexrelid); - relam = ((Form_pg_class)GETSTRUCT(indRel))->relam; - - indexTuple = SearchSysCacheTuple(INDEXRELID, - ObjectIdGetDatum(indexrelid), - 0,0,0); - if (!HeapTupleIsValid(indexTuple)) - elog(WARN, "IndexSelectivity: index %d not found", - indexrelid); - index = (IndexTupleForm)GETSTRUCT(indexTuple); - - /* - * Hack for non-functional btree npages estimation: - * npages = index_pages * selectivity_of_1st_attr_clause(s) - * - vadim 04/24/97 - */ - if ( relam == BTREE_AM_OID && - varAttributeNumbers[0] != InvalidAttrNumber ) - nphack = true; - - npages = 0.0; - select = 1.0; - for (n = 0; n < nIndexKeys; ++n) { - /* - * Find the AM class for this key. - * - * If the first attribute number is invalid then we have a - * functional index, and AM class is the first one defined - * since functional indices have exactly one key. + register i, + n; + HeapTuple indexTuple, + amopTuple, + indRel; + IndexTupleForm index; + Form_pg_amop amop; + Oid indclass; + float64data npages, + select; + float64 amopnpages, + amopselect; + Oid relam; + bool nphack = false; + float64data fattr_select = 1.0; + + indRel = SearchSysCacheTuple(RELOID, + ObjectIdGetDatum(indexrelid), + 0, 0, 0); + if (!HeapTupleIsValid(indRel)) + elog(WARN, "IndexSelectivity: index %d not found", + indexrelid); + relam = ((Form_pg_class) GETSTRUCT(indRel))->relam; + + indexTuple = SearchSysCacheTuple(INDEXRELID, + ObjectIdGetDatum(indexrelid), + 0, 0, 0); + if (!HeapTupleIsValid(indexTuple)) + elog(WARN, "IndexSelectivity: index %d not found", + indexrelid); + index = (IndexTupleForm) GETSTRUCT(indexTuple); + + /* + * Hack for non-functional btree npages estimation: npages = + * index_pages * selectivity_of_1st_attr_clause(s) - vadim 04/24/97 */ - indclass = (varAttributeNumbers[0] == InvalidAttrNumber) ? - index->indclass[0] : InvalidOid; - i = 0; - while ((i < nIndexKeys) && (indclass == InvalidOid)) { - if (varAttributeNumbers[n] == index->indkey[i]) { - indclass = index->indclass[i]; - break; - } - i++; - } - if (!OidIsValid(indclass)) { - /* - * Presumably this means that we are using a functional - * index clause and so had no variable to match to - * the index key ... if not we are in trouble. - */ - elog(NOTICE, "IndexSelectivity: no key %d in index %d", - varAttributeNumbers[n], indexrelid); - continue; - } + if (relam == BTREE_AM_OID && + varAttributeNumbers[0] != InvalidAttrNumber) + nphack = true; - amopTuple = SearchSysCacheTuple(AMOPOPID, - ObjectIdGetDatum(indclass), - ObjectIdGetDatum(operatorObjectIds[n]), - ObjectIdGetDatum(relam), - 0); - if (!HeapTupleIsValid(amopTuple)) - elog(WARN, "IndexSelectivity: no amop %d %d", - indclass, operatorObjectIds[n]); - amop = (Form_pg_amop)GETSTRUCT(amopTuple); - - if ( !nphack ) + npages = 0.0; + select = 1.0; + for (n = 0; n < nIndexKeys; ++n) { - amopnpages = (float64) fmgr(amop->amopnpages, - (char *) operatorObjectIds[n], - (char *) indrelid, - (char *) varAttributeNumbers[n], - (char *) constValues[n], - (char *) constFlags[n], - (char *) nIndexKeys, - (char *) indexrelid); -#if 0 -/* + + /* + * Find the AM class for this key. + * + * If the first attribute number is invalid then we have a functional + * index, and AM class is the first one defined since functional + * indices have exactly one key. + */ + indclass = (varAttributeNumbers[0] == InvalidAttrNumber) ? + index->indclass[0] : InvalidOid; + i = 0; + while ((i < nIndexKeys) && (indclass == InvalidOid)) + { + if (varAttributeNumbers[n] == index->indkey[i]) + { + indclass = index->indclass[i]; + break; + } + i++; + } + if (!OidIsValid(indclass)) + { + + /* + * Presumably this means that we are using a functional index + * clause and so had no variable to match to the index key ... + * if not we are in trouble. + */ + elog(NOTICE, "IndexSelectivity: no key %d in index %d", + varAttributeNumbers[n], indexrelid); + continue; + } + + amopTuple = SearchSysCacheTuple(AMOPOPID, + ObjectIdGetDatum(indclass), + ObjectIdGetDatum(operatorObjectIds[n]), + ObjectIdGetDatum(relam), + 0); + if (!HeapTupleIsValid(amopTuple)) + elog(WARN, "IndexSelectivity: no amop %d %d", + indclass, operatorObjectIds[n]); + amop = (Form_pg_amop) GETSTRUCT(amopTuple); + + if (!nphack) + { + amopnpages = (float64) fmgr(amop->amopnpages, + (char *) operatorObjectIds[n], + (char *) indrelid, + (char *) varAttributeNumbers[n], + (char *) constValues[n], + (char *) constFlags[n], + (char *) nIndexKeys, + (char *) indexrelid); +#if 0 +/* * So cool guys! Npages for x > 10 and x < 20 is twice as * npages for x > 10! - vadim 04/09/97 */ - npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0; - if ((i = npages) < npages) /* ceil(npages)? */ - npages += 1.0; + npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0; + if ((i = npages) < npages) /* ceil(npages)? */ + npages += 1.0; #endif - npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0; + npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0; + } + + amopselect = (float64) fmgr(amop->amopselect, + (char *) operatorObjectIds[n], + (char *) indrelid, + (char *) varAttributeNumbers[n], + (char *) constValues[n], + (char *) constFlags[n], + (char *) nIndexKeys, + (char *) indexrelid); + + if (nphack && varAttributeNumbers[n] == index->indkey[0]) + fattr_select *= PointerIsValid(amopselect) ? *amopselect : 1.0; + + select *= PointerIsValid(amopselect) ? *amopselect : 1.0; } - - amopselect = (float64) fmgr(amop->amopselect, - (char *) operatorObjectIds[n], - (char *) indrelid, - (char *) varAttributeNumbers[n], - (char *) constValues[n], - (char *) constFlags[n], - (char *) nIndexKeys, - (char *) indexrelid); - - if ( nphack && varAttributeNumbers[n] == index->indkey[0] ) - fattr_select *= PointerIsValid(amopselect) ? *amopselect : 1.0; - - select *= PointerIsValid(amopselect) ? *amopselect : 1.0; - } - /* - * Estimation of npages below is hack of course, but it's - * better than it was before. - vadim 04/09/97 - */ - if ( nphack ) - { - npages = fattr_select * ((Form_pg_class)GETSTRUCT(indRel))->relpages; - *idxPages = ceil ((double)npages); - } - else - { - if ( nIndexKeys > 1 ) - npages = npages / (1.0 + nIndexKeys); - *idxPages = ceil ((double)(npages/nIndexKeys)); - } - *idxSelec = select; -} + /* + * Estimation of npages below is hack of course, but it's better than + * it was before. - vadim 04/09/97 + */ + if (nphack) + { + npages = fattr_select * ((Form_pg_class) GETSTRUCT(indRel))->relpages; + *idxPages = ceil((double) npages); + } + else + { + if (nIndexKeys > 1) + npages = npages / (1.0 + nIndexKeys); + *idxPages = ceil((double) (npages / nIndexKeys)); + } + *idxSelec = select; +} diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 351fb182107..229dff98092 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * relnode.c-- - * Relation manipulation routines + * Relation manipulation routines * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.1.1.1 1996/07/09 06:21:39 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.2 1997/09/07 04:44:32 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -16,108 +16,118 @@ #include "nodes/relation.h" #include "optimizer/internal.h" -#include "optimizer/pathnode.h" /* where the decls go */ +#include "optimizer/pathnode.h" /* where the decls go */ #include "optimizer/plancat.h" -/* +/* * get_base_rel-- - * Returns relation entry corresponding to 'relid', creating a new one if - * necessary. This is for base relations. - * + * Returns relation entry corresponding to 'relid', creating a new one if + * necessary. This is for base relations. + * */ -Rel *get_base_rel(Query* root, int relid) +Rel * +get_base_rel(Query * root, int relid) { - List *relids; - Rel *rel; + List *relids; + Rel *rel; + + relids = lconsi(relid, NIL); + rel = rel_member(relids, root->base_relation_list_); + if (rel == NULL) + { + rel = makeNode(Rel); + rel->relids = relids; + rel->indexed = false; + rel->pages = 0; + rel->tuples = 0; + rel->width = 0; + rel->targetlist = NIL; + rel->pathlist = NIL; + rel->unorderedpath = (Path *) NULL; + rel->cheapestpath = (Path *) NULL; + rel->pruneable = true; + rel->classlist = NULL; + rel->ordering = NULL; + rel->relam = InvalidOid; + rel->clauseinfo = NIL; + rel->joininfo = NIL; + rel->innerjoin = NIL; + rel->superrels = NIL; + + root->base_relation_list_ = lcons(rel, + root->base_relation_list_); + + /* + * ??? the old lispy C code (get_rel) do a listp(relid) here but + * that can never happen since we already established relid is not + * a list. -ay 10/94 + */ + if (relid < 0) + { + + /* + * If the relation is a materialized relation, assume + * constants for sizes. + */ + rel->pages = _TEMP_RELATION_PAGES_; + rel->tuples = _TEMP_RELATION_TUPLES_; + + } + else + { + bool hasindex; + int pages, + tuples; - relids = lconsi(relid, NIL); - rel = rel_member(relids, root->base_relation_list_); - if (rel==NULL) { - rel = makeNode(Rel); - rel->relids = relids; - rel->indexed = false; - rel->pages = 0; - rel->tuples = 0; - rel->width = 0; - rel->targetlist = NIL; - rel->pathlist = NIL; - rel->unorderedpath = (Path *)NULL; - rel->cheapestpath = (Path *)NULL; - rel->pruneable = true; - rel->classlist = NULL; - rel->ordering = NULL; - rel->relam = InvalidOid; - rel->clauseinfo = NIL; - rel->joininfo = NIL; - rel->innerjoin = NIL; - rel->superrels = NIL; - - root->base_relation_list_ = lcons(rel, - root->base_relation_list_); - - /* - * ??? the old lispy C code (get_rel) do a listp(relid) here but - * that can never happen since we already established relid is not - * a list. -ay 10/94 - */ - if(relid < 0) { - /* - * If the relation is a materialized relation, assume - * constants for sizes. - */ - rel->pages = _TEMP_RELATION_PAGES_; - rel->tuples = _TEMP_RELATION_TUPLES_; - - } else { - bool hasindex; - int pages, tuples; - - /* - * Otherwise, retrieve relation characteristics from the - * system catalogs. - */ - relation_info(root, relid, &hasindex, &pages, &tuples); - rel->indexed = hasindex; - rel->pages = pages; - rel->tuples = tuples; - } - } - return rel; + /* + * Otherwise, retrieve relation characteristics from the + * system catalogs. + */ + relation_info(root, relid, &hasindex, &pages, &tuples); + rel->indexed = hasindex; + rel->pages = pages; + rel->tuples = tuples; + } + } + return rel; } -/* +/* * get_join_rel-- - * Returns relation entry corresponding to 'relid' (a list of relids), - * creating a new one if necessary. This is for join relations. - * + * Returns relation entry corresponding to 'relid' (a list of relids), + * creating a new one if necessary. This is for join relations. + * */ -Rel *get_join_rel(Query *root, List *relid) +Rel * +get_join_rel(Query * root, List * relid) { - return rel_member(relid, root->join_relation_list_); + return rel_member(relid, root->join_relation_list_); } -/* +/* * rel-member-- - * Determines whether a relation of id 'relid' is contained within a list - * 'rels'. - * + * Determines whether a relation of id 'relid' is contained within a list + * 'rels'. + * * Returns the corresponding entry in 'rels' if it is there. - * + * */ -Rel * -rel_member(List *relid, List *rels) +Rel * +rel_member(List * relid, List * rels) { - List *temp = NIL; - List *temprelid = NIL; - - if (relid!=NIL && rels!=NIL) { - foreach(temp,rels) { - temprelid = ((Rel*)lfirst(temp))->relids; - if(same(temprelid, relid)) - return((Rel*)(lfirst(temp))); + List *temp = NIL; + List *temprelid = NIL; + + if (relid != NIL && rels != NIL) + { + foreach(temp, rels) + { + temprelid = ((Rel *) lfirst(temp))->relids; + if (same(temprelid, relid)) + return ((Rel *) (lfirst(temp))); + } } - } - return(NULL); + return (NULL); } diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c index c0f11ff3293..7e8563d31ab 100644 --- a/src/backend/optimizer/util/tlist.c +++ b/src/backend/optimizer/util/tlist.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * tlist.c-- - * Target list manipulation routines + * Target list manipulation routines * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.4 1997/08/20 14:53:47 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.5 1997/09/07 04:44:33 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -28,498 +28,538 @@ #include "nodes/makefuncs.h" #include "parser/catalog_utils.h" -static Node *flatten_tlistentry(Node *tlistentry, List *flat_tlist); +static Node *flatten_tlistentry(Node * tlistentry, List * flat_tlist); /***************************************************************************** - * ---------- RELATION node target list routines ---------- + * ---------- RELATION node target list routines ---------- *****************************************************************************/ -/* +/* * tlistentry-member-- - * + * * RETURNS: the leftmost member of sequence "targetlist" that satisfies - * the predicate "var_equal" + * the predicate "var_equal" * MODIFIES: nothing * REQUIRES: test = function which can operate on a lispval union - * var = valid var-node - * targetlist = valid sequence + * var = valid var-node + * targetlist = valid sequence */ -TargetEntry * -tlistentry_member(Var *var, List *targetlist) +TargetEntry * +tlistentry_member(Var * var, List * targetlist) { - if (var) { - List *temp = NIL; - - foreach (temp,targetlist) { - if (var_equal(var, - get_expr(lfirst(temp)))) - return((TargetEntry*)lfirst(temp)); + if (var) + { + List *temp = NIL; + + foreach(temp, targetlist) + { + if (var_equal(var, + get_expr(lfirst(temp)))) + return ((TargetEntry *) lfirst(temp)); + } } - } - return (NULL); + return (NULL); } -/* +/* * matching_tlvar-- - * + * * RETURNS: var node in a target list which is var_equal to 'var', - * if one exists. + * if one exists. * REQUIRES: "test" operates on lispval unions, - * + * */ -Expr * -matching_tlvar(Var *var, List *targetlist) +Expr * +matching_tlvar(Var * var, List * targetlist) { - TargetEntry *tlentry; + TargetEntry *tlentry; - tlentry = tlistentry_member(var,targetlist); - if (tlentry) - return((Expr*)get_expr (tlentry) ); + tlentry = tlistentry_member(var, targetlist); + if (tlentry) + return ((Expr *) get_expr(tlentry)); - return((Expr*) NULL); + return ((Expr *) NULL); } -/* +/* * add_tl_element-- - * Creates a targetlist entry corresponding to the supplied var node + * Creates a targetlist entry corresponding to the supplied var node * * 'var' and adds the new targetlist entry to the targetlist field of - * 'rel' - * + * 'rel' + * * RETURNS: nothing * MODIFIES: vartype and varid fields of leftmost varnode that matches - * argument "var" (sometimes). + * argument "var" (sometimes). * CREATES: new var-node iff no matching var-node exists in targetlist */ void -add_tl_element(Rel *rel, Var *var) +add_tl_element(Rel * rel, Var * var) { - Expr *oldvar = (Expr *)NULL; - - oldvar = matching_tlvar(var, rel->targetlist); - - /* - * If 'var' is not already in 'rel's target list, add a new node. - */ - if (oldvar==NULL) { - List *tlist = rel->targetlist; - Var *newvar = makeVar(var->varno, - var->varattno, - var->vartype, - var->varno, - var->varoattno); - - rel->targetlist = - lappend (tlist, - create_tl_element(newvar, - length(tlist) + 1)); - - } + Expr *oldvar = (Expr *) NULL; + + oldvar = matching_tlvar(var, rel->targetlist); + + /* + * If 'var' is not already in 'rel's target list, add a new node. + */ + if (oldvar == NULL) + { + List *tlist = rel->targetlist; + Var *newvar = makeVar(var->varno, + var->varattno, + var->vartype, + var->varno, + var->varoattno); + + rel->targetlist = + lappend(tlist, + create_tl_element(newvar, + length(tlist) + 1)); + + } } -/* +/* * create_tl_element-- - * Creates a target list entry node and its associated (resdom var) pair - * with its resdom number equal to 'resdomno' and the joinlist field set - * to 'joinlist'. - * + * Creates a target list entry node and its associated (resdom var) pair + * with its resdom number equal to 'resdomno' and the joinlist field set + * to 'joinlist'. + * * RETURNS: newly created tlist-entry * CREATES: new targetlist entry (always). */ -TargetEntry* -create_tl_element(Var *var, int resdomno) +TargetEntry * +create_tl_element(Var * var, int resdomno) { - TargetEntry *tlelement= makeNode(TargetEntry); - - tlelement->resdom = - makeResdom(resdomno, - var->vartype, - get_typlen(var->vartype), - NULL, - (Index)0, - (Oid)0, - 0); - tlelement->expr = (Node*)var; - - return(tlelement); + TargetEntry *tlelement = makeNode(TargetEntry); + + tlelement->resdom = + makeResdom(resdomno, + var->vartype, + get_typlen(var->vartype), + NULL, + (Index) 0, + (Oid) 0, + 0); + tlelement->expr = (Node *) var; + + return (tlelement); } -/* +/* * get-actual-tlist-- - * Returns the targetlist elements from a relation tlist. - * + * Returns the targetlist elements from a relation tlist. + * */ -List * -get_actual_tlist(List *tlist) +List * +get_actual_tlist(List * tlist) { - /* - * this function is not making sense. - ay 10/94 - */ -#if 0 - List *element = NIL; - List *result = NIL; - - if (tlist==NULL) { - elog(DEBUG,"calling get_actual_tlist with empty tlist"); - return(NIL); - } - /* XXX - it is unclear to me what exactly get_entry - should be doing, as it is unclear to me the exact - relationship between "TL" "TLE" and joinlists */ - - foreach(element,tlist) - result = lappend(result, lfirst((List*)lfirst(element))); - - return(result); + + /* + * this function is not making sense. - ay 10/94 + */ +#if 0 + List *element = NIL; + List *result = NIL; + + if (tlist == NULL) + { + elog(DEBUG, "calling get_actual_tlist with empty tlist"); + return (NIL); + } + + /* + * XXX - it is unclear to me what exactly get_entry should be doing, + * as it is unclear to me the exact relationship between "TL" "TLE" + * and joinlists + */ + + foreach(element, tlist) + result = lappend(result, lfirst((List *) lfirst(element))); + + return (result); #endif - return tlist; + return tlist; } /***************************************************************************** - * ---------- GENERAL target list routines ---------- + * ---------- GENERAL target list routines ---------- *****************************************************************************/ -/* +/* * tlist-member-- - * Determines whether a var node is already contained within a - * target list. - * + * Determines whether a var node is already contained within a + * target list. + * * 'var' is the var node * 'tlist' is the target list * 'dots' is t if we must match dotfields to determine uniqueness - * + * * Returns the resdom entry of the matching var node. - * + * */ -Resdom * -tlist_member(Var *var, List *tlist) +Resdom * +tlist_member(Var * var, List * tlist) { - List *i = NIL; - TargetEntry *temp_tle = (TargetEntry *)NULL; - TargetEntry *tl_elt = (TargetEntry *)NULL; - - if (var) { - foreach (i,tlist) { - temp_tle = (TargetEntry *)lfirst(i); - if (var_equal(var, get_expr(temp_tle))) { - tl_elt = temp_tle; - break; - } + List *i = NIL; + TargetEntry *temp_tle = (TargetEntry *) NULL; + TargetEntry *tl_elt = (TargetEntry *) NULL; + + if (var) + { + foreach(i, tlist) + { + temp_tle = (TargetEntry *) lfirst(i); + if (var_equal(var, get_expr(temp_tle))) + { + tl_elt = temp_tle; + break; + } + } + + if (tl_elt != NULL) + return (tl_elt->resdom); + else + return ((Resdom *) NULL); } - - if (tl_elt != NULL) - return(tl_elt->resdom); - else - return((Resdom*)NULL); - } - return ((Resdom*)NULL); + return ((Resdom *) NULL); } /* - * Routine to get the resdom out of a targetlist. + * Routine to get the resdom out of a targetlist. */ -Resdom * -tlist_resdom(List *tlist, Resdom *resnode) +Resdom * +tlist_resdom(List * tlist, Resdom * resnode) { - Resdom *resdom = (Resdom*)NULL; - List *i = NIL; - TargetEntry *temp_tle = (TargetEntry *)NULL; - - foreach(i,tlist) { - temp_tle = (TargetEntry *)lfirst(i); - resdom = temp_tle->resdom; - /* Since resnos are supposed to be unique */ - if (resnode->resno == resdom->resno) - return(resdom); - } - return((Resdom*)NULL); + Resdom *resdom = (Resdom *) NULL; + List *i = NIL; + TargetEntry *temp_tle = (TargetEntry *) NULL; + + foreach(i, tlist) + { + temp_tle = (TargetEntry *) lfirst(i); + resdom = temp_tle->resdom; + /* Since resnos are supposed to be unique */ + if (resnode->resno == resdom->resno) + return (resdom); + } + return ((Resdom *) NULL); } -/* +/* * match_varid-- - * Searches a target list for an entry with some desired varid. - * + * Searches a target list for an entry with some desired varid. + * * 'varid' is the desired id * 'tlist' is the target list that is searched - * + * * Returns the target list entry (resdom var) of the matching var. * * Now checks to make sure array references (in addition to range * table indices) are identical - retrieve (a.b[1],a.b[2]) should * not be turned into retrieve (a.b[1],a.b[1]). - * + * * [what used to be varid is now broken up into two fields varnoold and - * varoattno. Also, nested attnos are long gone. - ay 2/95] + * varoattno. Also, nested attnos are long gone. - ay 2/95] */ -TargetEntry * -match_varid(Var *test_var, List *tlist) +TargetEntry * +match_varid(Var * test_var, List * tlist) { - List *tl; - Oid type_var; + List *tl; + Oid type_var; - type_var = (Oid) test_var->vartype; + type_var = (Oid) test_var->vartype; - foreach (tl, tlist) { - TargetEntry *entry; - Var *tlvar; + foreach(tl, tlist) + { + TargetEntry *entry; + Var *tlvar; - entry = lfirst(tl); - tlvar = get_expr(entry); - - if ( !IsA (tlvar, Var) ) - continue; + entry = lfirst(tl); + tlvar = get_expr(entry); - /* - * we test the original varno (instead of varno which might - * be changed to INNER/OUTER. - */ - if (tlvar->varnoold == test_var->varnoold && - tlvar->varoattno == test_var->varoattno) { + if (!IsA(tlvar, Var)) + continue; + + /* + * we test the original varno (instead of varno which might be + * changed to INNER/OUTER. + */ + if (tlvar->varnoold == test_var->varnoold && + tlvar->varoattno == test_var->varoattno) + { - if (tlvar->vartype == type_var) - return(entry); + if (tlvar->vartype == type_var) + return (entry); + } } - } - return (NULL); + return (NULL); } -/* +/* * new-unsorted-tlist-- - * Creates a copy of a target list by creating new resdom nodes - * without sort information. - * + * Creates a copy of a target list by creating new resdom nodes + * without sort information. + * * 'targetlist' is the target list to be copied. - * + * * Returns the resulting target list. - * + * */ -List * -new_unsorted_tlist(List *targetlist) +List * +new_unsorted_tlist(List * targetlist) { - List *new_targetlist = (List*)copyObject ((Node*)targetlist); - List *x = NIL; - - foreach (x, new_targetlist) { - TargetEntry *tle = (TargetEntry *)lfirst(x); - tle->resdom->reskey = 0; - tle->resdom->reskeyop = (Oid)0; - } - return(new_targetlist); + List *new_targetlist = (List *) copyObject((Node *) targetlist); + List *x = NIL; + + foreach(x, new_targetlist) + { + TargetEntry *tle = (TargetEntry *) lfirst(x); + + tle->resdom->reskey = 0; + tle->resdom->reskeyop = (Oid) 0; + } + return (new_targetlist); } -/* +/* * copy-vars-- - * Replaces the var nodes in the first target list with those from - * the second target list. The two target lists are assumed to be - * identical except their actual resdoms and vars are different. - * + * Replaces the var nodes in the first target list with those from + * the second target list. The two target lists are assumed to be + * identical except their actual resdoms and vars are different. + * * 'target' is the target list to be replaced * 'source' is the target list to be copied - * + * * Returns a new target list. - * + * */ -List * -copy_vars(List *target, List *source) +List * +copy_vars(List * target, List * source) { - List *result = NIL; - List *src = NIL; - List *dest = NIL; - - for ( src = source, dest = target; src != NIL && - dest != NIL; src = lnext(src), dest = lnext(dest)) { - TargetEntry *temp = MakeTLE(((TargetEntry *)lfirst(dest))->resdom, - (Node*)get_expr(lfirst(src))); - result = lappend(result,temp); - } - return(result); + List *result = NIL; + List *src = NIL; + List *dest = NIL; + + for (src = source, dest = target; src != NIL && + dest != NIL; src = lnext(src), dest = lnext(dest)) + { + TargetEntry *temp = MakeTLE(((TargetEntry *) lfirst(dest))->resdom, + (Node *) get_expr(lfirst(src))); + + result = lappend(result, temp); + } + return (result); } -/* +/* * flatten-tlist-- - * Create a target list that only contains unique variables. + * Create a target list that only contains unique variables. * * * 'tlist' is the current target list - * + * * Returns the "flattened" new target list. - * + * */ -List * -flatten_tlist(List *tlist) +List * +flatten_tlist(List * tlist) { - int last_resdomno = 1; - List *new_tlist = NIL; - List *tlist_vars = NIL; - List *temp; - - foreach (temp, tlist) { - TargetEntry *temp_entry = NULL; - List *vars; - - temp_entry = lfirst(temp); - vars = pull_var_clause((Node*)get_expr(temp_entry)); - if(vars != NULL) { - tlist_vars = nconc(tlist_vars, vars); + int last_resdomno = 1; + List *new_tlist = NIL; + List *tlist_vars = NIL; + List *temp; + + foreach(temp, tlist) + { + TargetEntry *temp_entry = NULL; + List *vars; + + temp_entry = lfirst(temp); + vars = pull_var_clause((Node *) get_expr(temp_entry)); + if (vars != NULL) + { + tlist_vars = nconc(tlist_vars, vars); + } } - } - - foreach (temp, tlist_vars) { - Var *var = lfirst(temp); - if (!(tlist_member(var, new_tlist))) { - Resdom *r; - - r = makeResdom(last_resdomno, - var->vartype, - get_typlen(var->vartype), - NULL, - (Index)0, - (Oid)0, - 0); - last_resdomno++; - new_tlist = lappend(new_tlist, MakeTLE (r, (Node*)var)); + + foreach(temp, tlist_vars) + { + Var *var = lfirst(temp); + + if (!(tlist_member(var, new_tlist))) + { + Resdom *r; + + r = makeResdom(last_resdomno, + var->vartype, + get_typlen(var->vartype), + NULL, + (Index) 0, + (Oid) 0, + 0); + last_resdomno++; + new_tlist = lappend(new_tlist, MakeTLE(r, (Node *) var)); + } } - } - return new_tlist; + return new_tlist; } -/* +/* * flatten-tlist-vars-- - * Redoes the target list of a query with no nested attributes by - * replacing vars within computational expressions with vars from - * the 'flattened' target list of the query. - * + * Redoes the target list of a query with no nested attributes by + * replacing vars within computational expressions with vars from + * the 'flattened' target list of the query. + * * 'full-tlist' is the actual target list * 'flat-tlist' is the flattened (var-only) target list - * + * * Returns the modified actual target list. - * + * */ -List * -flatten_tlist_vars(List *full_tlist, List *flat_tlist) +List * +flatten_tlist_vars(List * full_tlist, List * flat_tlist) { - List *x = NIL; - List *result = NIL; - - foreach(x,full_tlist) { - TargetEntry *tle= lfirst(x); - result = - lappend(result, - MakeTLE(tle->resdom, - flatten_tlistentry((Node*)get_expr(tle), - flat_tlist))); - } - - return(result); + List *x = NIL; + List *result = NIL; + + foreach(x, full_tlist) + { + TargetEntry *tle = lfirst(x); + + result = + lappend(result, + MakeTLE(tle->resdom, + flatten_tlistentry((Node *) get_expr(tle), + flat_tlist))); + } + + return (result); } -/* +/* * flatten-tlistentry-- - * Replaces vars within a target list entry with vars from a flattened - * target list. - * + * Replaces vars within a target list entry with vars from a flattened + * target list. + * * 'tlistentry' is the target list entry to be modified * 'flat-tlist' is the flattened target list - * + * * Returns the (modified) target_list entry from the target list. - * + * */ -static Node * -flatten_tlistentry(Node *tlistentry, List *flat_tlist) +static Node * +flatten_tlistentry(Node * tlistentry, List * flat_tlist) { - if (tlistentry==NULL) { - - return NULL; - - } else if (IsA (tlistentry,Var)) { - - return - ((Node *)get_expr(match_varid((Var*)tlistentry, - flat_tlist))); - } else if (IsA (tlistentry,Iter)) { - - ((Iter*)tlistentry)->iterexpr = - flatten_tlistentry((Node*)((Iter*)tlistentry)->iterexpr, - flat_tlist); - return tlistentry; - - } else if (single_node(tlistentry)) { - - return tlistentry; - - } else if (is_funcclause (tlistentry)) { - Expr *expr = (Expr*)tlistentry; - List *temp_result = NIL; - List *elt = NIL; - - foreach(elt, expr->args) - temp_result = lappend(temp_result, - flatten_tlistentry(lfirst(elt),flat_tlist)); - - return - ((Node *)make_funcclause((Func*)expr->oper, temp_result)); - - } else if (IsA(tlistentry,Aggreg)) { - - return tlistentry; - - } else if (IsA(tlistentry,ArrayRef)) { - ArrayRef *aref = (ArrayRef *)tlistentry; - List *temp = NIL; - List *elt = NIL; - - foreach(elt, aref->refupperindexpr) - temp = lappend(temp, flatten_tlistentry(lfirst(elt), flat_tlist)); - aref->refupperindexpr = temp; - - temp = NIL; - foreach(elt, aref->reflowerindexpr) - temp = lappend(temp, flatten_tlistentry(lfirst(elt), flat_tlist)); - aref->reflowerindexpr = temp; - - aref->refexpr = - flatten_tlistentry(aref->refexpr, flat_tlist); - - aref->refassgnexpr = - flatten_tlistentry(aref->refassgnexpr, flat_tlist); - - return tlistentry; - } else { - Expr *expr = (Expr*)tlistentry; - Var *left = - (Var*)flatten_tlistentry((Node*)get_leftop(expr), - flat_tlist); - Var *right = - (Var*)flatten_tlistentry((Node*)get_rightop(expr), - flat_tlist); - - return((Node *) - make_opclause((Oper*)expr->oper, left, right)); - } + if (tlistentry == NULL) + { + + return NULL; + + } + else if (IsA(tlistentry, Var)) + { + + return + ((Node *) get_expr(match_varid((Var *) tlistentry, + flat_tlist))); + } + else if (IsA(tlistentry, Iter)) + { + + ((Iter *) tlistentry)->iterexpr = + flatten_tlistentry((Node *) ((Iter *) tlistentry)->iterexpr, + flat_tlist); + return tlistentry; + + } + else if (single_node(tlistentry)) + { + + return tlistentry; + + } + else if (is_funcclause(tlistentry)) + { + Expr *expr = (Expr *) tlistentry; + List *temp_result = NIL; + List *elt = NIL; + + foreach(elt, expr->args) + temp_result = lappend(temp_result, + flatten_tlistentry(lfirst(elt), flat_tlist)); + + return + ((Node *) make_funcclause((Func *) expr->oper, temp_result)); + + } + else if (IsA(tlistentry, Aggreg)) + { + + return tlistentry; + + } + else if (IsA(tlistentry, ArrayRef)) + { + ArrayRef *aref = (ArrayRef *) tlistentry; + List *temp = NIL; + List *elt = NIL; + + foreach(elt, aref->refupperindexpr) + temp = lappend(temp, flatten_tlistentry(lfirst(elt), flat_tlist)); + aref->refupperindexpr = temp; + + temp = NIL; + foreach(elt, aref->reflowerindexpr) + temp = lappend(temp, flatten_tlistentry(lfirst(elt), flat_tlist)); + aref->reflowerindexpr = temp; + + aref->refexpr = + flatten_tlistentry(aref->refexpr, flat_tlist); + + aref->refassgnexpr = + flatten_tlistentry(aref->refassgnexpr, flat_tlist); + + return tlistentry; + } + else + { + Expr *expr = (Expr *) tlistentry; + Var *left = + (Var *) flatten_tlistentry((Node *) get_leftop(expr), + flat_tlist); + Var *right = + (Var *) flatten_tlistentry((Node *) get_rightop(expr), + flat_tlist); + + return ((Node *) + make_opclause((Oper *) expr->oper, left, right)); + } } -TargetEntry * -MakeTLE(Resdom *resdom, Node *expr) +TargetEntry * +MakeTLE(Resdom * resdom, Node * expr) { - TargetEntry *rt = makeNode(TargetEntry); + TargetEntry *rt = makeNode(TargetEntry); - rt->resdom = resdom; - rt->expr = expr; - return rt; + rt->resdom = resdom; + rt->expr = expr; + return rt; } -Var * -get_expr(TargetEntry *tle) +Var * +get_expr(TargetEntry * tle) { - Assert(tle!=NULL); - Assert(tle->expr!=NULL); + Assert(tle != NULL); + Assert(tle->expr != NULL); - return ((Var *)tle->expr); + return ((Var *) tle->expr); } @@ -529,54 +569,56 @@ get_expr(TargetEntry *tle) /* * AddGroupAttrToTlist - - * append the group attribute to the target list if it's not already - * in there. + * append the group attribute to the target list if it's not already + * in there. */ #ifdef NOT_USED void -AddGroupAttrToTlist(List *tlist, List *grpCl) +AddGroupAttrToTlist(List * tlist, List * grpCl) { - List *gl; - int last_resdomno = length(tlist) + 1; - - foreach (gl, grpCl) { - GroupClause *gc = (GroupClause*)lfirst(gl); - Var *var = gc->grpAttr; - - if (!(tlist_member(var, tlist))) { - Resdom *r; - - r = makeResdom(last_resdomno, - var->vartype, - get_typlen(var->vartype), - NULL, - (Index)0, - (Oid)0, - 0); - last_resdomno++; - tlist = lappend(tlist, MakeTLE(r, (Node*)var)); + List *gl; + int last_resdomno = length(tlist) + 1; + + foreach(gl, grpCl) + { + GroupClause *gc = (GroupClause *) lfirst(gl); + Var *var = gc->grpAttr; + + if (!(tlist_member(var, tlist))) + { + Resdom *r; + + r = makeResdom(last_resdomno, + var->vartype, + get_typlen(var->vartype), + NULL, + (Index) 0, + (Oid) 0, + 0); + last_resdomno++; + tlist = lappend(tlist, MakeTLE(r, (Node *) var)); + } } - } } + #endif -/* was ExecTargetListLength() in execQual.c, +/* was ExecTargetListLength() in execQual.c, moved here to reduce dependencies on the executor module */ int -exec_tlist_length(List *targetlist) +exec_tlist_length(List * targetlist) { - int len; - List *tl; - TargetEntry *curTle; - - len = 0; - foreach (tl, targetlist) { - curTle = lfirst(tl); - - if (curTle->resdom != NULL) - len++; - } - return len; -} + int len; + List *tl; + TargetEntry *curTle; + len = 0; + foreach(tl, targetlist) + { + curTle = lfirst(tl); + if (curTle->resdom != NULL) + len++; + } + return len; +} diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index 3eb0787e3ef..40abf5f80cb 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * var.c-- - * Var node manipulation routines + * Var node manipulation routines * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.3 1996/11/06 09:29:26 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.4 1997/09/07 04:44:35 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -27,169 +27,193 @@ #include "parser/parsetree.h" /* - * find_varnos + * find_varnos * - * Descends down part of a parsetree (qual or tlist), + * Descends down part of a parsetree (qual or tlist), * - * XXX assumes varno's are always integers, which shouldn't be true... - * (though it currently is, see primnodes.h) + * XXX assumes varno's are always integers, which shouldn't be true... + * (though it currently is, see primnodes.h) */ -List * -pull_varnos(Node *me) +List * +pull_varnos(Node * me) { - List *i, *result = NIL; - - if (me == NULL) - return (NIL); - - switch (nodeTag(me)) { - case T_List: - foreach (i, (List*)me) { - result = nconc(result, pull_varnos(lfirst(i))); + List *i, + *result = NIL; + + if (me == NULL) + return (NIL); + + switch (nodeTag(me)) + { + case T_List: + foreach(i, (List *) me) + { + result = nconc(result, pull_varnos(lfirst(i))); + } + break; + case T_ArrayRef: + foreach(i, ((ArrayRef *) me)->refupperindexpr) + result = nconc(result, pull_varnos(lfirst(i))); + foreach(i, ((ArrayRef *) me)->reflowerindexpr) + result = nconc(result, pull_varnos(lfirst(i))); + result = nconc(result, pull_varnos(((ArrayRef *) me)->refassgnexpr)); + break; + case T_Var: + result = lconsi(((Var *) me)->varno, NIL); + break; + default: + break; } - break; - case T_ArrayRef: - foreach (i, ((ArrayRef*) me)->refupperindexpr) - result = nconc(result, pull_varnos(lfirst(i))); - foreach (i, ((ArrayRef*) me)->reflowerindexpr) - result = nconc(result, pull_varnos(lfirst(i))); - result = nconc(result, pull_varnos(((ArrayRef*) me)->refassgnexpr)); - break; - case T_Var: - result = lconsi(((Var*) me)->varno, NIL); - break; - default: - break; - } - return(result); + return (result); } -/* +/* * contain_var_clause-- - * Recursively find var nodes from a clause by pulling vars from the - * left and right operands of the clause. - * - * Returns true if any varnode found. + * Recursively find var nodes from a clause by pulling vars from the + * left and right operands of the clause. + * + * Returns true if any varnode found. */ -bool contain_var_clause(Node *clause) +bool +contain_var_clause(Node * clause) { - if (clause==NULL) - return FALSE; - else if (IsA(clause,Var)) - return TRUE; - else if (IsA(clause,Iter)) - return contain_var_clause(((Iter*)clause)->iterexpr); - else if (single_node(clause)) - return FALSE; - else if (or_clause(clause)) { - List *temp; - - foreach (temp, ((Expr*)clause)->args) { - if (contain_var_clause(lfirst(temp))) - return TRUE; - } - return FALSE; - } else if (is_funcclause (clause)) { - List *temp; - - foreach(temp, ((Expr *)clause)->args) { - if (contain_var_clause(lfirst(temp))) + if (clause == NULL) + return FALSE; + else if (IsA(clause, Var)) return TRUE; + else if (IsA(clause, Iter)) + return contain_var_clause(((Iter *) clause)->iterexpr); + else if (single_node(clause)) + return FALSE; + else if (or_clause(clause)) + { + List *temp; + + foreach(temp, ((Expr *) clause)->args) + { + if (contain_var_clause(lfirst(temp))) + return TRUE; + } + return FALSE; } - return FALSE; - } else if (IsA(clause,ArrayRef)) { - List *temp; - - foreach(temp, ((ArrayRef*)clause)->refupperindexpr) { - if (contain_var_clause(lfirst(temp))) - return TRUE; + else if (is_funcclause(clause)) + { + List *temp; + + foreach(temp, ((Expr *) clause)->args) + { + if (contain_var_clause(lfirst(temp))) + return TRUE; + } + return FALSE; } - foreach(temp, ((ArrayRef*)clause)->reflowerindexpr) { - if (contain_var_clause(lfirst(temp))) - return TRUE; + else if (IsA(clause, ArrayRef)) + { + List *temp; + + foreach(temp, ((ArrayRef *) clause)->refupperindexpr) + { + if (contain_var_clause(lfirst(temp))) + return TRUE; + } + foreach(temp, ((ArrayRef *) clause)->reflowerindexpr) + { + if (contain_var_clause(lfirst(temp))) + return TRUE; + } + if (contain_var_clause(((ArrayRef *) clause)->refexpr)) + return TRUE; + if (contain_var_clause(((ArrayRef *) clause)->refassgnexpr)) + return TRUE; + return FALSE; } - if (contain_var_clause(((ArrayRef*)clause)->refexpr)) - return TRUE; - if (contain_var_clause(((ArrayRef*)clause)->refassgnexpr)) - return TRUE; - return FALSE; - } else if (not_clause(clause)) - return contain_var_clause((Node*)get_notclausearg((Expr*)clause)); - else if (is_opclause(clause)) - return (contain_var_clause((Node*)get_leftop((Expr*)clause)) || - contain_var_clause((Node*)get_rightop((Expr*)clause))); + else if (not_clause(clause)) + return contain_var_clause((Node *) get_notclausearg((Expr *) clause)); + else if (is_opclause(clause)) + return (contain_var_clause((Node *) get_leftop((Expr *) clause)) || + contain_var_clause((Node *) get_rightop((Expr *) clause))); - return FALSE; + return FALSE; } -/* +/* * pull_var_clause-- - * Recursively pulls all var nodes from a clause by pulling vars from the - * left and right operands of the clause. - * - * Returns list of varnodes found. + * Recursively pulls all var nodes from a clause by pulling vars from the + * left and right operands of the clause. + * + * Returns list of varnodes found. */ -List * -pull_var_clause(Node *clause) +List * +pull_var_clause(Node * clause) { - List *retval = NIL; - - if (clause==NULL) - return(NIL); - else if (IsA(clause,Var)) - retval = lcons(clause,NIL); - else if (IsA(clause,Iter)) - retval = pull_var_clause(((Iter*)clause)->iterexpr); - else if (single_node(clause)) - retval = NIL; - else if (or_clause(clause)) { - List *temp; - - foreach (temp, ((Expr*)clause)->args) - retval = nconc(retval, pull_var_clause(lfirst(temp))); - } else if (is_funcclause (clause)) { - List *temp; - - foreach(temp, ((Expr *)clause)->args) - retval = nconc (retval,pull_var_clause(lfirst(temp))); - } else if (IsA(clause,Aggreg)) { - retval = pull_var_clause(((Aggreg*)clause)->target); - } else if (IsA(clause,ArrayRef)) { - List *temp; - - foreach(temp, ((ArrayRef*)clause)->refupperindexpr) - retval = nconc (retval,pull_var_clause(lfirst(temp))); - foreach(temp, ((ArrayRef*)clause)->reflowerindexpr) - retval = nconc (retval,pull_var_clause(lfirst(temp))); - retval = nconc(retval, - pull_var_clause(((ArrayRef*)clause)->refexpr)); - retval = nconc(retval, - pull_var_clause(((ArrayRef*)clause)->refassgnexpr)); - } else if (not_clause(clause)) - retval = pull_var_clause((Node*)get_notclausearg((Expr*)clause)); - else if (is_opclause(clause)) - retval = nconc(pull_var_clause((Node*)get_leftop((Expr*)clause)), - pull_var_clause((Node*)get_rightop((Expr*)clause))); - else - retval = NIL; - - return (retval); + List *retval = NIL; + + if (clause == NULL) + return (NIL); + else if (IsA(clause, Var)) + retval = lcons(clause, NIL); + else if (IsA(clause, Iter)) + retval = pull_var_clause(((Iter *) clause)->iterexpr); + else if (single_node(clause)) + retval = NIL; + else if (or_clause(clause)) + { + List *temp; + + foreach(temp, ((Expr *) clause)->args) + retval = nconc(retval, pull_var_clause(lfirst(temp))); + } + else if (is_funcclause(clause)) + { + List *temp; + + foreach(temp, ((Expr *) clause)->args) + retval = nconc(retval, pull_var_clause(lfirst(temp))); + } + else if (IsA(clause, Aggreg)) + { + retval = pull_var_clause(((Aggreg *) clause)->target); + } + else if (IsA(clause, ArrayRef)) + { + List *temp; + + foreach(temp, ((ArrayRef *) clause)->refupperindexpr) + retval = nconc(retval, pull_var_clause(lfirst(temp))); + foreach(temp, ((ArrayRef *) clause)->reflowerindexpr) + retval = nconc(retval, pull_var_clause(lfirst(temp))); + retval = nconc(retval, + pull_var_clause(((ArrayRef *) clause)->refexpr)); + retval = nconc(retval, + pull_var_clause(((ArrayRef *) clause)->refassgnexpr)); + } + else if (not_clause(clause)) + retval = pull_var_clause((Node *) get_notclausearg((Expr *) clause)); + else if (is_opclause(clause)) + retval = nconc(pull_var_clause((Node *) get_leftop((Expr *) clause)), + pull_var_clause((Node *) get_rightop((Expr *) clause))); + else + retval = NIL; + + return (retval); } -/* - * var_equal - * - * Returns t iff two var nodes correspond to the same attribute. +/* + * var_equal + * + * Returns t iff two var nodes correspond to the same attribute. */ bool -var_equal(Var *var1, Var *var2) +var_equal(Var * var1, Var * var2) { - if (IsA (var1,Var) && IsA (var2,Var) && - (((Var*)var1)->varno == ((Var*)var2)->varno) && - (((Var*)var1)->vartype == ((Var*)var2)->vartype) && - (((Var*)var1)->varattno == ((Var*)var2)->varattno)) { - - return(true); - } else - return(false); + if (IsA(var1, Var) && IsA(var2, Var) && + (((Var *) var1)->varno == ((Var *) var2)->varno) && + (((Var *) var1)->vartype == ((Var *) var2)->vartype) && + (((Var *) var1)->varattno == ((Var *) var2)->varattno)) + { + + return (true); + } + else + return (false); } |