1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-25 01:02:05 +03:00

Massive commit to run PGINDENT on all *.c and *.h files.

This commit is contained in:
Bruce Momjian
1997-09-07 05:04:48 +00:00
parent 8fecd4febf
commit 1ccd423235
687 changed files with 150775 additions and 136888 deletions

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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
*
* gimme_edge() will set "shared" edges to negative values
* assumes circular tours and bidirectional edges
*
* returns average number edges/city in range 2.0 - 4.0
* where 2.0=homogeneous; 4.0=diverse
* 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
*
*/
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 */
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;
/* 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;
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 */
/*
* no point has edges to more than 4 other points thus, this contrived
* minimum will be replaced
*/
minimum_edges = 5;
minimum_edges = 5;
/* consider candidate destination points in edge list */
/* consider candidate destination points in edge list */
for (i=0; i<edge.unused_edges; i++) {
friend = (Gene) edge.edge_list[i];
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 shared edges that are negative; so return 'em
*/
/* 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 */
/*
* negative values are caught here so we need not worry about
* converting to absolute values
*/
if (friend < 0)
return ((Gene) Abs(friend));
if (edge_table[(int) friend].unused_edges < minimum_edges) {
minimum_edges = edge_table[(int) friend].unused_edges;
minimum_count = 1;
/*
* 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);
for (i=0; i<edge.unused_edges; i++) {
friend = (Gene) edge.edge_list[i];
/* random decision of the possible candidates to use */
rand_decision = (int) geqo_randint(minimum_count - 1, 0);
/* return the chosen candidate point */
if (edge_table[(int) friend].unused_edges == minimum_edges) {
minimum_count--;
if ( minimum_count == rand_decision ) return (friend);
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--;
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;
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++;
/*
* how many edges remain? how many gene with four total (initial)
* edges remain?
*/
if (edge_table[i].total_edges == 4) four_count++;
}
}
for (i = 1; i <= num_gene; i++)
{
if ((edge_table[i].unused_edges != -1) && (i != (int) fail_gene))
{
remaining_edges++;
/* random decision of the gene
with remaining edges and whose total_edges == 4 */
if (edge_table[i].total_edges == 4)
four_count++;
}
}
if (four_count != 0 ) {
/*
* random decision of the gene with remaining edges and whose
* total_edges == 4
*/
rand_decision = (int) geqo_randint(four_count-1, 0);
if (four_count != 0)
{
for (i=1; i<=num_gene; i++) {
rand_decision = (int) geqo_randint(four_count - 1, 0);
if ((Gene) i != fail_gene &&
for (i = 1; i <= num_gene; i++)
{
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 */
}

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -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");
int i;
double cumulative = 0.0;
for (i=0; i<pool->size; i++)
cumulative = cumulative + pool->data[i].worth;
return ((float) cumulative/pool->size);
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;
int lowest;
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));
/* 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;
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, "\nEDGE TABLE\n");
fprintf (fp, "\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;
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)) {
case T_MergePath:
case T_HashPath:
for(i=0; i < indent+1; i++)
for (i = 0; i < indent; 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;
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;
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 (join)
{
int size = path->parent->size;
if (nodeTag(path)==T_IndexPath) {
List *k, *l;
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");
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 (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;
List *l;
printf("______________________________\n");
printf("(");
foreach(l, rel->relids) {
printf("%d ", lfirsti(l));
}
printf("): size=%d width=%d\n", rel->size, rel->width);
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("\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);
printf("\tcheapest path:\n");
geqo_print_path(root, rel->cheapestpath, 1);
}

View File

@ -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;
}
}

View File

@ -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;
int left,
right,
k,
p,
temp;
/* initialize city table */
for (k = 1; k <= num_gene; k++)
city_table[k].used = 0;
/* 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;
}
/* select portion to copy from tour1 */
left = geqo_randint(num_gene - 1, 0);
right = geqo_randint(num_gene - 1, 0);
/* copy portion from tour1 to offspring */
for (k = left; k <= right; k++)
{
offspring[k] = tour1[k];
city_table[(int) tour1[k]].used = 1;
}
if (left > right)
{
temp = left;
left = right;
right = temp;
}
k = (right + 1) % num_gene; /* index into offspring */
p = k; /* index into tour2 */
/* copy portion from tour1 to offspring */
for (k = left; k <= right; k++)
{
offspring[k] = tour1[k];
city_table[(int) tour1[k]].used = 1;
}
/* 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 */
}
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 */
}
}

View File

@ -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;
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;
}
/* 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);
/* 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 */
}
/* 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;
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++;
/* 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++;
}
city_table[k].select_list = city_table[j].select_list;
city_table[j].select_list = -1;
count++;
}
else
count++;
k++;
}
select = 0;
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];
}
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];
}
}

View File

@ -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 )
{
i = next_token(file, buf, sizeof(buf));
if (i != EOF)
{
if (sscanf (buf, "%ld", &RandomSeed) == 1) random_seed = 1;
}
}
/*------------------------------------------- selection bias */
else if ( strcmp(buf, BIAS_TAG) == 0 )
else if (strcmp(buf, RAND_TAG) == 0)
{
i = next_token(file, buf, sizeof(buf));
if (i != EOF)
{
if (sscanf (buf, "%lf", &SelectionBias) == 1) selection_bias = 1;
if (sscanf(buf, "%ld", &RandomSeed) == 1)
random_seed = 1;
}
}
/*------------------------------------------- selection bias */
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;
}
}
/* 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);
}

View File

@ -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;
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);
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);
List *y = NIL;
Path *path = (Path *) NULL;
JoinPath *cheapest = (JoinPath *) NULL;
if(!path->p_ordering.ord.sortop)
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);
}

View File

@ -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;
}
/* locate crossover points */
left = geqo_randint(num_gene-1, 0);
right = geqo_randint(num_gene-1, 0);
for (k = 0; k < num_gene; k++)
{
failed[k] = -1;
from[k] = -1;
check_list[k + 1] = 0;
}
if (left > right) {
temp = left;
left = right;
right = temp;
}
/* locate crossover points */
left = geqo_randint(num_gene - 1, 0);
right = geqo_randint(num_gene - 1, 0);
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 */
for (k = left; k <= right; k++)
{ /* for all elements in the tour1-2 */
if (tour1[k] == tour2[k]) found = 1; /* find match in tour2 */
if (tour1[k] == tour2[k])
found = 1; /* find match in tour2 */
else {
found = 0; /* substitute elements */
else
{
found = 0; /* substitute elements */
j = 0;
while ( !(found) && (j < num_gene) ) {
if ( (offspring[j] == tour1[k]) && (from[j] == DAD) ) {
j = 0;
while (!(found) && (j < num_gene))
{
if ((offspring[j] == tour1[k]) && (from[j] == DAD))
{
check_list[offspring[j]]--;
offspring[j] = tour2[k];
found = 1;
check_list[tour2[k]]++;
}
check_list[offspring[j]]--;
offspring[j] = tour2[k];
found = 1;
check_list[tour2[k]]++;
}
j++;
}
j++;
}
}
}
if ( !(found) ) { /* failed to replace gene */
failed[mx_fail] = (int) tour1[k];
indx[mx_fail] = k;
mx_fail++;
}
if (!(found))
{ /* failed to replace gene */
failed[mx_fail] = (int) tour1[k];
indx[mx_fail] = k;
mx_fail++;
}
} /* ... for */
} /* ... for */
/* STEP 2 */
/* see if any genes could not be replaced */
if (mx_fail > 0) {
mx_hold = mx_fail;
/* see if any genes could not be replaced */
if (mx_fail > 0)
{
mx_hold = mx_fail;
for (k = 0; k < mx_hold; k++) {
found = 0;
for (k = 0; k < mx_hold; k++)
{
found = 0;
j = 0;
while ( !(found) && (j < num_gene) ) {
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]]]++;
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--;
}
found = 1;
failed[k] = -1;
mx_fail--;
}
j++;
}
j++;
}
} /* ... for */
} /* ... for */
} /* ... if */
} /* ... if */
/* STEP 3 */
for (k = 1; k <= num_gene; k++) {
for (k = 1; k <= num_gene; k++)
{
if (check_list[k] > 1) {
i = 0;
if (check_list[k] > 1)
{
i = 0;
while (i < num_gene) {
if ( (offspring[i] == (Gene) k) && (from[i] == DAD) ) {
j = 1;
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;
}
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++;
}
j++;
}
} /* ... if */
} /* ... if */
i++;
} /* end while */
i++;
} /* end while */
}
} /* ... for */
pfree(failed);
pfree(from);
pfree(indx);
pfree(check_list);
}
} /* ... for */
pfree(failed);
pfree(from);
pfree(indx);
pfree(check_list);
}

View File

@ -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;
Chromosome *chromo;
int i;
/* pool */
new_pool = (Pool *) palloc (sizeof(Pool));
new_pool->size = (int) pool_size;
new_pool->string_length = (int) string_length;
/* 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 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));
/* 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;
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);
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));
return (chromo);
chromo = (Chromosome *) palloc(sizeof(Chromosome));
chromo->string = (Gene *) palloc((string_length + 1) * sizeof(Gene));
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;
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;
/* 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 */
/* do a binary search to find the index of the new chromo */
top = 0;
mid = pool->size/2;
bot = pool->size-1;
index = -1;
top = 0;
mid = pool->size / 2;
bot = pool->size - 1;
index = -1;
while (index == -1) {
/* these 4 cases find a new location */
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;
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. */
/*
* 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 */
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 */
/* now we have index for chromo */
/* move every gene from index on down
one position to make room 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 */
/*
* copy new gene into pool storage; always replace worst gene in pool
*/
geqo_copy (&pool->data[pool->size-1], chromo, pool->string_length);
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;
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;
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;
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;
}
swap_chromo.string = tmp_chromo.string;
swap_chromo.worth = tmp_chromo.worth;
}
}

View File

@ -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++;
}
}
}
}
}

View File

@ -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);
}

View File

@ -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);
int first,
second;
if (pool->size > 1) {
while(first==second)
second = (int) linear(pool->size, bias);
}
first = (int) linear(pool->size, bias);
second = (int) linear(pool->size, bias);
geqo_copy (momma, &pool->data[first], pool->string_length);
geqo_copy (daddy, &pool->data[second], pool->string_length);
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);
}

View File

@ -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. */
int number_of_rels = length(root->base_relation_list_);
int number_of_joins = length(join_rels);
int *connectto;
Cost *disttoconnect; /* disttoconnect[i]: distance between i and connectto[i] */
/* 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 dist, /* temporary */
mindist; /* minimal distance between connected and unconnected node */
Cost *disttoconnect; /* disttoconnect[i]: distance
* between i and connectto[i] */
Cost mstlength = 0.0; /* the total length of the minimum spanning tree */
Cost dist, /* temporary */
mindist; /* minimal distance between connected and
* unconnected node */
int count;
int n, /* newly attached node */
nextn, /* next node to be attached */
tempn;
Cost mstlength = 0.0; /* the total length of the minimum
* spanning tree */
int i, id1, id2;
List *r = NIL;
Rel *joinrel = NULL;
Rel **tmprel_array;
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)));
/* 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 */
/* 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)
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? */
}
}
/* 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)
{
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][2];
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);
}
}
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
{
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);
}
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);
}

View File

@ -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;
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) {
/*
* 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.
*/
set_rest_relselec(root, rels);
levels_left = length(rels);
return(find_join_paths(root, rels, levels_left-1));
}
if (levels_left <= 0)
return NIL;
/*
* Find the base relation paths.
*/
find_rel_paths(root, rels);
if (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;
List *temp;
Rel *rel;
List *lastpath;
rel = (Rel *)lfirst(temp);
sequential_scan_list = lcons(create_seqscan_path(rel),
NIL);
foreach(temp, rels)
{
List *sequential_scan_list;
List *rel_index_scan_list;
List *or_index_scan_list;
rel_index_scan_list =
find_index_paths(root,
rel,
find_relation_indices(root,rel),
rel->clauseinfo,
rel->joininfo);
rel = (Rel *) lfirst(temp);
sequential_scan_list = lcons(create_seqscan_path(rel),
NIL);
or_index_scan_list =
create_or_index_paths(root, rel, rel->clauseinfo);
rel_index_scan_list =
find_index_paths(root,
rel,
find_relation_indices(root, rel),
rel->clauseinfo,
rel->joininfo);
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;
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;
List *x;
List *new_rels;
Rel *rel;
/*******************************************
* genetic query optimizer entry point *
* <utesch@aut.tu-freiberg.de> *
*******************************************/
/*******************************************
* 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 */
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 *
*******************************************/
/*******************************************
* 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);
/*
* 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);
find_all_join_paths(root, new_rels);
new_rels = prune_joinrels(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));
#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);
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);
}
if (BushyPlanFlag)
{
foreach(x, new_rels) {
rel = (Rel*)lfirst(x);
if ( rel->size <= 0 )
rel->size = compute_rel_size(rel);
rel->width = compute_rel_width(rel);
/*
* 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
}
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 (BushyPlanFlag)
{
if(levels_left == 1) {
if(BushyPlanFlag)
return(final_join_rels(outer_rels));
/*
* 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;
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)) {
case T_MergePath:
case T_HashPath:
for(i=0; i < indent+1; i++)
for (i = 0; i < indent; 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;
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;
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 (join)
{
int size = path->parent->size;
if (nodeTag(path)==T_IndexPath) {
List *k, *l;
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");
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 (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;
List *l;
printf("(");
foreach(l, rel->relids) {
printf("%d ", lfirsti(l));
}
printf("): size=%d width=%d\n", rel->size, rel->width);
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);
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 */

View File

@ -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;
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;
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;
Cost result = 1.0;
foreach(xclausenode,clauseinfo_list) {
temp = ((CInfo *)lfirst(xclausenode))->selectivity;
result = result * temp;
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);
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);
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);
/*
* 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
{
/*
* 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);
}
/*
* 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.
* 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.
*/
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);
if (length(clauses) < 2)
{
return (s1);
}
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);
{
/* Compute selectivity of the 'or'ed subclauses. */
/* Added check for taking lnext(NIL). -- JMH 3/9/92 */
Cost s2;
} 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.
*/
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));
else
s2 = compute_selec(root, lnext(clauses), NIL);
return(s1 + s2 - s1 * 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);
}
}

View File

@ -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;
temp += Min (relpages, (int)ceil (temp2));
/* expected base relation pages */
temp2 = (reltuples == 0) ? (double) 0 : (double) relpages / reltuples;
temp2 = temp2 * (double) selec *indextuples;
/* per index tuples */
temp = temp + (_cpu_index_page_wight_ * selec * indextuples);
temp += Min(relpages, (int) ceil(temp2));
/* per heap tuples */
temp = temp + (_cpu_page_wight_ * selec * reltuples);
/* per index tuples */
temp = temp + (_cpu_index_page_wight_ * selec * indextuples);
Assert(temp >= 0);
return(temp);
/* per heap tuples */
temp = temp + (_cpu_page_wight_ * selec * reltuples);
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;
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);
if (!_enable_mergesort_)
temp += _disable_cost_;
return(temp);
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);
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);
if (outerpages < innerpages)
return _disable_cost_;
if (!_enable_hashjoin_)
temp += _disable_cost_;
temp += _cpu_page_wight_ * (outersize + nrun * innersize);
Assert(temp >= 0);
/*
* 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);
return(temp);
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;
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);
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;
List *temp_tl;
int tuple_width = 0;
foreach (temp_tl, targetlist) {
tuple_width = tuple_width +
compute_attribute_width(lfirst(temp_tl));
}
return(tuple_width);
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;
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);
temp *= ((Path *) joinpath->outerjoinpath)->parent->size;
temp *= ((Path *) joinpath->innerjoinpath)->parent->size;
return(temp1);
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));
}

View File

@ -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;
List *hashinfo_list = NIL;
CInfo *clauseinfo = (CInfo *) NULL;
List *i = NIL;
Oid hashjoinop = 0;
xhashinfo->jmethod.jmkeys = NIL;
xhashinfo->jmethod.clauses = NIL;
foreach(i, clauseinfo_list)
{
clauseinfo = (CInfo *) lfirst(i);
hashjoinop = clauseinfo->hashjoinoperator;
/* XXX was push */
hashinfo_list = lappend(hashinfo_list,xhashinfo);
hashinfo_list = nreverse(hashinfo_list);
}
/*
* 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->jmethod.clauses =
lcons(clause, xhashinfo->jmethod.clauses);
xhashinfo =
match_hashop_hashinfo(hashjoinop, hashinfo_list);
xhashinfo->jmethod.jmkeys =
lcons(keys, xhashinfo->jmethod.jmkeys);
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);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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);
List *joins = NIL;
List *join_list = NIL;
List *r = NIL;
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_);
foreach(r, outer_rels)
{
Rel *outer_rel = (Rel *) lfirst(r);
join_list = nconc(join_list, joins);
}
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_);
return(join_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;
List *join_list = NIL;
List *i = NIL;
if(!joininfo->inactive) {
List *other_rels = joininfo->otherrels;
foreach(i, joininfo_list)
{
JInfo *joininfo = (JInfo *) lfirst(i);
Rel *rel;
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 (!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);
}
}
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);
}
}
Rel *inner_rel;
List *t_list = NIL;
List *temp_node = NIL;
List *i = NIL;
return(t_list);
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;
Rel *joinrel = makeNode(Rel);
List *joinrel_joininfo_list = NIL;
List *new_outer_tlist;
List *new_inner_tlist;
joinrel->relids = lcons(outer_rel->relids, /* ??? aren't they lists? -ay */
lcons(inner_rel->relids, NIL));
/*
* 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);
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;
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;
set_joinrel_size(joinrel, outer_rel, inner_rel, joininfo);
return(joinrel);
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);
}
}
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;
return(t_list);
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);
List *current_joininfo_list = NIL;
List *new_otherrels = NIL;
JInfo *other_joininfo = (JInfo *) NULL;
List *xjoininfo = NIL;
new_otherrels = joininfo->otherrels;
foreach (or, new_otherrels)
foreach(xjoininfo, joininfo_list)
{
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);
List *or;
JInfo *joininfo = (JInfo *) lfirst(xjoininfo);
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);
}
}
}
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);
return(current_joininfo_list);
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);
}
/*
* 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);
}
}
foreach(xjoinrel, joinrels) {
Rel *joinrel = (Rel *)lfirst(xjoinrel);
List *xjoinrel = NIL;
List *xrelid = NIL;
List *xrel = NIL;
List *xjoininfo = NIL;
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(xjoinrel, joinrels)
{
Rel *joinrel = (Rel *) lfirst(xjoinrel);
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(xrelid, joinrel->relids)
{
Relid relid = (Relid) lfirst(xrelid);
Rel *rel = get_join_rel(root, relid);
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);
}
}
add_superrels(rel, joinrel);
}
}
}
}
foreach(xrel, outerrels) {
Rel *rel = (Rel *)lfirst(xrel);
rel->superrels = NIL;
}
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;
}
}
/*
* 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;
List *xrel = NIL;
List *temp = NIL;
List *t_list = NIL;
foreach (xjoininfo, rel->joininfo) {
JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
/*
* 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;
if (joininfo->otherrels != NIL) {
final = false;
break;
}
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);
}
}
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;
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;
/*
* 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;
}
joinrel->tuples = ntuples;
/*
* 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;
}

View File

@ -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;
}
List *matched_joinkeys = NIL;
List *matched_joinclauses = NIL;
List *pathkey = NIL;
List *i = NIL;
int matched_joinkey_index = -1;
*matchedJoinClausesPtr = nreverse(matched_joinclauses);
return (nreverse(matched_joinkeys));
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;
Path *matched_path = NULL;
bool key_match = false;
List *i = NIL;
foreach(i,paths) {
Path *path = (Path*)lfirst(i);
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) {
key_match = every_func(joinkeys, path->keys, which_subkey);
if (matched_path) {
if (path->path_cost < matched_path->path_cost)
matched_path = path;
} else {
matched_path = path;
}
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;
List *pathkeys = NIL;
List *jk;
/*
* find the right Var in the target list for this key
*/
var = (Var*)extract_subkey(jkey, which_subkey);
key = (Var*)matching_tlvar(var, tlist);
foreach(jk, joinkeys)
{
JoinKey *jkey = (JoinKey *) lfirst(jk);
Var *var,
*key;
List *p;
/*
* 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;
/*
* 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));
}
if (p!=NIL)
continue; /* key already in pathkeys */
pathkeys =
lappend(pathkeys, lcons(key,NIL));
}
return(pathkeys);
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);
}
}
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.
*
* 'subkeys' is a list of subkeys for which matching subkeys are to be
* found
* 'considered-subkeys' is the current list of all subkeys corresponding
* 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)
List *
new_join_pathkeys(List * outer_pathkeys,
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);
List *outer_pathkey = NIL;
List *t_list = NIL;
List *x;
List *i = NIL;
t_list = nconc(t_list,newly_considered_subkeys);
}
return(t_list);
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);
}
/*
/*
* 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.
*
* 'subkeys' is a list of subkeys for which matching subkeys are to be
* found
* 'considered-subkeys' is the current list of all subkeys corresponding
* 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)
{
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))) {
Expr *joinclause = NULL;
List *t_list = NIL;
List *temp = NIL;
List *i = NIL;
Expr *tlist_other_var = (Expr *) NULL;
/* XXX was "push" function */
considered_subkeys = lappend(considered_subkeys,
tlist_other_var);
foreach(i, joinclauses)
{
joinclause = lfirst(i);
tlist_other_var =
matching_tlvar(other_join_clause_var(subkey, joinclause),
join_rel_tlist);
/* 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);
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);
}

View File

@ -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;
List *mergeinfo_list = NIL;
List *xclauseinfo = NIL;
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);
foreach(xclauseinfo, clauseinfo_list)
{
CInfo *clauseinfo = (CInfo *) lfirst(xclauseinfo);
MergeOrder *merge_ordering = clauseinfo->mergesortorder;
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);
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);
}

View File

@ -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;
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);
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);
}
#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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
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);
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);
List *x = NIL;
List *y = NIL;
Path *path = NULL;
Rel *rel = (Rel *) NULL;
JoinPath *cheapest = (JoinPath *) NULL;
if(!path->p_ordering.ord.sortop) {
break;
}
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))));
Rel *rel;
List *joininfo_list,
*xjoininfo;
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)));
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)));
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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);
List *tlist_vars = NIL;
List *l = NIL;
List *tvar = NIL;
tlist_vars = append(tlist_vars, pull_var_clause(entry->expr));
}
foreach(l, tlist)
{
TargetEntry *entry = (TargetEntry *) lfirst(l);
/* 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);
tlist_vars = append(tlist_vars, pull_var_clause(entry->expr));
}
add_tl_element(result, var);
}
/* 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;
List *l;
int varno;
relids = lconsi(varno, NIL);
if (rte->inFromCl &&
!rel_member(relids, root->base_relation_list_)) {
varno = 1;
foreach(l, root->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
List *relids;
Rel *result;
Var *var;
var = makeVar(varno, -2 , 26, varno, -2);
/* add it to base_relation_list_ */
result = get_base_rel(root, varno);
add_tl_element(result, 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);
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.
* 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;
if (length(relids) == 1)
{
Rel *rel = get_base_rel(root, lfirsti(relids));
/* the selectivity of the clause must be computed
regardless of whether it's a restriction or a join clause */
if (is_funcclause((Node*)clause))
{
/*
* 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;
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);
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;
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;
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 (_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;
}
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;
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);
sortable = op_mergesortable(((Oper *) clause->oper)->opno,
(get_leftop(clause))->vartype,
(get_rightop(clause))->vartype,
&leftOp,
&rightOp);
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);
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));
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
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;
Plan *result_plan = (Plan *) NULL;
int rt_index;
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 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);
}
/*
* 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 (special_plans)
result_plan = special_plans;
else
result_plan = init_query_planner(parse); /* regular plans */
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);
}
/*
* 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;
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.
/*
* First make a copy of the tlist so that we don't corrupt the the
* original .
*/
resdom->reskey = keyno;
resdom->reskeyop = get_opcode(sortcl->opoid);
keyno += 1;
}
sortplan = (Plan*)make_sort(temp_tlist,
_TEMP_RELATION_ID_,
(Plan*)plannode,
length(sortcls));
temp_tlist = new_unsorted_tlist(tlist);
/*
* 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....
*/
foreach(i, sortcls)
{
SortClause *sortcl = (SortClause *) lfirst(i);
sortplan->cost = plannode->cost;
return(sortplan);
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....
*/
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;
List *primary_qual;
List *existential_qual;
Existential *exist_plan;
List *tlist = root->targetList;
tlist = preprocess_targetlist(tlist,
root->commandType,
root->resultRelation,
root->rtable);
tlist = preprocess_targetlist(tlist,
root->commandType,
root->resultRelation,
root->rtable);
primary_qual =
preprocess_qualification((Expr*)root->qual,
tlist,
&existential_qual);
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;
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);
}
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;
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];
/* 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) {
/*
* 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");
}
{
if (cmd == CMD_SELECT)
elog(WARN,
"function declared with no return type, but final query is a retrieve");
else
return;
}
/* 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);
/* 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 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.
*/
/*
* 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));
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)));
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;
}
/* 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;
}
/*
* 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));
/*
* 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));
if (!RelationIsValid(reln))
elog(WARN, "cannot open relation relid %d", get_typrelid(typ));
relid = reln->rd_id;
relnatts = reln->rd_rel->relnatts;
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));
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;
/* 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);
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 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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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));
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
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);
if (result_relation >= 1 && command_type != CMD_SELECT)
{
relid = getrelid(result_relation, range_table);
}
/* 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 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);
/* ------------------
* 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;
/* XXX should the fix-opids be this early?? */
/* was mapCAR */
foreach(temp, expanded_tlist)
{
TargetEntry *tle = lfirst(temp);
resdom = makeResdom(length(t_list) + 1,
27,
6,
"ctid",
0,
0,
1);
if (tle->expr)
fix_opid(tle->expr);
}
t_list = copyObject(expanded_tlist);
var = makeVar(result_relation, -1, 27, result_relation, -1);
/* ------------------
* 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;
ctid = makeNode(TargetEntry);
ctid->resdom = resdom;
ctid->expr = (Node *)var;
t_list = lappend(t_list, ctid);
}
resdom = makeResdom(length(t_list) + 1,
27,
6,
"ctid",
0,
0,
1);
return(t_list);
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);
NodeTag node_type = T_Invalid;
return (replace_matching_resname(ntlist, tlist));
} else {
return (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;
switch (command_type)
{
case CMD_INSERT:
node_type = (NodeTag) T_Const;
break;
case CMD_UPDATE:
node_type = (NodeTag) T_Var;
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);
}
}
/*
* 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;
if (node_type != T_Invalid)
{
List *ntlist = new_relation_targetlist(relid,
result_relation,
node_type);
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 (replace_matching_resname(ntlist, tlist));
}
else
{
return (tlist);
}
}
return (t_list);
}
/*
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;
}
}
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);
}
}
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); */
AttrNumber attno;
List *t_list = NIL;
char *attname;
Oid atttype = 0;
int16 typlen = 0;
bool attisset = false;
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);
/* 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;
}
}
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);
return (t_list);
}

View File

@ -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;
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;
#if 0
case UNION_FLAG:
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;
}
case VERSION_FLAG:
union_relids = VersionGetParents(rt_entry->relid);
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;
}
case ARCHIVE_FLAG:
union_relids = find_archive_rels(rt_entry->relid);
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.
*/
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);
default:
/* do nothing */
break;
}
union_plans = lappend(union_plans, planner(new_root));
union_rtentries = lappend(union_rtentries, new_rt_entry);
}
/*
* 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;
}
*union_rtentriesPtr = union_rtentries;
return(union_plans);
/*
* 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.
*/
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);
}
union_plans = lappend(union_plans, planner(new_root));
union_rtentries = lappend(union_rtentries, new_rt_entry);
}
*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;
if (node == NULL)
return;
/* 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:
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);
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;
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);
return (node);
}

View File

@ -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;
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);
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;
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;
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);
}
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;
List *result1 = NIL;
List *result2 = NIL;
List *result3 = NIL;
List *temp;
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_);
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;
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);
foreach(i, clauseinfo_list)
{
temp = (CInfo *) lfirst(i);
result =
lappendi(result,
(((Oper *) temp->clause->oper)->opno));
}
return (result);
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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;
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);
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;
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;
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);
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;
TargetEntry *tlentry = NULL;
if (var) {
List *temp;
foreach (temp,tlist) {
if ((*test)(var, get_expr(lfirst(temp)))) {
tlentry = lfirst(temp);
break;
}
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;
List *retval = NIL;
Assert (index_keys != NULL);
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);
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);
}

View File

@ -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 true;
if (!path_ordering1 || !path_ordering2)
return false;
if (!path_ordering1 || !path_ordering2)
return false;
if (path_ordering1->ordtype == MERGE_ORDER &&
path_ordering2->ordtype == MERGE_ORDER) {
if (path_ordering1->ordtype == MERGE_ORDER &&
path_ordering2->ordtype == MERGE_ORDER)
{
return equal(path_ordering1->ord.merge, path_ordering2->ord.merge);
return equal(path_ordering1->ord.merge, path_ordering2->ord.merge);
} else if (path_ordering1->ordtype == SORTOP_ORDER &&
path_ordering2->ordtype == SORTOP_ORDER) {
}
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
(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_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));
}
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 == 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[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;
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++;
}
if (ordering1 == NULL || ordering2 == NULL)
return (ordering1 == ordering2);
return (ordering1[i]==0 && ordering2[i]==0);
while (ordering1[i] != 0 && ordering2[i] != 0)
{
if (ordering1[i] != ordering2[i])
break;
i++;
}
return (ordering1[i] == 0 && ordering2[i] == 0);
}

View File

@ -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;
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);
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));
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;
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);
/*
* 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 ((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;
}
}
return(retval);
else
{
*noOther = false;
if (path_is_cheaper(new_path, old_path))
{
retval = old_path;
}
}
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;
int relid = 0;
Path *pathnode = makeNode(Path);
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);
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;
if (rel->relids !=NULL)
relid = lfirsti(rel->relids);
/*
* copy clauseinfo list into path for expensive function processing --
* JMH, 7/7/92
*/
pathnode->locclauseinfo =
(List *) copyObject((Node *) rel->clauseinfo);
pathnode->path_cost = cost_seqscan (relid,
rel->pages, rel->tuples);
/* add in expensive functions cost! -- JMH, 7/7/92 */
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;
IndexPath *pathnode = makeNode(IndexPath);
pathnode->indexid = index->relids;
pathnode->indexkeys = index->indexkeys;
pathnode->indexqual = NIL;
pathnode->path.pathtype = T_IndexScan;
pathnode->path.parent = rel;
pathnode->path.p_ordering.ordtype = SORTOP_ORDER;
pathnode->path.p_ordering.ord.sortop = index->ordering;
/* 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);
pathnode->indexid = index->relids;
pathnode->indexkeys = index->indexkeys;
pathnode->indexqual = NIL;
/*
* 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);
/*
* 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;
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);
/*
* 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;
}
} 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
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;
}
else
{
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);
/*
* 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;
JoinPath *pathnode = makeNode(JoinPath);
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;
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;
}
} 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 */
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);
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 */
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);
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 */
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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
/*
* 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;
}
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;
/*
* get_join_rel--
* 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)
{
return rel_member(relid, root->join_relation_list_);
}
root->base_relation_list_ = lcons(rel,
root->base_relation_list_);
/*
* rel-member--
* 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)
{
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)));
/*
* ??? 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(NULL);
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.
*
*/
Rel *
get_join_rel(Query * root, List * relid)
{
return rel_member(relid, root->join_relation_list_);
}
/*
* rel-member--
* 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)
{
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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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);
List *i,
*result = NIL;
switch (nodeTag(me)) {
case T_List:
foreach (i, (List*)me) {
result = nconc(result, pull_varnos(lfirst(i)));
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.
*/
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)))
return TRUE;
}
return FALSE;
} 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;
} 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;
}
/*
* 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.
*/
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);
}
/*
* var_equal
*
* Returns t iff two var nodes correspond to the same attribute.
* 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
var_equal(Var *var1, Var *var2)
contain_var_clause(Node * clause)
{
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)) {
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;
return(true);
} else
return(false);
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)))
return TRUE;
}
return FALSE;
}
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;
}
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;
}
/*
* 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.
*/
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);
}
/*
* var_equal
*
* Returns t iff two var nodes correspond to the same attribute.
*/
bool
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);
}