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:
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
@ -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
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user