summaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>1997-09-07 05:04:48 +0000
committerBruce Momjian <bruce@momjian.us>1997-09-07 05:04:48 +0000
commit1ccd423235a48739d6f7a4d7889705b5f9ecc69b (patch)
tree8001c4e839dfad8f29ceda7f8c5f5dbb8759b564 /src/backend/optimizer
parent8fecd4febf8357f3cc20383ed29ced484877d5ac (diff)
Massive commit to run PGINDENT on all *.c and *.h files.
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/geqo/geqo_copy.c40
-rw-r--r--src/backend/optimizer/geqo/geqo_cx.c132
-rw-r--r--src/backend/optimizer/geqo/geqo_erx.c567
-rw-r--r--src/backend/optimizer/geqo/geqo_eval.c985
-rw-r--r--src/backend/optimizer/geqo/geqo_main.c249
-rw-r--r--src/backend/optimizer/geqo/geqo_misc.c347
-rw-r--r--src/backend/optimizer/geqo/geqo_mutation.c65
-rw-r--r--src/backend/optimizer/geqo/geqo_ox1.c122
-rw-r--r--src/backend/optimizer/geqo/geqo_ox2.c146
-rw-r--r--src/backend/optimizer/geqo/geqo_params.c268
-rw-r--r--src/backend/optimizer/geqo/geqo_paths.c190
-rw-r--r--src/backend/optimizer/geqo/geqo_pmx.c281
-rw-r--r--src/backend/optimizer/geqo/geqo_pool.c301
-rw-r--r--src/backend/optimizer/geqo/geqo_px.c121
-rw-r--r--src/backend/optimizer/geqo/geqo_recombination.c93
-rw-r--r--src/backend/optimizer/geqo/geqo_selection.c88
-rw-r--r--src/backend/optimizer/geqo/minspantree.c317
-rw-r--r--src/backend/optimizer/path/allpaths.c609
-rw-r--r--src/backend/optimizer/path/clausesel.c536
-rw-r--r--src/backend/optimizer/path/costsize.c624
-rw-r--r--src/backend/optimizer/path/hashutils.c174
-rw-r--r--src/backend/optimizer/path/indxpath.c2113
-rw-r--r--src/backend/optimizer/path/joinpath.c1097
-rw-r--r--src/backend/optimizer/path/joinrels.c884
-rw-r--r--src/backend/optimizer/path/joinutils.c679
-rw-r--r--src/backend/optimizer/path/mergeutils.c170
-rw-r--r--src/backend/optimizer/path/orindxpath.c430
-rw-r--r--src/backend/optimizer/path/predmig.c1064
-rw-r--r--src/backend/optimizer/path/prune.c284
-rw-r--r--src/backend/optimizer/path/xfunc.c2192
-rw-r--r--src/backend/optimizer/plan/createplan.c2005
-rw-r--r--src/backend/optimizer/plan/initsplan.c579
-rw-r--r--src/backend/optimizer/plan/planmain.c952
-rw-r--r--src/backend/optimizer/plan/planner.c635
-rw-r--r--src/backend/optimizer/plan/setrefs.c1148
-rw-r--r--src/backend/optimizer/prep/archive.c61
-rw-r--r--src/backend/optimizer/prep/prepqual.c980
-rw-r--r--src/backend/optimizer/prep/preptlist.c544
-rw-r--r--src/backend/optimizer/prep/prepunion.c628
-rw-r--r--src/backend/optimizer/util/clauseinfo.c259
-rw-r--r--src/backend/optimizer/util/clauses.c1026
-rw-r--r--src/backend/optimizer/util/indexnode.c113
-rw-r--r--src/backend/optimizer/util/internal.c48
-rw-r--r--src/backend/optimizer/util/joininfo.c132
-rw-r--r--src/backend/optimizer/util/keys.c261
-rw-r--r--src/backend/optimizer/util/ordering.c154
-rw-r--r--src/backend/optimizer/util/pathnode.c867
-rw-r--r--src/backend/optimizer/util/plancat.c969
-rw-r--r--src/backend/optimizer/util/relnode.c182
-rw-r--r--src/backend/optimizer/util/tlist.c834
-rw-r--r--src/backend/optimizer/util/var.c308
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);
}