pgindent run over code.
This commit is contained in:
parent
4b04b01aaa
commit
07842084fe
|
@ -43,8 +43,8 @@ array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
|
||||||
int ndim,
|
int ndim,
|
||||||
*dim;
|
*dim;
|
||||||
char *p;
|
char *p;
|
||||||
FmgrInfo finf; /*Tobias Gabele Jan 18 1999*/
|
FmgrInfo finf; /* Tobias Gabele Jan 18 1999 */
|
||||||
|
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
if ((array == (ArrayType *) NULL)
|
if ((array == (ArrayType *) NULL)
|
||||||
|
@ -75,9 +75,9 @@ array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
|
||||||
|
|
||||||
/* Lookup the function entry point */
|
/* Lookup the function entry point */
|
||||||
proc_fn = (func_ptr) NULL;
|
proc_fn = (func_ptr) NULL;
|
||||||
fmgr_info(proc,&finf); /*Tobias Gabele Jan 18 1999*/
|
fmgr_info(proc, &finf); /* Tobias Gabele Jan 18 1999 */
|
||||||
proc_fn=finf.fn_addr; /*Tobias Gabele Jan 18 1999*/
|
proc_fn = finf.fn_addr; /* Tobias Gabele Jan 18 1999 */
|
||||||
pronargs=finf.fn_nargs; /*Tobias Gabele Jan 18 1999*/
|
pronargs = finf.fn_nargs; /* Tobias Gabele Jan 18 1999 */
|
||||||
if ((proc_fn == NULL) || (pronargs != 2))
|
if ((proc_fn == NULL) || (pronargs != 2))
|
||||||
{
|
{
|
||||||
elog(ERROR, "array_iterator: fmgr_info lookup failed for oid %d", proc);
|
elog(ERROR, "array_iterator: fmgr_info lookup failed for oid %d", proc);
|
||||||
|
@ -110,38 +110,26 @@ array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
|
||||||
{
|
{
|
||||||
result = (int) (*proc_fn) (p, value);
|
result = (int) (*proc_fn) (p, value);
|
||||||
if (typlen > 0)
|
if (typlen > 0)
|
||||||
{
|
|
||||||
p += typlen;
|
p += typlen;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
p += INTALIGN(*(int32 *) p);
|
p += INTALIGN(*(int32 *) p);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
if (!and)
|
if (!and)
|
||||||
{
|
|
||||||
return (1);
|
return (1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (and)
|
if (and)
|
||||||
{
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (and && result)
|
if (and && result)
|
||||||
{
|
|
||||||
return (1);
|
return (1);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -344,7 +332,7 @@ int32
|
||||||
array_oideq(ArrayType *array, Oid value)
|
array_oideq(ArrayType *array, Oid value)
|
||||||
{
|
{
|
||||||
return array_iterator((Oid) 26, /* oid */
|
return array_iterator((Oid) 26, /* oid */
|
||||||
(Oid) 184, /* oideq */
|
(Oid) 184, /* oideq */
|
||||||
0, /* logical or */
|
0, /* logical or */
|
||||||
array, (Datum) value);
|
array, (Datum) value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
#ifndef ARRAY_ITERATOR_H
|
#ifndef ARRAY_ITERATOR_H
|
||||||
#define ARRAY_ITERATOR_H
|
#define ARRAY_ITERATOR_H
|
||||||
|
|
||||||
static int32
|
static int32 array_iterator(Oid elemtype, Oid proc, int and,
|
||||||
array_iterator(Oid elemtype, Oid proc, int and,
|
|
||||||
ArrayType *array, Datum value);
|
ArrayType *array, Datum value);
|
||||||
int32 array_texteq(ArrayType *array, char *value);
|
int32 array_texteq(ArrayType *array, char *value);
|
||||||
int32 array_all_texteq(ArrayType *array, char *value);
|
int32 array_all_texteq(ArrayType *array, char *value);
|
||||||
|
@ -24,6 +23,7 @@ int32 array_int4lt(ArrayType *array, int4 value);
|
||||||
int32 array_all_int4lt(ArrayType *array, int4 value);
|
int32 array_all_int4lt(ArrayType *array, int4 value);
|
||||||
int32 array_int4le(ArrayType *array, int4 value);
|
int32 array_int4le(ArrayType *array, int4 value);
|
||||||
int32 array_all_int4le(ArrayType *array, int4 value);
|
int32 array_all_int4le(ArrayType *array, int4 value);
|
||||||
int32 array_oideq(ArrayType *array, Oid value);
|
int32 array_oideq(ArrayType *array, Oid value);
|
||||||
int32 array_all_oidne(ArrayType *array, Oid value);
|
int32 array_all_oidne(ArrayType *array, Oid value);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -225,8 +225,8 @@ currentdate()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
* tab-width: 4
|
* tab-width: 4
|
||||||
* c-indent-level: 4
|
* c-indent-level: 4
|
||||||
* c-basic-offset: 4
|
* c-basic-offset: 4
|
||||||
* End:
|
* End:
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,23 +4,24 @@
|
||||||
|
|
||||||
#include <postgres.h>
|
#include <postgres.h>
|
||||||
#include <utils/geo_decls.h> /* for Pt */
|
#include <utils/geo_decls.h> /* for Pt */
|
||||||
#include <utils/palloc.h> /* for palloc */
|
#include <utils/palloc.h> /* for palloc */
|
||||||
|
|
||||||
/* Earth's radius is in statute miles. */
|
/* Earth's radius is in statute miles. */
|
||||||
const EARTH_RADIUS = 3958.747716;
|
const EARTH_RADIUS = 3958.747716;
|
||||||
const TWO_PI = 2.0 * M_PI;
|
const TWO_PI = 2.0 * M_PI;
|
||||||
|
|
||||||
/******************************************************
|
/******************************************************
|
||||||
*
|
*
|
||||||
* degtorad - convert degrees to radians
|
* degtorad - convert degrees to radians
|
||||||
*
|
*
|
||||||
* arg: double, angle in degrees
|
* arg: double, angle in degrees
|
||||||
*
|
*
|
||||||
* returns: double, same angle in radians
|
* returns: double, same angle in radians
|
||||||
******************************************************/
|
******************************************************/
|
||||||
|
|
||||||
static double
|
static double
|
||||||
degtorad (double degrees) {
|
degtorad(double degrees)
|
||||||
|
{
|
||||||
return (degrees / 360.0) * TWO_PI;
|
return (degrees / 360.0) * TWO_PI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,36 +31,40 @@ degtorad (double degrees) {
|
||||||
* geo_distance - distance between points
|
* geo_distance - distance between points
|
||||||
*
|
*
|
||||||
* args:
|
* args:
|
||||||
* a pair of points - for each point,
|
* a pair of points - for each point,
|
||||||
* x-coordinate is longitude in degrees west of Greenwich
|
* x-coordinate is longitude in degrees west of Greenwich
|
||||||
* y-coordinate is latitude in degrees above equator
|
* y-coordinate is latitude in degrees above equator
|
||||||
*
|
*
|
||||||
* returns: double
|
* returns: double
|
||||||
* distance between the points in miles on earth's surface
|
* distance between the points in miles on earth's surface
|
||||||
******************************************************/
|
******************************************************/
|
||||||
|
|
||||||
double *
|
double *
|
||||||
geo_distance (Point *pt1, Point *pt2) {
|
geo_distance(Point *pt1, Point *pt2)
|
||||||
|
{
|
||||||
|
|
||||||
double long1, lat1, long2, lat2;
|
double long1,
|
||||||
double longdiff;
|
lat1,
|
||||||
double * resultp = palloc (sizeof(double));
|
long2,
|
||||||
|
lat2;
|
||||||
|
double longdiff;
|
||||||
|
double *resultp = palloc(sizeof(double));
|
||||||
|
|
||||||
/* convert degrees to radians */
|
/* convert degrees to radians */
|
||||||
|
|
||||||
long1 = degtorad (pt1->x);
|
long1 = degtorad(pt1->x);
|
||||||
lat1 = degtorad (pt1->y);
|
lat1 = degtorad(pt1->y);
|
||||||
|
|
||||||
long2 = degtorad (pt2->x);
|
long2 = degtorad(pt2->x);
|
||||||
lat2 = degtorad (pt2->y);
|
lat2 = degtorad(pt2->y);
|
||||||
|
|
||||||
/* compute difference in longitudes - want < 180 degrees */
|
/* compute difference in longitudes - want < 180 degrees */
|
||||||
longdiff = fabs (long1 - long2);
|
longdiff = fabs(long1 - long2);
|
||||||
if (longdiff > M_PI)
|
if (longdiff > M_PI)
|
||||||
longdiff = TWO_PI - longdiff;
|
longdiff = TWO_PI - longdiff;
|
||||||
|
|
||||||
* resultp = EARTH_RADIUS * acos
|
*resultp = EARTH_RADIUS * acos
|
||||||
(sin (lat1) * sin (lat2) + cos (lat1) * cos (lat2) * cos (longdiff));
|
(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(longdiff));
|
||||||
|
|
||||||
return resultp;
|
return resultp;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
#include <libpq-fe.h>
|
#include <libpq-fe.h>
|
||||||
#include "pginterface.h"
|
#include "pginterface.h"
|
||||||
|
|
||||||
PGresult *attres, *relres;
|
PGresult *attres,
|
||||||
|
*relres;
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
|
@ -55,7 +56,7 @@ main(int argc, char **argv)
|
||||||
");
|
");
|
||||||
doquery("FETCH ALL IN c_relations");
|
doquery("FETCH ALL IN c_relations");
|
||||||
relres = get_result();
|
relres = get_result();
|
||||||
|
|
||||||
set_result(attres);
|
set_result(attres);
|
||||||
while (fetch(typname, relname, attname) != END_OF_TUPLES)
|
while (fetch(typname, relname, attname) != END_OF_TUPLES)
|
||||||
{
|
{
|
||||||
|
@ -65,17 +66,17 @@ main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
unset_result(relres);
|
unset_result(relres);
|
||||||
if (strcmp(typname, "oid") == 0)
|
if (strcmp(typname, "oid") == 0)
|
||||||
sprintf(query,"\
|
sprintf(query, "\
|
||||||
DECLARE c_matches BINARY CURSOR FOR \
|
DECLARE c_matches BINARY CURSOR FOR \
|
||||||
SELECT count(*)
|
SELECT count(*) \
|
||||||
FROM %s t1, %s t2 \
|
FROM % s t1, %s t2 \
|
||||||
WHERE t1.%s = t2.oid", relname, relname2, attname);
|
WHERE t1.% s = t2.oid ", relname, relname2, attname);
|
||||||
else
|
else
|
||||||
sprintf(query,"\
|
sprintf(query, "\
|
||||||
DECLARE c_matches BINARY CURSOR FOR \
|
DECLARE c_matches BINARY CURSOR FOR \
|
||||||
SELECT count(*)
|
SELECT count(*) \
|
||||||
FROM %s t1, %s t2 \
|
FROM % s t1, %s t2 \
|
||||||
WHERE RegprocToOid(t1.%s) = t2.oid", relname, relname2, attname);
|
WHERE RegprocToOid(t1.% s) = t2.oid ", relname, relname2, attname);
|
||||||
|
|
||||||
doquery(query);
|
doquery(query);
|
||||||
doquery("FETCH ALL IN c_matches");
|
doquery("FETCH ALL IN c_matches");
|
||||||
|
@ -96,7 +97,7 @@ main(int argc, char **argv)
|
||||||
doquery("CLOSE c_attributes");
|
doquery("CLOSE c_attributes");
|
||||||
PQclear(attres);
|
PQclear(attres);
|
||||||
unset_result(attres);
|
unset_result(attres);
|
||||||
|
|
||||||
doquery("COMMIT WORK");
|
doquery("COMMIT WORK");
|
||||||
|
|
||||||
disconnectdb();
|
disconnectdb();
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "executor/spi.h"
|
#include "executor/spi.h"
|
||||||
#include "commands/trigger.h"
|
#include "commands/trigger.h"
|
||||||
#include <ctype.h> /* tolower */
|
#include <ctype.h> /* tolower */
|
||||||
#include <stdio.h> /* debugging */
|
#include <stdio.h> /* debugging */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Trigger function takes 2 arguments:
|
* Trigger function takes 2 arguments:
|
||||||
1. relation in which to store the substrings
|
1. relation in which to store the substrings
|
||||||
2. field to extract substrings from
|
2. field to extract substrings from
|
||||||
|
|
||||||
The relation in which to insert *must* have the following layout:
|
The relation in which to insert *must* have the following layout:
|
||||||
|
|
||||||
string varchar(#)
|
string varchar(#)
|
||||||
id oid
|
id oid
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -24,9 +24,9 @@ create index title_fti_idx on title_fti (string);
|
||||||
|
|
||||||
create trigger title_fti_trigger after update or insert or delete on product
|
create trigger title_fti_trigger after update or insert or delete on product
|
||||||
for each row execute procedure fti(title_fti, title);
|
for each row execute procedure fti(title_fti, title);
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
where to store index in
|
where to store index in
|
||||||
^^^^^
|
^^^^^
|
||||||
which column to index
|
which column to index
|
||||||
|
|
||||||
ofcourse don't forget to create an index on title_idx, column string, else
|
ofcourse don't forget to create an index on title_idx, column string, else
|
||||||
|
@ -39,8 +39,8 @@ select p.* from product p, title_fti f1, title_fti f2 where
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
march 4 1998 Changed breakup() to return less substrings. Only breakup
|
march 4 1998 Changed breakup() to return less substrings. Only breakup
|
||||||
in word parts which are in turn shortened from the start
|
in word parts which are in turn shortened from the start
|
||||||
of the word (ie. word, ord, rd)
|
of the word (ie. word, ord, rd)
|
||||||
Did allocation of substring buffer outside of breakup()
|
Did allocation of substring buffer outside of breakup()
|
||||||
oct. 5 1997, fixed a bug in string breakup (where there are more nonalpha
|
oct. 5 1997, fixed a bug in string breakup (where there are more nonalpha
|
||||||
|
@ -62,14 +62,14 @@ select p.* from product p, title_fti f1, title_fti f2 where
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HeapTuple fti(void);
|
HeapTuple fti(void);
|
||||||
char *breakup(char*, char*);
|
char *breakup(char *, char *);
|
||||||
bool is_stopword(char*);
|
bool is_stopword(char *);
|
||||||
|
|
||||||
bool new_tuple = false;
|
bool new_tuple = false;
|
||||||
|
|
||||||
|
|
||||||
/* THIS LIST MUST BE IN SORTED ORDER, A BINARY SEARCH IS USED!!!! */
|
/* THIS LIST MUST BE IN SORTED ORDER, A BINARY SEARCH IS USED!!!! */
|
||||||
char *StopWords[] = { /* list of words to skip in indexing */
|
char *StopWords[] = { /* list of words to skip in indexing */
|
||||||
#ifdef SAMPLE_STOP_WORDS
|
#ifdef SAMPLE_STOP_WORDS
|
||||||
"no"
|
"no"
|
||||||
"the",
|
"the",
|
||||||
|
@ -88,7 +88,7 @@ typedef struct
|
||||||
static EPlan *InsertPlans = NULL;
|
static EPlan *InsertPlans = NULL;
|
||||||
static EPlan *DeletePlans = NULL;
|
static EPlan *DeletePlans = NULL;
|
||||||
static int nInsertPlans = 0;
|
static int nInsertPlans = 0;
|
||||||
static int nDeletePlans = 0;
|
static int nDeletePlans = 0;
|
||||||
|
|
||||||
static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
|
static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
|
||||||
|
|
||||||
|
@ -96,28 +96,28 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
|
||||||
HeapTuple
|
HeapTuple
|
||||||
fti()
|
fti()
|
||||||
{
|
{
|
||||||
Trigger *trigger; /* to get trigger name */
|
Trigger *trigger; /* to get trigger name */
|
||||||
int nargs; /* # of arguments */
|
int nargs; /* # of arguments */
|
||||||
char **args; /* arguments */
|
char **args; /* arguments */
|
||||||
char *relname; /* triggered relation name */
|
char *relname; /* triggered relation name */
|
||||||
Relation rel; /* triggered relation */
|
Relation rel; /* triggered relation */
|
||||||
char *indexname; /* name of table for substrings */
|
char *indexname; /* name of table for substrings */
|
||||||
HeapTuple rettuple = NULL;
|
HeapTuple rettuple = NULL;
|
||||||
TupleDesc tupdesc; /* tuple description */
|
TupleDesc tupdesc; /* tuple description */
|
||||||
bool isinsert=false;
|
bool isinsert = false;
|
||||||
bool isdelete=false;
|
bool isdelete = false;
|
||||||
int ret;
|
int ret;
|
||||||
char query[8192];
|
char query[8192];
|
||||||
Oid oid;
|
Oid oid;
|
||||||
/*
|
|
||||||
FILE *debug;
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
debug = fopen("/dev/xconsole", "w");
|
* FILE *debug;
|
||||||
fprintf(debug, "FTI: entered function\n");
|
*/
|
||||||
fflush(debug);
|
|
||||||
*/
|
/*
|
||||||
|
* debug = fopen("/dev/xconsole", "w"); fprintf(debug, "FTI: entered
|
||||||
|
* function\n"); fflush(debug);
|
||||||
|
*/
|
||||||
|
|
||||||
if (!CurrentTriggerData)
|
if (!CurrentTriggerData)
|
||||||
elog(ERROR, "Full Text Indexing: triggers are not initialized");
|
elog(ERROR, "Full Text Indexing: triggers are not initialized");
|
||||||
|
@ -127,47 +127,53 @@ fti()
|
||||||
elog(ERROR, "Full Text Indexing: must be fired AFTER event");
|
elog(ERROR, "Full Text Indexing: must be fired AFTER event");
|
||||||
|
|
||||||
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
|
||||||
isinsert=true;
|
isinsert = true;
|
||||||
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
||||||
{ isdelete=true;isinsert=true;}
|
{
|
||||||
|
isdelete = true;
|
||||||
|
isinsert = true;
|
||||||
|
}
|
||||||
if (TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event))
|
||||||
isdelete=true;
|
isdelete = true;
|
||||||
|
|
||||||
trigger = CurrentTriggerData->tg_trigger;
|
trigger = CurrentTriggerData->tg_trigger;
|
||||||
rel = CurrentTriggerData->tg_relation;
|
rel = CurrentTriggerData->tg_relation;
|
||||||
relname = SPI_getrelname(rel);
|
relname = SPI_getrelname(rel);
|
||||||
rettuple=CurrentTriggerData->tg_trigtuple;
|
rettuple = CurrentTriggerData->tg_trigtuple;
|
||||||
if (isdelete&&isinsert) /* is an UPDATE */
|
if (isdelete && isinsert) /* is an UPDATE */
|
||||||
rettuple=CurrentTriggerData->tg_newtuple;
|
rettuple = CurrentTriggerData->tg_newtuple;
|
||||||
|
|
||||||
CurrentTriggerData = NULL; /* invalidate 'normal' calls to this function */
|
CurrentTriggerData = NULL; /* invalidate 'normal' calls to this
|
||||||
|
* function */
|
||||||
|
|
||||||
|
if ((ret = SPI_connect()) < 0)
|
||||||
|
elog(ERROR, "Full Text Indexing: SPI_connect failed, returned %d\n", ret);
|
||||||
|
|
||||||
if ((ret = SPI_connect()) <0)
|
|
||||||
elog(ERROR,"Full Text Indexing: SPI_connect failed, returned %d\n",ret);
|
|
||||||
|
|
||||||
nargs = trigger->tgnargs;
|
nargs = trigger->tgnargs;
|
||||||
if (nargs != 2)
|
if (nargs != 2)
|
||||||
elog(ERROR, "Full Text Indexing: trigger can only have 2 arguments");
|
elog(ERROR, "Full Text Indexing: trigger can only have 2 arguments");
|
||||||
|
|
||||||
args = trigger->tgargs;
|
args = trigger->tgargs;
|
||||||
indexname = args[0];
|
indexname = args[0];
|
||||||
tupdesc = rel->rd_att; /* what the tuple looks like (?) */
|
tupdesc = rel->rd_att; /* what the tuple looks like (?) */
|
||||||
|
|
||||||
/* get oid of current tuple, needed by all, so place here */
|
/* get oid of current tuple, needed by all, so place here */
|
||||||
oid = rettuple->t_data->t_oid;
|
oid = rettuple->t_data->t_oid;
|
||||||
if (!OidIsValid(oid))
|
if (!OidIsValid(oid))
|
||||||
elog(ERROR,"Full Text Indexing: oid of current tuple is NULL");
|
elog(ERROR, "Full Text Indexing: oid of current tuple is NULL");
|
||||||
|
|
||||||
if (isdelete) {
|
if (isdelete)
|
||||||
void *pplan;
|
{
|
||||||
Oid *argtypes;
|
void *pplan;
|
||||||
Datum values[1];
|
Oid *argtypes;
|
||||||
EPlan *plan;
|
Datum values[1];
|
||||||
|
EPlan *plan;
|
||||||
|
|
||||||
sprintf(query, "D%s$%s", args[0], args[1]);
|
sprintf(query, "D%s$%s", args[0], args[1]);
|
||||||
plan = find_plan(query, &DeletePlans, &nDeletePlans);
|
plan = find_plan(query, &DeletePlans, &nDeletePlans);
|
||||||
if (plan->nplans <= 0) {
|
if (plan->nplans <= 0)
|
||||||
argtypes = (Oid *)palloc(sizeof(Oid));
|
{
|
||||||
|
argtypes = (Oid *) palloc(sizeof(Oid));
|
||||||
|
|
||||||
argtypes[0] = OIDOID;
|
argtypes[0] = OIDOID;
|
||||||
|
|
||||||
|
@ -181,7 +187,7 @@ fti()
|
||||||
elog(ERROR, "Full Text Indexing: SPI_saveplan returned NULL "
|
elog(ERROR, "Full Text Indexing: SPI_saveplan returned NULL "
|
||||||
"in delete");
|
"in delete");
|
||||||
|
|
||||||
plan->splan = (void **)malloc(sizeof(void*));
|
plan->splan = (void **) malloc(sizeof(void *));
|
||||||
*(plan->splan) = pplan;
|
*(plan->splan) = pplan;
|
||||||
plan->nplans = 1;
|
plan->nplans = 1;
|
||||||
}
|
}
|
||||||
|
@ -192,26 +198,29 @@ fti()
|
||||||
if (ret != SPI_OK_DELETE)
|
if (ret != SPI_OK_DELETE)
|
||||||
elog(ERROR, "Full Text Indexing: error executing plan in delete");
|
elog(ERROR, "Full Text Indexing: error executing plan in delete");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isinsert) {
|
if (isinsert)
|
||||||
char *substring, *column;
|
{
|
||||||
void *pplan;
|
char *substring,
|
||||||
Oid *argtypes;
|
*column;
|
||||||
Datum values[2];
|
void *pplan;
|
||||||
int colnum;
|
Oid *argtypes;
|
||||||
|
Datum values[2];
|
||||||
|
int colnum;
|
||||||
struct varlena *data;
|
struct varlena *data;
|
||||||
EPlan *plan;
|
EPlan *plan;
|
||||||
|
|
||||||
sprintf(query, "I%s$%s", args[0], args[1]);
|
sprintf(query, "I%s$%s", args[0], args[1]);
|
||||||
plan = find_plan(query, &InsertPlans, &nInsertPlans);
|
plan = find_plan(query, &InsertPlans, &nInsertPlans);
|
||||||
|
|
||||||
/* no plan yet, so allocate mem for argtypes */
|
/* no plan yet, so allocate mem for argtypes */
|
||||||
if (plan->nplans <= 0) {
|
if (plan->nplans <= 0)
|
||||||
argtypes = (Oid *)palloc(2*sizeof(Oid));
|
{
|
||||||
|
argtypes = (Oid *) palloc(2 * sizeof(Oid));
|
||||||
|
|
||||||
argtypes[0] = VARCHAROID; /*create table t_name
|
argtypes[0] = VARCHAROID; /* create table t_name (string
|
||||||
(string varchar, */
|
* varchar, */
|
||||||
argtypes[1] = OIDOID; /* id oid); */
|
argtypes[1] = OIDOID; /* id oid); */
|
||||||
|
|
||||||
/* prepare plan to gain speed */
|
/* prepare plan to gain speed */
|
||||||
sprintf(query, "INSERT INTO %s (string, id) VALUES ($1, $2)",
|
sprintf(query, "INSERT INTO %s (string, id) VALUES ($1, $2)",
|
||||||
|
@ -226,45 +235,49 @@ fti()
|
||||||
elog(ERROR, "Full Text Indexing: SPI_saveplan returned NULL"
|
elog(ERROR, "Full Text Indexing: SPI_saveplan returned NULL"
|
||||||
" in insert");
|
" in insert");
|
||||||
|
|
||||||
plan->splan = (void **)malloc(sizeof(void*));
|
plan->splan = (void **) malloc(sizeof(void *));
|
||||||
*(plan->splan) = pplan;
|
*(plan->splan) = pplan;
|
||||||
plan->nplans = 1;
|
plan->nplans = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* prepare plan for query */
|
/* prepare plan for query */
|
||||||
colnum=SPI_fnumber(tupdesc, args[1]);
|
colnum = SPI_fnumber(tupdesc, args[1]);
|
||||||
if (colnum == SPI_ERROR_NOATTRIBUTE)
|
if (colnum == SPI_ERROR_NOATTRIBUTE)
|
||||||
elog(ERROR, "Full Text Indexing: column '%s' of '%s' not found",
|
elog(ERROR, "Full Text Indexing: column '%s' of '%s' not found",
|
||||||
args[1], args[0]);
|
args[1], args[0]);
|
||||||
|
|
||||||
/* Get the char* representation of the column with name args[1] */
|
/* Get the char* representation of the column with name args[1] */
|
||||||
column = SPI_getvalue(rettuple, tupdesc, colnum);
|
column = SPI_getvalue(rettuple, tupdesc, colnum);
|
||||||
|
|
||||||
if (column) { /* make sure we don't try to index NULL's */
|
if (column)
|
||||||
char *buff;
|
{ /* make sure we don't try to index NULL's */
|
||||||
char *string = column;
|
char *buff;
|
||||||
|
char *string = column;
|
||||||
while(*string != '\0') { /* placed 'really' inline. */
|
|
||||||
*string = tolower(*string); /* some compilers will choke */
|
while (*string != '\0')
|
||||||
string++; /* on 'inline' keyword */
|
{ /* placed 'really' inline. */
|
||||||
|
*string = tolower(*string); /* some compilers will
|
||||||
|
* choke */
|
||||||
|
string++; /* on 'inline' keyword */
|
||||||
}
|
}
|
||||||
|
|
||||||
data = (struct varlena*)palloc(sizeof(int32)+strlen(column)+1);
|
data = (struct varlena *) palloc(sizeof(int32) + strlen(column) +1);
|
||||||
buff = palloc(strlen(column) + 1);
|
buff = palloc(strlen(column) + 1);
|
||||||
/* saves lots of calls in while-loop and in breakup()*/
|
/* saves lots of calls in while-loop and in breakup() */
|
||||||
|
|
||||||
new_tuple=true;
|
new_tuple = true;
|
||||||
while ((substring = breakup(column, buff))) {
|
while ((substring = breakup(column, buff)))
|
||||||
int l;
|
{
|
||||||
|
int l;
|
||||||
|
|
||||||
l = strlen(substring);
|
l = strlen(substring);
|
||||||
|
|
||||||
data->vl_len = l+sizeof(int32);
|
data->vl_len = l + sizeof(int32);
|
||||||
memcpy(VARDATA(data), substring, l);
|
memcpy(VARDATA(data), substring, l);
|
||||||
values[0] = PointerGetDatum(data);
|
values[0] = PointerGetDatum(data);
|
||||||
values[1] = oid;
|
values[1] = oid;
|
||||||
|
|
||||||
ret = SPI_execp(*(plan->splan), values, NULL, 0);
|
ret = SPI_execp(*(plan->splan), values, NULL, 0);
|
||||||
if (ret != SPI_OK_INSERT)
|
if (ret != SPI_OK_INSERT)
|
||||||
elog(ERROR, "Full Text Indexing: error executing plan "
|
elog(ERROR, "Full Text Indexing: error executing plan "
|
||||||
|
@ -279,76 +292,83 @@ fti()
|
||||||
return (rettuple);
|
return (rettuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *breakup(char *string, char *substring)
|
char *
|
||||||
|
breakup(char *string, char *substring)
|
||||||
{
|
{
|
||||||
static char *last_start;
|
static char *last_start;
|
||||||
static char *cur_pos;
|
static char *cur_pos;
|
||||||
|
|
||||||
if (new_tuple)
|
if (new_tuple)
|
||||||
{
|
{
|
||||||
cur_pos=last_start=&string[strlen(string)-1];
|
cur_pos = last_start = &string[strlen(string) - 1];
|
||||||
new_tuple=false; /* don't initialize this next time */
|
new_tuple = false; /* don't initialize this next time */
|
||||||
}
|
}
|
||||||
|
|
||||||
while (cur_pos > string) /* don't read before start of 'string' */
|
while (cur_pos > string) /* don't read before start of 'string' */
|
||||||
{
|
{
|
||||||
/* skip pieces at the end of a string that are not
|
|
||||||
alfa-numeric (ie. 'string$%^&', last_start first points to
|
/*
|
||||||
'&', and after this to 'g' */
|
* skip pieces at the end of a string that are not alfa-numeric
|
||||||
if (!isalnum((int)*last_start)) {
|
* (ie. 'string$%^&', last_start first points to '&', and after
|
||||||
while (!isalnum((int)*last_start) &&
|
* this to 'g'
|
||||||
|
*/
|
||||||
|
if (!isalnum((int) *last_start))
|
||||||
|
{
|
||||||
|
while (!isalnum((int) *last_start) &&
|
||||||
last_start > string)
|
last_start > string)
|
||||||
last_start--;
|
last_start--;
|
||||||
cur_pos=last_start;
|
cur_pos = last_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_pos--; /* substrings are at minimum 2 characters long */
|
cur_pos--; /* substrings are at minimum 2 characters
|
||||||
|
* long */
|
||||||
|
|
||||||
if (isalnum((int)*cur_pos))
|
if (isalnum((int) *cur_pos))
|
||||||
{
|
{
|
||||||
/* Houston, we have a substring! :) */
|
/* Houston, we have a substring! :) */
|
||||||
memcpy(substring, cur_pos, last_start - cur_pos + 1);
|
memcpy(substring, cur_pos, last_start - cur_pos + 1);
|
||||||
substring[last_start-cur_pos+1]='\0';
|
substring[last_start - cur_pos + 1] = '\0';
|
||||||
if (!is_stopword(substring)) return substring;
|
if (!is_stopword(substring))
|
||||||
|
return substring;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
last_start=cur_pos-1;
|
last_start = cur_pos - 1;
|
||||||
cur_pos = last_start;
|
cur_pos = last_start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL; /* we've processed all of 'string' */
|
return NULL; /* we've processed all of 'string' */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copied from src/backend/parser/keywords.c and adjusted for our situation*/
|
/* copied from src/backend/parser/keywords.c and adjusted for our situation*/
|
||||||
bool
|
bool
|
||||||
is_stopword(char *text)
|
is_stopword(char *text)
|
||||||
{
|
{
|
||||||
char **StopLow; /* for list of stop-words */
|
char **StopLow; /* for list of stop-words */
|
||||||
char **StopHigh;
|
char **StopHigh;
|
||||||
char **StopMiddle;
|
char **StopMiddle;
|
||||||
unsigned int difference;
|
unsigned int difference;
|
||||||
|
|
||||||
StopLow = &StopWords[0]; /* initialize stuff for binary search */
|
StopLow = &StopWords[0]; /* initialize stuff for binary search */
|
||||||
StopHigh = endof(StopWords);
|
StopHigh = endof(StopWords);
|
||||||
|
|
||||||
if (lengthof(StopWords) == 0)
|
if (lengthof(StopWords) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
while (StopLow <= StopHigh)
|
|
||||||
{
|
|
||||||
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
|
|
||||||
difference = strcmp(*StopMiddle, text);
|
|
||||||
if (difference == 0)
|
|
||||||
return (true);
|
|
||||||
else if (difference < 0)
|
|
||||||
StopLow = StopMiddle + 1;
|
|
||||||
else
|
|
||||||
StopHigh = StopMiddle - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (false);
|
while (StopLow <= StopHigh)
|
||||||
|
{
|
||||||
|
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
|
||||||
|
difference = strcmp(*StopMiddle, text);
|
||||||
|
if (difference == 0)
|
||||||
|
return (true);
|
||||||
|
else if (difference < 0)
|
||||||
|
StopLow = StopMiddle + 1;
|
||||||
|
else
|
||||||
|
StopHigh = StopMiddle - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for caching of query plans, stolen from contrib/spi/\*.c */
|
/* for caching of query plans, stolen from contrib/spi/\*.c */
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* PostgreSQL type definitions for ISBNs.
|
* PostgreSQL type definitions for ISBNs.
|
||||||
*
|
*
|
||||||
* $Id: isbn.c,v 1.1 1998/08/17 03:35:04 scrappy Exp $
|
* $Id: isbn.c,v 1.2 1999/05/25 16:05:40 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
typedef struct isbn
|
typedef struct isbn
|
||||||
{
|
{
|
||||||
char num[13];
|
char num[13];
|
||||||
char pad[3];
|
char pad[3];
|
||||||
} isbn;
|
} isbn;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -50,13 +50,15 @@ isbn_in(char *str)
|
||||||
char *cp;
|
char *cp;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
if (strlen(str) != 13) {
|
if (strlen(str) != 13)
|
||||||
|
{
|
||||||
elog(ERROR, "isbn_in: invalid ISBN \"%s\"", str);
|
elog(ERROR, "isbn_in: invalid ISBN \"%s\"", str);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
if (isbn_sum(str) != 0) {
|
if (isbn_sum(str) != 0)
|
||||||
|
{
|
||||||
elog(ERROR, "isbn_in: purported ISBN \"%s\" failed checksum",
|
elog(ERROR, "isbn_in: purported ISBN \"%s\" failed checksum",
|
||||||
str);
|
str);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,28 +86,40 @@ isbn_in(char *str)
|
||||||
int4
|
int4
|
||||||
isbn_sum(char *str)
|
isbn_sum(char *str)
|
||||||
{
|
{
|
||||||
int4 sum = 0, dashes = 0, val;
|
int4 sum = 0,
|
||||||
int i;
|
dashes = 0,
|
||||||
|
val;
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 0; str[i] && i < 13; i++) {
|
for (i = 0; str[i] && i < 13; i++)
|
||||||
switch(str[i]) {
|
{
|
||||||
case '-':
|
switch (str[i])
|
||||||
if (++dashes > 3)
|
{
|
||||||
|
case '-':
|
||||||
|
if (++dashes > 3)
|
||||||
|
return 12;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
val = str[i] - '0';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'X':
|
||||||
|
case 'x':
|
||||||
|
val = 10;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
return 12;
|
return 12;
|
||||||
continue;
|
|
||||||
|
|
||||||
case '0': case '1': case '2': case '3':
|
|
||||||
case '4': case '5': case '6': case '7':
|
|
||||||
case '8': case '9':
|
|
||||||
val = str[i] - '0';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'X': case 'x':
|
|
||||||
val = 10;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 12;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sum += val * (i + 1 - dashes);
|
sum += val * (i + 1 - dashes);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* PostgreSQL type definitions for ISSNs.
|
* PostgreSQL type definitions for ISSNs.
|
||||||
*
|
*
|
||||||
* $Id: issn.c,v 1.1 1998/08/17 03:35:05 scrappy Exp $
|
* $Id: issn.c,v 1.2 1999/05/25 16:05:42 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
typedef struct issn
|
typedef struct issn
|
||||||
{
|
{
|
||||||
char num[9];
|
char num[9];
|
||||||
char pad[7];
|
char pad[7];
|
||||||
} issn;
|
} issn;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -50,13 +50,15 @@ issn_in(char *str)
|
||||||
char *cp;
|
char *cp;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
if (strlen(str) != 9) {
|
if (strlen(str) != 9)
|
||||||
|
{
|
||||||
elog(ERROR, "issn_in: invalid ISSN \"%s\"", str);
|
elog(ERROR, "issn_in: invalid ISSN \"%s\"", str);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
if (issn_sum(str) != 0) {
|
if (issn_sum(str) != 0)
|
||||||
|
{
|
||||||
elog(ERROR, "issn_in: purported ISSN \"%s\" failed checksum",
|
elog(ERROR, "issn_in: purported ISSN \"%s\" failed checksum",
|
||||||
str);
|
str);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,28 +77,40 @@ issn_in(char *str)
|
||||||
int4
|
int4
|
||||||
issn_sum(char *str)
|
issn_sum(char *str)
|
||||||
{
|
{
|
||||||
int4 sum = 0, dashes = 0, val;
|
int4 sum = 0,
|
||||||
int i;
|
dashes = 0,
|
||||||
|
val;
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 0; str[i] && i < 9; i++) {
|
for (i = 0; str[i] && i < 9; i++)
|
||||||
switch(str[i]) {
|
{
|
||||||
case '-':
|
switch (str[i])
|
||||||
if (++dashes > 1)
|
{
|
||||||
|
case '-':
|
||||||
|
if (++dashes > 1)
|
||||||
|
return 12;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
val = str[i] - '0';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'X':
|
||||||
|
case 'x':
|
||||||
|
val = 10;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
return 12;
|
return 12;
|
||||||
continue;
|
|
||||||
|
|
||||||
case '0': case '1': case '2': case '3':
|
|
||||||
case '4': case '5': case '6': case '7':
|
|
||||||
case '8': case '9':
|
|
||||||
val = str[i] - '0';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'X': case 'x':
|
|
||||||
val = 10;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 12;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sum += val * (8 - (i - dashes));
|
sum += val * (8 - (i - dashes));
|
||||||
|
|
245
contrib/lo/lo.c
245
contrib/lo/lo.c
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* PostgreSQL type definitions for managed LargeObjects.
|
* PostgreSQL type definitions for managed LargeObjects.
|
||||||
*
|
*
|
||||||
* $Id: lo.c,v 1.1 1998/06/16 07:07:11 momjian Exp $
|
* $Id: lo.c,v 1.2 1999/05/25 16:05:45 momjian Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -33,11 +33,11 @@ typedef Oid Blob;
|
||||||
* Various forward declarations:
|
* Various forward declarations:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Blob *lo_in(char *str); /* Create from String */
|
Blob *lo_in(char *str); /* Create from String */
|
||||||
char *lo_out(Blob * addr); /* Output oid as String */
|
char *lo_out(Blob * addr);/* Output oid as String */
|
||||||
Oid lo_oid(Blob * addr); /* Return oid as an oid */
|
Oid lo_oid(Blob * addr);/* Return oid as an oid */
|
||||||
Blob *lo(Oid oid); /* Return Blob based on oid */
|
Blob *lo(Oid oid); /* Return Blob based on oid */
|
||||||
HeapTuple lo_manage(void); /* Trigger handler */
|
HeapTuple lo_manage(void); /* Trigger handler */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This creates a large object, and set's its OID to the value in the
|
* This creates a large object, and set's its OID to the value in the
|
||||||
|
@ -49,45 +49,46 @@ HeapTuple lo_manage(void); /* Trigger handler */
|
||||||
Blob *
|
Blob *
|
||||||
lo_in(char *str)
|
lo_in(char *str)
|
||||||
{
|
{
|
||||||
Blob *result;
|
Blob *result;
|
||||||
Oid oid;
|
Oid oid;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
if (strlen(str) > 0)
|
if (strlen(str) > 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
count = sscanf(str, "%d", &oid);
|
count = sscanf(str, "%d", &oid);
|
||||||
|
|
||||||
if (count < 1)
|
if (count < 1)
|
||||||
{
|
{
|
||||||
elog(ERROR, "lo_in: error in parsing \"%s\"", str);
|
elog(ERROR, "lo_in: error in parsing \"%s\"", str);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(oid < 0)
|
if (oid < 0)
|
||||||
{
|
{
|
||||||
elog(ERROR, "lo_in: illegal oid \"%s\"", str);
|
elog(ERROR, "lo_in: illegal oid \"%s\"", str);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* There is no Oid passed, so create a new one
|
/*
|
||||||
*/
|
* There is no Oid passed, so create a new one
|
||||||
oid = lo_creat(INV_READ|INV_WRITE);
|
*/
|
||||||
if(oid == InvalidOid)
|
oid = lo_creat(INV_READ | INV_WRITE);
|
||||||
|
if (oid == InvalidOid)
|
||||||
{
|
{
|
||||||
elog(ERROR,"lo_in: InvalidOid returned from lo_creat");
|
elog(ERROR, "lo_in: InvalidOid returned from lo_creat");
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = (Blob *) palloc(sizeof(Blob));
|
result = (Blob *) palloc(sizeof(Blob));
|
||||||
|
|
||||||
*result = oid;
|
*result = oid;
|
||||||
|
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -96,42 +97,43 @@ lo_in(char *str)
|
||||||
char *
|
char *
|
||||||
lo_out(Blob * addr)
|
lo_out(Blob * addr)
|
||||||
{
|
{
|
||||||
char *result;
|
char *result;
|
||||||
|
|
||||||
if (addr == NULL)
|
if (addr == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
result = (char *) palloc(32);
|
result = (char *) palloc(32);
|
||||||
sprintf(result,"%d",*addr);
|
sprintf(result, "%d", *addr);
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function converts Blob to oid.
|
* This function converts Blob to oid.
|
||||||
*
|
*
|
||||||
* eg: select lo_export(raster::oid,'/path/file') from table;
|
* eg: select lo_export(raster::oid,'/path/file') from table;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
Oid
|
Oid
|
||||||
lo_oid(Blob * addr)
|
lo_oid(Blob * addr)
|
||||||
{
|
{
|
||||||
if(addr == NULL)
|
if (addr == NULL)
|
||||||
return InvalidOid;
|
return InvalidOid;
|
||||||
return (Oid)(*addr);
|
return (Oid) (*addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is used so we can convert oid's to lo's
|
* This function is used so we can convert oid's to lo's
|
||||||
*
|
*
|
||||||
* ie: insert into table values(lo_import('/path/file')::lo);
|
* ie: insert into table values(lo_import('/path/file')::lo);
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
Blob *
|
Blob *
|
||||||
lo(Oid oid)
|
lo(Oid oid)
|
||||||
{
|
{
|
||||||
Blob *result = (Blob *) palloc(sizeof(Blob));
|
Blob *result = (Blob *) palloc(sizeof(Blob));
|
||||||
*result = oid;
|
|
||||||
return (result);
|
*result = oid;
|
||||||
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -140,74 +142,77 @@ lo(Oid oid)
|
||||||
HeapTuple
|
HeapTuple
|
||||||
lo_manage(void)
|
lo_manage(void)
|
||||||
{
|
{
|
||||||
int attnum; /* attribute number to monitor */
|
int attnum; /* attribute number to monitor */
|
||||||
char **args; /* Args containing attr name */
|
char **args; /* Args containing attr name */
|
||||||
TupleDesc tupdesc; /* Tuple Descriptor */
|
TupleDesc tupdesc; /* Tuple Descriptor */
|
||||||
HeapTuple rettuple; /* Tuple to be returned */
|
HeapTuple rettuple; /* Tuple to be returned */
|
||||||
bool isdelete; /* are we deleting? */
|
bool isdelete; /* are we deleting? */
|
||||||
HeapTuple newtuple=NULL; /* The new value for tuple */
|
HeapTuple newtuple = NULL;/* The new value for tuple */
|
||||||
HeapTuple trigtuple; /* The original value of tuple */
|
HeapTuple trigtuple; /* The original value of tuple */
|
||||||
|
|
||||||
if (!CurrentTriggerData)
|
if (!CurrentTriggerData)
|
||||||
elog(ERROR, "lo: triggers are not initialized");
|
elog(ERROR, "lo: triggers are not initialized");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fetch some values from CurrentTriggerData
|
* Fetch some values from CurrentTriggerData
|
||||||
*/
|
*/
|
||||||
newtuple = CurrentTriggerData->tg_newtuple;
|
newtuple = CurrentTriggerData->tg_newtuple;
|
||||||
trigtuple = CurrentTriggerData->tg_trigtuple;
|
trigtuple = CurrentTriggerData->tg_trigtuple;
|
||||||
tupdesc = CurrentTriggerData->tg_relation->rd_att;
|
tupdesc = CurrentTriggerData->tg_relation->rd_att;
|
||||||
args = CurrentTriggerData->tg_trigger->tgargs;
|
args = CurrentTriggerData->tg_trigger->tgargs;
|
||||||
|
|
||||||
/* tuple to return to Executor */
|
/* tuple to return to Executor */
|
||||||
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
||||||
rettuple = newtuple;
|
rettuple = newtuple;
|
||||||
else
|
else
|
||||||
rettuple = trigtuple;
|
rettuple = trigtuple;
|
||||||
|
|
||||||
/* Are we deleting the row? */
|
/* Are we deleting the row? */
|
||||||
isdelete = TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event);
|
isdelete = TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event);
|
||||||
|
|
||||||
/* Were done with it */
|
/* Were done with it */
|
||||||
CurrentTriggerData = NULL;
|
CurrentTriggerData = NULL;
|
||||||
|
|
||||||
/* Get the column were interested in */
|
/* Get the column were interested in */
|
||||||
attnum = SPI_fnumber(tupdesc,args[0]);
|
attnum = SPI_fnumber(tupdesc, args[0]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle updates
|
* Handle updates
|
||||||
*
|
*
|
||||||
* Here, if the value of the monitored attribute changes, then the
|
* Here, if the value of the monitored attribute changes, then the large
|
||||||
* large object associated with the original value is unlinked.
|
* object associated with the original value is unlinked.
|
||||||
*/
|
*/
|
||||||
if(newtuple!=NULL) {
|
if (newtuple != NULL)
|
||||||
char *orig = SPI_getvalue(trigtuple,tupdesc,attnum);
|
{
|
||||||
char *newv = SPI_getvalue(newtuple,tupdesc,attnum);
|
char *orig = SPI_getvalue(trigtuple, tupdesc, attnum);
|
||||||
|
char *newv = SPI_getvalue(newtuple, tupdesc, attnum);
|
||||||
if((orig != newv && (orig==NULL || newv==NULL)) || (orig!=NULL && newv!=NULL && strcmp(orig,newv)))
|
|
||||||
lo_unlink(atoi(orig));
|
if ((orig != newv && (orig == NULL || newv == NULL)) || (orig != NULL && newv != NULL && strcmp(orig, newv)))
|
||||||
|
lo_unlink(atoi(orig));
|
||||||
if(newv)
|
|
||||||
pfree(newv);
|
if (newv)
|
||||||
if(orig)
|
pfree(newv);
|
||||||
pfree(orig);
|
if (orig)
|
||||||
}
|
pfree(orig);
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle deleting of rows
|
|
||||||
*
|
|
||||||
* Here, we unlink the large object associated with the managed attribute
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
if(isdelete) {
|
|
||||||
char *orig = SPI_getvalue(trigtuple,tupdesc,attnum);
|
|
||||||
|
|
||||||
if(orig != NULL) {
|
|
||||||
lo_unlink(atoi(orig));
|
|
||||||
|
|
||||||
pfree(orig);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/*
|
||||||
return (rettuple);
|
* Handle deleting of rows
|
||||||
|
*
|
||||||
|
* Here, we unlink the large object associated with the managed attribute
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (isdelete)
|
||||||
|
{
|
||||||
|
char *orig = SPI_getvalue(trigtuple, tupdesc, attnum);
|
||||||
|
|
||||||
|
if (orig != NULL)
|
||||||
|
{
|
||||||
|
lo_unlink(atoi(orig));
|
||||||
|
|
||||||
|
pfree(orig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (rettuple);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,270 +6,360 @@
|
||||||
|
|
||||||
#define HNDMAX 10
|
#define HNDMAX 10
|
||||||
|
|
||||||
PGconn *PGh[HNDMAX] = {
|
PGconn *PGh[HNDMAX] = {
|
||||||
NULL, NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL, NULL, NULL, NULL
|
NULL, NULL, NULL, NULL, NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
#define E_NOHANDLERS 0
|
#define E_NOHANDLERS 0
|
||||||
|
|
||||||
char *msqlErrors[] = {
|
char *msqlErrors[] = {
|
||||||
"Out of database handlers."
|
"Out of database handlers."
|
||||||
};
|
};
|
||||||
|
|
||||||
char msqlErrMsg[BUFSIZ], *tfrom = "dunno";
|
char msqlErrMsg[BUFSIZ],
|
||||||
PGresult *queryres = NULL;
|
*tfrom = "dunno";
|
||||||
|
PGresult *queryres = NULL;
|
||||||
|
|
||||||
int msqlConnect (char *host) {
|
int
|
||||||
int count;
|
msqlConnect(char *host)
|
||||||
|
{
|
||||||
for (count = 0; count < HNDMAX; count++)
|
int count;
|
||||||
if (PGh[count] == NULL) break;
|
|
||||||
|
|
||||||
if (count == HNDMAX) {
|
|
||||||
strncpy(msqlErrMsg, msqlErrors[E_NOHANDLERS], BUFSIZ);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
PGh[count] = malloc(sizeof (PGconn));
|
for (count = 0; count < HNDMAX; count++)
|
||||||
PGh[count]->pghost = host ? strdup(host) : NULL;
|
if (PGh[count] == NULL)
|
||||||
return count;
|
break;
|
||||||
|
|
||||||
|
if (count == HNDMAX)
|
||||||
|
{
|
||||||
|
strncpy(msqlErrMsg, msqlErrors[E_NOHANDLERS], BUFSIZ);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PGh[count] = malloc(sizeof(PGconn));
|
||||||
|
PGh[count]->pghost = host ? strdup(host) : NULL;
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int msqlSelectDB(int handle, char *dbname) {
|
int
|
||||||
char *options = calloc(1, BUFSIZ);
|
msqlSelectDB(int handle, char *dbname)
|
||||||
char *e = getenv("PG_OPTIONS");
|
{
|
||||||
|
char *options = calloc(1, BUFSIZ);
|
||||||
if (e == NULL)
|
char *e = getenv("PG_OPTIONS");
|
||||||
e = "";
|
|
||||||
|
if (e == NULL)
|
||||||
if (PGh[handle]->pghost) {
|
e = "";
|
||||||
strcat(options, "host=");
|
|
||||||
strncat(options, PGh[handle]->pghost, BUFSIZ);
|
if (PGh[handle]->pghost)
|
||||||
strncat(options, " ", BUFSIZ);
|
{
|
||||||
free(PGh[handle]->pghost);
|
strcat(options, "host=");
|
||||||
PGh[handle]->pghost = NULL;
|
strncat(options, PGh[handle]->pghost, BUFSIZ);
|
||||||
}
|
strncat(options, " ", BUFSIZ);
|
||||||
strncat(options, "dbname=", BUFSIZ);
|
free(PGh[handle]->pghost);
|
||||||
strncat(options, dbname, BUFSIZ);
|
PGh[handle]->pghost = NULL;
|
||||||
strncat(options, " ", BUFSIZ);
|
}
|
||||||
strncat(options, e, BUFSIZ);
|
strncat(options, "dbname=", BUFSIZ);
|
||||||
free(PGh[handle]);
|
strncat(options, dbname, BUFSIZ);
|
||||||
PGh[handle] = PQconnectdb(options);
|
strncat(options, " ", BUFSIZ);
|
||||||
free(options);
|
strncat(options, e, BUFSIZ);
|
||||||
strncpy(msqlErrMsg, PQerrorMessage(PGh[handle]), BUFSIZ);
|
free(PGh[handle]);
|
||||||
return (PQstatus(PGh[handle]) == CONNECTION_BAD ? -1 : 0);
|
PGh[handle] = PQconnectdb(options);
|
||||||
|
free(options);
|
||||||
|
strncpy(msqlErrMsg, PQerrorMessage(PGh[handle]), BUFSIZ);
|
||||||
|
return (PQstatus(PGh[handle]) == CONNECTION_BAD ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int msqlQuery(int handle, char *query) {
|
int
|
||||||
char *tq = strdup(query);
|
msqlQuery(int handle, char *query)
|
||||||
char *p = tq;
|
{
|
||||||
PGresult *res;
|
char *tq = strdup(query);
|
||||||
PGconn *conn = PGh[handle];
|
char *p = tq;
|
||||||
ExecStatusType rcode;
|
PGresult *res;
|
||||||
|
PGconn *conn = PGh[handle];
|
||||||
res = PQexec(conn, p);
|
ExecStatusType rcode;
|
||||||
|
|
||||||
rcode = PQresultStatus(res);
|
res = PQexec(conn, p);
|
||||||
|
|
||||||
if (rcode == PGRES_TUPLES_OK) {
|
rcode = PQresultStatus(res);
|
||||||
queryres = res;
|
|
||||||
return PQntuples(res);
|
if (rcode == PGRES_TUPLES_OK)
|
||||||
} else if (rcode == PGRES_FATAL_ERROR || rcode == PGRES_NONFATAL_ERROR) {
|
{
|
||||||
PQclear(res);
|
queryres = res;
|
||||||
queryres = NULL;
|
return PQntuples(res);
|
||||||
return -1;
|
}
|
||||||
} else {
|
else if (rcode == PGRES_FATAL_ERROR || rcode == PGRES_NONFATAL_ERROR)
|
||||||
PQclear(res);
|
{
|
||||||
queryres = NULL;
|
PQclear(res);
|
||||||
return 0;
|
queryres = NULL;
|
||||||
}
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PQclear(res);
|
||||||
|
queryres = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int msqlCreateDB (int a, char*b) {
|
int
|
||||||
char tbuf[BUFSIZ];
|
msqlCreateDB(int a, char *b)
|
||||||
sprintf(tbuf, "create database %s", b);
|
{
|
||||||
return msqlQuery(a, tbuf) >= 0 ? 0 : -1;
|
char tbuf[BUFSIZ];
|
||||||
|
|
||||||
|
sprintf(tbuf, "create database %s", b);
|
||||||
|
return msqlQuery(a, tbuf) >= 0 ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int msqlDropDB (int a, char* b) {
|
int
|
||||||
char tbuf[BUFSIZ];
|
msqlDropDB(int a, char *b)
|
||||||
sprintf(tbuf, "drop database %s", b);
|
{
|
||||||
return msqlQuery(a, tbuf) >= 0 ? 0 : -1;
|
char tbuf[BUFSIZ];
|
||||||
|
|
||||||
|
sprintf(tbuf, "drop database %s", b);
|
||||||
|
return msqlQuery(a, tbuf) >= 0 ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int msqlShutdown(int a) {
|
int
|
||||||
|
msqlShutdown(int a)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int msqlGetProtoInfo(void) {
|
int
|
||||||
|
msqlGetProtoInfo(void)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int msqlReloadAcls(int a) {
|
int
|
||||||
|
msqlReloadAcls(int a)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
char *msqlGetServerInfo(void) {
|
char *
|
||||||
|
msqlGetServerInfo(void)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
char *msqlGetHostInfo(void) {
|
char *
|
||||||
|
msqlGetHostInfo(void)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
char *msqlUnixTimeToDate(time_t date) {
|
char *
|
||||||
|
msqlUnixTimeToDate(time_t date)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
char *msqlUnixTimeToTime(time_t time) {
|
char *
|
||||||
|
msqlUnixTimeToTime(time_t time)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void msqlClose(int a) {
|
void
|
||||||
PQfinish(PGh[a]);
|
msqlClose(int a)
|
||||||
PGh[a] = NULL;
|
{
|
||||||
if (queryres) {
|
PQfinish(PGh[a]);
|
||||||
free(queryres);
|
PGh[a] = NULL;
|
||||||
queryres = NULL;
|
if (queryres)
|
||||||
}
|
{
|
||||||
|
free(queryres);
|
||||||
|
queryres = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void msqlDataSeek(m_result *result, int count) {
|
void
|
||||||
int c;
|
msqlDataSeek(m_result * result, int count)
|
||||||
result->cursor = result->queryData;
|
{
|
||||||
for (c = 1; c < count; c++)
|
int c;
|
||||||
if (result->cursor->next)
|
|
||||||
result->cursor = result->cursor->next;
|
result->cursor = result->queryData;
|
||||||
|
for (c = 1; c < count; c++)
|
||||||
|
if (result->cursor->next)
|
||||||
|
result->cursor = result->cursor->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void msqlFieldSeek(m_result *result, int count) {
|
void
|
||||||
int c;
|
msqlFieldSeek(m_result * result, int count)
|
||||||
result->fieldCursor = result->fieldData;
|
{
|
||||||
for (c = 1; c < count; c++)
|
int c;
|
||||||
if (result->fieldCursor->next)
|
|
||||||
result->fieldCursor = result->fieldCursor->next;
|
result->fieldCursor = result->fieldData;
|
||||||
|
for (c = 1; c < count; c++)
|
||||||
|
if (result->fieldCursor->next)
|
||||||
|
result->fieldCursor = result->fieldCursor->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void msqlFreeResult(m_result *result) {
|
void
|
||||||
if (result) {
|
msqlFreeResult(m_result * result)
|
||||||
/* Clears fields */
|
{
|
||||||
free(result->fieldData);
|
if (result)
|
||||||
result->cursor = result->queryData;
|
{
|
||||||
while (result->cursor) {
|
/* Clears fields */
|
||||||
int c;
|
free(result->fieldData);
|
||||||
m_row m = result->cursor->data;
|
result->cursor = result->queryData;
|
||||||
|
while (result->cursor)
|
||||||
for (c = 0; m[c]; c++)
|
{
|
||||||
free(m[c]);
|
int c;
|
||||||
|
m_row m = result->cursor->data;
|
||||||
|
|
||||||
result->cursor = result->cursor->next;
|
for (c = 0; m[c]; c++)
|
||||||
}
|
free(m[c]);
|
||||||
free(result->queryData);
|
|
||||||
free(result);
|
result->cursor = result->cursor->next;
|
||||||
}
|
}
|
||||||
|
free(result->queryData);
|
||||||
|
free(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_row msqlFetchRow(m_result *row) {
|
m_row
|
||||||
m_data *r = row->cursor;
|
msqlFetchRow(m_result * row)
|
||||||
if (r) {
|
{
|
||||||
row->cursor = row->cursor->next;
|
m_data *r = row->cursor;
|
||||||
return (m_row)r->data;
|
|
||||||
}
|
if (r)
|
||||||
return (m_row)NULL;
|
{
|
||||||
|
row->cursor = row->cursor->next;
|
||||||
|
return (m_row) r->data;
|
||||||
|
}
|
||||||
|
return (m_row) NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_seq *msqlGetSequenceInfo(int a, char *b) {
|
m_seq *
|
||||||
|
msqlGetSequenceInfo(int a, char *b)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
m_field *msqlFetchField (m_result *mr) {
|
m_field *
|
||||||
m_field *m = (m_field*)mr->fieldCursor;
|
msqlFetchField(m_result * mr)
|
||||||
if (m) {
|
{
|
||||||
mr->fieldCursor = mr->fieldCursor->next;
|
m_field *m = (m_field *) mr->fieldCursor;
|
||||||
return m;
|
|
||||||
}
|
if (m)
|
||||||
return NULL;
|
{
|
||||||
|
mr->fieldCursor = mr->fieldCursor->next;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_result *msqlListDBs(int a) {
|
m_result *
|
||||||
m_result *m;
|
msqlListDBs(int a)
|
||||||
if (msqlQuery(a, "select datname from pg_database") > 0) {
|
{
|
||||||
m = msqlStoreResult();
|
m_result *m;
|
||||||
return m;
|
|
||||||
} else return NULL;
|
if (msqlQuery(a, "select datname from pg_database") > 0)
|
||||||
|
{
|
||||||
|
m = msqlStoreResult();
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_result *msqlListTables(int a) {
|
m_result *
|
||||||
m_result *m;
|
msqlListTables(int a)
|
||||||
char tbuf[BUFSIZ];
|
{
|
||||||
|
m_result *m;
|
||||||
sprintf(tbuf, "select relname from pg_class where relkind='r' and relowner=%d", getuid());
|
char tbuf[BUFSIZ];
|
||||||
if (msqlQuery(a, tbuf) > 0) {
|
|
||||||
m = msqlStoreResult();
|
sprintf(tbuf, "select relname from pg_class where relkind='r' and relowner=%d", getuid());
|
||||||
return m;
|
if (msqlQuery(a, tbuf) > 0)
|
||||||
} else return NULL;
|
{
|
||||||
|
m = msqlStoreResult();
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_result *msqlListFields(int a, char *b) {
|
m_result *
|
||||||
|
msqlListFields(int a, char *b)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_result *msqlListIndex(int a, char *b, char *c) {
|
m_result *
|
||||||
m_result *m;
|
msqlListIndex(int a, char *b, char *c)
|
||||||
char tbuf[BUFSIZ];
|
{
|
||||||
|
m_result *m;
|
||||||
sprintf(tbuf, "select relname from pg_class where relkind='i' and relowner=%d", getuid());
|
char tbuf[BUFSIZ];
|
||||||
if (msqlQuery(a, tbuf) > 0) {
|
|
||||||
m = msqlStoreResult();
|
sprintf(tbuf, "select relname from pg_class where relkind='i' and relowner=%d", getuid());
|
||||||
return m;
|
if (msqlQuery(a, tbuf) > 0)
|
||||||
} else return NULL;
|
{
|
||||||
|
m = msqlStoreResult();
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_result *msqlStoreResult(void) {
|
m_result *
|
||||||
if (queryres) {
|
msqlStoreResult(void)
|
||||||
m_result *mr = malloc(sizeof(m_result));
|
{
|
||||||
m_fdata *mf;
|
if (queryres)
|
||||||
m_data *md;
|
{
|
||||||
int count;
|
m_result *mr = malloc(sizeof(m_result));
|
||||||
mr->queryData = mr->cursor = NULL;
|
m_fdata *mf;
|
||||||
mr->numRows = PQntuples(queryres);
|
m_data *md;
|
||||||
mr->numFields = PQnfields(queryres);
|
int count;
|
||||||
|
|
||||||
mf = calloc(PQnfields(queryres), sizeof(m_fdata));
|
|
||||||
for (count = 0; count < PQnfields(queryres); count++) {
|
|
||||||
(m_fdata*)(mf+count)->field.name = strdup(PQfname(queryres, count));
|
|
||||||
(m_fdata*)(mf+count)->field.table = tfrom;
|
|
||||||
(m_fdata*)(mf+count)->field.type = CHAR_TYPE;
|
|
||||||
(m_fdata*)(mf+count)->field.length = PQfsize(queryres, count);
|
|
||||||
(m_fdata*)(mf+count)->next = (m_fdata*)(mf+count+1);
|
|
||||||
}
|
|
||||||
(m_fdata*)(mf+count-1)->next = NULL;
|
|
||||||
|
|
||||||
md = calloc(PQntuples(queryres), sizeof(m_data));
|
|
||||||
for (count = 0; count < PQntuples(queryres); count++) {
|
|
||||||
m_row rows = calloc(PQnfields(queryres)*sizeof(m_row)+1, 1);
|
|
||||||
int c;
|
|
||||||
|
|
||||||
for (c = 0; c < PQnfields(queryres); c++) {
|
|
||||||
rows[c] = strdup(PQgetvalue(queryres, count, c));
|
|
||||||
}
|
|
||||||
(m_data*)(md+count)->data = rows;
|
|
||||||
|
|
||||||
(m_data*)(md+count)->width = PQnfields(queryres);
|
|
||||||
(m_data*)(md+count)->next = (m_data*)(md+count+1);
|
|
||||||
}
|
|
||||||
(m_data*)(md+count-1)->next = NULL;
|
|
||||||
|
|
||||||
mr->queryData = mr->cursor = md;
|
|
||||||
mr->fieldCursor = mr->fieldData = mf;
|
|
||||||
|
|
||||||
return mr;
|
mr->queryData = mr->cursor = NULL;
|
||||||
} else return NULL;
|
mr->numRows = PQntuples(queryres);
|
||||||
|
mr->numFields = PQnfields(queryres);
|
||||||
|
|
||||||
|
mf = calloc(PQnfields(queryres), sizeof(m_fdata));
|
||||||
|
for (count = 0; count < PQnfields(queryres); count++)
|
||||||
|
{
|
||||||
|
(m_fdata *) (mf + count)->field.name = strdup(PQfname(queryres, count));
|
||||||
|
(m_fdata *) (mf + count)->field.table = tfrom;
|
||||||
|
(m_fdata *) (mf + count)->field.type = CHAR_TYPE;
|
||||||
|
(m_fdata *) (mf + count)->field.length = PQfsize(queryres, count);
|
||||||
|
(m_fdata *) (mf + count)->next = (m_fdata *) (mf + count + 1);
|
||||||
|
}
|
||||||
|
(m_fdata *) (mf + count - 1)->next = NULL;
|
||||||
|
|
||||||
|
md = calloc(PQntuples(queryres), sizeof(m_data));
|
||||||
|
for (count = 0; count < PQntuples(queryres); count++)
|
||||||
|
{
|
||||||
|
m_row rows = calloc(PQnfields(queryres) * sizeof(m_row) + 1, 1);
|
||||||
|
int c;
|
||||||
|
|
||||||
|
for (c = 0; c < PQnfields(queryres); c++)
|
||||||
|
rows[c] = strdup(PQgetvalue(queryres, count, c));
|
||||||
|
(m_data *) (md + count)->data = rows;
|
||||||
|
|
||||||
|
(m_data *) (md + count)->width = PQnfields(queryres);
|
||||||
|
(m_data *) (md + count)->next = (m_data *) (md + count + 1);
|
||||||
|
}
|
||||||
|
(m_data *) (md + count - 1)->next = NULL;
|
||||||
|
|
||||||
|
mr->queryData = mr->cursor = md;
|
||||||
|
mr->fieldCursor = mr->fieldData = mf;
|
||||||
|
|
||||||
|
return mr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t msqlDateToUnixTime(char *a) {
|
time_t
|
||||||
|
msqlDateToUnixTime(char *a)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t msqlTimeToUnixTime(char *b) {
|
time_t
|
||||||
|
msqlTimeToUnixTime(char *b)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
char *msql_tmpnam(void) {
|
char *
|
||||||
return tmpnam("/tmp/msql.XXXXXX");
|
msql_tmpnam(void)
|
||||||
|
{
|
||||||
|
return tmpnam("/tmp/msql.XXXXXX");
|
||||||
}
|
}
|
||||||
|
|
||||||
int msqlLoadConfigFile(char *a) {
|
int
|
||||||
|
msqlLoadConfigFile(char *a)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ extern int assertTest(int val);
|
||||||
|
|
||||||
#ifdef ASSERT_CHECKING_TEST
|
#ifdef ASSERT_CHECKING_TEST
|
||||||
extern int assertEnable(int val);
|
extern int assertEnable(int val);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -68,14 +69,15 @@ assert_test(int val)
|
||||||
{
|
{
|
||||||
return assertTest(val);
|
return assertTest(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* end of file */
|
/* end of file */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
* tab-width: 4
|
* tab-width: 4
|
||||||
* c-indent-level: 4
|
* c-indent-level: 4
|
||||||
* c-basic-offset: 4
|
* c-basic-offset: 4
|
||||||
* End:
|
* End:
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -7,16 +7,18 @@ int unlisten(char *relname);
|
||||||
int max(int x, int y);
|
int max(int x, int y);
|
||||||
int min(int x, int y);
|
int min(int x, int y);
|
||||||
int assert_enable(int val);
|
int assert_enable(int val);
|
||||||
|
|
||||||
#ifdef ASSERT_CHECKING_TEST
|
#ifdef ASSERT_CHECKING_TEST
|
||||||
int assert_test(int val);
|
int assert_test(int val);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
* tab-width: 4
|
* tab-width: 4
|
||||||
* c-indent-level: 4
|
* c-indent-level: 4
|
||||||
* c-basic-offset: 4
|
* c-basic-offset: 4
|
||||||
* End:
|
* End:
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -12,7 +12,7 @@ HeapTuple noup(void);
|
||||||
* noup () -- revoke permission on column
|
* noup () -- revoke permission on column
|
||||||
*
|
*
|
||||||
* Though it's called without args You have to specify referenced
|
* Though it's called without args You have to specify referenced
|
||||||
* table/column while creating trigger:
|
* table/column while creating trigger:
|
||||||
* EXECUTE PROCEDURE noup ('col').
|
* EXECUTE PROCEDURE noup ('col').
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -98,8 +98,8 @@ noup()
|
||||||
*/
|
*/
|
||||||
if (!isnull)
|
if (!isnull)
|
||||||
{
|
{
|
||||||
|
|
||||||
elog(WARN, "%s: update not allowed", args[i] );
|
elog(WARN, "%s: update not allowed", args[i]);
|
||||||
SPI_finish();
|
SPI_finish();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#undef PORTNAME
|
#undef PORTNAME
|
||||||
#define PORTNAME OS2
|
#define PORTNAME OS2
|
||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* c.h--
|
* c.h--
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: c.h,v 1.1 1998/10/31 04:10:53 scrappy Exp $
|
* $Id: c.h,v 1.2 1999/05/25 16:06:01 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -65,7 +65,8 @@
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
#ifndef bool
|
#ifndef bool
|
||||||
typedef char bool;
|
typedef char bool;
|
||||||
#endif /* ndef bool */
|
|
||||||
|
#endif /* ndef bool */
|
||||||
#endif /* not C++ */
|
#endif /* not C++ */
|
||||||
typedef bool *BoolPtr;
|
typedef bool *BoolPtr;
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
|
|
||||||
#ifndef TCPIPV4
|
#ifndef TCPIPV4
|
||||||
# define TCPIPV4
|
#define TCPIPV4
|
||||||
#endif
|
#endif /*
*/
|
||||||
|
|
||||||
#ifndef MAXSOCKETS
|
#ifndef MAXSOCKETS
|
||||||
#define MAXSOCKETS 2048
|
#define MAXSOCKETS 2048
|
||||||
#endif
|
#endif /*
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DEF_PGPORT is the TCP port number on which the Postmaster listens by
|
* DEF_PGPORT is the TCP port number on which the Postmaster listens by
|
||||||
* default. This can be overriden by command options, environment variables,
|
* default. This can be overriden by command options, environment variables,
|
||||||
* and the postconfig hook. (set by build script)
|
* and the postconfig hook. (set by build script)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DEF_PGPORT "5432"
|
#define DEF_PGPORT "5432"
|
||||||
|
|
||||||
|
|
|
@ -206,28 +206,30 @@ on_error_continue()
|
||||||
** get_result
|
** get_result
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
PGresult *get_result()
|
PGresult *
|
||||||
|
get_result()
|
||||||
{
|
{
|
||||||
char *cmdstatus = PQcmdStatus(res);
|
char *cmdstatus = PQcmdStatus(res);
|
||||||
|
|
||||||
was_get_unset_result = TRUE;
|
was_get_unset_result = TRUE;
|
||||||
|
|
||||||
/* we have to store the fetch location somewhere */
|
/* we have to store the fetch location somewhere */
|
||||||
cmdstatus[0] = NUL;
|
cmdstatus[0] = NUL;
|
||||||
memcpy(&cmdstatus[1],&tuple, sizeof(tuple));
|
memcpy(&cmdstatus[1], &tuple, sizeof(tuple));
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
**
|
**
|
||||||
** set_result
|
** set_result
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
void set_result(PGresult *newres)
|
void
|
||||||
|
set_result(PGresult *newres)
|
||||||
{
|
{
|
||||||
|
|
||||||
char *cmdstatus = PQcmdStatus(res);
|
char *cmdstatus = PQcmdStatus(res);
|
||||||
|
|
||||||
if (newres == NULL)
|
if (newres == NULL)
|
||||||
halt("set_result called with null result pointer\n");
|
halt("set_result called with null result pointer\n");
|
||||||
|
@ -256,9 +258,10 @@ void set_result(PGresult *newres)
|
||||||
** unset_result
|
** unset_result
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
void unset_result(PGresult *oldres)
|
void
|
||||||
|
unset_result(PGresult *oldres)
|
||||||
{
|
{
|
||||||
char *cmdstatus = PQcmdStatus(oldres);
|
char *cmdstatus = PQcmdStatus(oldres);
|
||||||
|
|
||||||
if (oldres == NULL)
|
if (oldres == NULL)
|
||||||
halt("unset_result called with null result pointer\n");
|
halt("unset_result called with null result pointer\n");
|
||||||
|
@ -277,8 +280,8 @@ void unset_result(PGresult *oldres)
|
||||||
** reset_fetch
|
** reset_fetch
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
void reset_fetch()
|
void
|
||||||
|
reset_fetch()
|
||||||
{
|
{
|
||||||
tuple = 0;
|
tuple = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ int fetchwithnulls(void *param,...);
|
||||||
void on_error_continue();
|
void on_error_continue();
|
||||||
void on_error_stop();
|
void on_error_stop();
|
||||||
PGresult *get_result();
|
PGresult *get_result();
|
||||||
void set_result(PGresult *newres);
|
void set_result(PGresult *newres);
|
||||||
void unset_result(PGresult *oldres);
|
void unset_result(PGresult *oldres);
|
||||||
void reset_fetch();
|
void reset_fetch();
|
||||||
|
|
||||||
#define END_OF_TUPLES (-1)
|
#define END_OF_TUPLES (-1)
|
||||||
|
|
|
@ -7,7 +7,7 @@ a modification datetime stamp in a record when that record is UPDATEd.
|
||||||
|
|
||||||
Credits
|
Credits
|
||||||
This is 95%+ based on autoinc.c, which I used as a starting point as I do
|
This is 95%+ based on autoinc.c, which I used as a starting point as I do
|
||||||
not really know what I am doing. I also had help from
|
not really know what I am doing. I also had help from
|
||||||
Jan Wieck <jwieck@debis.com> who told me about the datetime_in("now") function.
|
Jan Wieck <jwieck@debis.com> who told me about the datetime_in("now") function.
|
||||||
OH, me, I'm Terry Mackintosh <terry@terrym.com>
|
OH, me, I'm Terry Mackintosh <terry@terrym.com>
|
||||||
*/
|
*/
|
||||||
|
@ -17,17 +17,18 @@ OH, me, I'm Terry Mackintosh <terry@terrym.com>
|
||||||
|
|
||||||
HeapTuple moddatetime(void);
|
HeapTuple moddatetime(void);
|
||||||
|
|
||||||
HeapTuple moddatetime()
|
HeapTuple
|
||||||
|
moddatetime()
|
||||||
{
|
{
|
||||||
Trigger *trigger; /* to get trigger name */
|
Trigger *trigger; /* to get trigger name */
|
||||||
int nargs; /* # of arguments */
|
int nargs; /* # of arguments */
|
||||||
int attnum; /* positional number of field to change */
|
int attnum; /* positional number of field to change */
|
||||||
Datum newdt; /* The current datetime. */
|
Datum newdt; /* The current datetime. */
|
||||||
char **args; /* arguments */
|
char **args; /* arguments */
|
||||||
char *relname; /* triggered relation name */
|
char *relname; /* triggered relation name */
|
||||||
Relation rel; /* triggered relation */
|
Relation rel; /* triggered relation */
|
||||||
HeapTuple rettuple = NULL;
|
HeapTuple rettuple = NULL;
|
||||||
TupleDesc tupdesc; /* tuple description */
|
TupleDesc tupdesc; /* tuple description */
|
||||||
|
|
||||||
if (!CurrentTriggerData)
|
if (!CurrentTriggerData)
|
||||||
elog(ERROR, "moddatetime: triggers are not initialized.");
|
elog(ERROR, "moddatetime: triggers are not initialized.");
|
||||||
|
@ -65,28 +66,31 @@ HeapTuple moddatetime()
|
||||||
/* Get the current datetime. */
|
/* Get the current datetime. */
|
||||||
newdt = datetime_in("now");
|
newdt = datetime_in("now");
|
||||||
|
|
||||||
/* This gets the position in the turple of the field we want.
|
/*
|
||||||
args[0] being the name of the field to update, as passed in
|
* This gets the position in the turple of the field we want. args[0]
|
||||||
from the trigger.
|
* being the name of the field to update, as passed in from the
|
||||||
*/
|
* trigger.
|
||||||
|
*/
|
||||||
attnum = SPI_fnumber(tupdesc, args[0]);
|
attnum = SPI_fnumber(tupdesc, args[0]);
|
||||||
|
|
||||||
/* This is were we check to see if the feild we are suppost to update even
|
/*
|
||||||
exits. The above function must return -1 if name not found?
|
* This is were we check to see if the feild we are suppost to update
|
||||||
*/
|
* even exits. The above function must return -1 if name not found?
|
||||||
|
*/
|
||||||
if (attnum < 0)
|
if (attnum < 0)
|
||||||
elog(ERROR, "moddatetime (%s): there is no attribute %s", relname,
|
elog(ERROR, "moddatetime (%s): there is no attribute %s", relname,
|
||||||
args[0]);
|
args[0]);
|
||||||
|
|
||||||
/* OK, this is where we make sure the datetime field that we are
|
/*
|
||||||
modifying is really a datetime field.
|
* OK, this is where we make sure the datetime field that we are
|
||||||
Hay, error checking, what a novel idea !-)
|
* modifying is really a datetime field. Hay, error checking, what a
|
||||||
*/
|
* novel idea !-)
|
||||||
if (SPI_gettypeid(tupdesc, attnum) != DATETIMEOID )
|
*/
|
||||||
|
if (SPI_gettypeid(tupdesc, attnum) != DATETIMEOID)
|
||||||
elog(ERROR, "moddatetime (%s): attribute %s must be of DATETIME type",
|
elog(ERROR, "moddatetime (%s): attribute %s must be of DATETIME type",
|
||||||
relname, args[0]);
|
relname, args[0]);
|
||||||
|
|
||||||
/* 1 is the number of items in the arrays attnum and newdt.
|
/* 1 is the number of items in the arrays attnum and newdt.
|
||||||
attnum is the positional number of the field to be updated.
|
attnum is the positional number of the field to be updated.
|
||||||
newdt is the new datetime stamp.
|
newdt is the new datetime stamp.
|
||||||
NOTE that attnum and newdt are not arrays, but then a 1 ellement array
|
NOTE that attnum and newdt are not arrays, but then a 1 ellement array
|
||||||
|
|
|
@ -1,24 +1,27 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
char *strtoupper(char *string)
|
char *
|
||||||
|
strtoupper(char *string)
|
||||||
{
|
{
|
||||||
int i ;
|
int i;
|
||||||
for (i=0;i<strlen(string);i++)
|
|
||||||
{
|
for (i = 0; i < strlen(string); i++)
|
||||||
string[i]=toupper(string[i]);
|
string[i] = toupper(string[i]);
|
||||||
}
|
return string;
|
||||||
return string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void main ( char argc , char **argv )
|
void
|
||||||
|
main(char argc, char **argv)
|
||||||
{
|
{
|
||||||
char str[250];
|
char str[250];
|
||||||
int sw = 0 ;
|
int sw = 0;
|
||||||
while ( fgets (str,240,stdin) )
|
|
||||||
{
|
while (fgets(str, 240, stdin))
|
||||||
if ( sw == 0 ) printf("%s",strtoupper(str));
|
{
|
||||||
}
|
if (sw == 0)
|
||||||
|
printf("%s", strtoupper(str));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,8 +60,8 @@ check_primary_key()
|
||||||
/*
|
/*
|
||||||
* Some checks first...
|
* Some checks first...
|
||||||
*/
|
*/
|
||||||
#ifdef DEBUG_QUERY
|
#ifdef DEBUG_QUERY
|
||||||
elog(NOTICE,"Check_primary_key Enter Function");
|
elog(NOTICE, "Check_primary_key Enter Function");
|
||||||
#endif
|
#endif
|
||||||
/* Called by trigger manager ? */
|
/* Called by trigger manager ? */
|
||||||
if (!CurrentTriggerData)
|
if (!CurrentTriggerData)
|
||||||
|
@ -228,7 +228,7 @@ check_foreign_key()
|
||||||
Trigger *trigger; /* to get trigger name */
|
Trigger *trigger; /* to get trigger name */
|
||||||
int nargs; /* # of args specified in CREATE TRIGGER */
|
int nargs; /* # of args specified in CREATE TRIGGER */
|
||||||
char **args; /* arguments: as described above */
|
char **args; /* arguments: as described above */
|
||||||
char **args_temp ;
|
char **args_temp;
|
||||||
int nrefs; /* number of references (== # of plans) */
|
int nrefs; /* number of references (== # of plans) */
|
||||||
char action; /* 'R'estrict | 'S'etnull | 'C'ascade */
|
char action; /* 'R'estrict | 'S'etnull | 'C'ascade */
|
||||||
int nkeys; /* # of key columns */
|
int nkeys; /* # of key columns */
|
||||||
|
@ -244,13 +244,15 @@ check_foreign_key()
|
||||||
bool isequal = true; /* are keys in both tuples equal (in
|
bool isequal = true; /* are keys in both tuples equal (in
|
||||||
* UPDATE) */
|
* UPDATE) */
|
||||||
char ident[2 * NAMEDATALEN]; /* to identify myself */
|
char ident[2 * NAMEDATALEN]; /* to identify myself */
|
||||||
int is_update=0;
|
int is_update = 0;
|
||||||
int ret;
|
int ret;
|
||||||
int i,
|
int i,
|
||||||
r;
|
r;
|
||||||
#ifdef DEBUG_QUERY
|
|
||||||
elog(NOTICE,"Check_foreign_key Enter Function");
|
#ifdef DEBUG_QUERY
|
||||||
|
elog(NOTICE, "Check_foreign_key Enter Function");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some checks first...
|
* Some checks first...
|
||||||
*/
|
*/
|
||||||
|
@ -275,12 +277,12 @@ check_foreign_key()
|
||||||
* key in tg_newtuple is the same as in tg_trigtuple then nothing to
|
* key in tg_newtuple is the same as in tg_trigtuple then nothing to
|
||||||
* do.
|
* do.
|
||||||
*/
|
*/
|
||||||
is_update=0;
|
is_update = 0;
|
||||||
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
|
||||||
{
|
{
|
||||||
newtuple = CurrentTriggerData->tg_newtuple;
|
newtuple = CurrentTriggerData->tg_newtuple;
|
||||||
is_update=1;
|
is_update = 1;
|
||||||
}
|
}
|
||||||
trigger = CurrentTriggerData->tg_trigger;
|
trigger = CurrentTriggerData->tg_trigger;
|
||||||
nargs = trigger->tgnargs;
|
nargs = trigger->tgnargs;
|
||||||
args = trigger->tgargs;
|
args = trigger->tgargs;
|
||||||
|
@ -288,7 +290,7 @@ check_foreign_key()
|
||||||
if (nargs < 5) /* nrefs, action, key, Relation, key - at
|
if (nargs < 5) /* nrefs, action, key, Relation, key - at
|
||||||
* least */
|
* least */
|
||||||
elog(ERROR, "check_foreign_key: too short %d (< 5) list of arguments", nargs);
|
elog(ERROR, "check_foreign_key: too short %d (< 5) list of arguments", nargs);
|
||||||
|
|
||||||
nrefs = pg_atoi(args[0], sizeof(int), 0);
|
nrefs = pg_atoi(args[0], sizeof(int), 0);
|
||||||
if (nrefs < 1)
|
if (nrefs < 1)
|
||||||
elog(ERROR, "check_foreign_key: %d (< 1) number of references specified", nrefs);
|
elog(ERROR, "check_foreign_key: %d (< 1) number of references specified", nrefs);
|
||||||
|
@ -386,7 +388,7 @@ check_foreign_key()
|
||||||
if (plan->nplans <= 0) /* Get typeId of column */
|
if (plan->nplans <= 0) /* Get typeId of column */
|
||||||
argtypes[i] = SPI_gettypeid(tupdesc, fnumber);
|
argtypes[i] = SPI_gettypeid(tupdesc, fnumber);
|
||||||
}
|
}
|
||||||
args_temp = args;
|
args_temp = args;
|
||||||
nargs -= nkeys;
|
nargs -= nkeys;
|
||||||
args += nkeys;
|
args += nkeys;
|
||||||
|
|
||||||
|
@ -397,13 +399,14 @@ check_foreign_key()
|
||||||
{
|
{
|
||||||
void *pplan;
|
void *pplan;
|
||||||
char sql[8192];
|
char sql[8192];
|
||||||
char **args2 = args ;
|
char **args2 = args;
|
||||||
|
|
||||||
plan->splan = (void **) malloc(nrefs * sizeof(void *));
|
plan->splan = (void **) malloc(nrefs * sizeof(void *));
|
||||||
|
|
||||||
for (r = 0; r < nrefs; r++)
|
for (r = 0; r < nrefs; r++)
|
||||||
{
|
{
|
||||||
relname = args2[0];
|
relname = args2[0];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For 'R'estrict action we construct SELECT query - SELECT 1
|
* For 'R'estrict action we construct SELECT query - SELECT 1
|
||||||
* FROM _referencing_relation_ WHERE Fkey1 = $1 [AND Fkey2 =
|
* FROM _referencing_relation_ WHERE Fkey1 = $1 [AND Fkey2 =
|
||||||
|
@ -417,50 +420,59 @@ check_foreign_key()
|
||||||
* For 'C'ascade action we construct DELETE query - DELETE
|
* For 'C'ascade action we construct DELETE query - DELETE
|
||||||
* FROM _referencing_relation_ WHERE Fkey1 = $1 [AND Fkey2 =
|
* FROM _referencing_relation_ WHERE Fkey1 = $1 [AND Fkey2 =
|
||||||
* $2 [...]] - to delete all referencing tuples.
|
* $2 [...]] - to delete all referencing tuples.
|
||||||
*/
|
*/
|
||||||
/*Max : Cascade with UPDATE query i create update query that
|
|
||||||
updates new key values in referenced tables
|
/*
|
||||||
*/
|
* Max : Cascade with UPDATE query i create update query that
|
||||||
|
* updates new key values in referenced tables
|
||||||
|
*/
|
||||||
else if (action == 'c'){
|
|
||||||
if (is_update == 1)
|
|
||||||
{
|
else if (action == 'c')
|
||||||
int fn;
|
{
|
||||||
char *nv;
|
if (is_update == 1)
|
||||||
int k ;
|
|
||||||
sprintf(sql, "update %s set ", relname);
|
|
||||||
for (k = 1; k <= nkeys; k++)
|
|
||||||
{
|
{
|
||||||
int is_char_type =0;
|
int fn;
|
||||||
char *type;
|
char *nv;
|
||||||
|
int k;
|
||||||
fn = SPI_fnumber(tupdesc, args_temp[k-1]);
|
|
||||||
nv = SPI_getvalue(newtuple, tupdesc, fn);
|
sprintf(sql, "update %s set ", relname);
|
||||||
type=SPI_gettype(tupdesc,fn);
|
for (k = 1; k <= nkeys; k++)
|
||||||
|
{
|
||||||
if ( (strcmp(type,"text") && strcmp (type,"varchar") &&
|
int is_char_type = 0;
|
||||||
strcmp(type,"char") && strcmp (type,"bpchar") &&
|
char *type;
|
||||||
strcmp(type,"date") && strcmp (type,"datetime")) == 0 )
|
|
||||||
is_char_type=1;
|
fn = SPI_fnumber(tupdesc, args_temp[k - 1]);
|
||||||
#ifdef DEBUG_QUERY
|
nv = SPI_getvalue(newtuple, tupdesc, fn);
|
||||||
elog(NOTICE,"Check_foreign_key Debug value %s type %s %d",
|
type = SPI_gettype(tupdesc, fn);
|
||||||
nv,type,is_char_type);
|
|
||||||
|
if ((strcmp(type, "text") && strcmp(type, "varchar") &&
|
||||||
|
strcmp(type, "char") && strcmp(type, "bpchar") &&
|
||||||
|
strcmp(type, "date") && strcmp(type, "datetime")) == 0)
|
||||||
|
is_char_type = 1;
|
||||||
|
#ifdef DEBUG_QUERY
|
||||||
|
elog(NOTICE, "Check_foreign_key Debug value %s type %s %d",
|
||||||
|
nv, type, is_char_type);
|
||||||
#endif
|
#endif
|
||||||
/* is_char_type =1 i set ' ' for define a new value
|
|
||||||
*/
|
/*
|
||||||
sprintf(sql + strlen(sql), " %s = %s%s%s %s ",
|
* is_char_type =1 i set ' ' for define a new
|
||||||
args2[k], (is_char_type>0) ? "'" :"" ,
|
* value
|
||||||
nv, (is_char_type >0) ? "'" :"",(k < nkeys) ? ", " : "");
|
*/
|
||||||
is_char_type=0;
|
sprintf(sql + strlen(sql), " %s = %s%s%s %s ",
|
||||||
|
args2[k], (is_char_type > 0) ? "'" : "",
|
||||||
|
nv, (is_char_type > 0) ? "'" : "", (k < nkeys) ? ", " : "");
|
||||||
|
is_char_type = 0;
|
||||||
|
}
|
||||||
|
strcat(sql, " where ");
|
||||||
|
|
||||||
}
|
}
|
||||||
strcat(sql, " where ");
|
else
|
||||||
|
/* DELETE */
|
||||||
}
|
sprintf(sql, "delete from %s where ", relname);
|
||||||
else /* DELETE */
|
|
||||||
sprintf(sql, "delete from %s where ", relname);
|
}
|
||||||
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* For 'S'etnull action we construct UPDATE query - UPDATE
|
* For 'S'etnull action we construct UPDATE query - UPDATE
|
||||||
* _referencing_relation_ SET Fkey1 null [, Fkey2 null [...]]
|
* _referencing_relation_ SET Fkey1 null [, Fkey2 null [...]]
|
||||||
|
@ -500,15 +512,15 @@ check_foreign_key()
|
||||||
elog(ERROR, "check_foreign_key: SPI_saveplan returned %d", SPI_result);
|
elog(ERROR, "check_foreign_key: SPI_saveplan returned %d", SPI_result);
|
||||||
|
|
||||||
plan->splan[r] = pplan;
|
plan->splan[r] = pplan;
|
||||||
|
|
||||||
args2 += nkeys + 1; /* to the next relation */
|
args2 += nkeys + 1; /* to the next relation */
|
||||||
}
|
}
|
||||||
plan->nplans = nrefs;
|
plan->nplans = nrefs;
|
||||||
#ifdef DEBUG_QUERY
|
#ifdef DEBUG_QUERY
|
||||||
elog(NOTICE,"Check_foreign_key Debug Query is : %s ", sql);
|
elog(NOTICE, "Check_foreign_key Debug Query is : %s ", sql);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If UPDATE and key is not changed ...
|
* If UPDATE and key is not changed ...
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -352,14 +352,15 @@ c_charin(char *str)
|
||||||
{
|
{
|
||||||
return (string_input(str, 1, 0, NULL));
|
return (string_input(str, 1, 0, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* end of file */
|
/* end of file */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
* tab-width: 4
|
* tab-width: 4
|
||||||
* c-indent-level: 4
|
* c-indent-level: 4
|
||||||
* c-basic-offset: 4
|
* c-basic-offset: 4
|
||||||
* End:
|
* End:
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -14,14 +14,15 @@ char *c_varcharout(char *s);
|
||||||
#if 0
|
#if 0
|
||||||
struct varlena *c_textin(char *str);
|
struct varlena *c_textin(char *str);
|
||||||
char *c_char16in(char *str);
|
char *c_char16in(char *str);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
* tab-width: 4
|
* tab-width: 4
|
||||||
* c-indent-level: 4
|
* c-indent-level: 4
|
||||||
* c-basic-offset: 4
|
* c-basic-offset: 4
|
||||||
* End:
|
* End:
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -29,7 +29,7 @@ user_lock(unsigned int id1, unsigned int id2, LOCKMODE lockmode)
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
memset(&tag, 0, sizeof(LOCKTAG));
|
memset(&tag, 0, sizeof(LOCKTAG));
|
||||||
tag.dbId = MyDatabaseId;
|
tag.dbId = MyDatabaseId;
|
||||||
tag.relId = 0;
|
tag.relId = 0;
|
||||||
tag.tupleId.ip_blkid.bi_hi = id2 >> 16;
|
tag.tupleId.ip_blkid.bi_hi = id2 >> 16;
|
||||||
tag.tupleId.ip_blkid.bi_lo = id2 & 0xffff;
|
tag.tupleId.ip_blkid.bi_lo = id2 & 0xffff;
|
||||||
|
@ -44,7 +44,7 @@ user_unlock(unsigned int id1, unsigned int id2, LOCKMODE lockmode)
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
memset(&tag, 0, sizeof(LOCKTAG));
|
memset(&tag, 0, sizeof(LOCKTAG));
|
||||||
tag.dbId = MyDatabaseId;
|
tag.dbId = MyDatabaseId;
|
||||||
tag.relId = 0;
|
tag.relId = 0;
|
||||||
tag.tupleId.ip_blkid.bi_hi = id2 >> 16;
|
tag.tupleId.ip_blkid.bi_hi = id2 >> 16;
|
||||||
tag.tupleId.ip_blkid.bi_lo = id2 & 0xffff;
|
tag.tupleId.ip_blkid.bi_lo = id2 & 0xffff;
|
||||||
|
@ -99,8 +99,8 @@ user_unlock_all()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
* tab-width: 4
|
* tab-width: 4
|
||||||
* c-indent-level: 4
|
* c-indent-level: 4
|
||||||
* c-basic-offset: 4
|
* c-basic-offset: 4
|
||||||
* End:
|
* End:
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -13,8 +13,8 @@ int user_unlock_all(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
* tab-width: 4
|
* tab-width: 4
|
||||||
* c-indent-level: 4
|
* c-indent-level: 4
|
||||||
* c-basic-offset: 4
|
* c-basic-offset: 4
|
||||||
* End:
|
* End:
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/contrib/vacuumlo/vacuumlo.c,v 1.1 1999/04/10 16:48:05 peter Exp $
|
* $Header: /cvsroot/pgsql/contrib/vacuumlo/vacuumlo.c,v 1.2 1999/05/25 16:06:31 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -25,177 +25,187 @@
|
||||||
|
|
||||||
#define BUFSIZE 1024
|
#define BUFSIZE 1024
|
||||||
|
|
||||||
int vacuumlo(char *,int);
|
int vacuumlo(char *, int);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This vacuums a database. It returns 1 on success, -1 on failure.
|
* This vacuums a database. It returns 1 on success, -1 on failure.
|
||||||
*/
|
*/
|
||||||
int vacuumlo(char *database,int verbose)
|
int
|
||||||
|
vacuumlo(char *database, int verbose)
|
||||||
{
|
{
|
||||||
PGconn *conn;
|
PGconn *conn;
|
||||||
PGresult *res, *res2;
|
PGresult *res,
|
||||||
char buf[BUFSIZE];
|
*res2;
|
||||||
int matched=0; /* Number matched per scan */
|
char buf[BUFSIZE];
|
||||||
int i;
|
int matched = 0; /* Number matched per scan */
|
||||||
|
int i;
|
||||||
conn = PQsetdb(NULL, NULL, NULL, NULL, database);
|
|
||||||
|
|
||||||
/* check to see that the backend connection was successfully made */
|
|
||||||
if (PQstatus(conn) == CONNECTION_BAD)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Connection to database '%s' failed.\n", database);
|
|
||||||
fprintf(stderr, "%s", PQerrorMessage(conn));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(verbose)
|
|
||||||
fprintf(stdout,"Connected to %s\n",database);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* First we create and populate the lo temp table
|
|
||||||
*/
|
|
||||||
buf[0]='\0';
|
|
||||||
strcat(buf,"SELECT oid AS lo ");
|
|
||||||
strcat(buf,"INTO TEMP TABLE vacuum_l ");
|
|
||||||
strcat(buf,"FROM pg_class ");
|
|
||||||
strcat(buf,"WHERE relkind='l'");
|
|
||||||
if(!(res = PQexec(conn,buf))) {
|
|
||||||
fprintf(stderr,"Failed to create temp table.\n");
|
|
||||||
PQfinish(conn);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
PQclear(res);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now find any candidate tables who have columns of type oid (the column
|
|
||||||
* oid is ignored, as it has attnum < 1)
|
|
||||||
*/
|
|
||||||
buf[0]='\0';
|
|
||||||
strcat(buf,"SELECT c.relname, a.attname ");
|
|
||||||
strcat(buf,"FROM pg_class c, pg_attribute a, pg_type t ");
|
|
||||||
strcat(buf,"WHERE a.attnum > 0 ");
|
|
||||||
strcat(buf," AND a.attrelid = c.oid ");
|
|
||||||
strcat(buf," AND a.atttypid = t.oid ");
|
|
||||||
strcat(buf," AND t.typname = 'oid' ");
|
|
||||||
strcat(buf," AND c.relname NOT LIKE 'pg_%'");
|
|
||||||
if(!(res = PQexec(conn,buf))) {
|
|
||||||
fprintf(stderr,"Failed to create temp table.\n");
|
|
||||||
PQfinish(conn);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
for(i=0;i<PQntuples(res);i++)
|
|
||||||
{
|
|
||||||
char *table,*field;
|
|
||||||
|
|
||||||
table = PQgetvalue(res,i,0);
|
|
||||||
field = PQgetvalue(res,i,1);
|
|
||||||
|
|
||||||
if(verbose) {
|
|
||||||
fprintf(stdout,"Checking %s in %s: ",field,table);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
res2 = PQexec(conn, "begin");
|
|
||||||
PQclear(res2);
|
|
||||||
|
|
||||||
buf[0] = '\0';
|
|
||||||
strcat(buf,"DELETE FROM vacuum_l ");
|
|
||||||
strcat(buf,"WHERE lo IN (");
|
|
||||||
strcat(buf,"SELECT ");
|
|
||||||
strcat(buf,field);
|
|
||||||
strcat(buf," FROM ");
|
|
||||||
strcat(buf,table);
|
|
||||||
strcat(buf,");");
|
|
||||||
if(!(res2 = PQexec(conn,buf))) {
|
|
||||||
fprintf(stderr,"Failed to check %s in table %s\n",field,table);
|
|
||||||
PQclear(res);
|
|
||||||
PQfinish(conn);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(PQresultStatus(res2)!=PGRES_COMMAND_OK) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Failed to check %s in table %s\n%s\n",
|
|
||||||
field,table,
|
|
||||||
PQerrorMessage(conn)
|
|
||||||
);
|
|
||||||
PQclear(res2);
|
|
||||||
PQclear(res);
|
|
||||||
PQfinish(conn);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
PQclear(res2);
|
|
||||||
|
|
||||||
res2 = PQexec(conn, "end");
|
conn = PQsetdb(NULL, NULL, NULL, NULL, database);
|
||||||
PQclear(res2);
|
|
||||||
|
/* check to see that the backend connection was successfully made */
|
||||||
}
|
if (PQstatus(conn) == CONNECTION_BAD)
|
||||||
PQclear(res);
|
|
||||||
|
|
||||||
/* Start the transaction */
|
|
||||||
res = PQexec(conn, "begin");
|
|
||||||
PQclear(res);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Finally, those entries remaining in vacuum_l are orphans.
|
|
||||||
*/
|
|
||||||
buf[0]='\0';
|
|
||||||
strcat(buf,"SELECT lo ");
|
|
||||||
strcat(buf,"FROM vacuum_l");
|
|
||||||
if(!(res = PQexec(conn,buf))) {
|
|
||||||
fprintf(stderr,"Failed to read temp table.\n");
|
|
||||||
PQfinish(conn);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
matched=PQntuples(res);
|
|
||||||
for(i=0;i<matched;i++)
|
|
||||||
{
|
{
|
||||||
Oid lo = (Oid) atoi(PQgetvalue(res,i,0));
|
fprintf(stderr, "Connection to database '%s' failed.\n", database);
|
||||||
|
fprintf(stderr, "%s", PQerrorMessage(conn));
|
||||||
if(verbose) {
|
return -1;
|
||||||
fprintf(stdout,"\rRemoving lo %6d \n",lo);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(lo_unlink(conn,lo)<0) {
|
|
||||||
fprintf(stderr,"Failed to remove lo %d\n",lo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
PQclear(res);
|
|
||||||
|
if (verbose)
|
||||||
/*
|
fprintf(stdout, "Connected to %s\n", database);
|
||||||
* That's all folks!
|
|
||||||
*/
|
/*
|
||||||
res = PQexec(conn, "end");
|
* First we create and populate the lo temp table
|
||||||
PQclear(res);
|
*/
|
||||||
PQfinish(conn);
|
buf[0] = '\0';
|
||||||
|
strcat(buf, "SELECT oid AS lo ");
|
||||||
if(verbose)
|
strcat(buf, "INTO TEMP TABLE vacuum_l ");
|
||||||
fprintf(stdout,"\rRemoved %d large objects from %s.\n",matched,database);
|
strcat(buf, "FROM pg_class ");
|
||||||
|
strcat(buf, "WHERE relkind='l'");
|
||||||
return 0;
|
if (!(res = PQexec(conn, buf)))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to create temp table.\n");
|
||||||
|
PQfinish(conn);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now find any candidate tables who have columns of type oid (the
|
||||||
|
* column oid is ignored, as it has attnum < 1)
|
||||||
|
*/
|
||||||
|
buf[0] = '\0';
|
||||||
|
strcat(buf, "SELECT c.relname, a.attname ");
|
||||||
|
strcat(buf, "FROM pg_class c, pg_attribute a, pg_type t ");
|
||||||
|
strcat(buf, "WHERE a.attnum > 0 ");
|
||||||
|
strcat(buf, " AND a.attrelid = c.oid ");
|
||||||
|
strcat(buf, " AND a.atttypid = t.oid ");
|
||||||
|
strcat(buf, " AND t.typname = 'oid' ");
|
||||||
|
strcat(buf, " AND c.relname NOT LIKE 'pg_%'");
|
||||||
|
if (!(res = PQexec(conn, buf)))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to create temp table.\n");
|
||||||
|
PQfinish(conn);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (i = 0; i < PQntuples(res); i++)
|
||||||
|
{
|
||||||
|
char *table,
|
||||||
|
*field;
|
||||||
|
|
||||||
|
table = PQgetvalue(res, i, 0);
|
||||||
|
field = PQgetvalue(res, i, 1);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "Checking %s in %s: ", field, table);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
res2 = PQexec(conn, "begin");
|
||||||
|
PQclear(res2);
|
||||||
|
|
||||||
|
buf[0] = '\0';
|
||||||
|
strcat(buf, "DELETE FROM vacuum_l ");
|
||||||
|
strcat(buf, "WHERE lo IN (");
|
||||||
|
strcat(buf, "SELECT ");
|
||||||
|
strcat(buf, field);
|
||||||
|
strcat(buf, " FROM ");
|
||||||
|
strcat(buf, table);
|
||||||
|
strcat(buf, ");");
|
||||||
|
if (!(res2 = PQexec(conn, buf)))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to check %s in table %s\n", field, table);
|
||||||
|
PQclear(res);
|
||||||
|
PQfinish(conn);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (PQresultStatus(res2) != PGRES_COMMAND_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Failed to check %s in table %s\n%s\n",
|
||||||
|
field, table,
|
||||||
|
PQerrorMessage(conn)
|
||||||
|
);
|
||||||
|
PQclear(res2);
|
||||||
|
PQclear(res);
|
||||||
|
PQfinish(conn);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PQclear(res2);
|
||||||
|
|
||||||
|
res2 = PQexec(conn, "end");
|
||||||
|
PQclear(res2);
|
||||||
|
|
||||||
|
}
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
/* Start the transaction */
|
||||||
|
res = PQexec(conn, "begin");
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finally, those entries remaining in vacuum_l are orphans.
|
||||||
|
*/
|
||||||
|
buf[0] = '\0';
|
||||||
|
strcat(buf, "SELECT lo ");
|
||||||
|
strcat(buf, "FROM vacuum_l");
|
||||||
|
if (!(res = PQexec(conn, buf)))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to read temp table.\n");
|
||||||
|
PQfinish(conn);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
matched = PQntuples(res);
|
||||||
|
for (i = 0; i < matched; i++)
|
||||||
|
{
|
||||||
|
Oid lo = (Oid) atoi(PQgetvalue(res, i, 0));
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "\rRemoving lo %6d \n", lo);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lo_unlink(conn, lo) < 0)
|
||||||
|
fprintf(stderr, "Failed to remove lo %d\n", lo);
|
||||||
|
}
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* That's all folks!
|
||||||
|
*/
|
||||||
|
res = PQexec(conn, "end");
|
||||||
|
PQclear(res);
|
||||||
|
PQfinish(conn);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
fprintf(stdout, "\rRemoved %d large objects from %s.\n", matched, database);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int verbose = 0;
|
int verbose = 0;
|
||||||
int arg;
|
int arg;
|
||||||
int rc=0;
|
int rc = 0;
|
||||||
|
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s [-v] database_name [db2 ... dbn]\n",
|
fprintf(stderr, "Usage: %s [-v] database_name [db2 ... dbn]\n",
|
||||||
argv[0]);
|
argv[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(arg=1;arg<argc;arg++) {
|
for (arg = 1; arg < argc; arg++)
|
||||||
if(strcmp("-v",argv[arg])==0)
|
{
|
||||||
verbose=!verbose;
|
if (strcmp("-v", argv[arg]) == 0)
|
||||||
else
|
verbose = !verbose;
|
||||||
rc += vacuumlo(argv[arg],verbose);
|
else
|
||||||
}
|
rc += vacuumlo(argv[arg], verbose);
|
||||||
|
}
|
||||||
return rc;
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.50 1999/03/14 20:17:20 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.51 1999/05/25 16:06:35 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The old interface functions have been converted to macros
|
* The old interface functions have been converted to macros
|
||||||
|
@ -124,7 +124,7 @@ DataFill(char *data,
|
||||||
*bitP |= bitmask;
|
*bitP |= bitmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = (char *)att_align((long)data, att[i]->attlen, att[i]->attalign);
|
data = (char *) att_align((long) data, att[i]->attlen, att[i]->attalign);
|
||||||
switch (att[i]->attlen)
|
switch (att[i]->attlen)
|
||||||
{
|
{
|
||||||
case -1:
|
case -1:
|
||||||
|
@ -151,7 +151,7 @@ DataFill(char *data,
|
||||||
att[i]->attlen);
|
att[i]->attlen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
data = (char *)att_addlength((long)data, att[i]->attlen, value[i]);
|
data = (char *) att_addlength((long) data, att[i]->attlen, value[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ heap_attisnull(HeapTuple tup, int attnum)
|
||||||
int
|
int
|
||||||
heap_sysattrlen(AttrNumber attno)
|
heap_sysattrlen(AttrNumber attno)
|
||||||
{
|
{
|
||||||
HeapTupleHeader f = NULL;
|
HeapTupleHeader f = NULL;
|
||||||
|
|
||||||
switch (attno)
|
switch (attno)
|
||||||
{
|
{
|
||||||
|
@ -301,6 +301,7 @@ heap_getsysattr(HeapTuple tup, Buffer b, int attnum)
|
||||||
}
|
}
|
||||||
return (Datum) NULL;
|
return (Datum) NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -328,11 +329,11 @@ nocachegetattr(HeapTuple tuple,
|
||||||
TupleDesc tupleDesc,
|
TupleDesc tupleDesc,
|
||||||
bool *isnull)
|
bool *isnull)
|
||||||
{
|
{
|
||||||
char *tp; /* ptr to att in tuple */
|
char *tp; /* ptr to att in tuple */
|
||||||
HeapTupleHeader tup = tuple->t_data;
|
HeapTupleHeader tup = tuple->t_data;
|
||||||
bits8 *bp = tup->t_bits; /* ptr to att in tuple */
|
bits8 *bp = tup->t_bits; /* ptr to att in tuple */
|
||||||
Form_pg_attribute *att = tupleDesc->attrs;
|
Form_pg_attribute *att = tupleDesc->attrs;
|
||||||
int slow = 0; /* do we have to walk nulls? */
|
int slow = 0; /* do we have to walk nulls? */
|
||||||
|
|
||||||
|
|
||||||
#if IN_MACRO
|
#if IN_MACRO
|
||||||
|
@ -376,6 +377,7 @@ nocachegetattr(HeapTuple tuple,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* there's a null somewhere in the tuple
|
* there's a null somewhere in the tuple
|
||||||
*/
|
*/
|
||||||
|
@ -404,12 +406,13 @@ nocachegetattr(HeapTuple tuple,
|
||||||
int finalbit = attnum & 0x07;
|
int finalbit = attnum & 0x07;
|
||||||
|
|
||||||
/* check for nulls "before" final bit of last byte */
|
/* check for nulls "before" final bit of last byte */
|
||||||
if ((~ bp[byte]) & ((1 << finalbit) - 1))
|
if ((~bp[byte]) & ((1 << finalbit) - 1))
|
||||||
slow = 1;
|
slow = 1;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* check for nulls in any "earlier" bytes */
|
/* check for nulls in any "earlier" bytes */
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < byte; i++)
|
for (i = 0; i < byte; i++)
|
||||||
{
|
{
|
||||||
if (bp[i] != 0xFF)
|
if (bp[i] != 0xFF)
|
||||||
|
@ -439,6 +442,7 @@ nocachegetattr(HeapTuple tuple,
|
||||||
else if (!HeapTupleAllFixed(tuple))
|
else if (!HeapTupleAllFixed(tuple))
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In for(), we make this <= and not < because we want to test
|
* In for(), we make this <= and not < because we want to test
|
||||||
* if we can go past it in initializing offsets.
|
* if we can go past it in initializing offsets.
|
||||||
|
@ -456,9 +460,9 @@ nocachegetattr(HeapTuple tuple,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If slow is zero, and we got here, we know that we have a tuple with
|
* If slow is zero, and we got here, we know that we have a tuple with
|
||||||
* no nulls or varlenas before the target attribute.
|
* no nulls or varlenas before the target attribute. If possible, we
|
||||||
* If possible, we also want to initialize the remainder of the
|
* also want to initialize the remainder of the attribute cached
|
||||||
* attribute cached offset values.
|
* offset values.
|
||||||
*/
|
*/
|
||||||
if (!slow)
|
if (!slow)
|
||||||
{
|
{
|
||||||
|
@ -570,7 +574,7 @@ heap_copytuple(HeapTuple tuple)
|
||||||
newTuple->t_len = tuple->t_len;
|
newTuple->t_len = tuple->t_len;
|
||||||
newTuple->t_self = tuple->t_self;
|
newTuple->t_self = tuple->t_self;
|
||||||
newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
|
newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
|
||||||
memmove((char *) newTuple->t_data,
|
memmove((char *) newTuple->t_data,
|
||||||
(char *) tuple->t_data, (int) tuple->t_len);
|
(char *) tuple->t_data, (int) tuple->t_len);
|
||||||
return newTuple;
|
return newTuple;
|
||||||
}
|
}
|
||||||
|
@ -589,11 +593,11 @@ heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest)
|
||||||
dest->t_data = NULL;
|
dest->t_data = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dest->t_len = src->t_len;
|
dest->t_len = src->t_len;
|
||||||
dest->t_self = src->t_self;
|
dest->t_self = src->t_self;
|
||||||
dest->t_data = (HeapTupleHeader) palloc(src->t_len);
|
dest->t_data = (HeapTupleHeader) palloc(src->t_len);
|
||||||
memmove((char *) dest->t_data,
|
memmove((char *) dest->t_data,
|
||||||
(char *) src->t_data, (int) src->t_len);
|
(char *) src->t_data, (int) src->t_len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -657,14 +661,14 @@ heap_formtuple(TupleDesc tupleDescriptor,
|
||||||
Datum *value,
|
Datum *value,
|
||||||
char *nulls)
|
char *nulls)
|
||||||
{
|
{
|
||||||
HeapTuple tuple; /* return tuple */
|
HeapTuple tuple; /* return tuple */
|
||||||
HeapTupleHeader td; /* tuple data */
|
HeapTupleHeader td; /* tuple data */
|
||||||
int bitmaplen;
|
int bitmaplen;
|
||||||
long len;
|
long len;
|
||||||
int hoff;
|
int hoff;
|
||||||
bool hasnull = false;
|
bool hasnull = false;
|
||||||
int i;
|
int i;
|
||||||
int numberOfAttributes = tupleDescriptor->natts;
|
int numberOfAttributes = tupleDescriptor->natts;
|
||||||
|
|
||||||
len = offsetof(HeapTupleHeaderData, t_bits);
|
len = offsetof(HeapTupleHeaderData, t_bits);
|
||||||
|
|
||||||
|
@ -760,9 +764,9 @@ heap_modifytuple(HeapTuple tuple,
|
||||||
if (repl[attoff] == ' ')
|
if (repl[attoff] == ' ')
|
||||||
{
|
{
|
||||||
value[attoff] = heap_getattr(tuple,
|
value[attoff] = heap_getattr(tuple,
|
||||||
AttrOffsetGetAttrNumber(attoff),
|
AttrOffsetGetAttrNumber(attoff),
|
||||||
RelationGetDescr(relation),
|
RelationGetDescr(relation),
|
||||||
&isNull);
|
&isNull);
|
||||||
nulls[attoff] = (isNull) ? 'n' : ' ';
|
nulls[attoff] = (isNull) ? 'n' : ' ';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -790,12 +794,12 @@ heap_modifytuple(HeapTuple tuple,
|
||||||
infomask = newTuple->t_data->t_infomask;
|
infomask = newTuple->t_data->t_infomask;
|
||||||
memmove((char *) &newTuple->t_data->t_oid, /* XXX */
|
memmove((char *) &newTuple->t_data->t_oid, /* XXX */
|
||||||
(char *) &tuple->t_data->t_oid,
|
(char *) &tuple->t_data->t_oid,
|
||||||
((char *) &tuple->t_data->t_hoff -
|
((char *) &tuple->t_data->t_hoff -
|
||||||
(char *) &tuple->t_data->t_oid)); /* XXX */
|
(char *) &tuple->t_data->t_oid)); /* XXX */
|
||||||
newTuple->t_data->t_infomask = infomask;
|
newTuple->t_data->t_infomask = infomask;
|
||||||
newTuple->t_data->t_natts = numberOfAttributes;
|
newTuple->t_data->t_natts = numberOfAttributes;
|
||||||
newTuple->t_self = tuple->t_self;
|
newTuple->t_self = tuple->t_self;
|
||||||
|
|
||||||
return newTuple;
|
return newTuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -809,10 +813,10 @@ heap_addheader(uint32 natts, /* max domain index */
|
||||||
int structlen, /* its length */
|
int structlen, /* its length */
|
||||||
char *structure) /* pointer to the struct */
|
char *structure) /* pointer to the struct */
|
||||||
{
|
{
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
HeapTupleHeader td; /* tuple data */
|
HeapTupleHeader td; /* tuple data */
|
||||||
long len;
|
long len;
|
||||||
int hoff;
|
int hoff;
|
||||||
|
|
||||||
AssertArg(natts > 0);
|
AssertArg(natts > 0);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.45 1999/05/10 00:44:50 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.46 1999/05/25 16:06:39 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -25,9 +25,9 @@
|
||||||
#include "libpq/pqformat.h"
|
#include "libpq/pqformat.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
static void printtup_setup(DestReceiver* self, TupleDesc typeinfo);
|
static void printtup_setup(DestReceiver * self, TupleDesc typeinfo);
|
||||||
static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self);
|
static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver * self);
|
||||||
static void printtup_cleanup(DestReceiver* self);
|
static void printtup_cleanup(DestReceiver * self);
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* printtup / debugtup support
|
* printtup / debugtup support
|
||||||
|
@ -43,7 +43,7 @@ static void printtup_cleanup(DestReceiver* self);
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
getTypeOutAndElem(Oid type, Oid* typOutput, Oid* typElem)
|
getTypeOutAndElem(Oid type, Oid *typOutput, Oid *typElem)
|
||||||
{
|
{
|
||||||
HeapTuple typeTuple;
|
HeapTuple typeTuple;
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ getTypeOutAndElem(Oid type, Oid* typOutput, Oid* typElem)
|
||||||
if (HeapTupleIsValid(typeTuple))
|
if (HeapTupleIsValid(typeTuple))
|
||||||
{
|
{
|
||||||
Form_pg_type pt = (Form_pg_type) GETSTRUCT(typeTuple);
|
Form_pg_type pt = (Form_pg_type) GETSTRUCT(typeTuple);
|
||||||
|
|
||||||
*typOutput = (Oid) pt->typoutput;
|
*typOutput = (Oid) pt->typoutput;
|
||||||
*typElem = (Oid) pt->typelem;
|
*typElem = (Oid) pt->typelem;
|
||||||
return OidIsValid(*typOutput);
|
return OidIsValid(*typOutput);
|
||||||
|
@ -70,27 +71,29 @@ getTypeOutAndElem(Oid type, Oid* typOutput, Oid* typElem)
|
||||||
* Private state for a printtup destination object
|
* Private state for a printtup destination object
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
typedef struct { /* Per-attribute information */
|
typedef struct
|
||||||
|
{ /* Per-attribute information */
|
||||||
Oid typoutput; /* Oid for the attribute's type output fn */
|
Oid typoutput; /* Oid for the attribute's type output fn */
|
||||||
Oid typelem; /* typelem value to pass to the output fn */
|
Oid typelem; /* typelem value to pass to the output fn */
|
||||||
FmgrInfo finfo; /* Precomputed call info for typoutput */
|
FmgrInfo finfo; /* Precomputed call info for typoutput */
|
||||||
} PrinttupAttrInfo;
|
} PrinttupAttrInfo;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
DestReceiver pub; /* publicly-known function pointers */
|
{
|
||||||
TupleDesc attrinfo; /* The attr info we are set up for */
|
DestReceiver pub; /* publicly-known function pointers */
|
||||||
int nattrs;
|
TupleDesc attrinfo; /* The attr info we are set up for */
|
||||||
PrinttupAttrInfo *myinfo; /* Cached info about each attr */
|
int nattrs;
|
||||||
} DR_printtup;
|
PrinttupAttrInfo *myinfo; /* Cached info about each attr */
|
||||||
|
} DR_printtup;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Initialize: create a DestReceiver for printtup
|
* Initialize: create a DestReceiver for printtup
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
DestReceiver*
|
DestReceiver *
|
||||||
printtup_create_DR()
|
printtup_create_DR()
|
||||||
{
|
{
|
||||||
DR_printtup* self = (DR_printtup*) palloc(sizeof(DR_printtup));
|
DR_printtup *self = (DR_printtup *) palloc(sizeof(DR_printtup));
|
||||||
|
|
||||||
self->pub.receiveTuple = printtup;
|
self->pub.receiveTuple = printtup;
|
||||||
self->pub.setup = printtup_setup;
|
self->pub.setup = printtup_setup;
|
||||||
|
@ -100,42 +103,43 @@ printtup_create_DR()
|
||||||
self->nattrs = 0;
|
self->nattrs = 0;
|
||||||
self->myinfo = NULL;
|
self->myinfo = NULL;
|
||||||
|
|
||||||
return (DestReceiver*) self;
|
return (DestReceiver *) self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
printtup_setup(DestReceiver* self, TupleDesc typeinfo)
|
printtup_setup(DestReceiver * self, TupleDesc typeinfo)
|
||||||
{
|
{
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* We could set up the derived attr info at this time, but we postpone it
|
* We could set up the derived attr info at this time, but we postpone it
|
||||||
* until the first call of printtup, for 3 reasons:
|
* until the first call of printtup, for 3 reasons:
|
||||||
* 1. We don't waste time (compared to the old way) if there are no
|
* 1. We don't waste time (compared to the old way) if there are no
|
||||||
* tuples at all to output.
|
* tuples at all to output.
|
||||||
* 2. Checking in printtup allows us to handle the case that the tuples
|
* 2. Checking in printtup allows us to handle the case that the tuples
|
||||||
* change type midway through (although this probably can't happen in
|
* change type midway through (although this probably can't happen in
|
||||||
* the current executor).
|
* the current executor).
|
||||||
* 3. Right now, ExecutorRun passes a NULL for typeinfo anyway :-(
|
* 3. Right now, ExecutorRun passes a NULL for typeinfo anyway :-(
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
printtup_prepare_info(DR_printtup* myState, TupleDesc typeinfo, int numAttrs)
|
printtup_prepare_info(DR_printtup * myState, TupleDesc typeinfo, int numAttrs)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (myState->myinfo)
|
if (myState->myinfo)
|
||||||
pfree(myState->myinfo); /* get rid of any old data */
|
pfree(myState->myinfo); /* get rid of any old data */
|
||||||
myState->myinfo = NULL;
|
myState->myinfo = NULL;
|
||||||
myState->attrinfo = typeinfo;
|
myState->attrinfo = typeinfo;
|
||||||
myState->nattrs = numAttrs;
|
myState->nattrs = numAttrs;
|
||||||
if (numAttrs <= 0)
|
if (numAttrs <= 0)
|
||||||
return;
|
return;
|
||||||
myState->myinfo = (PrinttupAttrInfo*)
|
myState->myinfo = (PrinttupAttrInfo *)
|
||||||
palloc(numAttrs * sizeof(PrinttupAttrInfo));
|
palloc(numAttrs * sizeof(PrinttupAttrInfo));
|
||||||
for (i = 0; i < numAttrs; i++)
|
for (i = 0; i < numAttrs; i++)
|
||||||
{
|
{
|
||||||
PrinttupAttrInfo* thisState = myState->myinfo + i;
|
PrinttupAttrInfo *thisState = myState->myinfo + i;
|
||||||
|
|
||||||
if (getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,
|
if (getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,
|
||||||
&thisState->typoutput, &thisState->typelem))
|
&thisState->typoutput, &thisState->typelem))
|
||||||
fmgr_info(thisState->typoutput, &thisState->finfo);
|
fmgr_info(thisState->typoutput, &thisState->finfo);
|
||||||
|
@ -147,9 +151,9 @@ printtup_prepare_info(DR_printtup* myState, TupleDesc typeinfo, int numAttrs)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver * self)
|
||||||
{
|
{
|
||||||
DR_printtup *myState = (DR_printtup*) self;
|
DR_printtup *myState = (DR_printtup *) self;
|
||||||
StringInfoData buf;
|
StringInfoData buf;
|
||||||
int i,
|
int i,
|
||||||
j,
|
j,
|
||||||
|
@ -178,7 +182,7 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
||||||
k = 1 << 7;
|
k = 1 << 7;
|
||||||
for (i = 0; i < tuple->t_data->t_natts; ++i)
|
for (i = 0; i < tuple->t_data->t_natts; ++i)
|
||||||
{
|
{
|
||||||
if (! heap_attisnull(tuple, i + 1))
|
if (!heap_attisnull(tuple, i + 1))
|
||||||
j |= k; /* set bit if not null */
|
j |= k; /* set bit if not null */
|
||||||
k >>= 1;
|
k >>= 1;
|
||||||
if (k == 0) /* end of byte? */
|
if (k == 0) /* end of byte? */
|
||||||
|
@ -197,7 +201,8 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < tuple->t_data->t_natts; ++i)
|
for (i = 0; i < tuple->t_data->t_natts; ++i)
|
||||||
{
|
{
|
||||||
PrinttupAttrInfo* thisState = myState->myinfo + i;
|
PrinttupAttrInfo *thisState = myState->myinfo + i;
|
||||||
|
|
||||||
attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
|
attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
|
||||||
if (isnull)
|
if (isnull)
|
||||||
continue;
|
continue;
|
||||||
|
@ -223,9 +228,10 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
printtup_cleanup(DestReceiver* self)
|
printtup_cleanup(DestReceiver * self)
|
||||||
{
|
{
|
||||||
DR_printtup* myState = (DR_printtup*) self;
|
DR_printtup *myState = (DR_printtup *) self;
|
||||||
|
|
||||||
if (myState->myinfo)
|
if (myState->myinfo)
|
||||||
pfree(myState->myinfo);
|
pfree(myState->myinfo);
|
||||||
pfree(myState);
|
pfree(myState);
|
||||||
|
@ -274,7 +280,7 @@ showatts(char *name, TupleDesc tupleDesc)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver * self)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
Datum attr;
|
Datum attr;
|
||||||
|
@ -310,7 +316,7 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver * self)
|
||||||
{
|
{
|
||||||
StringInfoData buf;
|
StringInfoData buf;
|
||||||
int i,
|
int i,
|
||||||
|
@ -334,7 +340,7 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
|
||||||
k = 1 << 7;
|
k = 1 << 7;
|
||||||
for (i = 0; i < tuple->t_data->t_natts; ++i)
|
for (i = 0; i < tuple->t_data->t_natts; ++i)
|
||||||
{
|
{
|
||||||
if (! heap_attisnull(tuple, i + 1))
|
if (!heap_attisnull(tuple, i + 1))
|
||||||
j |= k; /* set bit if not null */
|
j |= k; /* set bit if not null */
|
||||||
k >>= 1;
|
k >>= 1;
|
||||||
if (k == 0) /* end of byte? */
|
if (k == 0) /* end of byte? */
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/scankey.c,v 1.13 1999/02/13 23:14:13 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/scankey.c,v 1.14 1999/05/25 16:06:41 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
#include <access/skey.h>
|
#include <access/skey.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ScanKeyEntryIsLegal
|
* ScanKeyEntryIsLegal
|
||||||
* True iff the scan key entry is legal.
|
* True iff the scan key entry is legal.
|
||||||
*/
|
*/
|
||||||
#define ScanKeyEntryIsLegal(entry) \
|
#define ScanKeyEntryIsLegal(entry) \
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ScanKeyEntrySetIllegal
|
* ScanKeyEntrySetIllegal
|
||||||
* Marks a scan key entry as illegal.
|
* Marks a scan key entry as illegal.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
@ -43,7 +43,7 @@ ScanKeyEntrySetIllegal(ScanKey entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ScanKeyEntryInitialize
|
* ScanKeyEntryInitialize
|
||||||
* Initializes an scan key entry.
|
* Initializes an scan key entry.
|
||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.48 1999/02/13 23:14:14 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.49 1999/05/25 16:06:42 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* some of the executor utility code such as "ExecTypeFromTL" should be
|
* some of the executor utility code such as "ExecTypeFromTL" should be
|
||||||
|
@ -487,7 +487,7 @@ BuildDescForRelation(List *schema, char *relname)
|
||||||
{
|
{
|
||||||
/* array of XXX is _XXX */
|
/* array of XXX is _XXX */
|
||||||
snprintf(typename, NAMEDATALEN,
|
snprintf(typename, NAMEDATALEN,
|
||||||
"_%.*s", NAMEDATALEN - 2, entry->typename->name);
|
"_%.*s", NAMEDATALEN - 2, entry->typename->name);
|
||||||
attdim = length(arry);
|
attdim = length(arry);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -344,7 +344,7 @@ gistinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation
|
||||||
/*
|
/*
|
||||||
* Notes in ExecUtils:ExecOpenIndices()
|
* Notes in ExecUtils:ExecOpenIndices()
|
||||||
*
|
*
|
||||||
RelationSetLockForWrite(r);
|
* RelationSetLockForWrite(r);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
res = gistdoinsert(r, itup, &giststate);
|
res = gistdoinsert(r, itup, &giststate);
|
||||||
|
@ -1106,10 +1106,10 @@ gistdelete(Relation r, ItemPointer tid)
|
||||||
Page page;
|
Page page;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Notes in ExecUtils:ExecOpenIndices()
|
* Notes in ExecUtils:ExecOpenIndices() Also note that only vacuum
|
||||||
* Also note that only vacuum deletes index tuples now...
|
* deletes index tuples now...
|
||||||
*
|
*
|
||||||
RelationSetLockForWrite(r);
|
* RelationSetLockForWrite(r);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
blkno = ItemPointerGetBlockNumber(tid);
|
blkno = ItemPointerGetBlockNumber(tid);
|
||||||
|
|
|
@ -68,7 +68,7 @@ gistbeginscan(Relation r,
|
||||||
/*
|
/*
|
||||||
* Let index_beginscan does its work...
|
* Let index_beginscan does its work...
|
||||||
*
|
*
|
||||||
RelationSetLockForRead(r);
|
* RelationSetLockForRead(r);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
s = RelationGetIndexScan(r, fromEnd, nkeys, key);
|
s = RelationGetIndexScan(r, fromEnd, nkeys, key);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.25 1999/02/13 23:14:17 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.26 1999/05/25 16:06:54 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* This file contains only the public interface routines.
|
* This file contains only the public interface routines.
|
||||||
|
@ -485,9 +485,9 @@ hashrestrpos(IndexScanDesc scan)
|
||||||
/* bump lock on currentMarkData and copy to currentItemData */
|
/* bump lock on currentMarkData and copy to currentItemData */
|
||||||
if (ItemPointerIsValid(&(scan->currentMarkData)))
|
if (ItemPointerIsValid(&(scan->currentMarkData)))
|
||||||
{
|
{
|
||||||
so->hashso_curbuf =_hash_getbuf(scan->relation,
|
so->hashso_curbuf = _hash_getbuf(scan->relation,
|
||||||
BufferGetBlockNumber(so->hashso_mrkbuf),
|
BufferGetBlockNumber(so->hashso_mrkbuf),
|
||||||
HASH_READ);
|
HASH_READ);
|
||||||
|
|
||||||
scan->currentItemData = scan->currentMarkData;
|
scan->currentItemData = scan->currentMarkData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashfunc.c,v 1.16 1999/03/14 16:27:59 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashfunc.c,v 1.17 1999/05/25 16:06:56 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* These functions are stored in pg_amproc. For each operator class
|
* These functions are stored in pg_amproc. For each operator class
|
||||||
|
@ -34,9 +34,9 @@ hashint4(uint32 key)
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32
|
uint32
|
||||||
hashint8(int64 *key)
|
hashint8(int64 * key)
|
||||||
{
|
{
|
||||||
return ~((uint32)*key);
|
return ~((uint32) *key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hash function from Chris Torek. */
|
/* Hash function from Chris Torek. */
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.19 1999/02/13 23:14:20 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.20 1999/05/25 16:06:58 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Postgres hash pages look like ordinary relation pages. The opaque
|
* Postgres hash pages look like ordinary relation pages. The opaque
|
||||||
|
@ -321,7 +321,7 @@ _hash_setpagelock(Relation rel,
|
||||||
{
|
{
|
||||||
switch (access)
|
switch (access)
|
||||||
{
|
{
|
||||||
case HASH_WRITE:
|
case HASH_WRITE:
|
||||||
LockPage(rel, blkno, ExclusiveLock);
|
LockPage(rel, blkno, ExclusiveLock);
|
||||||
break;
|
break;
|
||||||
case HASH_READ:
|
case HASH_READ:
|
||||||
|
@ -345,7 +345,7 @@ _hash_unsetpagelock(Relation rel,
|
||||||
{
|
{
|
||||||
switch (access)
|
switch (access)
|
||||||
{
|
{
|
||||||
case HASH_WRITE:
|
case HASH_WRITE:
|
||||||
UnlockPage(rel, blkno, ExclusiveLock);
|
UnlockPage(rel, blkno, ExclusiveLock);
|
||||||
break;
|
break;
|
||||||
case HASH_READ:
|
case HASH_READ:
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.42 1999/03/28 20:31:56 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.43 1999/05/25 16:07:04 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
|
@ -117,7 +117,7 @@ initscan(HeapScanDesc scan,
|
||||||
* relation is empty
|
* relation is empty
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
scan->rs_ntup.t_data = scan->rs_ctup.t_data =
|
scan->rs_ntup.t_data = scan->rs_ctup.t_data =
|
||||||
scan->rs_ptup.t_data = NULL;
|
scan->rs_ptup.t_data = NULL;
|
||||||
scan->rs_nbuf = scan->rs_cbuf = scan->rs_pbuf = InvalidBuffer;
|
scan->rs_nbuf = scan->rs_cbuf = scan->rs_pbuf = InvalidBuffer;
|
||||||
}
|
}
|
||||||
|
@ -216,15 +216,15 @@ heapgettup(Relation relation,
|
||||||
int nkeys,
|
int nkeys,
|
||||||
ScanKey key)
|
ScanKey key)
|
||||||
{
|
{
|
||||||
ItemId lpp;
|
ItemId lpp;
|
||||||
Page dp;
|
Page dp;
|
||||||
int page;
|
int page;
|
||||||
int pages;
|
int pages;
|
||||||
int lines;
|
int lines;
|
||||||
OffsetNumber lineoff;
|
OffsetNumber lineoff;
|
||||||
int linesleft;
|
int linesleft;
|
||||||
ItemPointer tid = (tuple->t_data == NULL) ?
|
ItemPointer tid = (tuple->t_data == NULL) ?
|
||||||
(ItemPointer) NULL : &(tuple->t_self);
|
(ItemPointer) NULL : &(tuple->t_self);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
|
@ -290,8 +290,8 @@ heapgettup(Relation relation,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*buffer = RelationGetBufferWithBuffer(relation,
|
*buffer = RelationGetBufferWithBuffer(relation,
|
||||||
ItemPointerGetBlockNumber(tid),
|
ItemPointerGetBlockNumber(tid),
|
||||||
*buffer);
|
*buffer);
|
||||||
|
|
||||||
if (!BufferIsValid(*buffer))
|
if (!BufferIsValid(*buffer))
|
||||||
elog(ERROR, "heapgettup: failed ReadBuffer");
|
elog(ERROR, "heapgettup: failed ReadBuffer");
|
||||||
|
@ -439,7 +439,8 @@ heapgettup(Relation relation,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
++lpp; /* move forward in this page's ItemId array */
|
++lpp; /* move forward in this page's ItemId
|
||||||
|
* array */
|
||||||
++lineoff;
|
++lineoff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -816,6 +817,7 @@ heap_getnext(HeapScanDesc scandesc, int backw)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ /* NONTUP */
|
{ /* NONTUP */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't release scan->rs_cbuf at this point, because
|
* Don't release scan->rs_cbuf at this point, because
|
||||||
* heapgettup doesn't increase PrivateRefCount if it is
|
* heapgettup doesn't increase PrivateRefCount if it is
|
||||||
|
@ -897,6 +899,7 @@ heap_getnext(HeapScanDesc scandesc, int backw)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ /* NONTUP */
|
{ /* NONTUP */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't release scan->rs_cbuf at this point, because
|
* Don't release scan->rs_cbuf at this point, because
|
||||||
* heapgettup doesn't increase PrivateRefCount if it is
|
* heapgettup doesn't increase PrivateRefCount if it is
|
||||||
|
@ -966,11 +969,11 @@ heap_fetch(Relation relation,
|
||||||
HeapTuple tuple,
|
HeapTuple tuple,
|
||||||
Buffer *userbuf)
|
Buffer *userbuf)
|
||||||
{
|
{
|
||||||
ItemId lp;
|
ItemId lp;
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
PageHeader dp;
|
PageHeader dp;
|
||||||
ItemPointer tid = &(tuple->t_self);
|
ItemPointer tid = &(tuple->t_self);
|
||||||
OffsetNumber offnum;
|
OffsetNumber offnum;
|
||||||
|
|
||||||
AssertMacro(PointerIsValid(userbuf)); /* see comments above */
|
AssertMacro(PointerIsValid(userbuf)); /* see comments above */
|
||||||
|
|
||||||
|
@ -1093,9 +1096,7 @@ heap_insert(Relation relation, HeapTuple tup)
|
||||||
RelationPutHeapTupleAtEnd(relation, tup);
|
RelationPutHeapTupleAtEnd(relation, tup);
|
||||||
|
|
||||||
if (IsSystemRelationName(RelationGetRelationName(relation)->data))
|
if (IsSystemRelationName(RelationGetRelationName(relation)->data))
|
||||||
{
|
|
||||||
RelationInvalidateHeapTuple(relation, tup);
|
RelationInvalidateHeapTuple(relation, tup);
|
||||||
}
|
|
||||||
|
|
||||||
return tup->t_data->t_oid;
|
return tup->t_data->t_oid;
|
||||||
}
|
}
|
||||||
|
@ -1106,11 +1107,11 @@ heap_insert(Relation relation, HeapTuple tup)
|
||||||
int
|
int
|
||||||
heap_delete(Relation relation, ItemPointer tid, ItemPointer ctid)
|
heap_delete(Relation relation, ItemPointer tid, ItemPointer ctid)
|
||||||
{
|
{
|
||||||
ItemId lp;
|
ItemId lp;
|
||||||
HeapTupleData tp;
|
HeapTupleData tp;
|
||||||
PageHeader dp;
|
PageHeader dp;
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
/* increment access statistics */
|
/* increment access statistics */
|
||||||
IncrHeapAccessStat(local_delete);
|
IncrHeapAccessStat(local_delete);
|
||||||
|
@ -1130,10 +1131,10 @@ heap_delete(Relation relation, ItemPointer tid, ItemPointer ctid)
|
||||||
tp.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
|
tp.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
|
||||||
tp.t_len = ItemIdGetLength(lp);
|
tp.t_len = ItemIdGetLength(lp);
|
||||||
tp.t_self = *tid;
|
tp.t_self = *tid;
|
||||||
|
|
||||||
l1:
|
l1:
|
||||||
result = HeapTupleSatisfiesUpdate(&tp);
|
result = HeapTupleSatisfiesUpdate(&tp);
|
||||||
|
|
||||||
if (result == HeapTupleInvisible)
|
if (result == HeapTupleInvisible)
|
||||||
{
|
{
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
@ -1142,7 +1143,7 @@ l1:
|
||||||
}
|
}
|
||||||
else if (result == HeapTupleBeingUpdated)
|
else if (result == HeapTupleBeingUpdated)
|
||||||
{
|
{
|
||||||
TransactionId xwait = tp.t_data->t_xmax;
|
TransactionId xwait = tp.t_data->t_xmax;
|
||||||
|
|
||||||
/* sleep untill concurrent transaction ends */
|
/* sleep untill concurrent transaction ends */
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
@ -1177,8 +1178,8 @@ l1:
|
||||||
/* store transaction information of xact deleting the tuple */
|
/* store transaction information of xact deleting the tuple */
|
||||||
TransactionIdStore(GetCurrentTransactionId(), &(tp.t_data->t_xmax));
|
TransactionIdStore(GetCurrentTransactionId(), &(tp.t_data->t_xmax));
|
||||||
tp.t_data->t_cmax = GetCurrentCommandId();
|
tp.t_data->t_cmax = GetCurrentCommandId();
|
||||||
tp.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
|
tp.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
|
||||||
HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
|
HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
|
||||||
|
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
|
||||||
|
@ -1194,14 +1195,14 @@ l1:
|
||||||
* heap_replace - replace a tuple
|
* heap_replace - replace a tuple
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
heap_replace(Relation relation, ItemPointer otid, HeapTuple newtup,
|
heap_replace(Relation relation, ItemPointer otid, HeapTuple newtup,
|
||||||
ItemPointer ctid)
|
ItemPointer ctid)
|
||||||
{
|
{
|
||||||
ItemId lp;
|
ItemId lp;
|
||||||
HeapTupleData oldtup;
|
HeapTupleData oldtup;
|
||||||
PageHeader dp;
|
PageHeader dp;
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
/* increment access statistics */
|
/* increment access statistics */
|
||||||
IncrHeapAccessStat(local_replace);
|
IncrHeapAccessStat(local_replace);
|
||||||
|
@ -1223,7 +1224,7 @@ heap_replace(Relation relation, ItemPointer otid, HeapTuple newtup,
|
||||||
|
|
||||||
l2:
|
l2:
|
||||||
result = HeapTupleSatisfiesUpdate(&oldtup);
|
result = HeapTupleSatisfiesUpdate(&oldtup);
|
||||||
|
|
||||||
if (result == HeapTupleInvisible)
|
if (result == HeapTupleInvisible)
|
||||||
{
|
{
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
@ -1232,7 +1233,7 @@ l2:
|
||||||
}
|
}
|
||||||
else if (result == HeapTupleBeingUpdated)
|
else if (result == HeapTupleBeingUpdated)
|
||||||
{
|
{
|
||||||
TransactionId xwait = oldtup.t_data->t_xmax;
|
TransactionId xwait = oldtup.t_data->t_xmax;
|
||||||
|
|
||||||
/* sleep untill concurrent transaction ends */
|
/* sleep untill concurrent transaction ends */
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
@ -1275,19 +1276,20 @@ l2:
|
||||||
/* logically delete old item */
|
/* logically delete old item */
|
||||||
TransactionIdStore(GetCurrentTransactionId(), &(oldtup.t_data->t_xmax));
|
TransactionIdStore(GetCurrentTransactionId(), &(oldtup.t_data->t_xmax));
|
||||||
oldtup.t_data->t_cmax = GetCurrentCommandId();
|
oldtup.t_data->t_cmax = GetCurrentCommandId();
|
||||||
oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
|
oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
|
||||||
HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
|
HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
|
||||||
|
|
||||||
/* insert new item */
|
/* insert new item */
|
||||||
if ((unsigned) DOUBLEALIGN(newtup->t_len) <= PageGetFreeSpace((Page) dp))
|
if ((unsigned) DOUBLEALIGN(newtup->t_len) <= PageGetFreeSpace((Page) dp))
|
||||||
RelationPutHeapTuple(relation, buffer, newtup);
|
RelationPutHeapTuple(relation, buffer, newtup);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* New item won't fit on same page as old item, have to look
|
* New item won't fit on same page as old item, have to look for a
|
||||||
* for a new place to put it. Note that we have to unlock
|
* new place to put it. Note that we have to unlock current buffer
|
||||||
* current buffer context - not good but RelationPutHeapTupleAtEnd
|
* context - not good but RelationPutHeapTupleAtEnd uses extend
|
||||||
* uses extend lock.
|
* lock.
|
||||||
*/
|
*/
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
RelationPutHeapTupleAtEnd(relation, newtup);
|
RelationPutHeapTupleAtEnd(relation, newtup);
|
||||||
|
@ -1295,8 +1297,8 @@ l2:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* New item in place, now record address of new tuple in
|
* New item in place, now record address of new tuple in t_ctid of old
|
||||||
* t_ctid of old one.
|
* one.
|
||||||
*/
|
*/
|
||||||
oldtup.t_data->t_ctid = newtup->t_self;
|
oldtup.t_data->t_ctid = newtup->t_self;
|
||||||
|
|
||||||
|
@ -1316,10 +1318,10 @@ l2:
|
||||||
int
|
int
|
||||||
heap_mark4update(Relation relation, HeapTuple tuple, Buffer *buffer)
|
heap_mark4update(Relation relation, HeapTuple tuple, Buffer *buffer)
|
||||||
{
|
{
|
||||||
ItemPointer tid = &(tuple->t_self);
|
ItemPointer tid = &(tuple->t_self);
|
||||||
ItemId lp;
|
ItemId lp;
|
||||||
PageHeader dp;
|
PageHeader dp;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
/* increment access statistics */
|
/* increment access statistics */
|
||||||
IncrHeapAccessStat(local_mark4update);
|
IncrHeapAccessStat(local_mark4update);
|
||||||
|
@ -1336,10 +1338,10 @@ heap_mark4update(Relation relation, HeapTuple tuple, Buffer *buffer)
|
||||||
lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
|
lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
|
||||||
tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
|
tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
|
||||||
tuple->t_len = ItemIdGetLength(lp);
|
tuple->t_len = ItemIdGetLength(lp);
|
||||||
|
|
||||||
l3:
|
l3:
|
||||||
result = HeapTupleSatisfiesUpdate(tuple);
|
result = HeapTupleSatisfiesUpdate(tuple);
|
||||||
|
|
||||||
if (result == HeapTupleInvisible)
|
if (result == HeapTupleInvisible)
|
||||||
{
|
{
|
||||||
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
@ -1348,7 +1350,7 @@ l3:
|
||||||
}
|
}
|
||||||
else if (result == HeapTupleBeingUpdated)
|
else if (result == HeapTupleBeingUpdated)
|
||||||
{
|
{
|
||||||
TransactionId xwait = tuple->t_data->t_xmax;
|
TransactionId xwait = tuple->t_data->t_xmax;
|
||||||
|
|
||||||
/* sleep untill concurrent transaction ends */
|
/* sleep untill concurrent transaction ends */
|
||||||
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Id: hio.c,v 1.19 1999/05/07 01:22:53 vadim Exp $
|
* $Id: hio.c,v 1.20 1999/05/25 16:07:07 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -39,11 +39,11 @@ RelationPutHeapTuple(Relation relation,
|
||||||
Buffer buffer,
|
Buffer buffer,
|
||||||
HeapTuple tuple)
|
HeapTuple tuple)
|
||||||
{
|
{
|
||||||
Page pageHeader;
|
Page pageHeader;
|
||||||
OffsetNumber offnum;
|
OffsetNumber offnum;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
ItemId itemId;
|
ItemId itemId;
|
||||||
Item item;
|
Item item;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
|
@ -62,13 +62,13 @@ RelationPutHeapTuple(Relation relation,
|
||||||
itemId = PageGetItemId((Page) pageHeader, offnum);
|
itemId = PageGetItemId((Page) pageHeader, offnum);
|
||||||
item = PageGetItem((Page) pageHeader, itemId);
|
item = PageGetItem((Page) pageHeader, itemId);
|
||||||
|
|
||||||
ItemPointerSet(&((HeapTupleHeader) item)->t_ctid,
|
ItemPointerSet(&((HeapTupleHeader) item)->t_ctid,
|
||||||
BufferGetBlockNumber(buffer), offnum);
|
BufferGetBlockNumber(buffer), offnum);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Let the caller do this!
|
* Let the caller do this!
|
||||||
*
|
*
|
||||||
WriteBuffer(buffer);
|
* WriteBuffer(buffer);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* return an accurate tuple */
|
/* return an accurate tuple */
|
||||||
|
@ -111,8 +111,8 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
|
||||||
Item item;
|
Item item;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock relation for extention. We can use LockPage here as long as
|
* Lock relation for extention. We can use LockPage here as long as in
|
||||||
* in all other places we use page-level locking for indices only.
|
* all other places we use page-level locking for indices only.
|
||||||
* Alternatevely, we could define pseudo-table as we do for
|
* Alternatevely, we could define pseudo-table as we do for
|
||||||
* transactions with XactLockTable.
|
* transactions with XactLockTable.
|
||||||
*/
|
*/
|
||||||
|
@ -132,6 +132,7 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
|
||||||
{
|
{
|
||||||
buffer = ReadBuffer(relation, lastblock);
|
buffer = ReadBuffer(relation, lastblock);
|
||||||
pageHeader = (Page) BufferGetPage(buffer);
|
pageHeader = (Page) BufferGetPage(buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There was IF instead of ASSERT here ?!
|
* There was IF instead of ASSERT here ?!
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.16 1999/02/13 23:14:29 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.17 1999/05/25 16:07:12 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* many of the old access method routines have been turned into
|
* many of the old access method routines have been turned into
|
||||||
|
@ -270,5 +270,5 @@ IndexScanRestorePosition(IndexScanDesc scan)
|
||||||
|
|
||||||
scan->flags = 0x0; /* XXX should have a symbolic name */
|
scan->flags = 0x0; /* XXX should have a symbolic name */
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.31 1999/02/13 23:14:30 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.32 1999/05/25 16:07:15 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -57,7 +57,7 @@ static bool StrategyTermIsValid(StrategyTerm term,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* StrategyMapGetScanKeyEntry
|
* StrategyMapGetScanKeyEntry
|
||||||
* Returns a scan key entry of a index strategy mapping member.
|
* Returns a scan key entry of a index strategy mapping member.
|
||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
|
@ -75,7 +75,7 @@ StrategyMapGetScanKeyEntry(StrategyMap map,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IndexStrategyGetStrategyMap
|
* IndexStrategyGetStrategyMap
|
||||||
* Returns an index strategy mapping of an index strategy.
|
* Returns an index strategy mapping of an index strategy.
|
||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
|
@ -97,7 +97,7 @@ IndexStrategyGetStrategyMap(IndexStrategy indexStrategy,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AttributeNumberGetIndexStrategySize
|
* AttributeNumberGetIndexStrategySize
|
||||||
* Computes the size of an index strategy.
|
* Computes the size of an index strategy.
|
||||||
*/
|
*/
|
||||||
Size
|
Size
|
||||||
|
@ -294,8 +294,8 @@ RelationGetStrategy(Relation relation,
|
||||||
Assert(RegProcedureIsValid(procedure));
|
Assert(RegProcedureIsValid(procedure));
|
||||||
|
|
||||||
strategyMap = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
|
strategyMap = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
|
||||||
evaluation->maxStrategy,
|
evaluation->maxStrategy,
|
||||||
attributeNumber);
|
attributeNumber);
|
||||||
|
|
||||||
/* get a strategy number for the procedure ignoring flags for now */
|
/* get a strategy number for the procedure ignoring flags for now */
|
||||||
for (index = 0; index < evaluation->maxStrategy; index += 1)
|
for (index = 0; index < evaluation->maxStrategy; index += 1)
|
||||||
|
@ -526,7 +526,7 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation,
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IndexSupportInitialize
|
* IndexSupportInitialize
|
||||||
* Initializes an index strategy and associated support procedures.
|
* Initializes an index strategy and associated support procedures.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.22 1999/03/14 05:08:56 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.23 1999/05/25 16:07:21 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* These functions are stored in pg_amproc. For each operator class
|
* These functions are stored in pg_amproc. For each operator class
|
||||||
|
@ -40,7 +40,7 @@ btint4cmp(int32 a, int32 b)
|
||||||
}
|
}
|
||||||
|
|
||||||
int32
|
int32
|
||||||
btint8cmp(int64 *a, int64 *b)
|
btint8cmp(int64 * a, int64 * b)
|
||||||
{
|
{
|
||||||
if (*a > *b)
|
if (*a > *b)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.39 1999/05/01 16:09:45 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.40 1999/05/25 16:07:23 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -99,13 +99,13 @@ l1:
|
||||||
/* key on the page before trying to compare it */
|
/* key on the page before trying to compare it */
|
||||||
if (!PageIsEmpty(page) && offset <= maxoff)
|
if (!PageIsEmpty(page) && offset <= maxoff)
|
||||||
{
|
{
|
||||||
TupleDesc itupdesc;
|
TupleDesc itupdesc;
|
||||||
BTItem cbti;
|
BTItem cbti;
|
||||||
HeapTupleData htup;
|
HeapTupleData htup;
|
||||||
BTPageOpaque opaque;
|
BTPageOpaque opaque;
|
||||||
Buffer nbuf;
|
Buffer nbuf;
|
||||||
BlockNumber blkno;
|
BlockNumber blkno;
|
||||||
bool chtup = true;
|
bool chtup = true;
|
||||||
|
|
||||||
itupdesc = RelationGetDescr(rel);
|
itupdesc = RelationGetDescr(rel);
|
||||||
nbuf = InvalidBuffer;
|
nbuf = InvalidBuffer;
|
||||||
|
@ -122,15 +122,16 @@ l1:
|
||||||
*/
|
*/
|
||||||
while (_bt_isequal(itupdesc, page, offset, natts, itup_scankey))
|
while (_bt_isequal(itupdesc, page, offset, natts, itup_scankey))
|
||||||
{ /* they're equal */
|
{ /* they're equal */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Have to check is inserted heap tuple deleted one
|
* Have to check is inserted heap tuple deleted one (i.e.
|
||||||
* (i.e. just moved to another place by vacuum)!
|
* just moved to another place by vacuum)!
|
||||||
*/
|
*/
|
||||||
if (chtup)
|
if (chtup)
|
||||||
{
|
{
|
||||||
htup.t_self = btitem->bti_itup.t_tid;
|
htup.t_self = btitem->bti_itup.t_tid;
|
||||||
heap_fetch(heapRel, SnapshotDirty, &htup, &buffer);
|
heap_fetch(heapRel, SnapshotDirty, &htup, &buffer);
|
||||||
if (htup.t_data == NULL) /* YES! */
|
if (htup.t_data == NULL) /* YES! */
|
||||||
break;
|
break;
|
||||||
/* Live tuple was inserted */
|
/* Live tuple was inserted */
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
|
@ -139,11 +140,11 @@ l1:
|
||||||
cbti = (BTItem) PageGetItem(page, PageGetItemId(page, offset));
|
cbti = (BTItem) PageGetItem(page, PageGetItemId(page, offset));
|
||||||
htup.t_self = cbti->bti_itup.t_tid;
|
htup.t_self = cbti->bti_itup.t_tid;
|
||||||
heap_fetch(heapRel, SnapshotDirty, &htup, &buffer);
|
heap_fetch(heapRel, SnapshotDirty, &htup, &buffer);
|
||||||
if (htup.t_data != NULL) /* it is a duplicate */
|
if (htup.t_data != NULL) /* it is a duplicate */
|
||||||
{
|
{
|
||||||
TransactionId xwait =
|
TransactionId xwait =
|
||||||
(TransactionIdIsValid(SnapshotDirty->xmin)) ?
|
(TransactionIdIsValid(SnapshotDirty->xmin)) ?
|
||||||
SnapshotDirty->xmin : SnapshotDirty->xmax;
|
SnapshotDirty->xmin : SnapshotDirty->xmax;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this tuple is being updated by other transaction
|
* If this tuple is being updated by other transaction
|
||||||
|
@ -156,7 +157,7 @@ l1:
|
||||||
_bt_relbuf(rel, nbuf, BT_READ);
|
_bt_relbuf(rel, nbuf, BT_READ);
|
||||||
_bt_relbuf(rel, buf, BT_WRITE);
|
_bt_relbuf(rel, buf, BT_WRITE);
|
||||||
XactLockTableWait(xwait);
|
XactLockTableWait(xwait);
|
||||||
goto l1; /* continue from the begin */
|
goto l1;/* continue from the begin */
|
||||||
}
|
}
|
||||||
elog(ERROR, "Cannot insert a duplicate key into a unique index");
|
elog(ERROR, "Cannot insert a duplicate key into a unique index");
|
||||||
}
|
}
|
||||||
|
@ -571,10 +572,10 @@ _bt_insertonpg(Relation rel,
|
||||||
* reasoning).
|
* reasoning).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
l_spl:;
|
l_spl: ;
|
||||||
if (stack == (BTStack) NULL)
|
if (stack == (BTStack) NULL)
|
||||||
{
|
{
|
||||||
if (!is_root) /* if this page was not root page */
|
if (!is_root) /* if this page was not root page */
|
||||||
{
|
{
|
||||||
elog(DEBUG, "btree: concurrent ROOT page split");
|
elog(DEBUG, "btree: concurrent ROOT page split");
|
||||||
stack = (BTStack) palloc(sizeof(BTStackData));
|
stack = (BTStack) palloc(sizeof(BTStackData));
|
||||||
|
@ -1144,8 +1145,8 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
|
||||||
lpage = BufferGetPage(lbuf);
|
lpage = BufferGetPage(lbuf);
|
||||||
rpage = BufferGetPage(rbuf);
|
rpage = BufferGetPage(rbuf);
|
||||||
|
|
||||||
((BTPageOpaque) PageGetSpecialPointer(lpage))->btpo_parent =
|
((BTPageOpaque) PageGetSpecialPointer(lpage))->btpo_parent =
|
||||||
((BTPageOpaque) PageGetSpecialPointer(rpage))->btpo_parent =
|
((BTPageOpaque) PageGetSpecialPointer(rpage))->btpo_parent =
|
||||||
rootbknum;
|
rootbknum;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.20 1999/04/22 08:19:59 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.21 1999/05/25 16:07:26 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Postgres btree pages look like ordinary relation pages. The opaque
|
* Postgres btree pages look like ordinary relation pages. The opaque
|
||||||
|
@ -421,7 +421,7 @@ _bt_pageinit(Page page, Size size)
|
||||||
MemSet(page, 0, size);
|
MemSet(page, 0, size);
|
||||||
|
|
||||||
PageInit(page, size, sizeof(BTPageOpaqueData));
|
PageInit(page, size, sizeof(BTPageOpaqueData));
|
||||||
((BTPageOpaque) PageGetSpecialPointer(page))->btpo_parent =
|
((BTPageOpaque) PageGetSpecialPointer(page))->btpo_parent =
|
||||||
InvalidBlockNumber;
|
InvalidBlockNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,17 +494,16 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
|
|
||||||
if (stack->bts_offset == InvalidOffsetNumber ||
|
if (stack->bts_offset == InvalidOffsetNumber ||
|
||||||
maxoff >= stack->bts_offset)
|
maxoff >= stack->bts_offset)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* _bt_insertonpg set bts_offset to InvalidOffsetNumber
|
* _bt_insertonpg set bts_offset to InvalidOffsetNumber in the
|
||||||
* in the case of concurrent ROOT page split
|
* case of concurrent ROOT page split
|
||||||
*/
|
*/
|
||||||
if (stack->bts_offset == InvalidOffsetNumber)
|
if (stack->bts_offset == InvalidOffsetNumber)
|
||||||
{
|
|
||||||
i = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
|
i = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
itemid = PageGetItemId(page, stack->bts_offset);
|
itemid = PageGetItemId(page, stack->bts_offset);
|
||||||
|
@ -524,7 +523,7 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if the item has just moved right on this page, we're done */
|
/* if the item has just moved right on this page, we're done */
|
||||||
for ( ;
|
for (;
|
||||||
i <= maxoff;
|
i <= maxoff;
|
||||||
i = OffsetNumberNext(i))
|
i = OffsetNumberNext(i))
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.37 1999/03/28 20:31:58 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.38 1999/05/25 16:07:27 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* This file contains only the public interface routines.
|
* This file contains only the public interface routines.
|
||||||
|
@ -367,7 +367,7 @@ btinsert(Relation rel, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation
|
||||||
btitem = _bt_formitem(itup);
|
btitem = _bt_formitem(itup);
|
||||||
|
|
||||||
res = _bt_doinsert(rel, btitem,
|
res = _bt_doinsert(rel, btitem,
|
||||||
IndexIsUnique(RelationGetRelid(rel)), heapRel);
|
IndexIsUnique(RelationGetRelid(rel)), heapRel);
|
||||||
|
|
||||||
pfree(btitem);
|
pfree(btitem);
|
||||||
pfree(itup);
|
pfree(itup);
|
||||||
|
@ -391,9 +391,10 @@ btgettuple(IndexScanDesc scan, ScanDirection dir)
|
||||||
|
|
||||||
if (ItemPointerIsValid(&(scan->currentItemData)))
|
if (ItemPointerIsValid(&(scan->currentItemData)))
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore scan position using heap TID returned
|
* Restore scan position using heap TID returned by previous call
|
||||||
* by previous call to btgettuple().
|
* to btgettuple().
|
||||||
*/
|
*/
|
||||||
_bt_restscan(scan);
|
_bt_restscan(scan);
|
||||||
res = _bt_next(scan, dir);
|
res = _bt_next(scan, dir);
|
||||||
|
@ -623,16 +624,15 @@ _bt_restscan(IndexScanDesc scan)
|
||||||
BlockNumber blkno;
|
BlockNumber blkno;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We use this as flag when first index tuple on page
|
* We use this as flag when first index tuple on page is deleted but
|
||||||
* is deleted but we do not move left (this would
|
* we do not move left (this would slowdown vacuum) - so we set
|
||||||
* slowdown vacuum) - so we set current->ip_posid
|
* current->ip_posid before first index tuple on the current page
|
||||||
* before first index tuple on the current page
|
|
||||||
* (_bt_step will move it right)...
|
* (_bt_step will move it right)...
|
||||||
*/
|
*/
|
||||||
if (!ItemPointerIsValid(&target))
|
if (!ItemPointerIsValid(&target))
|
||||||
{
|
{
|
||||||
ItemPointerSetOffsetNumber(&(scan->currentItemData),
|
ItemPointerSetOffsetNumber(&(scan->currentItemData),
|
||||||
OffsetNumberPrev(P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY));
|
OffsetNumberPrev(P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtscan.c,v 1.20 1999/03/28 20:31:58 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtscan.c,v 1.21 1999/05/25 16:07:29 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
|
@ -112,12 +112,12 @@ _bt_adjscans(Relation rel, ItemPointer tid)
|
||||||
static void
|
static void
|
||||||
_bt_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
|
_bt_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
|
||||||
{
|
{
|
||||||
ItemPointer current;
|
ItemPointer current;
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
BTScanOpaque so;
|
BTScanOpaque so;
|
||||||
OffsetNumber start;
|
OffsetNumber start;
|
||||||
Page page;
|
Page page;
|
||||||
BTPageOpaque opaque;
|
BTPageOpaque opaque;
|
||||||
|
|
||||||
so = (BTScanOpaque) scan->opaque;
|
so = (BTScanOpaque) scan->opaque;
|
||||||
buf = so->btso_curbuf;
|
buf = so->btso_curbuf;
|
||||||
|
@ -140,7 +140,7 @@ _bt_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
|
||||||
{
|
{
|
||||||
Page pg = BufferGetPage(buf);
|
Page pg = BufferGetPage(buf);
|
||||||
BTItem btitem = (BTItem) PageGetItem(pg,
|
BTItem btitem = (BTItem) PageGetItem(pg,
|
||||||
PageGetItemId(pg, ItemPointerGetOffsetNumber(current)));
|
PageGetItemId(pg, ItemPointerGetOffsetNumber(current)));
|
||||||
|
|
||||||
so->curHeapIptr = btitem->bti_itup.t_tid;
|
so->curHeapIptr = btitem->bti_itup.t_tid;
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ _bt_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
|
||||||
{
|
{
|
||||||
Page pg = BufferGetPage(buf);
|
Page pg = BufferGetPage(buf);
|
||||||
BTItem btitem = (BTItem) PageGetItem(pg,
|
BTItem btitem = (BTItem) PageGetItem(pg,
|
||||||
PageGetItemId(pg, ItemPointerGetOffsetNumber(current)));
|
PageGetItemId(pg, ItemPointerGetOffsetNumber(current)));
|
||||||
|
|
||||||
so->mrkHeapIptr = btitem->bti_itup.t_tid;
|
so->mrkHeapIptr = btitem->bti_itup.t_tid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.43 1999/04/13 17:18:28 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.44 1999/05/25 16:07:31 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -706,7 +706,7 @@ _bt_next(IndexScanDesc scan, ScanDirection dir)
|
||||||
so = (BTScanOpaque) scan->opaque;
|
so = (BTScanOpaque) scan->opaque;
|
||||||
current = &(scan->currentItemData);
|
current = &(scan->currentItemData);
|
||||||
|
|
||||||
Assert (BufferIsValid(so->btso_curbuf));
|
Assert(BufferIsValid(so->btso_curbuf));
|
||||||
|
|
||||||
/* we still have the buffer pinned and locked */
|
/* we still have the buffer pinned and locked */
|
||||||
buf = so->btso_curbuf;
|
buf = so->btso_curbuf;
|
||||||
|
@ -733,8 +733,8 @@ _bt_next(IndexScanDesc scan, ScanDirection dir)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (keysok >= so->numberOfFirstKeys ||
|
} while (keysok >= so->numberOfFirstKeys ||
|
||||||
(keysok == -1 && ScanDirectionIsBackward(dir)));
|
(keysok == -1 && ScanDirectionIsBackward(dir)));
|
||||||
|
|
||||||
ItemPointerSetInvalid(current);
|
ItemPointerSetInvalid(current);
|
||||||
so->btso_curbuf = InvalidBuffer;
|
so->btso_curbuf = InvalidBuffer;
|
||||||
|
@ -776,8 +776,8 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
BTScanOpaque so;
|
BTScanOpaque so;
|
||||||
ScanKeyData skdata;
|
ScanKeyData skdata;
|
||||||
Size keysok;
|
Size keysok;
|
||||||
int i;
|
int i;
|
||||||
int nKeyIndex = -1;
|
int nKeyIndex = -1;
|
||||||
|
|
||||||
rel = scan->relation;
|
rel = scan->relation;
|
||||||
so = (BTScanOpaque) scan->opaque;
|
so = (BTScanOpaque) scan->opaque;
|
||||||
|
@ -795,27 +795,27 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
|
|
||||||
if (ScanDirectionIsBackward(dir))
|
if (ScanDirectionIsBackward(dir))
|
||||||
{
|
{
|
||||||
for (i=0; i<so->numberOfKeys; i++)
|
for (i = 0; i < so->numberOfKeys; i++)
|
||||||
{
|
{
|
||||||
if (so->keyData[i].sk_attno != 1)
|
if (so->keyData[i].sk_attno != 1)
|
||||||
break;
|
break;
|
||||||
strat = _bt_getstrat(rel, so->keyData[i].sk_attno,
|
strat = _bt_getstrat(rel, so->keyData[i].sk_attno,
|
||||||
so->keyData[i].sk_procedure);
|
so->keyData[i].sk_procedure);
|
||||||
if (strat == BTLessStrategyNumber ||
|
if (strat == BTLessStrategyNumber ||
|
||||||
strat == BTLessEqualStrategyNumber||
|
strat == BTLessEqualStrategyNumber ||
|
||||||
strat == BTEqualStrategyNumber)
|
strat == BTEqualStrategyNumber)
|
||||||
{
|
{
|
||||||
nKeyIndex = i;
|
nKeyIndex = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strat = _bt_getstrat(rel, 1, so->keyData[0].sk_procedure);
|
strat = _bt_getstrat(rel, 1, so->keyData[0].sk_procedure);
|
||||||
|
|
||||||
if (strat == BTLessStrategyNumber ||
|
if (strat == BTLessStrategyNumber ||
|
||||||
strat == BTLessEqualStrategyNumber)
|
strat == BTLessEqualStrategyNumber)
|
||||||
;
|
;
|
||||||
else
|
else
|
||||||
nKeyIndex = 0;
|
nKeyIndex = 0;
|
||||||
|
@ -850,7 +850,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
}
|
}
|
||||||
proc = index_getprocid(rel, 1, BTORDER_PROC);
|
proc = index_getprocid(rel, 1, BTORDER_PROC);
|
||||||
ScanKeyEntryInitialize(&skdata, so->keyData[nKeyIndex].sk_flags,
|
ScanKeyEntryInitialize(&skdata, so->keyData[nKeyIndex].sk_flags,
|
||||||
1, proc, so->keyData[nKeyIndex].sk_argument);
|
1, proc, so->keyData[nKeyIndex].sk_argument);
|
||||||
|
|
||||||
stack = _bt_search(rel, 1, &skdata, &buf);
|
stack = _bt_search(rel, 1, &skdata, &buf);
|
||||||
_bt_freestack(stack);
|
_bt_freestack(stack);
|
||||||
|
@ -1104,9 +1104,10 @@ _bt_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
||||||
|
|
||||||
rel = scan->relation;
|
rel = scan->relation;
|
||||||
current = &(scan->currentItemData);
|
current = &(scan->currentItemData);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't use ItemPointerGetOffsetNumber or you risk to get
|
* Don't use ItemPointerGetOffsetNumber or you risk to get assertion
|
||||||
* assertion due to ability of ip_posid to be equal 0.
|
* due to ability of ip_posid to be equal 0.
|
||||||
*/
|
*/
|
||||||
offnum = current->ip_posid;
|
offnum = current->ip_posid;
|
||||||
page = BufferGetPage(*bufP);
|
page = BufferGetPage(*bufP);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Id: nbtsort.c,v 1.38 1999/05/09 00:53:19 tgl Exp $
|
* $Id: nbtsort.c,v 1.39 1999/05/25 16:07:34 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
*
|
*
|
||||||
|
@ -552,16 +552,16 @@ _bt_spoolinit(Relation index, int ntapes, bool isunique)
|
||||||
btspool->bts_tape = 0;
|
btspool->bts_tape = 0;
|
||||||
btspool->isunique = isunique;
|
btspool->isunique = isunique;
|
||||||
|
|
||||||
btspool->bts_itape =(BTTapeBlock **) palloc(sizeof(BTTapeBlock *) * ntapes);
|
btspool->bts_itape = (BTTapeBlock **) palloc(sizeof(BTTapeBlock *) * ntapes);
|
||||||
btspool->bts_otape =(BTTapeBlock **) palloc(sizeof(BTTapeBlock *) * ntapes);
|
btspool->bts_otape = (BTTapeBlock **) palloc(sizeof(BTTapeBlock *) * ntapes);
|
||||||
if (btspool->bts_itape == (BTTapeBlock **) NULL ||
|
if (btspool->bts_itape == (BTTapeBlock **) NULL ||
|
||||||
btspool->bts_otape == (BTTapeBlock **) NULL)
|
btspool->bts_otape == (BTTapeBlock **) NULL)
|
||||||
elog(ERROR, "_bt_spoolinit: out of memory");
|
elog(ERROR, "_bt_spoolinit: out of memory");
|
||||||
|
|
||||||
for (i = 0; i < ntapes; ++i)
|
for (i = 0; i < ntapes; ++i)
|
||||||
{
|
{
|
||||||
btspool->bts_itape[i] = _bt_tapecreate();
|
btspool->bts_itape[i] = _bt_tapecreate();
|
||||||
btspool->bts_otape[i] = _bt_tapecreate();
|
btspool->bts_otape[i] = _bt_tapecreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
_bt_isortcmpinit(index, btspool);
|
_bt_isortcmpinit(index, btspool);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.31 1999/02/13 23:14:42 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.32 1999/05/25 16:07:38 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -307,7 +307,7 @@ rtinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation he
|
||||||
/*
|
/*
|
||||||
* Notes in ExecUtils:ExecOpenIndices()
|
* Notes in ExecUtils:ExecOpenIndices()
|
||||||
*
|
*
|
||||||
RelationSetLockForWrite(r);
|
* RelationSetLockForWrite(r);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
res = rtdoinsert(r, itup, &rtState);
|
res = rtdoinsert(r, itup, &rtState);
|
||||||
|
@ -947,10 +947,10 @@ rtdelete(Relation r, ItemPointer tid)
|
||||||
Page page;
|
Page page;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Notes in ExecUtils:ExecOpenIndices()
|
* Notes in ExecUtils:ExecOpenIndices() Also note that only vacuum
|
||||||
* Also note that only vacuum deletes index tuples now...
|
* deletes index tuples now...
|
||||||
*
|
*
|
||||||
RelationSetLockForWrite(r);
|
* RelationSetLockForWrite(r);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
blkno = ItemPointerGetBlockNumber(tid);
|
blkno = ItemPointerGetBlockNumber(tid);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.22 1999/02/13 23:14:43 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.23 1999/05/25 16:07:40 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -69,7 +69,7 @@ rtbeginscan(Relation r,
|
||||||
/*
|
/*
|
||||||
* Let index_beginscan does its work...
|
* Let index_beginscan does its work...
|
||||||
*
|
*
|
||||||
RelationSetLockForRead(r);
|
* RelationSetLockForRead(r);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
s = RelationGetIndexScan(r, fromEnd, nkeys, key);
|
s = RelationGetIndexScan(r, fromEnd, nkeys, key);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.25 1999/03/30 01:37:21 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.26 1999/05/25 16:07:45 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* This file contains the high level access-method interface to the
|
* This file contains the high level access-method interface to the
|
||||||
|
@ -221,7 +221,7 @@ TransactionLogUpdate(TransactionId transactionId, /* trans id to update */
|
||||||
/*
|
/*
|
||||||
* update (invalidate) our single item TransactionLogTest cache.
|
* update (invalidate) our single item TransactionLogTest cache.
|
||||||
*
|
*
|
||||||
if (status != XID_COMMIT)
|
* if (status != XID_COMMIT)
|
||||||
*
|
*
|
||||||
* What's the hell ?! Why != XID_COMMIT ?!
|
* What's the hell ?! Why != XID_COMMIT ?!
|
||||||
*/
|
*/
|
||||||
|
@ -374,7 +374,7 @@ TransRecover(Relation logRelation)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* InitializeTransactionLog
|
* InitializeTransactionLog
|
||||||
* Initializes transaction logging.
|
* Initializes transaction logging.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
@ -484,7 +484,7 @@ InitializeTransactionLog(void)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TransactionIdDidCommit
|
* TransactionIdDidCommit
|
||||||
* True iff transaction associated with the identifier did commit.
|
* True iff transaction associated with the identifier did commit.
|
||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
|
@ -500,7 +500,7 @@ TransactionIdDidCommit(TransactionId transactionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TransactionIdDidAborted
|
* TransactionIdDidAborted
|
||||||
* True iff transaction associated with the identifier did abort.
|
* True iff transaction associated with the identifier did abort.
|
||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
|
@ -541,7 +541,7 @@ TransactionIdIsInProgress(TransactionId transactionId)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TransactionIdCommit
|
* TransactionIdCommit
|
||||||
* Commits the transaction associated with the identifier.
|
* Commits the transaction associated with the identifier.
|
||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
|
@ -557,7 +557,7 @@ TransactionIdCommit(TransactionId transactionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TransactionIdAbort
|
* TransactionIdAbort
|
||||||
* Aborts the transaction associated with the identifier.
|
* Aborts the transaction associated with the identifier.
|
||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.19 1999/02/13 23:14:48 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.20 1999/05/25 16:07:48 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -260,7 +260,7 @@ VariableRelationPutNextOid(Oid *oidP)
|
||||||
* In the version 2 transaction system, transaction id's are
|
* In the version 2 transaction system, transaction id's are
|
||||||
* restricted in several ways.
|
* restricted in several ways.
|
||||||
*
|
*
|
||||||
* -- Old comments removed
|
* -- Old comments removed
|
||||||
*
|
*
|
||||||
* Second, since we may someday preform compression of the data
|
* Second, since we may someday preform compression of the data
|
||||||
* in the log and time relations, we cause the numbering of the
|
* in the log and time relations, we cause the numbering of the
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.35 1999/05/13 00:34:57 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.36 1999/05/25 16:07:50 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Transaction aborts can now occur two ways:
|
* Transaction aborts can now occur two ways:
|
||||||
|
@ -194,8 +194,8 @@ TransactionStateData CurrentTransactionStateData = {
|
||||||
|
|
||||||
TransactionState CurrentTransactionState = &CurrentTransactionStateData;
|
TransactionState CurrentTransactionState = &CurrentTransactionStateData;
|
||||||
|
|
||||||
int DefaultXactIsoLevel = XACT_READ_COMMITTED;
|
int DefaultXactIsoLevel = XACT_READ_COMMITTED;
|
||||||
int XactIsoLevel;
|
int XactIsoLevel;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* info returned when the system is disabled
|
* info returned when the system is disabled
|
||||||
|
@ -299,6 +299,7 @@ IsTransactionState(void)
|
||||||
*/
|
*/
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
|
@ -516,7 +517,7 @@ CommandCounterIncrement()
|
||||||
AtStart_Cache();
|
AtStart_Cache();
|
||||||
|
|
||||||
TransactionIdFlushCache();
|
TransactionIdFlushCache();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -695,9 +696,9 @@ AtCommit_Memory()
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Release memory in the blank portal.
|
* Release memory in the blank portal.
|
||||||
* Since EndPortalAllocMode implicitly works on the current context,
|
* Since EndPortalAllocMode implicitly works on the current context,
|
||||||
* first make real sure that the blank portal is the selected context.
|
* first make real sure that the blank portal is the selected context.
|
||||||
* (This is probably not necessary, but seems like a good idea...)
|
* (This is probably not necessary, but seems like a good idea...)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
portal = GetPortalByName(NULL);
|
portal = GetPortalByName(NULL);
|
||||||
|
@ -789,9 +790,9 @@ AtAbort_Memory()
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Release memory in the blank portal.
|
* Release memory in the blank portal.
|
||||||
* Since EndPortalAllocMode implicitly works on the current context,
|
* Since EndPortalAllocMode implicitly works on the current context,
|
||||||
* first make real sure that the blank portal is the selected context.
|
* first make real sure that the blank portal is the selected context.
|
||||||
* (This is ESSENTIAL in case we aborted from someplace where it wasn't.)
|
* (This is ESSENTIAL in case we aborted from someplace where it wasn't.)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
portal = GetPortalByName(NULL);
|
portal = GetPortalByName(NULL);
|
||||||
|
@ -1074,7 +1075,7 @@ StartTransactionCommand()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* As with BEGIN, we should never experience this
|
* As with BEGIN, we should never experience this
|
||||||
* if we do it means the END state was not changed in the
|
* if we do it means the END state was not changed in the
|
||||||
* previous CommitTransactionCommand(). If we get it, we
|
* previous CommitTransactionCommand(). If we get it, we
|
||||||
* print a warning, commit the transaction, start a new
|
* print a warning, commit the transaction, start a new
|
||||||
|
@ -1509,6 +1510,7 @@ AbortOutOfAnyTransaction()
|
||||||
*/
|
*/
|
||||||
if (s->state != TRANS_DEFAULT)
|
if (s->state != TRANS_DEFAULT)
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now reset the high-level state
|
* Now reset the high-level state
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: xid.c,v 1.21 1999/02/13 23:14:49 momjian Exp $
|
* $Id: xid.c,v 1.22 1999/05/25 16:07:52 momjian Exp $
|
||||||
*
|
*
|
||||||
* OLD COMMENTS
|
* OLD COMMENTS
|
||||||
* XXX WARNING
|
* XXX WARNING
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.59 1999/05/10 00:44:52 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.60 1999/05/25 16:07:56 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -182,7 +182,7 @@ static char *relname; /* current relation name */
|
||||||
Form_pg_attribute attrtypes[MAXATTR]; /* points to attribute info */
|
Form_pg_attribute attrtypes[MAXATTR]; /* points to attribute info */
|
||||||
static char *values[MAXATTR]; /* cooresponding attribute values */
|
static char *values[MAXATTR]; /* cooresponding attribute values */
|
||||||
int numattr; /* number of attributes for cur. rel */
|
int numattr; /* number of attributes for cur. rel */
|
||||||
extern bool disableFsync; /* do not fsync the database */
|
extern bool disableFsync; /* do not fsync the database */
|
||||||
|
|
||||||
int DebugMode;
|
int DebugMode;
|
||||||
static GlobalMemory nogc = (GlobalMemory) NULL; /* special no-gc mem
|
static GlobalMemory nogc = (GlobalMemory) NULL; /* special no-gc mem
|
||||||
|
@ -587,7 +587,9 @@ DefineAttr(char *name, char *type, int attnum)
|
||||||
printf("<%s %s> ", attrtypes[attnum]->attname.data, type);
|
printf("<%s %s> ", attrtypes[attnum]->attname.data, type);
|
||||||
attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
|
attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
|
||||||
attlen = attrtypes[attnum]->attlen = Procid[typeoid].len;
|
attlen = attrtypes[attnum]->attlen = Procid[typeoid].len;
|
||||||
/* Cheat like mad to fill in these items from the length only.
|
|
||||||
|
/*
|
||||||
|
* Cheat like mad to fill in these items from the length only.
|
||||||
* This only has to work for types used in the system catalogs...
|
* This only has to work for types used in the system catalogs...
|
||||||
*/
|
*/
|
||||||
switch (attlen)
|
switch (attlen)
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.20 1999/02/13 23:14:55 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.21 1999/05/25 16:08:01 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -29,8 +29,8 @@
|
||||||
char *
|
char *
|
||||||
relpath(char *relname)
|
relpath(char *relname)
|
||||||
{
|
{
|
||||||
char *path;
|
char *path;
|
||||||
int bufsize = 0;
|
int bufsize = 0;
|
||||||
|
|
||||||
if (IsSharedSystemRelationName(relname))
|
if (IsSharedSystemRelationName(relname))
|
||||||
{
|
{
|
||||||
|
@ -43,7 +43,7 @@ relpath(char *relname)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IsSystemRelationName
|
* IsSystemRelationName
|
||||||
* True iff name is the name of a system catalog relation.
|
* True iff name is the name of a system catalog relation.
|
||||||
*
|
*
|
||||||
* We now make a new requirement where system catalog relns must begin
|
* We now make a new requirement where system catalog relns must begin
|
||||||
|
@ -64,7 +64,7 @@ IsSystemRelationName(char *relname)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IsSharedSystemRelationName
|
* IsSharedSystemRelationName
|
||||||
* True iff name is the name of a shared system catalog relation.
|
* True iff name is the name of a shared system catalog relation.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.84 1999/05/22 04:12:24 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.85 1999/05/25 16:08:03 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
|
@ -70,8 +70,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void AddNewRelationTuple(Relation pg_class_desc,
|
static void AddNewRelationTuple(Relation pg_class_desc,
|
||||||
Relation new_rel_desc, Oid new_rel_oid, unsigned natts,
|
Relation new_rel_desc, Oid new_rel_oid, unsigned natts,
|
||||||
char relkind, char *temp_relname);
|
char relkind, char *temp_relname);
|
||||||
static void AddToNoNameRelList(Relation r);
|
static void AddToNoNameRelList(Relation r);
|
||||||
static void DeleteAttributeTuples(Relation rel);
|
static void DeleteAttributeTuples(Relation rel);
|
||||||
static void DeleteRelationTuple(Relation rel);
|
static void DeleteRelationTuple(Relation rel);
|
||||||
|
@ -185,7 +185,7 @@ heap_create(char *relname,
|
||||||
bool nailme = false;
|
bool nailme = false;
|
||||||
int natts = tupDesc->natts;
|
int natts = tupDesc->natts;
|
||||||
static unsigned int uniqueId = 0;
|
static unsigned int uniqueId = 0;
|
||||||
|
|
||||||
extern GlobalMemory CacheCxt;
|
extern GlobalMemory CacheCxt;
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
|
@ -240,23 +240,21 @@ heap_create(char *relname,
|
||||||
nailme = true;
|
nailme = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
relid = newoid();
|
relid = newoid();
|
||||||
}
|
|
||||||
|
|
||||||
if (isnoname)
|
if (isnoname)
|
||||||
{
|
{
|
||||||
Assert(!relname);
|
Assert(!relname);
|
||||||
relname = palloc(NAMEDATALEN);
|
relname = palloc(NAMEDATALEN);
|
||||||
snprintf(relname, NAMEDATALEN, "pg_noname.%d.%u",
|
snprintf(relname, NAMEDATALEN, "pg_noname.%d.%u",
|
||||||
(int) MyProcPid, uniqueId++);
|
(int) MyProcPid, uniqueId++);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (istemp)
|
if (istemp)
|
||||||
{
|
{
|
||||||
/* replace relname of caller */
|
/* replace relname of caller */
|
||||||
snprintf(relname, NAMEDATALEN, "pg_temp.%d.%u",
|
snprintf(relname, NAMEDATALEN, "pg_temp.%d.%u",
|
||||||
(int) MyProcPid, uniqueId++);
|
(int) MyProcPid, uniqueId++);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -272,7 +270,7 @@ heap_create(char *relname,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create a new tuple descriptor from the one passed in
|
* create a new tuple descriptor from the one passed in
|
||||||
*/
|
*/
|
||||||
rel->rd_att = CreateTupleDescCopyConstr(tupDesc);
|
rel->rd_att = CreateTupleDescCopyConstr(tupDesc);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -321,7 +319,7 @@ heap_create(char *relname,
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
rel->rd_nonameunlinked = TRUE; /* change once table is created */
|
rel->rd_nonameunlinked = TRUE; /* change once table is created */
|
||||||
rel->rd_fd = (File) smgrcreate(DEFAULT_SMGR, rel);
|
rel->rd_fd = (File) smgrcreate(DEFAULT_SMGR, rel);
|
||||||
rel->rd_nonameunlinked = FALSE;
|
rel->rd_nonameunlinked = FALSE;
|
||||||
|
|
||||||
|
@ -479,8 +477,8 @@ RelnameFindRelid(char *relname)
|
||||||
if (!IsBootstrapProcessingMode())
|
if (!IsBootstrapProcessingMode())
|
||||||
{
|
{
|
||||||
tuple = SearchSysCacheTuple(RELNAME,
|
tuple = SearchSysCacheTuple(RELNAME,
|
||||||
PointerGetDatum(relname),
|
PointerGetDatum(relname),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
if (HeapTupleIsValid(tuple))
|
if (HeapTupleIsValid(tuple))
|
||||||
relid = tuple->t_data->t_oid;
|
relid = tuple->t_data->t_oid;
|
||||||
else
|
else
|
||||||
|
@ -488,10 +486,10 @@ RelnameFindRelid(char *relname)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Relation pg_class_desc;
|
Relation pg_class_desc;
|
||||||
ScanKeyData key;
|
ScanKeyData key;
|
||||||
HeapScanDesc pg_class_scan;
|
HeapScanDesc pg_class_scan;
|
||||||
|
|
||||||
pg_class_desc = heap_openr(RelationRelationName);
|
pg_class_desc = heap_openr(RelationRelationName);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -504,7 +502,7 @@ RelnameFindRelid(char *relname)
|
||||||
(AttrNumber) Anum_pg_class_relname,
|
(AttrNumber) Anum_pg_class_relname,
|
||||||
(RegProcedure) F_NAMEEQ,
|
(RegProcedure) F_NAMEEQ,
|
||||||
(Datum) relname);
|
(Datum) relname);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* begin the scan
|
* begin the scan
|
||||||
* ----------------
|
* ----------------
|
||||||
|
@ -514,14 +512,14 @@ RelnameFindRelid(char *relname)
|
||||||
SnapshotNow,
|
SnapshotNow,
|
||||||
1,
|
1,
|
||||||
&key);
|
&key);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* get a tuple. if the tuple is NULL then it means we
|
* get a tuple. if the tuple is NULL then it means we
|
||||||
* didn't find an existing relation.
|
* didn't find an existing relation.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
tuple = heap_getnext(pg_class_scan, 0);
|
tuple = heap_getnext(pg_class_scan, 0);
|
||||||
|
|
||||||
if (HeapTupleIsValid(tuple))
|
if (HeapTupleIsValid(tuple))
|
||||||
relid = tuple->t_data->t_oid;
|
relid = tuple->t_data->t_oid;
|
||||||
else
|
else
|
||||||
|
@ -594,7 +592,7 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
||||||
(char *) *dpp);
|
(char *) *dpp);
|
||||||
|
|
||||||
heap_insert(rel, tup);
|
heap_insert(rel, tup);
|
||||||
|
|
||||||
if (hasindex)
|
if (hasindex)
|
||||||
CatalogIndexInsert(idescs, Num_pg_attr_indices, rel, tup);
|
CatalogIndexInsert(idescs, Num_pg_attr_indices, rel, tup);
|
||||||
|
|
||||||
|
@ -643,11 +641,11 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
AddNewRelationTuple(Relation pg_class_desc,
|
AddNewRelationTuple(Relation pg_class_desc,
|
||||||
Relation new_rel_desc,
|
Relation new_rel_desc,
|
||||||
Oid new_rel_oid,
|
Oid new_rel_oid,
|
||||||
unsigned natts,
|
unsigned natts,
|
||||||
char relkind,
|
char relkind,
|
||||||
char *temp_relname)
|
char *temp_relname)
|
||||||
{
|
{
|
||||||
Form_pg_class new_rel_reltup;
|
Form_pg_class new_rel_reltup;
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
|
@ -678,12 +676,12 @@ AddNewRelationTuple(Relation pg_class_desc,
|
||||||
* the table has been proven to be small by VACUUM or CREATE INDEX.
|
* the table has been proven to be small by VACUUM or CREATE INDEX.
|
||||||
* (NOTE: if user does CREATE TABLE, then CREATE INDEX, then loads
|
* (NOTE: if user does CREATE TABLE, then CREATE INDEX, then loads
|
||||||
* the table, he still loses until he vacuums, because CREATE INDEX
|
* the table, he still loses until he vacuums, because CREATE INDEX
|
||||||
* will set reltuples to zero. Can't win 'em all. Maintaining the
|
* will set reltuples to zero. Can't win 'em all. Maintaining the
|
||||||
* stats on-the-fly would solve the problem, but the overhead of that
|
* stats on-the-fly would solve the problem, but the overhead of that
|
||||||
* would likely cost more than it'd save.)
|
* would likely cost more than it'd save.)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
new_rel_reltup->relpages = 10; /* bogus estimates */
|
new_rel_reltup->relpages = 10; /* bogus estimates */
|
||||||
new_rel_reltup->reltuples = 1000;
|
new_rel_reltup->reltuples = 1000;
|
||||||
|
|
||||||
new_rel_reltup->relowner = GetUserId();
|
new_rel_reltup->relowner = GetUserId();
|
||||||
|
@ -716,9 +714,10 @@ AddNewRelationTuple(Relation pg_class_desc,
|
||||||
|
|
||||||
if (temp_relname)
|
if (temp_relname)
|
||||||
create_temp_relation(temp_relname, tup);
|
create_temp_relation(temp_relname, tup);
|
||||||
|
|
||||||
if (!isBootstrap)
|
if (!isBootstrap)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First, open the catalog indices and insert index tuples for the
|
* First, open the catalog indices and insert index tuples for the
|
||||||
* new relation.
|
* new relation.
|
||||||
|
@ -730,7 +729,7 @@ AddNewRelationTuple(Relation pg_class_desc,
|
||||||
/* now restore processing mode */
|
/* now restore processing mode */
|
||||||
SetProcessingMode(NormalProcessing);
|
SetProcessingMode(NormalProcessing);
|
||||||
}
|
}
|
||||||
|
|
||||||
pfree(tup);
|
pfree(tup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,8 +787,8 @@ heap_create_with_catalog(char *relname,
|
||||||
Relation new_rel_desc;
|
Relation new_rel_desc;
|
||||||
Oid new_rel_oid;
|
Oid new_rel_oid;
|
||||||
int natts = tupdesc->natts;
|
int natts = tupdesc->natts;
|
||||||
char *temp_relname = NULL;
|
char *temp_relname = NULL;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
* ----------------
|
||||||
|
@ -804,33 +803,34 @@ heap_create_with_catalog(char *relname,
|
||||||
|
|
||||||
/* temp tables can mask non-temp tables */
|
/* temp tables can mask non-temp tables */
|
||||||
if ((!istemp && RelnameFindRelid(relname)) ||
|
if ((!istemp && RelnameFindRelid(relname)) ||
|
||||||
(istemp && get_temp_rel_by_name(relname) != NULL))
|
(istemp && get_temp_rel_by_name(relname) != NULL))
|
||||||
elog(ERROR, "Relation '%s' already exists", relname);
|
elog(ERROR, "Relation '%s' already exists", relname);
|
||||||
|
|
||||||
/* invalidate cache so non-temp table is masked by temp */
|
/* invalidate cache so non-temp table is masked by temp */
|
||||||
if (istemp)
|
if (istemp)
|
||||||
{
|
{
|
||||||
Oid relid = RelnameFindRelid(relname);
|
Oid relid = RelnameFindRelid(relname);
|
||||||
|
|
||||||
if (relid != InvalidOid)
|
if (relid != InvalidOid)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is heavy-handed, but appears necessary bjm 1999/02/01
|
* This is heavy-handed, but appears necessary bjm 1999/02/01
|
||||||
* SystemCacheRelationFlushed(relid) is not enough either.
|
* SystemCacheRelationFlushed(relid) is not enough either.
|
||||||
*/
|
*/
|
||||||
RelationForgetRelation(relid);
|
RelationForgetRelation(relid);
|
||||||
ResetSystemCache();
|
ResetSystemCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* save user relation name because heap_create changes it */
|
/* save user relation name because heap_create changes it */
|
||||||
if (istemp)
|
if (istemp)
|
||||||
{
|
{
|
||||||
temp_relname = pstrdup(relname); /* save original value */
|
temp_relname = pstrdup(relname); /* save original value */
|
||||||
relname = palloc(NAMEDATALEN);
|
relname = palloc(NAMEDATALEN);
|
||||||
strcpy(relname, temp_relname); /* heap_create will change this */
|
strcpy(relname, temp_relname); /* heap_create will change this */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* ok, relation does not already exist so now we
|
* ok, relation does not already exist so now we
|
||||||
* create an uncataloged relation and pull its relation oid
|
* create an uncataloged relation and pull its relation oid
|
||||||
|
@ -838,7 +838,7 @@ heap_create_with_catalog(char *relname,
|
||||||
*
|
*
|
||||||
* Note: The call to heap_create() does all the "real" work
|
* Note: The call to heap_create() does all the "real" work
|
||||||
* of creating the disk file for the relation.
|
* of creating the disk file for the relation.
|
||||||
* This changes relname for noname and temp tables.
|
* This changes relname for noname and temp tables.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
new_rel_desc = heap_create(relname, tupdesc, false, istemp);
|
new_rel_desc = heap_create(relname, tupdesc, false, istemp);
|
||||||
|
@ -866,11 +866,11 @@ heap_create_with_catalog(char *relname,
|
||||||
pg_class_desc = heap_openr(RelationRelationName);
|
pg_class_desc = heap_openr(RelationRelationName);
|
||||||
|
|
||||||
AddNewRelationTuple(pg_class_desc,
|
AddNewRelationTuple(pg_class_desc,
|
||||||
new_rel_desc,
|
new_rel_desc,
|
||||||
new_rel_oid,
|
new_rel_oid,
|
||||||
natts,
|
natts,
|
||||||
relkind,
|
relkind,
|
||||||
temp_relname);
|
temp_relname);
|
||||||
|
|
||||||
StoreConstraints(new_rel_desc);
|
StoreConstraints(new_rel_desc);
|
||||||
|
|
||||||
|
@ -1320,7 +1320,7 @@ heap_destroy_with_catalog(char *relname)
|
||||||
|
|
||||||
if (istemp)
|
if (istemp)
|
||||||
remove_temp_relation(rid);
|
remove_temp_relation(rid);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* delete type tuple. here we want to see the effects
|
* delete type tuple. here we want to see the effects
|
||||||
* of the deletions we just did, so we use setheapoverride().
|
* of the deletions we just did, so we use setheapoverride().
|
||||||
|
@ -1334,7 +1334,7 @@ heap_destroy_with_catalog(char *relname)
|
||||||
* delete relation tuple
|
* delete relation tuple
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
/* must delete fake tuple in cache */
|
/* must delete fake tuple in cache */
|
||||||
DeleteRelationTuple(rel);
|
DeleteRelationTuple(rel);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1516,10 +1516,12 @@ StoreAttrDefault(Relation rel, AttrDefault *attrdef)
|
||||||
extern GlobalMemory CacheCxt;
|
extern GlobalMemory CacheCxt;
|
||||||
|
|
||||||
start:
|
start:
|
||||||
/* Surround table name with double quotes to allow mixed-case and
|
|
||||||
|
/*
|
||||||
|
* Surround table name with double quotes to allow mixed-case and
|
||||||
* whitespaces in names. - BGA 1998-11-14
|
* whitespaces in names. - BGA 1998-11-14
|
||||||
*/
|
*/
|
||||||
snprintf(str, MAX_PARSE_BUFFER,
|
snprintf(str, MAX_PARSE_BUFFER,
|
||||||
"select %s%s from \"%.*s\"", attrdef->adsrc, cast,
|
"select %s%s from \"%.*s\"", attrdef->adsrc, cast,
|
||||||
NAMEDATALEN, rel->rd_rel->relname.data);
|
NAMEDATALEN, rel->rd_rel->relname.data);
|
||||||
setheapoverride(true);
|
setheapoverride(true);
|
||||||
|
@ -1539,16 +1541,16 @@ start:
|
||||||
if (type != atp->atttypid)
|
if (type != atp->atttypid)
|
||||||
{
|
{
|
||||||
if (IS_BINARY_COMPATIBLE(type, atp->atttypid))
|
if (IS_BINARY_COMPATIBLE(type, atp->atttypid))
|
||||||
; /* use without change */
|
; /* use without change */
|
||||||
else if (can_coerce_type(1, &(type), &(atp->atttypid)))
|
else if (can_coerce_type(1, &(type), &(atp->atttypid)))
|
||||||
expr = coerce_type(NULL, (Node *)expr, type, atp->atttypid,
|
expr = coerce_type(NULL, (Node *) expr, type, atp->atttypid,
|
||||||
atp->atttypmod);
|
atp->atttypmod);
|
||||||
else if (IsA(expr, Const))
|
else if (IsA(expr, Const))
|
||||||
{
|
{
|
||||||
if (*cast != 0)
|
if (*cast != 0)
|
||||||
elog(ERROR, "DEFAULT clause const type '%s' mismatched with column type '%s'",
|
elog(ERROR, "DEFAULT clause const type '%s' mismatched with column type '%s'",
|
||||||
typeidTypeName(type), typeidTypeName(atp->atttypid));
|
typeidTypeName(type), typeidTypeName(atp->atttypid));
|
||||||
snprintf(cast, 2*NAMEDATALEN, ":: %s", typeidTypeName(atp->atttypid));
|
snprintf(cast, 2 * NAMEDATALEN, ":: %s", typeidTypeName(atp->atttypid));
|
||||||
goto start;
|
goto start;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1598,12 +1600,13 @@ StoreRelCheck(Relation rel, ConstrCheck *check)
|
||||||
char nulls[4] = {' ', ' ', ' ', ' '};
|
char nulls[4] = {' ', ' ', ' ', ' '};
|
||||||
extern GlobalMemory CacheCxt;
|
extern GlobalMemory CacheCxt;
|
||||||
|
|
||||||
/* Check for table's existance. Surround table name with double-quotes
|
/*
|
||||||
|
* Check for table's existance. Surround table name with double-quotes
|
||||||
* to allow mixed-case and whitespace names. - thomas 1998-11-12
|
* to allow mixed-case and whitespace names. - thomas 1998-11-12
|
||||||
*/
|
*/
|
||||||
snprintf(str, MAX_PARSE_BUFFER,
|
snprintf(str, MAX_PARSE_BUFFER,
|
||||||
"select 1 from \"%.*s\" where %s",
|
"select 1 from \"%.*s\" where %s",
|
||||||
NAMEDATALEN, rel->rd_rel->relname.data, check->ccsrc);
|
NAMEDATALEN, rel->rd_rel->relname.data, check->ccsrc);
|
||||||
setheapoverride(true);
|
setheapoverride(true);
|
||||||
planTree_list = pg_parse_and_plan(str, NULL, 0,
|
planTree_list = pg_parse_and_plan(str, NULL, 0,
|
||||||
&queryTree_list, None, FALSE);
|
&queryTree_list, None, FALSE);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.74 1999/05/17 00:27:45 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.75 1999/05/25 16:08:06 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
|
@ -60,8 +60,8 @@
|
||||||
#define NTUPLES_PER_PAGE(natts) (BLCKSZ/((natts)*AVG_TUPLE_SIZE))
|
#define NTUPLES_PER_PAGE(natts) (BLCKSZ/((natts)*AVG_TUPLE_SIZE))
|
||||||
|
|
||||||
/* non-export function prototypes */
|
/* non-export function prototypes */
|
||||||
static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
|
static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
|
||||||
bool istemp);
|
bool istemp);
|
||||||
static TupleDesc BuildFuncTupleDesc(FuncIndexInfo *funcInfo);
|
static TupleDesc BuildFuncTupleDesc(FuncIndexInfo *funcInfo);
|
||||||
static TupleDesc ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
|
static TupleDesc ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
|
||||||
List *attributeList,
|
List *attributeList,
|
||||||
|
@ -77,7 +77,7 @@ static void
|
||||||
static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
|
static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
|
||||||
FuncIndexInfo *funcInfo, int natts,
|
FuncIndexInfo *funcInfo, int natts,
|
||||||
AttrNumber *attNums, Oid *classOids, Node *predicate,
|
AttrNumber *attNums, Oid *classOids, Node *predicate,
|
||||||
List *attributeList, bool islossy, bool unique, bool primary);
|
List *attributeList, bool islossy, bool unique, bool primary);
|
||||||
static void DefaultBuild(Relation heapRelation, Relation indexRelation,
|
static void DefaultBuild(Relation heapRelation, Relation indexRelation,
|
||||||
int numberOfAttributes, AttrNumber *attributeNumber,
|
int numberOfAttributes, AttrNumber *attributeNumber,
|
||||||
IndexStrategy indexStrategy, uint16 parameterCount,
|
IndexStrategy indexStrategy, uint16 parameterCount,
|
||||||
|
@ -126,11 +126,11 @@ GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp)
|
||||||
Oid indoid;
|
Oid indoid;
|
||||||
Oid heapoid;
|
Oid heapoid;
|
||||||
|
|
||||||
|
|
||||||
indoid = RelnameFindRelid(indexRelationName);
|
indoid = RelnameFindRelid(indexRelationName);
|
||||||
|
|
||||||
if ((!istemp && OidIsValid(indoid)) ||
|
if ((!istemp && OidIsValid(indoid)) ||
|
||||||
(istemp && get_temp_rel_by_name(indexRelationName) != NULL))
|
(istemp && get_temp_rel_by_name(indexRelationName) != NULL))
|
||||||
elog(ERROR, "Cannot create index: '%s' already exists",
|
elog(ERROR, "Cannot create index: '%s' already exists",
|
||||||
indexRelationName);
|
indexRelationName);
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp)
|
||||||
if (!OidIsValid(heapoid))
|
if (!OidIsValid(heapoid))
|
||||||
elog(ERROR, "Cannot create index on '%s': relation does not exist",
|
elog(ERROR, "Cannot create index on '%s': relation does not exist",
|
||||||
heapRelationName);
|
heapRelationName);
|
||||||
|
|
||||||
return heapoid;
|
return heapoid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +356,7 @@ ConstructTupleDescriptor(Oid heapoid,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* AccessMethodObjectIdGetForm
|
* AccessMethodObjectIdGetForm
|
||||||
* Returns the formated access method tuple given its object identifier.
|
* Returns the formated access method tuple given its object identifier.
|
||||||
*
|
*
|
||||||
* XXX ADD INDEXING
|
* XXX ADD INDEXING
|
||||||
|
@ -482,7 +482,7 @@ UpdateRelationRelation(Relation indexRelation, char *temp_relname)
|
||||||
|
|
||||||
if (temp_relname)
|
if (temp_relname)
|
||||||
create_temp_relation(temp_relname, tuple);
|
create_temp_relation(temp_relname, tuple);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* During normal processing, we need to make sure that the system
|
* During normal processing, we need to make sure that the system
|
||||||
* catalog indices are correct. Bootstrap (initdb) time doesn't
|
* catalog indices are correct. Bootstrap (initdb) time doesn't
|
||||||
|
@ -571,7 +571,7 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
|
||||||
value[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
|
value[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
|
||||||
|
|
||||||
init_tuple = heap_addheader(Natts_pg_attribute,
|
init_tuple = heap_addheader(Natts_pg_attribute,
|
||||||
ATTRIBUTE_TUPLE_SIZE,
|
ATTRIBUTE_TUPLE_SIZE,
|
||||||
(char *) (indexRelation->rd_att->attrs[0]));
|
(char *) (indexRelation->rd_att->attrs[0]));
|
||||||
|
|
||||||
hasind = false;
|
hasind = false;
|
||||||
|
@ -611,7 +611,7 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
|
||||||
*/
|
*/
|
||||||
memmove(GETSTRUCT(cur_tuple),
|
memmove(GETSTRUCT(cur_tuple),
|
||||||
(char *) indexTupDesc->attrs[i],
|
(char *) indexTupDesc->attrs[i],
|
||||||
ATTRIBUTE_TUPLE_SIZE);
|
ATTRIBUTE_TUPLE_SIZE);
|
||||||
|
|
||||||
value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(i + 1);
|
value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(i + 1);
|
||||||
|
|
||||||
|
@ -657,7 +657,7 @@ UpdateIndexRelation(Oid indexoid,
|
||||||
List *attributeList,
|
List *attributeList,
|
||||||
bool islossy,
|
bool islossy,
|
||||||
bool unique,
|
bool unique,
|
||||||
bool primary)
|
bool primary)
|
||||||
{
|
{
|
||||||
Form_pg_index indexForm;
|
Form_pg_index indexForm;
|
||||||
IndexElem *IndexKey;
|
IndexElem *IndexKey;
|
||||||
|
@ -686,7 +686,7 @@ UpdateIndexRelation(Oid indexoid,
|
||||||
predLen = VARSIZE(predText);
|
predLen = VARSIZE(predText);
|
||||||
itupLen = predLen + sizeof(FormData_pg_index);
|
itupLen = predLen + sizeof(FormData_pg_index);
|
||||||
indexForm = (Form_pg_index) palloc(itupLen);
|
indexForm = (Form_pg_index) palloc(itupLen);
|
||||||
memset (indexForm, 0, sizeof(FormData_pg_index));
|
memset(indexForm, 0, sizeof(FormData_pg_index));
|
||||||
|
|
||||||
memmove((char *) &indexForm->indpred, (char *) predText, predLen);
|
memmove((char *) &indexForm->indpred, (char *) predText, predLen);
|
||||||
|
|
||||||
|
@ -939,7 +939,7 @@ index_create(char *heapRelationName,
|
||||||
Node *predicate,
|
Node *predicate,
|
||||||
bool islossy,
|
bool islossy,
|
||||||
bool unique,
|
bool unique,
|
||||||
bool primary)
|
bool primary)
|
||||||
{
|
{
|
||||||
Relation heapRelation;
|
Relation heapRelation;
|
||||||
Relation indexRelation;
|
Relation indexRelation;
|
||||||
|
@ -948,15 +948,15 @@ index_create(char *heapRelationName,
|
||||||
Oid indexoid;
|
Oid indexoid;
|
||||||
PredInfo *predInfo;
|
PredInfo *predInfo;
|
||||||
bool istemp = (get_temp_rel_by_name(heapRelationName) != NULL);
|
bool istemp = (get_temp_rel_by_name(heapRelationName) != NULL);
|
||||||
char *temp_relname = NULL;
|
char *temp_relname = NULL;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* check parameters
|
* check parameters
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (numatts < 1)
|
if (numatts < 1)
|
||||||
elog(ERROR, "must index at least one attribute");
|
elog(ERROR, "must index at least one attribute");
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* get heap relation oid and open the heap relation
|
* get heap relation oid and open the heap relation
|
||||||
* XXX ADD INDEXING
|
* XXX ADD INDEXING
|
||||||
|
@ -987,25 +987,27 @@ index_create(char *heapRelationName,
|
||||||
/* invalidate cache so possible non-temp index is masked by temp */
|
/* invalidate cache so possible non-temp index is masked by temp */
|
||||||
if (istemp)
|
if (istemp)
|
||||||
{
|
{
|
||||||
Oid relid = RelnameFindRelid(indexRelationName);
|
Oid relid = RelnameFindRelid(indexRelationName);
|
||||||
|
|
||||||
if (relid != InvalidOid)
|
if (relid != InvalidOid)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is heavy-handed, but appears necessary bjm 1999/02/01
|
* This is heavy-handed, but appears necessary bjm 1999/02/01
|
||||||
* SystemCacheRelationFlushed(relid) is not enough either.
|
* SystemCacheRelationFlushed(relid) is not enough either.
|
||||||
*/
|
*/
|
||||||
RelationForgetRelation(relid);
|
RelationForgetRelation(relid);
|
||||||
ResetSystemCache();
|
ResetSystemCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* save user relation name because heap_create changes it */
|
/* save user relation name because heap_create changes it */
|
||||||
if (istemp)
|
if (istemp)
|
||||||
{
|
{
|
||||||
temp_relname = pstrdup(indexRelationName); /* save original value */
|
temp_relname = pstrdup(indexRelationName); /* save original value */
|
||||||
indexRelationName = palloc(NAMEDATALEN);
|
indexRelationName = palloc(NAMEDATALEN);
|
||||||
strcpy(indexRelationName, temp_relname); /* heap_create will change this */
|
strcpy(indexRelationName, temp_relname); /* heap_create will
|
||||||
|
* change this */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -1122,8 +1124,8 @@ index_destroy(Oid indexId)
|
||||||
Relation relationRelation;
|
Relation relationRelation;
|
||||||
Relation attributeRelation;
|
Relation attributeRelation;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
int16 attnum;
|
int16 attnum;
|
||||||
|
|
||||||
Assert(OidIsValid(indexId));
|
Assert(OidIsValid(indexId));
|
||||||
|
|
||||||
/* Open now to obtain lock by referencing table? bjm */
|
/* Open now to obtain lock by referencing table? bjm */
|
||||||
|
@ -1166,7 +1168,7 @@ index_destroy(Oid indexId)
|
||||||
|
|
||||||
/* does something only if it is a temp index */
|
/* does something only if it is a temp index */
|
||||||
remove_temp_relation(indexId);
|
remove_temp_relation(indexId);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* fix INDEX relation
|
* fix INDEX relation
|
||||||
* ----------------
|
* ----------------
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.37 1999/05/10 00:44:55 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.38 1999/05/25 16:08:07 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -46,15 +46,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char *Name_pg_attr_indices[Num_pg_attr_indices] = {AttributeNameIndex,
|
char *Name_pg_attr_indices[Num_pg_attr_indices] = {AttributeNameIndex,
|
||||||
AttributeNumIndex,
|
AttributeNumIndex,
|
||||||
AttributeRelidIndex};
|
AttributeRelidIndex};
|
||||||
char *Name_pg_proc_indices[Num_pg_proc_indices] = {ProcedureNameIndex,
|
char *Name_pg_proc_indices[Num_pg_proc_indices] = {ProcedureNameIndex,
|
||||||
ProcedureOidIndex,
|
ProcedureOidIndex,
|
||||||
ProcedureSrcIndex};
|
ProcedureSrcIndex};
|
||||||
char *Name_pg_type_indices[Num_pg_type_indices] = {TypeNameIndex,
|
char *Name_pg_type_indices[Num_pg_type_indices] = {TypeNameIndex,
|
||||||
TypeOidIndex};
|
TypeOidIndex};
|
||||||
char *Name_pg_class_indices[Num_pg_class_indices] = {ClassNameIndex,
|
char *Name_pg_class_indices[Num_pg_class_indices] = {ClassNameIndex,
|
||||||
ClassOidIndex};
|
ClassOidIndex};
|
||||||
char *Name_pg_attrdef_indices[Num_pg_attrdef_indices] = {AttrDefaultIndex};
|
char *Name_pg_attrdef_indices[Num_pg_attrdef_indices] = {AttrDefaultIndex};
|
||||||
|
|
||||||
char *Name_pg_relcheck_indices[Num_pg_relcheck_indices] = {RelCheckIndex};
|
char *Name_pg_relcheck_indices[Num_pg_relcheck_indices] = {RelCheckIndex};
|
||||||
|
@ -63,9 +63,9 @@ char *Name_pg_trigger_indices[Num_pg_trigger_indices] = {TriggerRelidIndex};
|
||||||
|
|
||||||
|
|
||||||
static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
|
static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
|
||||||
Relation idesc,
|
Relation idesc,
|
||||||
ScanKey skey,
|
ScanKey skey,
|
||||||
int16 num_keys);
|
int16 num_keys);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -126,13 +126,13 @@ CatalogIndexInsert(Relation *idescs,
|
||||||
|
|
||||||
index_tup = SearchSysCacheTupleCopy(INDEXRELID,
|
index_tup = SearchSysCacheTupleCopy(INDEXRELID,
|
||||||
ObjectIdGetDatum(idescs[i]->rd_id),
|
ObjectIdGetDatum(idescs[i]->rd_id),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
Assert(index_tup);
|
Assert(index_tup);
|
||||||
index_form = (Form_pg_index) GETSTRUCT(index_tup);
|
index_form = (Form_pg_index) GETSTRUCT(index_tup);
|
||||||
|
|
||||||
if (index_form->indproc != InvalidOid)
|
if (index_form->indproc != InvalidOid)
|
||||||
{
|
{
|
||||||
int fatts;
|
int fatts;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute the number of attributes we are indexing upon.
|
* Compute the number of attributes we are indexing upon.
|
||||||
|
@ -152,7 +152,7 @@ CatalogIndexInsert(Relation *idescs,
|
||||||
natts = RelationGetDescr(idescs[i])->natts;
|
natts = RelationGetDescr(idescs[i])->natts;
|
||||||
finfoP = (FuncIndexInfo *) NULL;
|
finfoP = (FuncIndexInfo *) NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
FormIndexDatum(natts,
|
FormIndexDatum(natts,
|
||||||
(AttrNumber *) index_form->indkey,
|
(AttrNumber *) index_form->indkey,
|
||||||
heapTuple,
|
heapTuple,
|
||||||
|
@ -229,11 +229,11 @@ CatalogIndexFetchTuple(Relation heapRelation,
|
||||||
ScanKey skey,
|
ScanKey skey,
|
||||||
int16 num_keys)
|
int16 num_keys)
|
||||||
{
|
{
|
||||||
IndexScanDesc sd;
|
IndexScanDesc sd;
|
||||||
RetrieveIndexResult indexRes;
|
RetrieveIndexResult indexRes;
|
||||||
HeapTupleData tuple;
|
HeapTupleData tuple;
|
||||||
HeapTuple result = NULL;
|
HeapTuple result = NULL;
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
sd = index_beginscan(idesc, false, num_keys, skey);
|
sd = index_beginscan(idesc, false, num_keys, skey);
|
||||||
tuple.t_data = NULL;
|
tuple.t_data = NULL;
|
||||||
|
@ -462,7 +462,7 @@ ClassNameIndexScan(Relation heapRelation, char *relName)
|
||||||
*/
|
*/
|
||||||
if ((tuple = get_temp_rel_by_name(relName)) != NULL)
|
if ((tuple = get_temp_rel_by_name(relName)) != NULL)
|
||||||
return heap_copytuple(tuple);
|
return heap_copytuple(tuple);
|
||||||
|
|
||||||
ScanKeyEntryInitialize(&skey[0],
|
ScanKeyEntryInitialize(&skey[0],
|
||||||
(bits16) 0x0,
|
(bits16) 0x0,
|
||||||
(AttrNumber) 1,
|
(AttrNumber) 1,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.36 1999/05/10 00:44:56 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.37 1999/05/25 16:08:09 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* these routines moved here from commands/define.c and somewhat cleaned up.
|
* these routines moved here from commands/define.c and somewhat cleaned up.
|
||||||
|
@ -36,15 +36,15 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static Oid OperatorGetWithOpenRelation(Relation pg_operator_desc,
|
static Oid OperatorGetWithOpenRelation(Relation pg_operator_desc,
|
||||||
const char *operatorName,
|
const char *operatorName,
|
||||||
Oid leftObjectId,
|
Oid leftObjectId,
|
||||||
Oid rightObjectId,
|
Oid rightObjectId,
|
||||||
bool *defined);
|
bool *defined);
|
||||||
|
|
||||||
static Oid OperatorGet(char *operatorName,
|
static Oid OperatorGet(char *operatorName,
|
||||||
char *leftTypeName,
|
char *leftTypeName,
|
||||||
char *rightTypeName,
|
char *rightTypeName,
|
||||||
bool *defined);
|
bool *defined);
|
||||||
|
|
||||||
static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
|
static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
|
||||||
char *operatorName,
|
char *operatorName,
|
||||||
|
@ -135,6 +135,7 @@ OperatorGetWithOpenRelation(Relation pg_operator_desc,
|
||||||
if (HeapTupleIsValid(tup))
|
if (HeapTupleIsValid(tup))
|
||||||
{
|
{
|
||||||
regproc oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
|
regproc oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
|
||||||
|
|
||||||
operatorObjectId = tup->t_data->t_oid;
|
operatorObjectId = tup->t_data->t_oid;
|
||||||
*defined = RegProcedureIsValid(oprcode);
|
*defined = RegProcedureIsValid(oprcode);
|
||||||
}
|
}
|
||||||
|
@ -259,7 +260,7 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* initialize *values with the operator name and input data types.
|
* initialize *values with the operator name and input data types.
|
||||||
* Note that oprcode is set to InvalidOid, indicating it's a shell.
|
* Note that oprcode is set to InvalidOid, indicating it's a shell.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -356,9 +357,9 @@ OperatorShellMake(char *operatorName,
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
operatorObjectId = OperatorShellMakeWithOpenRelation(pg_operator_desc,
|
operatorObjectId = OperatorShellMakeWithOpenRelation(pg_operator_desc,
|
||||||
operatorName,
|
operatorName,
|
||||||
leftObjectId,
|
leftObjectId,
|
||||||
rightObjectId);
|
rightObjectId);
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* close the operator relation and return the oid.
|
* close the operator relation and return the oid.
|
||||||
* ----------------
|
* ----------------
|
||||||
|
@ -506,8 +507,9 @@ OperatorDef(char *operatorName,
|
||||||
elog(ERROR, "OperatorDef: operator \"%s\" already defined",
|
elog(ERROR, "OperatorDef: operator \"%s\" already defined",
|
||||||
operatorName);
|
operatorName);
|
||||||
|
|
||||||
/* At this point, if operatorObjectId is not InvalidOid then
|
/*
|
||||||
* we are filling in a previously-created shell.
|
* At this point, if operatorObjectId is not InvalidOid then we are
|
||||||
|
* filling in a previously-created shell.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -580,7 +582,7 @@ OperatorDef(char *operatorName,
|
||||||
|
|
||||||
values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
|
values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
|
||||||
values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(((Form_pg_proc)
|
values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(((Form_pg_proc)
|
||||||
GETSTRUCT(tup))->prorettype);
|
GETSTRUCT(tup))->prorettype);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* find restriction
|
* find restriction
|
||||||
|
@ -648,7 +650,8 @@ OperatorDef(char *operatorName,
|
||||||
values[i++] = ObjectIdGetDatum(leftTypeId);
|
values[i++] = ObjectIdGetDatum(leftTypeId);
|
||||||
values[i++] = ObjectIdGetDatum(rightTypeId);
|
values[i++] = ObjectIdGetDatum(rightTypeId);
|
||||||
|
|
||||||
++i; /* Skip "oprresult", it was filled in above */
|
++i; /* Skip "oprresult", it was filled in
|
||||||
|
* above */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up the other operators. If they do not currently exist, create
|
* Set up the other operators. If they do not currently exist, create
|
||||||
|
@ -663,16 +666,16 @@ OperatorDef(char *operatorName,
|
||||||
{
|
{
|
||||||
if (name[j])
|
if (name[j])
|
||||||
{
|
{
|
||||||
char *otherLeftTypeName = NULL;
|
char *otherLeftTypeName = NULL;
|
||||||
char *otherRightTypeName = NULL;
|
char *otherRightTypeName = NULL;
|
||||||
Oid otherLeftTypeId = InvalidOid;
|
Oid otherLeftTypeId = InvalidOid;
|
||||||
Oid otherRightTypeId = InvalidOid;
|
Oid otherRightTypeId = InvalidOid;
|
||||||
Oid other_oid = InvalidOid;
|
Oid other_oid = InvalidOid;
|
||||||
bool otherDefined = false;
|
bool otherDefined = false;
|
||||||
|
|
||||||
switch (j)
|
switch (j)
|
||||||
{
|
{
|
||||||
case 0: /* commutator has reversed arg types */
|
case 0: /* commutator has reversed arg types */
|
||||||
otherLeftTypeName = rightTypeName;
|
otherLeftTypeName = rightTypeName;
|
||||||
otherRightTypeName = leftTypeName;
|
otherRightTypeName = leftTypeName;
|
||||||
otherLeftTypeId = rightTypeId;
|
otherLeftTypeId = rightTypeId;
|
||||||
|
@ -683,7 +686,7 @@ OperatorDef(char *operatorName,
|
||||||
&otherDefined);
|
&otherDefined);
|
||||||
commutatorId = other_oid;
|
commutatorId = other_oid;
|
||||||
break;
|
break;
|
||||||
case 1: /* negator has same arg types */
|
case 1: /* negator has same arg types */
|
||||||
otherLeftTypeName = leftTypeName;
|
otherLeftTypeName = leftTypeName;
|
||||||
otherRightTypeName = rightTypeName;
|
otherRightTypeName = rightTypeName;
|
||||||
otherLeftTypeId = leftTypeId;
|
otherLeftTypeId = leftTypeId;
|
||||||
|
@ -694,7 +697,7 @@ OperatorDef(char *operatorName,
|
||||||
&otherDefined);
|
&otherDefined);
|
||||||
negatorId = other_oid;
|
negatorId = other_oid;
|
||||||
break;
|
break;
|
||||||
case 2: /* left sort op takes left-side data type */
|
case 2: /* left sort op takes left-side data type */
|
||||||
otherLeftTypeName = leftTypeName;
|
otherLeftTypeName = leftTypeName;
|
||||||
otherRightTypeName = leftTypeName;
|
otherRightTypeName = leftTypeName;
|
||||||
otherLeftTypeId = leftTypeId;
|
otherLeftTypeId = leftTypeId;
|
||||||
|
@ -704,7 +707,8 @@ OperatorDef(char *operatorName,
|
||||||
otherRightTypeName,
|
otherRightTypeName,
|
||||||
&otherDefined);
|
&otherDefined);
|
||||||
break;
|
break;
|
||||||
case 3: /* right sort op takes right-side data type */
|
case 3: /* right sort op takes right-side data
|
||||||
|
* type */
|
||||||
otherLeftTypeName = rightTypeName;
|
otherLeftTypeName = rightTypeName;
|
||||||
otherRightTypeName = rightTypeName;
|
otherRightTypeName = rightTypeName;
|
||||||
otherLeftTypeId = rightTypeId;
|
otherLeftTypeId = rightTypeId;
|
||||||
|
@ -737,8 +741,10 @@ OperatorDef(char *operatorName,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* self-linkage to this operator; will fix below.
|
|
||||||
* Note that only self-linkage for commutation makes sense.
|
/*
|
||||||
|
* self-linkage to this operator; will fix below. Note
|
||||||
|
* that only self-linkage for commutation makes sense.
|
||||||
*/
|
*/
|
||||||
if (j != 0)
|
if (j != 0)
|
||||||
elog(ERROR,
|
elog(ERROR,
|
||||||
|
@ -804,15 +810,14 @@ OperatorDef(char *operatorName,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If a commutator and/or negator link is provided, update the other
|
* If a commutator and/or negator link is provided, update the other
|
||||||
* operator(s) to point at this one, if they don't already have a link.
|
* operator(s) to point at this one, if they don't already have a
|
||||||
* This supports an alternate style of operator definition wherein the
|
* link. This supports an alternate style of operator definition
|
||||||
* user first defines one operator without giving negator or
|
* wherein the user first defines one operator without giving negator
|
||||||
* commutator, then defines the other operator of the pair with the
|
* or commutator, then defines the other operator of the pair with the
|
||||||
* proper commutator or negator attribute. That style doesn't require
|
* proper commutator or negator attribute. That style doesn't require
|
||||||
* creation of a shell, and it's the only style that worked right before
|
* creation of a shell, and it's the only style that worked right
|
||||||
* Postgres version 6.5.
|
* before Postgres version 6.5. This code also takes care of the
|
||||||
* This code also takes care of the situation where the new operator
|
* situation where the new operator is its own commutator.
|
||||||
* is its own commutator.
|
|
||||||
*/
|
*/
|
||||||
if (selfCommutator)
|
if (selfCommutator)
|
||||||
commutatorId = operatorObjectId;
|
commutatorId = operatorObjectId;
|
||||||
|
@ -869,7 +874,8 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
|
||||||
|
|
||||||
tup = heap_getnext(pg_operator_scan, 0);
|
tup = heap_getnext(pg_operator_scan, 0);
|
||||||
|
|
||||||
/* if the commutator and negator are the same operator, do one update.
|
/*
|
||||||
|
* if the commutator and negator are the same operator, do one update.
|
||||||
* XXX this is probably useless code --- I doubt it ever makes sense
|
* XXX this is probably useless code --- I doubt it ever makes sense
|
||||||
* for commutator and negator to be the same thing...
|
* for commutator and negator to be the same thing...
|
||||||
*/
|
*/
|
||||||
|
@ -1008,7 +1014,7 @@ OperatorCreate(char *operatorName,
|
||||||
if (!leftTypeName && !rightTypeName)
|
if (!leftTypeName && !rightTypeName)
|
||||||
elog(ERROR, "OperatorCreate: at least one of leftarg or rightarg must be defined");
|
elog(ERROR, "OperatorCreate: at least one of leftarg or rightarg must be defined");
|
||||||
|
|
||||||
if (! (leftTypeName && rightTypeName))
|
if (!(leftTypeName && rightTypeName))
|
||||||
{
|
{
|
||||||
/* If it's not a binary op, these things mustn't be set: */
|
/* If it's not a binary op, these things mustn't be set: */
|
||||||
if (commutatorName)
|
if (commutatorName)
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.28 1999/05/13 07:28:27 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.29 1999/05/25 16:08:11 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -226,11 +226,11 @@ ProcedureCreate(char *procedureName,
|
||||||
* function name (the 'prosrc' value) is a known builtin function.
|
* function name (the 'prosrc' value) is a known builtin function.
|
||||||
*
|
*
|
||||||
* NOTE: in Postgres versions before 6.5, the SQL name of the created
|
* NOTE: in Postgres versions before 6.5, the SQL name of the created
|
||||||
* function could not be different from the internal name, and 'prosrc'
|
* function could not be different from the internal name, and
|
||||||
* wasn't used. So there is code out there that does CREATE FUNCTION
|
* 'prosrc' wasn't used. So there is code out there that does CREATE
|
||||||
* xyz AS '' LANGUAGE 'internal'. To preserve some modicum of
|
* FUNCTION xyz AS '' LANGUAGE 'internal'. To preserve some modicum
|
||||||
* backwards compatibility, accept an empty 'prosrc' value as meaning
|
* of backwards compatibility, accept an empty 'prosrc' value as
|
||||||
* the supplied SQL function name.
|
* meaning the supplied SQL function name.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (strcmp(languageName, "internal") == 0)
|
if (strcmp(languageName, "internal") == 0)
|
||||||
|
@ -239,7 +239,7 @@ ProcedureCreate(char *procedureName,
|
||||||
prosrc = procedureName;
|
prosrc = procedureName;
|
||||||
if (fmgr_lookupByName(prosrc) == (func_ptr) NULL)
|
if (fmgr_lookupByName(prosrc) == (func_ptr) NULL)
|
||||||
elog(ERROR,
|
elog(ERROR,
|
||||||
"ProcedureCreate: there is no builtin function named \"%s\"",
|
"ProcedureCreate: there is no builtin function named \"%s\"",
|
||||||
prosrc);
|
prosrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.36 1999/04/20 03:51:14 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.37 1999/05/25 16:08:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -400,8 +400,8 @@ TypeCreate(char *typeName,
|
||||||
procname = procs[j];
|
procname = procs[j];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First look for a 1-argument func with all argtypes 0.
|
* First look for a 1-argument func with all argtypes 0. This is
|
||||||
* This is valid for all four kinds of procedure.
|
* valid for all four kinds of procedure.
|
||||||
*/
|
*/
|
||||||
MemSet(argList, 0, 8 * sizeof(Oid));
|
MemSet(argList, 0, 8 * sizeof(Oid));
|
||||||
|
|
||||||
|
@ -413,20 +413,23 @@ TypeCreate(char *typeName,
|
||||||
|
|
||||||
if (!HeapTupleIsValid(tup))
|
if (!HeapTupleIsValid(tup))
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For array types, the input procedures may take 3 args
|
* For array types, the input procedures may take 3 args (data
|
||||||
* (data value, element OID, atttypmod); the pg_proc
|
* value, element OID, atttypmod); the pg_proc argtype
|
||||||
* argtype signature is 0,0,INT4OID. The output procedures
|
* signature is 0,0,INT4OID. The output procedures may take 2
|
||||||
* may take 2 args (data value, element OID).
|
* args (data value, element OID).
|
||||||
*/
|
*/
|
||||||
if (OidIsValid(elementObjectId))
|
if (OidIsValid(elementObjectId))
|
||||||
{
|
{
|
||||||
int nargs;
|
int nargs;
|
||||||
|
|
||||||
if (j % 2)
|
if (j % 2)
|
||||||
{
|
{
|
||||||
/* output proc */
|
/* output proc */
|
||||||
nargs = 2;
|
nargs = 2;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
/* input proc */
|
/* input proc */
|
||||||
nargs = 3;
|
nargs = 3;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/recipe.c,v 1.2 1999/03/16 04:25:46 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/recipe.c,v 1.3 1999/05/25 16:08:30 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -121,18 +121,18 @@ static QueryTreeList *tg_parseTeeNode(TgRecipe * r,
|
||||||
void
|
void
|
||||||
beginRecipe(RecipeStmt *stmt)
|
beginRecipe(RecipeStmt *stmt)
|
||||||
{
|
{
|
||||||
TgRecipe *r;
|
TgRecipe *r;
|
||||||
int i,
|
int i,
|
||||||
numTees;
|
numTees;
|
||||||
QueryTreeList *qList;
|
QueryTreeList *qList;
|
||||||
char portalName[1024];
|
char portalName[1024];
|
||||||
|
|
||||||
Plan *plan;
|
Plan *plan;
|
||||||
TupleDesc attinfo;
|
TupleDesc attinfo;
|
||||||
QueryDesc *queryDesc;
|
QueryDesc *queryDesc;
|
||||||
Query *parsetree;
|
Query *parsetree;
|
||||||
|
|
||||||
TeeInfo *teeInfo;
|
TeeInfo *teeInfo;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* retrieveRecipe() reads the recipe from the database and returns a
|
* retrieveRecipe() reads the recipe from the database and returns a
|
||||||
|
@ -808,21 +808,21 @@ tg_parseTeeNode(TgRecipe * r,
|
||||||
static QueryTreeList *
|
static QueryTreeList *
|
||||||
tg_parseSubQuery(TgRecipe * r, TgNode * n, TeeInfo * teeInfo)
|
tg_parseSubQuery(TgRecipe * r, TgNode * n, TeeInfo * teeInfo)
|
||||||
{
|
{
|
||||||
TgElement *elem;
|
TgElement *elem;
|
||||||
char *funcName;
|
char *funcName;
|
||||||
Oid typev[8], /* eight arguments maximum */
|
Oid typev[8], /* eight arguments maximum */
|
||||||
relid;
|
relid;
|
||||||
int i,
|
int i,
|
||||||
parameterCount;
|
parameterCount;
|
||||||
|
|
||||||
QueryTreeList *qList; /* the parse tree of the nodeElement */
|
QueryTreeList *qList; /* the parse tree of the nodeElement */
|
||||||
QueryTreeList *inputQlist; /* the list of parse trees for the inputs
|
QueryTreeList *inputQlist; /* the list of parse trees for the inputs
|
||||||
* to this node */
|
* to this node */
|
||||||
QueryTreeList *q;
|
QueryTreeList *q;
|
||||||
TgNode *child;
|
TgNode *child;
|
||||||
Relation rel;
|
Relation rel;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
|
|
||||||
qList = NULL;
|
qList = NULL;
|
||||||
|
|
||||||
|
|
|
@ -5,17 +5,17 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* The version stuff has not been tested under postgres95 and probably
|
* The version stuff has not been tested under postgres95 and probably
|
||||||
* doesn't work! - jolly 8/19/95
|
* doesn't work! - jolly 8/19/95
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* $Id: version.c,v 1.18 1999/02/13 23:15:12 momjian Exp $
|
* $Id: version.c,v 1.19 1999/05/25 16:08:32 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* At the point the version is defined, 2 physical relations are created
|
* At the point the version is defined, 2 physical relations are created
|
||||||
* <vname>_added and <vname>_deleted.
|
* <vname>_added and <vname>_deleted.
|
||||||
*
|
*
|
||||||
* In addition, 4 rules are defined which govern the semantics of
|
* In addition, 4 rules are defined which govern the semantics of
|
||||||
* versions w.r.t retrieves, appends, replaces and deletes.
|
* versions w.r.t retrieves, appends, replaces and deletes.
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.46 1999/04/25 19:27:43 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.47 1999/05/25 16:08:15 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -31,17 +31,17 @@
|
||||||
* relname to a list of outstanding NOTIFY requests. Actual processing
|
* relname to a list of outstanding NOTIFY requests. Actual processing
|
||||||
* happens if and only if we reach transaction commit. At that time (in
|
* happens if and only if we reach transaction commit. At that time (in
|
||||||
* routine AtCommit_Notify) we scan pg_listener for matching relnames.
|
* routine AtCommit_Notify) we scan pg_listener for matching relnames.
|
||||||
* If the listenerPID in a matching tuple is ours, we just send a notify
|
* If the listenerPID in a matching tuple is ours, we just send a notify
|
||||||
* message to our own front end. If it is not ours, and "notification"
|
* message to our own front end. If it is not ours, and "notification"
|
||||||
* is not already nonzero, we set notification to our own PID and send a
|
* is not already nonzero, we set notification to our own PID and send a
|
||||||
* SIGUSR2 signal to the receiving process (indicated by listenerPID).
|
* SIGUSR2 signal to the receiving process (indicated by listenerPID).
|
||||||
* BTW: if the signal operation fails, we presume that the listener backend
|
* BTW: if the signal operation fails, we presume that the listener backend
|
||||||
* crashed without removing this tuple, and remove the tuple for it.
|
* crashed without removing this tuple, and remove the tuple for it.
|
||||||
*
|
*
|
||||||
* 4. Upon receipt of a SIGUSR2 signal, the signal handler can call inbound-
|
* 4. Upon receipt of a SIGUSR2 signal, the signal handler can call inbound-
|
||||||
* notify processing immediately if this backend is idle (ie, it is
|
* notify processing immediately if this backend is idle (ie, it is
|
||||||
* waiting for a frontend command and is not within a transaction block).
|
* waiting for a frontend command and is not within a transaction block).
|
||||||
* Otherwise the handler may only set a flag, which will cause the
|
* Otherwise the handler may only set a flag, which will cause the
|
||||||
* processing to occur just before we next go idle.
|
* processing to occur just before we next go idle.
|
||||||
*
|
*
|
||||||
* 5. Inbound-notify processing consists of scanning pg_listener for tuples
|
* 5. Inbound-notify processing consists of scanning pg_listener for tuples
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
*
|
*
|
||||||
* Note that the system's use of pg_listener is confined to very short
|
* Note that the system's use of pg_listener is confined to very short
|
||||||
* intervals at the end of a transaction that contains NOTIFY statements,
|
* intervals at the end of a transaction that contains NOTIFY statements,
|
||||||
* or during the transaction caused by an inbound SIGUSR2. So the fact that
|
* or during the transaction caused by an inbound SIGUSR2. So the fact that
|
||||||
* pg_listener is a global resource shouldn't cause too much performance
|
* pg_listener is a global resource shouldn't cause too much performance
|
||||||
* problem. But application authors ought to be discouraged from doing
|
* problem. But application authors ought to be discouraged from doing
|
||||||
* LISTEN or UNLISTEN near the start of a long transaction --- that would
|
* LISTEN or UNLISTEN near the start of a long transaction --- that would
|
||||||
|
@ -109,8 +109,8 @@ extern CommandDest whereToSendOutput;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* State for outbound notifies consists of a list of all relnames NOTIFYed
|
* State for outbound notifies consists of a list of all relnames NOTIFYed
|
||||||
* in the current transaction. We do not actually perform a NOTIFY until
|
* in the current transaction. We do not actually perform a NOTIFY until
|
||||||
* and unless the transaction commits. pendingNotifies is NULL if no
|
* and unless the transaction commits. pendingNotifies is NULL if no
|
||||||
* NOTIFYs have been done in the current transaction.
|
* NOTIFYs have been done in the current transaction.
|
||||||
*/
|
*/
|
||||||
static Dllist *pendingNotifies = NULL;
|
static Dllist *pendingNotifies = NULL;
|
||||||
|
@ -125,8 +125,8 @@ static Dllist *pendingNotifies = NULL;
|
||||||
* does not grok "volatile", you'd be best advised to compile this file
|
* does not grok "volatile", you'd be best advised to compile this file
|
||||||
* with all optimization turned off.
|
* with all optimization turned off.
|
||||||
*/
|
*/
|
||||||
static volatile int notifyInterruptEnabled = 0;
|
static volatile int notifyInterruptEnabled = 0;
|
||||||
static volatile int notifyInterruptOccurred = 0;
|
static volatile int notifyInterruptOccurred = 0;
|
||||||
|
|
||||||
/* True if we've registered an on_shmem_exit cleanup (or at least tried to). */
|
/* True if we've registered an on_shmem_exit cleanup (or at least tried to). */
|
||||||
static int unlistenExitRegistered = 0;
|
static int unlistenExitRegistered = 0;
|
||||||
|
@ -142,7 +142,7 @@ static void ClearPendingNotifies(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------
|
*--------------------------------------------------------------
|
||||||
* Async_Notify
|
* Async_Notify
|
||||||
*
|
*
|
||||||
* This is executed by the SQL notify command.
|
* This is executed by the SQL notify command.
|
||||||
*
|
*
|
||||||
|
@ -164,28 +164,29 @@ Async_Notify(char *relname)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We allocate list memory from the global malloc pool to ensure that
|
* We allocate list memory from the global malloc pool to ensure that
|
||||||
* it will live until we want to use it. This is probably not necessary
|
* it will live until we want to use it. This is probably not
|
||||||
* any longer, since we will use it before the end of the transaction.
|
* necessary any longer, since we will use it before the end of the
|
||||||
* DLList only knows how to use malloc() anyway, but we could probably
|
* transaction. DLList only knows how to use malloc() anyway, but we
|
||||||
* palloc() the strings...
|
* could probably palloc() the strings...
|
||||||
*/
|
*/
|
||||||
if (!pendingNotifies)
|
if (!pendingNotifies)
|
||||||
pendingNotifies = DLNewList();
|
pendingNotifies = DLNewList();
|
||||||
notifyName = strdup(relname);
|
notifyName = strdup(relname);
|
||||||
DLAddHead(pendingNotifies, DLNewElem(notifyName));
|
DLAddHead(pendingNotifies, DLNewElem(notifyName));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE: we could check to see if pendingNotifies already has an entry
|
* NOTE: we could check to see if pendingNotifies already has an entry
|
||||||
* for relname, and thus avoid making duplicate entries. However, most
|
* for relname, and thus avoid making duplicate entries. However,
|
||||||
* apps probably don't notify the same name multiple times per transaction,
|
* most apps probably don't notify the same name multiple times per
|
||||||
* so we'd likely just be wasting cycles to make such a check.
|
* transaction, so we'd likely just be wasting cycles to make such a
|
||||||
* AsyncExistsPendingNotify() doesn't really care whether the list
|
* check. AsyncExistsPendingNotify() doesn't really care whether the
|
||||||
* contains duplicates...
|
* list contains duplicates...
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------
|
*--------------------------------------------------------------
|
||||||
* Async_Listen
|
* Async_Listen
|
||||||
*
|
*
|
||||||
* This is executed by the SQL listen command.
|
* This is executed by the SQL listen command.
|
||||||
*
|
*
|
||||||
|
@ -274,7 +275,7 @@ Async_Listen(char *relname, int pid)
|
||||||
/*
|
/*
|
||||||
* now that we are listening, make sure we will unlisten before dying.
|
* now that we are listening, make sure we will unlisten before dying.
|
||||||
*/
|
*/
|
||||||
if (! unlistenExitRegistered)
|
if (!unlistenExitRegistered)
|
||||||
{
|
{
|
||||||
if (on_shmem_exit(Async_UnlistenOnExit, (caddr_t) NULL) < 0)
|
if (on_shmem_exit(Async_UnlistenOnExit, (caddr_t) NULL) < 0)
|
||||||
elog(NOTICE, "Async_Listen: out of shmem_exit slots");
|
elog(NOTICE, "Async_Listen: out of shmem_exit slots");
|
||||||
|
@ -284,7 +285,7 @@ Async_Listen(char *relname, int pid)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------
|
*--------------------------------------------------------------
|
||||||
* Async_Unlisten
|
* Async_Unlisten
|
||||||
*
|
*
|
||||||
* This is executed by the SQL unlisten command.
|
* This is executed by the SQL unlisten command.
|
||||||
*
|
*
|
||||||
|
@ -326,14 +327,16 @@ Async_Unlisten(char *relname, int pid)
|
||||||
UnlockRelation(lRel, AccessExclusiveLock);
|
UnlockRelation(lRel, AccessExclusiveLock);
|
||||||
heap_close(lRel);
|
heap_close(lRel);
|
||||||
}
|
}
|
||||||
/* We do not complain about unlistening something not being listened;
|
|
||||||
|
/*
|
||||||
|
* We do not complain about unlistening something not being listened;
|
||||||
* should we?
|
* should we?
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------
|
*--------------------------------------------------------------
|
||||||
* Async_UnlistenAll
|
* Async_UnlistenAll
|
||||||
*
|
*
|
||||||
* Unlisten all relations for this backend.
|
* Unlisten all relations for this backend.
|
||||||
*
|
*
|
||||||
|
@ -379,7 +382,7 @@ Async_UnlistenAll()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------
|
*--------------------------------------------------------------
|
||||||
* Async_UnlistenOnExit
|
* Async_UnlistenOnExit
|
||||||
*
|
*
|
||||||
* Clean up the pg_listener table at backend exit.
|
* Clean up the pg_listener table at backend exit.
|
||||||
*
|
*
|
||||||
|
@ -398,11 +401,12 @@ Async_UnlistenAll()
|
||||||
static void
|
static void
|
||||||
Async_UnlistenOnExit()
|
Async_UnlistenOnExit()
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to start/commit a transaction for the unlisten,
|
* We need to start/commit a transaction for the unlisten, but if
|
||||||
* but if there is already an active transaction we had better
|
* there is already an active transaction we had better abort that one
|
||||||
* abort that one first. Otherwise we'd end up committing changes
|
* first. Otherwise we'd end up committing changes that probably
|
||||||
* that probably ought to be discarded.
|
* ought to be discarded.
|
||||||
*/
|
*/
|
||||||
AbortOutOfAnyTransaction();
|
AbortOutOfAnyTransaction();
|
||||||
/* Now we can do the unlisten */
|
/* Now we can do the unlisten */
|
||||||
|
@ -413,7 +417,7 @@ Async_UnlistenOnExit()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------
|
*--------------------------------------------------------------
|
||||||
* AtCommit_Notify
|
* AtCommit_Notify
|
||||||
*
|
*
|
||||||
* This is called at transaction commit.
|
* This is called at transaction commit.
|
||||||
*
|
*
|
||||||
|
@ -450,12 +454,14 @@ AtCommit_Notify()
|
||||||
int32 listenerPID;
|
int32 listenerPID;
|
||||||
|
|
||||||
if (!pendingNotifies)
|
if (!pendingNotifies)
|
||||||
return; /* no NOTIFY statements in this transaction */
|
return; /* no NOTIFY statements in this
|
||||||
|
* transaction */
|
||||||
|
|
||||||
/* NOTIFY is disabled if not normal processing mode.
|
/*
|
||||||
* This test used to be in xact.c, but it seems cleaner to do it here.
|
* NOTIFY is disabled if not normal processing mode. This test used to
|
||||||
|
* be in xact.c, but it seems cleaner to do it here.
|
||||||
*/
|
*/
|
||||||
if (! IsNormalProcessingMode())
|
if (!IsNormalProcessingMode())
|
||||||
{
|
{
|
||||||
ClearPendingNotifies();
|
ClearPendingNotifies();
|
||||||
return;
|
return;
|
||||||
|
@ -487,10 +493,13 @@ AtCommit_Notify()
|
||||||
|
|
||||||
if (listenerPID == MyProcPid)
|
if (listenerPID == MyProcPid)
|
||||||
{
|
{
|
||||||
/* Self-notify: no need to bother with table update.
|
|
||||||
|
/*
|
||||||
|
* Self-notify: no need to bother with table update.
|
||||||
* Indeed, we *must not* clear the notification field in
|
* Indeed, we *must not* clear the notification field in
|
||||||
* this path, or we could lose an outside notify, which'd be
|
* this path, or we could lose an outside notify, which'd
|
||||||
* bad for applications that ignore self-notify messages.
|
* be bad for applications that ignore self-notify
|
||||||
|
* messages.
|
||||||
*/
|
*/
|
||||||
TPRINTF(TRACE_NOTIFY, "AtCommit_Notify: notifying self");
|
TPRINTF(TRACE_NOTIFY, "AtCommit_Notify: notifying self");
|
||||||
NotifyMyFrontEnd(relname, listenerPID);
|
NotifyMyFrontEnd(relname, listenerPID);
|
||||||
|
@ -499,23 +508,27 @@ AtCommit_Notify()
|
||||||
{
|
{
|
||||||
TPRINTF(TRACE_NOTIFY, "AtCommit_Notify: notifying pid %d",
|
TPRINTF(TRACE_NOTIFY, "AtCommit_Notify: notifying pid %d",
|
||||||
listenerPID);
|
listenerPID);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If someone has already notified this listener,
|
* If someone has already notified this listener, we don't
|
||||||
* we don't bother modifying the table, but we do still send
|
* bother modifying the table, but we do still send a
|
||||||
* a SIGUSR2 signal, just in case that backend missed the
|
* SIGUSR2 signal, just in case that backend missed the
|
||||||
* earlier signal for some reason. It's OK to send the signal
|
* earlier signal for some reason. It's OK to send the
|
||||||
* first, because the other guy can't read pg_listener until
|
* signal first, because the other guy can't read
|
||||||
* we unlock it.
|
* pg_listener until we unlock it.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_KILL
|
#ifdef HAVE_KILL
|
||||||
if (kill(listenerPID, SIGUSR2) < 0)
|
if (kill(listenerPID, SIGUSR2) < 0)
|
||||||
{
|
{
|
||||||
/* Get rid of pg_listener entry if it refers to a PID
|
|
||||||
|
/*
|
||||||
|
* Get rid of pg_listener entry if it refers to a PID
|
||||||
* that no longer exists. Presumably, that backend
|
* that no longer exists. Presumably, that backend
|
||||||
* crashed without deleting its pg_listener entries.
|
* crashed without deleting its pg_listener entries.
|
||||||
* This code used to only delete the entry if errno==ESRCH,
|
* This code used to only delete the entry if
|
||||||
* but as far as I can see we should just do it for any
|
* errno==ESRCH, but as far as I can see we should
|
||||||
* failure (certainly at least for EPERM too...)
|
* just do it for any failure (certainly at least for
|
||||||
|
* EPERM too...)
|
||||||
*/
|
*/
|
||||||
heap_delete(lRel, &lTuple->t_self, NULL);
|
heap_delete(lRel, &lTuple->t_self, NULL);
|
||||||
}
|
}
|
||||||
|
@ -536,6 +549,7 @@ AtCommit_Notify()
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_endscan(sRel);
|
heap_endscan(sRel);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do not do RelationUnsetLockForWrite(lRel) here, because the
|
* We do not do RelationUnsetLockForWrite(lRel) here, because the
|
||||||
* transaction is about to be committed anyway.
|
* transaction is about to be committed anyway.
|
||||||
|
@ -549,7 +563,7 @@ AtCommit_Notify()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------
|
*--------------------------------------------------------------
|
||||||
* AtAbort_Notify
|
* AtAbort_Notify
|
||||||
*
|
*
|
||||||
* This is called at transaction abort.
|
* This is called at transaction abort.
|
||||||
*
|
*
|
||||||
|
@ -569,7 +583,7 @@ AtAbort_Notify()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------
|
*--------------------------------------------------------------
|
||||||
* Async_NotifyHandler
|
* Async_NotifyHandler
|
||||||
*
|
*
|
||||||
* This is the signal handler for SIGUSR2.
|
* This is the signal handler for SIGUSR2.
|
||||||
*
|
*
|
||||||
|
@ -588,25 +602,30 @@ AtAbort_Notify()
|
||||||
void
|
void
|
||||||
Async_NotifyHandler(SIGNAL_ARGS)
|
Async_NotifyHandler(SIGNAL_ARGS)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: this is a SIGNAL HANDLER. You must be very wary what you do here.
|
* Note: this is a SIGNAL HANDLER. You must be very wary what you do
|
||||||
* Some helpful soul had this routine sprinkled with TPRINTFs, which would
|
* here. Some helpful soul had this routine sprinkled with TPRINTFs,
|
||||||
* likely lead to corruption of stdio buffers if they were ever turned on.
|
* which would likely lead to corruption of stdio buffers if they were
|
||||||
|
* ever turned on.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (notifyInterruptEnabled)
|
if (notifyInterruptEnabled)
|
||||||
{
|
{
|
||||||
/* I'm not sure whether some flavors of Unix might allow another
|
|
||||||
* SIGUSR2 occurrence to recursively interrupt this routine.
|
/*
|
||||||
* To cope with the possibility, we do the same sort of dance that
|
* I'm not sure whether some flavors of Unix might allow another
|
||||||
* EnableNotifyInterrupt must do --- see that routine for comments.
|
* SIGUSR2 occurrence to recursively interrupt this routine. To
|
||||||
|
* cope with the possibility, we do the same sort of dance that
|
||||||
|
* EnableNotifyInterrupt must do --- see that routine for
|
||||||
|
* comments.
|
||||||
*/
|
*/
|
||||||
notifyInterruptEnabled = 0; /* disable any recursive signal */
|
notifyInterruptEnabled = 0; /* disable any recursive signal */
|
||||||
notifyInterruptOccurred = 1; /* do at least one iteration */
|
notifyInterruptOccurred = 1; /* do at least one iteration */
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
notifyInterruptEnabled = 1;
|
notifyInterruptEnabled = 1;
|
||||||
if (! notifyInterruptOccurred)
|
if (!notifyInterruptOccurred)
|
||||||
break;
|
break;
|
||||||
notifyInterruptEnabled = 0;
|
notifyInterruptEnabled = 0;
|
||||||
if (notifyInterruptOccurred)
|
if (notifyInterruptOccurred)
|
||||||
|
@ -621,14 +640,18 @@ Async_NotifyHandler(SIGNAL_ARGS)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* In this path it is NOT SAFE to do much of anything, except this: */
|
|
||||||
|
/*
|
||||||
|
* In this path it is NOT SAFE to do much of anything, except
|
||||||
|
* this:
|
||||||
|
*/
|
||||||
notifyInterruptOccurred = 1;
|
notifyInterruptOccurred = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* --------------------------------------------------------------
|
* --------------------------------------------------------------
|
||||||
* EnableNotifyInterrupt
|
* EnableNotifyInterrupt
|
||||||
*
|
*
|
||||||
* This is called by the PostgresMain main loop just before waiting
|
* This is called by the PostgresMain main loop just before waiting
|
||||||
* for a frontend command. If we are truly idle (ie, *not* inside
|
* for a frontend command. If we are truly idle (ie, *not* inside
|
||||||
|
@ -652,26 +675,27 @@ EnableNotifyInterrupt(void)
|
||||||
* notifyInterruptOccurred and then set notifyInterruptEnabled, we
|
* notifyInterruptOccurred and then set notifyInterruptEnabled, we
|
||||||
* could fail to respond promptly to a signal that happens in between
|
* could fail to respond promptly to a signal that happens in between
|
||||||
* those two steps. (A very small time window, perhaps, but Murphy's
|
* those two steps. (A very small time window, perhaps, but Murphy's
|
||||||
* Law says you can hit it...) Instead, we first set the enable flag,
|
* Law says you can hit it...) Instead, we first set the enable flag,
|
||||||
* then test the occurred flag. If we see an unserviced interrupt
|
* then test the occurred flag. If we see an unserviced interrupt has
|
||||||
* has occurred, we re-clear the enable flag before going off to do
|
* occurred, we re-clear the enable flag before going off to do the
|
||||||
* the service work. (That prevents re-entrant invocation of
|
* service work. (That prevents re-entrant invocation of
|
||||||
* ProcessIncomingNotify() if another interrupt occurs.)
|
* ProcessIncomingNotify() if another interrupt occurs.) If an
|
||||||
* If an interrupt comes in between the setting and clearing of
|
* interrupt comes in between the setting and clearing of
|
||||||
* notifyInterruptEnabled, then it will have done the service
|
* notifyInterruptEnabled, then it will have done the service work and
|
||||||
* work and left notifyInterruptOccurred zero, so we have to check
|
* left notifyInterruptOccurred zero, so we have to check again after
|
||||||
* again after clearing enable. The whole thing has to be in a loop
|
* clearing enable. The whole thing has to be in a loop in case
|
||||||
* in case another interrupt occurs while we're servicing the first.
|
* another interrupt occurs while we're servicing the first. Once we
|
||||||
* Once we get out of the loop, enable is set and we know there is no
|
* get out of the loop, enable is set and we know there is no
|
||||||
* unserviced interrupt.
|
* unserviced interrupt.
|
||||||
*
|
*
|
||||||
* NB: an overenthusiastic optimizing compiler could easily break this
|
* NB: an overenthusiastic optimizing compiler could easily break this
|
||||||
* code. Hopefully, they all understand what "volatile" means these days.
|
* code. Hopefully, they all understand what "volatile" means these
|
||||||
|
* days.
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
notifyInterruptEnabled = 1;
|
notifyInterruptEnabled = 1;
|
||||||
if (! notifyInterruptOccurred)
|
if (!notifyInterruptOccurred)
|
||||||
break;
|
break;
|
||||||
notifyInterruptEnabled = 0;
|
notifyInterruptEnabled = 0;
|
||||||
if (notifyInterruptOccurred)
|
if (notifyInterruptOccurred)
|
||||||
|
@ -686,7 +710,7 @@ EnableNotifyInterrupt(void)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* --------------------------------------------------------------
|
* --------------------------------------------------------------
|
||||||
* DisableNotifyInterrupt
|
* DisableNotifyInterrupt
|
||||||
*
|
*
|
||||||
* This is called by the PostgresMain main loop just after receiving
|
* This is called by the PostgresMain main loop just after receiving
|
||||||
* a frontend command. Signal handler execution of inbound notifies
|
* a frontend command. Signal handler execution of inbound notifies
|
||||||
|
@ -702,7 +726,7 @@ DisableNotifyInterrupt(void)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* --------------------------------------------------------------
|
* --------------------------------------------------------------
|
||||||
* ProcessIncomingNotify
|
* ProcessIncomingNotify
|
||||||
*
|
*
|
||||||
* Deal with arriving NOTIFYs from other backends.
|
* Deal with arriving NOTIFYs from other backends.
|
||||||
* This is called either directly from the SIGUSR2 signal handler,
|
* This is called either directly from the SIGUSR2 signal handler,
|
||||||
|
@ -777,6 +801,7 @@ ProcessIncomingNotify(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
heap_endscan(sRel);
|
heap_endscan(sRel);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do not do RelationUnsetLockForWrite(lRel) here, because the
|
* We do not do RelationUnsetLockForWrite(lRel) here, because the
|
||||||
* transaction is about to be committed anyway.
|
* transaction is about to be committed anyway.
|
||||||
|
@ -785,7 +810,10 @@ ProcessIncomingNotify(void)
|
||||||
|
|
||||||
CommitTransactionCommand();
|
CommitTransactionCommand();
|
||||||
|
|
||||||
/* Must flush the notify messages to ensure frontend gets them promptly. */
|
/*
|
||||||
|
* Must flush the notify messages to ensure frontend gets them
|
||||||
|
* promptly.
|
||||||
|
*/
|
||||||
pq_flush();
|
pq_flush();
|
||||||
|
|
||||||
PS_SET_STATUS("idle");
|
PS_SET_STATUS("idle");
|
||||||
|
@ -800,20 +828,22 @@ NotifyMyFrontEnd(char *relname, int32 listenerPID)
|
||||||
if (whereToSendOutput == Remote)
|
if (whereToSendOutput == Remote)
|
||||||
{
|
{
|
||||||
StringInfoData buf;
|
StringInfoData buf;
|
||||||
|
|
||||||
pq_beginmessage(&buf);
|
pq_beginmessage(&buf);
|
||||||
pq_sendbyte(&buf, 'A');
|
pq_sendbyte(&buf, 'A');
|
||||||
pq_sendint(&buf, listenerPID, sizeof(int32));
|
pq_sendint(&buf, listenerPID, sizeof(int32));
|
||||||
pq_sendstring(&buf, relname);
|
pq_sendstring(&buf, relname);
|
||||||
pq_endmessage(&buf);
|
pq_endmessage(&buf);
|
||||||
/* NOTE: we do not do pq_flush() here. For a self-notify, it will
|
|
||||||
|
/*
|
||||||
|
* NOTE: we do not do pq_flush() here. For a self-notify, it will
|
||||||
* happen at the end of the transaction, and for incoming notifies
|
* happen at the end of the transaction, and for incoming notifies
|
||||||
* ProcessIncomingNotify will do it after finding all the notifies.
|
* ProcessIncomingNotify will do it after finding all the
|
||||||
|
* notifies.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
elog(NOTICE, "NOTIFY for %s", relname);
|
elog(NOTICE, "NOTIFY for %s", relname);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Does pendingNotifies include the given relname?
|
/* Does pendingNotifies include the given relname?
|
||||||
|
@ -847,10 +877,12 @@ ClearPendingNotifies()
|
||||||
|
|
||||||
if (pendingNotifies)
|
if (pendingNotifies)
|
||||||
{
|
{
|
||||||
/* Since the referenced strings are malloc'd, we have to scan the
|
|
||||||
|
/*
|
||||||
|
* Since the referenced strings are malloc'd, we have to scan the
|
||||||
* list and delete them individually. If we used palloc for the
|
* list and delete them individually. If we used palloc for the
|
||||||
* strings then we could just do DLFreeList to get rid of both
|
* strings then we could just do DLFreeList to get rid of both the
|
||||||
* the list nodes and the list base...
|
* list nodes and the list base...
|
||||||
*/
|
*/
|
||||||
while ((p = DLRemHead(pendingNotifies)) != NULL)
|
while ((p = DLRemHead(pendingNotifies)) != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.38 1999/02/13 23:15:02 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.39 1999/05/25 16:08:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -236,17 +236,17 @@ copy_heap(Oid OIDOldHeap)
|
||||||
static void
|
static void
|
||||||
copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
|
copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
|
||||||
{
|
{
|
||||||
Relation OldIndex,
|
Relation OldIndex,
|
||||||
NewHeap;
|
NewHeap;
|
||||||
HeapTuple Old_pg_index_Tuple,
|
HeapTuple Old_pg_index_Tuple,
|
||||||
Old_pg_index_relation_Tuple,
|
Old_pg_index_relation_Tuple,
|
||||||
pg_proc_Tuple;
|
pg_proc_Tuple;
|
||||||
Form_pg_index Old_pg_index_Form;
|
Form_pg_index Old_pg_index_Form;
|
||||||
Form_pg_class Old_pg_index_relation_Form;
|
Form_pg_class Old_pg_index_relation_Form;
|
||||||
Form_pg_proc pg_proc_Form;
|
Form_pg_proc pg_proc_Form;
|
||||||
char *NewIndexName;
|
char *NewIndexName;
|
||||||
AttrNumber *attnumP;
|
AttrNumber *attnumP;
|
||||||
int natts;
|
int natts;
|
||||||
FuncIndexInfo *finfo;
|
FuncIndexInfo *finfo;
|
||||||
|
|
||||||
NewHeap = heap_open(OIDNewHeap);
|
NewHeap = heap_open(OIDNewHeap);
|
||||||
|
@ -259,14 +259,14 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
|
||||||
*/
|
*/
|
||||||
Old_pg_index_Tuple = SearchSysCacheTuple(INDEXRELID,
|
Old_pg_index_Tuple = SearchSysCacheTuple(INDEXRELID,
|
||||||
ObjectIdGetDatum(RelationGetRelid(OldIndex)),
|
ObjectIdGetDatum(RelationGetRelid(OldIndex)),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
|
|
||||||
Assert(Old_pg_index_Tuple);
|
Assert(Old_pg_index_Tuple);
|
||||||
Old_pg_index_Form = (Form_pg_index) GETSTRUCT(Old_pg_index_Tuple);
|
Old_pg_index_Form = (Form_pg_index) GETSTRUCT(Old_pg_index_Tuple);
|
||||||
|
|
||||||
Old_pg_index_relation_Tuple = SearchSysCacheTuple(RELOID,
|
Old_pg_index_relation_Tuple = SearchSysCacheTuple(RELOID,
|
||||||
ObjectIdGetDatum(RelationGetRelid(OldIndex)),
|
ObjectIdGetDatum(RelationGetRelid(OldIndex)),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
|
|
||||||
Assert(Old_pg_index_relation_Tuple);
|
Assert(Old_pg_index_relation_Tuple);
|
||||||
Old_pg_index_relation_Form = (Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple);
|
Old_pg_index_relation_Form = (Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple);
|
||||||
|
@ -296,7 +296,7 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
|
||||||
|
|
||||||
pg_proc_Tuple = SearchSysCacheTuple(PROOID,
|
pg_proc_Tuple = SearchSysCacheTuple(PROOID,
|
||||||
ObjectIdGetDatum(Old_pg_index_Form->indproc),
|
ObjectIdGetDatum(Old_pg_index_Form->indproc),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
|
|
||||||
Assert(pg_proc_Tuple);
|
Assert(pg_proc_Tuple);
|
||||||
pg_proc_Form = (Form_pg_proc) GETSTRUCT(pg_proc_Tuple);
|
pg_proc_Form = (Form_pg_proc) GETSTRUCT(pg_proc_Tuple);
|
||||||
|
@ -319,7 +319,7 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
|
||||||
(uint16) 0, (Datum) NULL, NULL,
|
(uint16) 0, (Datum) NULL, NULL,
|
||||||
Old_pg_index_Form->indislossy,
|
Old_pg_index_Form->indislossy,
|
||||||
Old_pg_index_Form->indisunique,
|
Old_pg_index_Form->indisunique,
|
||||||
Old_pg_index_Form->indisprimary);
|
Old_pg_index_Form->indisprimary);
|
||||||
|
|
||||||
heap_close(OldIndex);
|
heap_close(OldIndex);
|
||||||
heap_close(NewHeap);
|
heap_close(NewHeap);
|
||||||
|
@ -329,14 +329,14 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
|
||||||
static void
|
static void
|
||||||
rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
|
rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
|
||||||
{
|
{
|
||||||
Relation LocalNewHeap,
|
Relation LocalNewHeap,
|
||||||
LocalOldHeap,
|
LocalOldHeap,
|
||||||
LocalOldIndex;
|
LocalOldIndex;
|
||||||
IndexScanDesc ScanDesc;
|
IndexScanDesc ScanDesc;
|
||||||
RetrieveIndexResult ScanResult;
|
RetrieveIndexResult ScanResult;
|
||||||
HeapTupleData LocalHeapTuple;
|
HeapTupleData LocalHeapTuple;
|
||||||
Buffer LocalBuffer;
|
Buffer LocalBuffer;
|
||||||
Oid OIDNewHeapInsert;
|
Oid OIDNewHeapInsert;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open the relations I need. Scan through the OldHeap on the OldIndex
|
* Open the relations I need. Scan through the OldHeap on the OldIndex
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.44 1999/05/10 00:44:56 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.45 1999/05/25 16:08:17 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The PortalExecutorHeapMemory crap needs to be eliminated
|
* The PortalExecutorHeapMemory crap needs to be eliminated
|
||||||
|
@ -117,18 +117,18 @@ PerformPortalFetch(char *name,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Create a const node from the given count value
|
* Create a const node from the given count value
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
memset(&limcount, 0, sizeof(limcount));
|
memset(&limcount, 0, sizeof(limcount));
|
||||||
limcount.type = T_Const;
|
limcount.type = T_Const;
|
||||||
limcount.consttype = INT4OID;
|
limcount.consttype = INT4OID;
|
||||||
limcount.constlen = sizeof(int4);
|
limcount.constlen = sizeof(int4);
|
||||||
limcount.constvalue = (Datum)count;
|
limcount.constvalue = (Datum) count;
|
||||||
limcount.constisnull = FALSE;
|
limcount.constisnull = FALSE;
|
||||||
limcount.constbyval = TRUE;
|
limcount.constbyval = TRUE;
|
||||||
limcount.constisset = FALSE;
|
limcount.constisset = FALSE;
|
||||||
limcount.constiscast = FALSE;
|
limcount.constiscast = FALSE;
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -193,8 +193,8 @@ PerformPortalFetch(char *name,
|
||||||
*/
|
*/
|
||||||
PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
|
PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
|
||||||
|
|
||||||
ExecutorRun(queryDesc, PortalGetState(portal), feature,
|
ExecutorRun(queryDesc, PortalGetState(portal), feature,
|
||||||
(Node *)NULL, (Node *)&limcount);
|
(Node *) NULL, (Node *) &limcount);
|
||||||
|
|
||||||
if (dest == None) /* MOVE */
|
if (dest == None) /* MOVE */
|
||||||
pfree(queryDesc);
|
pfree(queryDesc);
|
||||||
|
@ -211,7 +211,7 @@ PerformPortalFetch(char *name,
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(
|
MemoryContextSwitchTo(
|
||||||
(MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
|
(MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
|
@ -503,7 +503,7 @@ PerformAddAttribute(char *relationName,
|
||||||
heap_replace(rel, &reltup->t_self, reltup, NULL);
|
heap_replace(rel, &reltup->t_self, reltup, NULL);
|
||||||
|
|
||||||
{
|
{
|
||||||
HeapTuple temptup;
|
HeapTuple temptup;
|
||||||
|
|
||||||
if ((temptup = get_temp_rel_by_name(relationName)) != NULL)
|
if ((temptup = get_temp_rel_by_name(relationName)) != NULL)
|
||||||
((Form_pg_class) GETSTRUCT(temptup))->relnatts = maxatts;
|
((Form_pg_class) GETSTRUCT(temptup))->relnatts = maxatts;
|
||||||
|
@ -519,7 +519,7 @@ PerformAddAttribute(char *relationName,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LockTableCommand(LockStmt *lockstmt)
|
LockTableCommand(LockStmt * lockstmt)
|
||||||
{
|
{
|
||||||
Relation rel;
|
Relation rel;
|
||||||
int aclresult;
|
int aclresult;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.76 1999/05/10 00:44:58 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.77 1999/05/25 16:08:19 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -70,111 +70,138 @@ static int CountTuples(Relation relation);
|
||||||
|
|
||||||
static int lineno;
|
static int lineno;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal communications functions
|
* Internal communications functions
|
||||||
*/
|
*/
|
||||||
inline void CopySendData(void *databuf, int datasize, FILE *fp);
|
inline void CopySendData(void *databuf, int datasize, FILE *fp);
|
||||||
inline void CopySendString(char *str, FILE *fp);
|
inline void CopySendString(char *str, FILE *fp);
|
||||||
inline void CopySendChar(char c, FILE *fp);
|
inline void CopySendChar(char c, FILE *fp);
|
||||||
inline void CopyGetData(void *databuf, int datasize, FILE *fp);
|
inline void CopyGetData(void *databuf, int datasize, FILE *fp);
|
||||||
inline int CopyGetChar(FILE *fp);
|
inline int CopyGetChar(FILE *fp);
|
||||||
inline int CopyGetEof(FILE *fp);
|
inline int CopyGetEof(FILE *fp);
|
||||||
inline int CopyPeekChar(FILE *fp);
|
inline int CopyPeekChar(FILE *fp);
|
||||||
inline void CopyDonePeek(FILE *fp, int c, int pickup);
|
inline void CopyDonePeek(FILE *fp, int c, int pickup);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CopySendData sends output data either to the file
|
* CopySendData sends output data either to the file
|
||||||
* specified by fp or, if fp is NULL, using the standard
|
* specified by fp or, if fp is NULL, using the standard
|
||||||
* backend->frontend functions
|
* backend->frontend functions
|
||||||
*
|
*
|
||||||
* CopySendString does the same for null-terminated strings
|
* CopySendString does the same for null-terminated strings
|
||||||
* CopySendChar does the same for single characters
|
* CopySendChar does the same for single characters
|
||||||
*
|
*
|
||||||
* NB: no data conversion is applied by these functions
|
* NB: no data conversion is applied by these functions
|
||||||
*/
|
*/
|
||||||
inline void CopySendData(void *databuf, int datasize, FILE *fp) {
|
inline void
|
||||||
if (!fp)
|
CopySendData(void *databuf, int datasize, FILE *fp)
|
||||||
pq_putbytes((char*) databuf, datasize);
|
{
|
||||||
else
|
if (!fp)
|
||||||
fwrite(databuf, datasize, 1, fp);
|
pq_putbytes((char *) databuf, datasize);
|
||||||
}
|
else
|
||||||
|
fwrite(databuf, datasize, 1, fp);
|
||||||
inline void CopySendString(char *str, FILE *fp) {
|
|
||||||
CopySendData(str,strlen(str),fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void CopySendChar(char c, FILE *fp) {
|
inline void
|
||||||
CopySendData(&c,1,fp);
|
CopySendString(char *str, FILE *fp)
|
||||||
|
{
|
||||||
|
CopySendData(str, strlen(str), fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
CopySendChar(char c, FILE *fp)
|
||||||
|
{
|
||||||
|
CopySendData(&c, 1, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CopyGetData reads output data either from the file
|
* CopyGetData reads output data either from the file
|
||||||
* specified by fp or, if fp is NULL, using the standard
|
* specified by fp or, if fp is NULL, using the standard
|
||||||
* backend->frontend functions
|
* backend->frontend functions
|
||||||
*
|
*
|
||||||
* CopyGetChar does the same for single characters
|
* CopyGetChar does the same for single characters
|
||||||
* CopyGetEof checks if it's EOF on the input
|
* CopyGetEof checks if it's EOF on the input
|
||||||
*
|
*
|
||||||
* NB: no data conversion is applied by these functions
|
* NB: no data conversion is applied by these functions
|
||||||
*/
|
*/
|
||||||
inline void CopyGetData(void *databuf, int datasize, FILE *fp) {
|
inline void
|
||||||
if (!fp)
|
CopyGetData(void *databuf, int datasize, FILE *fp)
|
||||||
pq_getbytes((char*) databuf, datasize);
|
{
|
||||||
else
|
if (!fp)
|
||||||
fread(databuf, datasize, 1, fp);
|
pq_getbytes((char *) databuf, datasize);
|
||||||
|
else
|
||||||
|
fread(databuf, datasize, 1, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int CopyGetChar(FILE *fp) {
|
inline int
|
||||||
if (!fp)
|
CopyGetChar(FILE *fp)
|
||||||
{
|
{
|
||||||
unsigned char ch;
|
if (!fp)
|
||||||
if (pq_getbytes((char*) &ch, 1))
|
{
|
||||||
return EOF;
|
unsigned char ch;
|
||||||
return ch;
|
|
||||||
}
|
if (pq_getbytes((char *) &ch, 1))
|
||||||
else
|
return EOF;
|
||||||
return getc(fp);
|
return ch;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return getc(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int CopyGetEof(FILE *fp) {
|
inline int
|
||||||
if (!fp)
|
CopyGetEof(FILE *fp)
|
||||||
return 0; /* Never return EOF when talking to frontend ? */
|
{
|
||||||
else
|
if (!fp)
|
||||||
return feof(fp);
|
return 0; /* Never return EOF when talking to
|
||||||
|
* frontend ? */
|
||||||
|
else
|
||||||
|
return feof(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CopyPeekChar reads a byte in "peekable" mode.
|
* CopyPeekChar reads a byte in "peekable" mode.
|
||||||
* after each call to CopyPeekChar, a call to CopyDonePeek _must_
|
* after each call to CopyPeekChar, a call to CopyDonePeek _must_
|
||||||
* follow.
|
* follow.
|
||||||
* CopyDonePeek will either take the peeked char off the steam
|
* CopyDonePeek will either take the peeked char off the steam
|
||||||
* (if pickup is != 0) or leave it on the stream (if pickup == 0)
|
* (if pickup is != 0) or leave it on the stream (if pickup == 0)
|
||||||
*/
|
*/
|
||||||
inline int CopyPeekChar(FILE *fp) {
|
inline int
|
||||||
if (!fp)
|
CopyPeekChar(FILE *fp)
|
||||||
return pq_peekbyte();
|
{
|
||||||
else
|
if (!fp)
|
||||||
return getc(fp);
|
return pq_peekbyte();
|
||||||
|
else
|
||||||
|
return getc(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void CopyDonePeek(FILE *fp, int c, int pickup) {
|
inline void
|
||||||
if (!fp) {
|
CopyDonePeek(FILE *fp, int c, int pickup)
|
||||||
if (pickup) {
|
{
|
||||||
/* We want to pick it up - just receive again into dummy buffer */
|
if (!fp)
|
||||||
char c;
|
{
|
||||||
pq_getbytes(&c, 1);
|
if (pickup)
|
||||||
}
|
{
|
||||||
/* If we didn't want to pick it up, just leave it where it sits */
|
|
||||||
}
|
/*
|
||||||
else {
|
* We want to pick it up - just receive again into dummy
|
||||||
if (!pickup) {
|
* buffer
|
||||||
/* We don't want to pick it up - so put it back in there */
|
*/
|
||||||
ungetc(c,fp);
|
char c;
|
||||||
}
|
|
||||||
/* If we wanted to pick it up, it's already there */
|
pq_getbytes(&c, 1);
|
||||||
}
|
}
|
||||||
|
/* If we didn't want to pick it up, just leave it where it sits */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!pickup)
|
||||||
|
{
|
||||||
|
/* We don't want to pick it up - so put it back in there */
|
||||||
|
ungetc(c, fp);
|
||||||
|
}
|
||||||
|
/* If we wanted to pick it up, it's already there */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -317,7 +344,7 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
|
||||||
else if (!from)
|
else if (!from)
|
||||||
{
|
{
|
||||||
if (!binary)
|
if (!binary)
|
||||||
CopySendData("\\.\n",3,fp);
|
CopySendData("\\.\n", 3, fp);
|
||||||
if (IsUnderPostmaster)
|
if (IsUnderPostmaster)
|
||||||
pq_endcopyout(false);
|
pq_endcopyout(false);
|
||||||
}
|
}
|
||||||
|
@ -395,8 +422,8 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
||||||
|
|
||||||
if (oids && !binary)
|
if (oids && !binary)
|
||||||
{
|
{
|
||||||
CopySendString(oidout(tuple->t_data->t_oid),fp);
|
CopySendString(oidout(tuple->t_data->t_oid), fp);
|
||||||
CopySendChar(delim[0],fp);
|
CopySendChar(delim[0], fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < attr_count; i++)
|
for (i = 0; i < attr_count; i++)
|
||||||
|
@ -466,8 +493,8 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CopySendData((char *) tuple->t_data + tuple->t_data->t_hoff,
|
CopySendData((char *) tuple->t_data + tuple->t_data->t_hoff,
|
||||||
length, fp);
|
length, fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,7 +548,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
||||||
Node **indexPred = NULL;
|
Node **indexPred = NULL;
|
||||||
TupleDesc rtupdesc;
|
TupleDesc rtupdesc;
|
||||||
ExprContext *econtext = NULL;
|
ExprContext *econtext = NULL;
|
||||||
EState *estate = makeNode(EState); /* for ExecConstraints() */
|
EState *estate = makeNode(EState); /* for ExecConstraints() */
|
||||||
|
|
||||||
#ifndef OMIT_PARTIAL_INDEX
|
#ifndef OMIT_PARTIAL_INDEX
|
||||||
TupleTable tupleTable;
|
TupleTable tupleTable;
|
||||||
|
@ -566,11 +593,11 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
||||||
itupdescArr[i] = RelationGetDescr(index_rels[i]);
|
itupdescArr[i] = RelationGetDescr(index_rels[i]);
|
||||||
pgIndexTup = SearchSysCacheTuple(INDEXRELID,
|
pgIndexTup = SearchSysCacheTuple(INDEXRELID,
|
||||||
ObjectIdGetDatum(RelationGetRelid(index_rels[i])),
|
ObjectIdGetDatum(RelationGetRelid(index_rels[i])),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
Assert(pgIndexTup);
|
Assert(pgIndexTup);
|
||||||
pgIndexP[i] = (Form_pg_index) GETSTRUCT(pgIndexTup);
|
pgIndexP[i] = (Form_pg_index) GETSTRUCT(pgIndexTup);
|
||||||
for (attnumP = &(pgIndexP[i]->indkey[0]), natts = 0;
|
for (attnumP = &(pgIndexP[i]->indkey[0]), natts = 0;
|
||||||
natts < INDEX_MAX_KEYS && *attnumP != InvalidAttrNumber;
|
natts < INDEX_MAX_KEYS && *attnumP != InvalidAttrNumber;
|
||||||
attnumP++, natts++);
|
attnumP++, natts++);
|
||||||
if (pgIndexP[i]->indproc != InvalidOid)
|
if (pgIndexP[i]->indproc != InvalidOid)
|
||||||
{
|
{
|
||||||
|
@ -777,7 +804,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
||||||
}
|
}
|
||||||
else if (nulls[i] != 'n')
|
else if (nulls[i] != 'n')
|
||||||
{
|
{
|
||||||
ptr = (char *)att_align(ptr, attr[i]->attlen, attr[i]->attalign);
|
ptr = (char *) att_align(ptr, attr[i]->attlen, attr[i]->attalign);
|
||||||
values[i] = (Datum) ptr;
|
values[i] = (Datum) ptr;
|
||||||
ptr = att_addlength(ptr, attr[i]->attlen, ptr);
|
ptr = att_addlength(ptr, attr[i]->attlen, ptr);
|
||||||
}
|
}
|
||||||
|
@ -888,7 +915,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
||||||
pfree(index_nulls);
|
pfree(index_nulls);
|
||||||
pfree(idatum);
|
pfree(idatum);
|
||||||
pfree(byval);
|
pfree(byval);
|
||||||
|
|
||||||
if (!binary)
|
if (!binary)
|
||||||
{
|
{
|
||||||
pfree(in_functions);
|
pfree(in_functions);
|
||||||
|
@ -903,7 +930,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
|
||||||
{
|
{
|
||||||
if (index_rels[i] == NULL)
|
if (index_rels[i] == NULL)
|
||||||
continue;
|
continue;
|
||||||
if ((index_rels[i])->rd_rel->relam != BTREE_AM_OID &&
|
if ((index_rels[i])->rd_rel->relam != BTREE_AM_OID &&
|
||||||
(index_rels[i])->rd_rel->relam != HASH_AM_OID)
|
(index_rels[i])->rd_rel->relam != HASH_AM_OID)
|
||||||
UnlockRelation(index_rels[i], AccessExclusiveLock);
|
UnlockRelation(index_rels[i], AccessExclusiveLock);
|
||||||
index_close(index_rels[i]);
|
index_close(index_rels[i]);
|
||||||
|
@ -1022,12 +1049,12 @@ GetIndexRelations(Oid main_relation_oid,
|
||||||
{
|
{
|
||||||
|
|
||||||
index_relation_oid = (Oid) DatumGetInt32(heap_getattr(tuple, 2,
|
index_relation_oid = (Oid) DatumGetInt32(heap_getattr(tuple, 2,
|
||||||
tupDesc, &isnull));
|
tupDesc, &isnull));
|
||||||
if (index_relation_oid == main_relation_oid)
|
if (index_relation_oid == main_relation_oid)
|
||||||
{
|
{
|
||||||
scan->index_rel_oid = (Oid) DatumGetInt32(heap_getattr(tuple,
|
scan->index_rel_oid = (Oid) DatumGetInt32(heap_getattr(tuple,
|
||||||
Anum_pg_index_indexrelid,
|
Anum_pg_index_indexrelid,
|
||||||
tupDesc, &isnull));
|
tupDesc, &isnull));
|
||||||
(*n_indices)++;
|
(*n_indices)++;
|
||||||
scan->next = (RelationList *) palloc(sizeof(RelationList));
|
scan->next = (RelationList *) palloc(sizeof(RelationList));
|
||||||
scan = scan->next;
|
scan = scan->next;
|
||||||
|
@ -1047,7 +1074,7 @@ GetIndexRelations(Oid main_relation_oid,
|
||||||
{
|
{
|
||||||
(*index_rels)[i] = index_open(scan->index_rel_oid);
|
(*index_rels)[i] = index_open(scan->index_rel_oid);
|
||||||
/* comments in execUtils.c */
|
/* comments in execUtils.c */
|
||||||
if ((*index_rels)[i] != NULL &&
|
if ((*index_rels)[i] != NULL &&
|
||||||
((*index_rels)[i])->rd_rel->relam != BTREE_AM_OID &&
|
((*index_rels)[i])->rd_rel->relam != BTREE_AM_OID &&
|
||||||
((*index_rels)[i])->rd_rel->relam != HASH_AM_OID)
|
((*index_rels)[i])->rd_rel->relam != HASH_AM_OID)
|
||||||
LockRelation((*index_rels)[i], AccessExclusiveLock);
|
LockRelation((*index_rels)[i], AccessExclusiveLock);
|
||||||
|
@ -1176,26 +1203,29 @@ CopyReadAttribute(FILE *fp, bool *isnull, char *delim)
|
||||||
if (ISOCTAL(c))
|
if (ISOCTAL(c))
|
||||||
{
|
{
|
||||||
val = (val << 3) + VALUE(c);
|
val = (val << 3) + VALUE(c);
|
||||||
CopyDonePeek(fp, c, 1); /* Pick up the character! */
|
CopyDonePeek(fp, c, 1); /* Pick up the
|
||||||
|
* character! */
|
||||||
c = CopyPeekChar(fp);
|
c = CopyPeekChar(fp);
|
||||||
if (ISOCTAL(c)) {
|
if (ISOCTAL(c))
|
||||||
CopyDonePeek(fp,c,1); /* pick up! */
|
{
|
||||||
|
CopyDonePeek(fp, c, 1); /* pick up! */
|
||||||
val = (val << 3) + VALUE(c);
|
val = (val << 3) + VALUE(c);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (CopyGetEof(fp)) {
|
if (CopyGetEof(fp))
|
||||||
CopyDonePeek(fp,c,1); /* pick up */
|
{
|
||||||
|
CopyDonePeek(fp, c, 1); /* pick up */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
CopyDonePeek(fp,c,0); /* Return to stream! */
|
CopyDonePeek(fp, c, 0); /* Return to stream! */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (CopyGetEof(fp))
|
if (CopyGetEof(fp))
|
||||||
return NULL;
|
return NULL;
|
||||||
CopyDonePeek(fp,c,0); /* Return to stream! */
|
CopyDonePeek(fp, c, 0); /* Return to stream! */
|
||||||
}
|
}
|
||||||
c = val & 0377;
|
c = val & 0377;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.40 1999/02/13 23:15:05 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.41 1999/05/25 16:08:20 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -39,7 +39,7 @@ static List *MergeAttributes(List *schema, List *supers, List **supconstr);
|
||||||
static void StoreCatalogInheritance(Oid relationId, List *supers);
|
static void StoreCatalogInheritance(Oid relationId, List *supers);
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* DefineRelation
|
* DefineRelation
|
||||||
* Creates a new relation.
|
* Creates a new relation.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -90,10 +90,10 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
||||||
|
|
||||||
if (constraints != NIL)
|
if (constraints != NIL)
|
||||||
{
|
{
|
||||||
List *entry;
|
List *entry;
|
||||||
int nconstr = length(constraints),
|
int nconstr = length(constraints),
|
||||||
ncheck = 0,
|
ncheck = 0,
|
||||||
i;
|
i;
|
||||||
ConstrCheck *check = (ConstrCheck *) palloc(nconstr * sizeof(ConstrCheck));
|
ConstrCheck *check = (ConstrCheck *) palloc(nconstr * sizeof(ConstrCheck));
|
||||||
|
|
||||||
foreach(entry, constraints)
|
foreach(entry, constraints)
|
||||||
|
@ -107,9 +107,9 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
||||||
for (i = 0; i < ncheck; i++)
|
for (i = 0; i < ncheck; i++)
|
||||||
{
|
{
|
||||||
if (strcmp(check[i].ccname, cdef->name) == 0)
|
if (strcmp(check[i].ccname, cdef->name) == 0)
|
||||||
elog(ERROR,
|
elog(ERROR,
|
||||||
"DefineRelation: name (%s) of CHECK constraint duplicated",
|
"DefineRelation: name (%s) of CHECK constraint duplicated",
|
||||||
cdef->name);
|
cdef->name);
|
||||||
}
|
}
|
||||||
check[ncheck].ccname = cdef->name;
|
check[ncheck].ccname = cdef->name;
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RemoveRelation
|
* RemoveRelation
|
||||||
* Deletes a new relation.
|
* Deletes a new relation.
|
||||||
*
|
*
|
||||||
* Exceptions:
|
* Exceptions:
|
||||||
|
@ -164,7 +164,7 @@ RemoveRelation(char *name)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MergeAttributes
|
* MergeAttributes
|
||||||
* Returns new schema given initial schema and supers.
|
* Returns new schema given initial schema and supers.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -276,8 +276,8 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
|
||||||
*/
|
*/
|
||||||
attributeName = (attribute->attname).data;
|
attributeName = (attribute->attname).data;
|
||||||
tuple = SearchSysCacheTuple(TYPOID,
|
tuple = SearchSysCacheTuple(TYPOID,
|
||||||
ObjectIdGetDatum(attribute->atttypid),
|
ObjectIdGetDatum(attribute->atttypid),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
Assert(HeapTupleIsValid(tuple));
|
Assert(HeapTupleIsValid(tuple));
|
||||||
attributeType = (((Form_pg_type) GETSTRUCT(tuple))->typname).data;
|
attributeType = (((Form_pg_type) GETSTRUCT(tuple))->typname).data;
|
||||||
|
|
||||||
|
@ -365,7 +365,7 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* StoreCatalogInheritance
|
* StoreCatalogInheritance
|
||||||
* Updates the system catalogs with proper inheritance information.
|
* Updates the system catalogs with proper inheritance information.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
|
@ -411,9 +411,9 @@ StoreCatalogInheritance(Oid relationId, List *supers)
|
||||||
*/
|
*/
|
||||||
idList = lappendi(idList, tuple->t_data->t_oid);
|
idList = lappendi(idList, tuple->t_data->t_oid);
|
||||||
|
|
||||||
datum[0] = ObjectIdGetDatum(relationId); /* inhrel */
|
datum[0] = ObjectIdGetDatum(relationId); /* inhrel */
|
||||||
datum[1] = ObjectIdGetDatum(tuple->t_data->t_oid); /* inhparent */
|
datum[1] = ObjectIdGetDatum(tuple->t_data->t_oid); /* inhparent */
|
||||||
datum[2] = Int16GetDatum(seqNumber); /* inhseqno */
|
datum[2] = Int16GetDatum(seqNumber); /* inhseqno */
|
||||||
|
|
||||||
nullarr[0] = ' ';
|
nullarr[0] = ' ';
|
||||||
nullarr[1] = ' ';
|
nullarr[1] = ' ';
|
||||||
|
@ -467,8 +467,8 @@ StoreCatalogInheritance(Oid relationId, List *supers)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
lnext(current) = lconsi(((Form_pg_inherits)
|
lnext(current) = lconsi(((Form_pg_inherits)
|
||||||
GETSTRUCT(tuple))->inhparent,
|
GETSTRUCT(tuple))->inhparent,
|
||||||
NIL);
|
NIL);
|
||||||
|
|
||||||
current = lnext(current);
|
current = lnext(current);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.34 1999/05/10 00:44:59 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.35 1999/05/25 16:08:21 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -47,8 +47,8 @@ createdb(char *dbname, char *dbpath, int encoding, CommandDest dest)
|
||||||
Oid db_id;
|
Oid db_id;
|
||||||
int4 user_id;
|
int4 user_id;
|
||||||
char buf[512];
|
char buf[512];
|
||||||
char *lp,
|
char *lp,
|
||||||
loc[512];
|
loc[512];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this call returns, the database does not exist and we're allowed
|
* If this call returns, the database does not exist and we're allowed
|
||||||
|
@ -80,13 +80,13 @@ createdb(char *dbname, char *dbpath, int encoding, CommandDest dest)
|
||||||
elog(ERROR, "Unable to create database directory '%s'", lp);
|
elog(ERROR, "Unable to create database directory '%s'", lp);
|
||||||
|
|
||||||
snprintf(buf, 512, "%s %s%cbase%ctemplate1%c* %s",
|
snprintf(buf, 512, "%s %s%cbase%ctemplate1%c* %s",
|
||||||
COPY_CMD, DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, lp);
|
COPY_CMD, DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, lp);
|
||||||
system(buf);
|
system(buf);
|
||||||
|
|
||||||
snprintf(buf, 512,
|
snprintf(buf, 512,
|
||||||
"insert into pg_database (datname, datdba, encoding, datpath)"
|
"insert into pg_database (datname, datdba, encoding, datpath)"
|
||||||
" values ('%s', '%d', '%d', '%s');", dbname, user_id, encoding,
|
" values ('%s', '%d', '%d', '%s');", dbname, user_id, encoding,
|
||||||
loc);
|
loc);
|
||||||
|
|
||||||
pg_exec_query_dest(buf, dest, false);
|
pg_exec_query_dest(buf, dest, false);
|
||||||
}
|
}
|
||||||
|
@ -96,9 +96,9 @@ destroydb(char *dbname, CommandDest dest)
|
||||||
{
|
{
|
||||||
int4 user_id;
|
int4 user_id;
|
||||||
Oid db_id;
|
Oid db_id;
|
||||||
char *path,
|
char *path,
|
||||||
dbpath[MAXPGPATH + 1],
|
dbpath[MAXPGPATH + 1],
|
||||||
buf[512];
|
buf[512];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this call returns, the database exists and we're allowed to
|
* If this call returns, the database exists and we're allowed to
|
||||||
|
@ -122,9 +122,9 @@ destroydb(char *dbname, CommandDest dest)
|
||||||
* remove the pg_database tuple FIRST, this may fail due to
|
* remove the pg_database tuple FIRST, this may fail due to
|
||||||
* permissions problems
|
* permissions problems
|
||||||
*/
|
*/
|
||||||
snprintf(buf, 512,
|
snprintf(buf, 512,
|
||||||
"delete from pg_database where pg_database.oid = \'%u\'::oid", db_id);
|
"delete from pg_database where pg_database.oid = \'%u\'::oid", db_id);
|
||||||
pg_exec_query_dest(buf ,dest, false);
|
pg_exec_query_dest(buf, dest, false);
|
||||||
|
|
||||||
/* drop pages for this database that are in the shared buffer cache */
|
/* drop pages for this database that are in the shared buffer cache */
|
||||||
DropBuffers(db_id);
|
DropBuffers(db_id);
|
||||||
|
@ -294,13 +294,13 @@ static void
|
||||||
stop_vacuum(char *dbpath, char *dbname)
|
stop_vacuum(char *dbpath, char *dbname)
|
||||||
{
|
{
|
||||||
char filename[256];
|
char filename[256];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
if (strchr(dbpath, SEP_CHAR) != 0)
|
if (strchr(dbpath, SEP_CHAR) != 0)
|
||||||
{
|
{
|
||||||
snprintf(filename, 256, "%s%cbase%c%s%c%s.vacuum",
|
snprintf(filename, 256, "%s%cbase%c%s%c%s.vacuum",
|
||||||
DataDir, SEP_CHAR, SEP_CHAR, dbname, SEP_CHAR, dbname);
|
DataDir, SEP_CHAR, SEP_CHAR, dbname, SEP_CHAR, dbname);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
snprintf(filename, 256, "%s%c%s.vacuum", dbpath, SEP_CHAR, dbname);
|
snprintf(filename, 256, "%s%c%s.vacuum", dbpath, SEP_CHAR, dbname);
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.28 1999/04/09 22:35:41 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.29 1999/05/25 16:08:22 momjian Exp $
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* The "DefineFoo" routines take the parse tree and pick out the
|
* The "DefineFoo" routines take the parse tree and pick out the
|
||||||
|
@ -203,7 +203,7 @@ interpret_AS_clause(const char *languageName, const char *as,
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CreateFunction
|
* CreateFunction
|
||||||
* Execute a CREATE FUNCTION utility statement.
|
* Execute a CREATE FUNCTION utility statement.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -574,7 +574,7 @@ DefineAggregate(char *aggName, List *parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DefineType
|
* DefineType
|
||||||
* Registers a new type.
|
* Registers a new type.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994-5, Regents of the University of California
|
* Copyright (c) 1994-5, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: explain.c,v 1.36 1999/05/09 23:31:45 tgl Exp $
|
* $Id: explain.c,v 1.37 1999/05/25 16:08:23 momjian Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -34,7 +34,7 @@ typedef struct ExplainState
|
||||||
} ExplainState;
|
} ExplainState;
|
||||||
|
|
||||||
static char *Explain_PlanToString(Plan *plan, ExplainState *es);
|
static char *Explain_PlanToString(Plan *plan, ExplainState *es);
|
||||||
static void printLongNotice(const char * header, const char * message);
|
static void printLongNotice(const char *header, const char *message);
|
||||||
static void ExplainOneQuery(Query *query, bool verbose, CommandDest dest);
|
static void ExplainOneQuery(Query *query, bool verbose, CommandDest dest);
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,8 +46,8 @@ static void ExplainOneQuery(Query *query, bool verbose, CommandDest dest);
|
||||||
void
|
void
|
||||||
ExplainQuery(Query *query, bool verbose, CommandDest dest)
|
ExplainQuery(Query *query, bool verbose, CommandDest dest)
|
||||||
{
|
{
|
||||||
List *rewritten;
|
List *rewritten;
|
||||||
List *l;
|
List *l;
|
||||||
|
|
||||||
/* rewriter and planner may not work in aborted state? */
|
/* rewriter and planner may not work in aborted state? */
|
||||||
if (IsAbortedTransactionBlockState())
|
if (IsAbortedTransactionBlockState())
|
||||||
|
@ -145,10 +145,10 @@ ExplainOneQuery(Query *query, bool verbose, CommandDest dest)
|
||||||
static void
|
static void
|
||||||
explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||||
{
|
{
|
||||||
List *l;
|
List *l;
|
||||||
Relation relation;
|
Relation relation;
|
||||||
char *pname;
|
char *pname;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (plan == NULL)
|
if (plan == NULL)
|
||||||
{
|
{
|
||||||
|
@ -208,15 +208,13 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||||
case T_IndexScan:
|
case T_IndexScan:
|
||||||
appendStringInfo(str, " using ");
|
appendStringInfo(str, " using ");
|
||||||
i = 0;
|
i = 0;
|
||||||
foreach (l, ((IndexScan *) plan)->indxid)
|
foreach(l, ((IndexScan *) plan)->indxid)
|
||||||
{
|
{
|
||||||
relation = RelationIdCacheGetRelation((int) lfirst(l));
|
relation = RelationIdCacheGetRelation((int) lfirst(l));
|
||||||
if (++i > 1)
|
if (++i > 1)
|
||||||
{
|
|
||||||
appendStringInfo(str, ", ");
|
appendStringInfo(str, ", ");
|
||||||
}
|
appendStringInfo(str,
|
||||||
appendStringInfo(str,
|
stringStringInfo((RelationGetRelationName(relation))->data));
|
||||||
stringStringInfo((RelationGetRelationName(relation))->data));
|
|
||||||
}
|
}
|
||||||
case T_SeqScan:
|
case T_SeqScan:
|
||||||
if (((Scan *) plan)->scanrelid > 0)
|
if (((Scan *) plan)->scanrelid > 0)
|
||||||
|
@ -227,7 +225,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||||
if (strcmp(rte->refname, rte->relname) != 0)
|
if (strcmp(rte->refname, rte->relname) != 0)
|
||||||
{
|
{
|
||||||
appendStringInfo(str, "%s ",
|
appendStringInfo(str, "%s ",
|
||||||
stringStringInfo(rte->relname));
|
stringStringInfo(rte->relname));
|
||||||
}
|
}
|
||||||
appendStringInfo(str, stringStringInfo(rte->refname));
|
appendStringInfo(str, stringStringInfo(rte->refname));
|
||||||
}
|
}
|
||||||
|
@ -238,7 +236,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||||
if (es->printCost)
|
if (es->printCost)
|
||||||
{
|
{
|
||||||
appendStringInfo(str, " (cost=%.2f rows=%d width=%d)",
|
appendStringInfo(str, " (cost=%.2f rows=%d width=%d)",
|
||||||
plan->cost, plan->plan_size, plan->plan_width);
|
plan->cost, plan->plan_size, plan->plan_width);
|
||||||
}
|
}
|
||||||
appendStringInfo(str, "\n");
|
appendStringInfo(str, "\n");
|
||||||
|
|
||||||
|
@ -248,18 +246,14 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||||
List *saved_rtable = es->rtable;
|
List *saved_rtable = es->rtable;
|
||||||
List *lst;
|
List *lst;
|
||||||
|
|
||||||
for (i = 0; i < indent; i++)
|
for (i = 0; i < indent; i++)
|
||||||
{
|
|
||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
}
|
|
||||||
appendStringInfo(str, " InitPlan\n");
|
appendStringInfo(str, " InitPlan\n");
|
||||||
foreach(lst, plan->initPlan)
|
foreach(lst, plan->initPlan)
|
||||||
{
|
{
|
||||||
es->rtable = ((SubPlan *) lfirst(lst))->rtable;
|
es->rtable = ((SubPlan *) lfirst(lst))->rtable;
|
||||||
for (i = 0; i < indent; i++)
|
for (i = 0; i < indent; i++)
|
||||||
{
|
|
||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
}
|
|
||||||
appendStringInfo(str, " -> ");
|
appendStringInfo(str, " -> ");
|
||||||
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, indent + 2, es);
|
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, indent + 2, es);
|
||||||
}
|
}
|
||||||
|
@ -270,9 +264,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||||
if (outerPlan(plan))
|
if (outerPlan(plan))
|
||||||
{
|
{
|
||||||
for (i = 0; i < indent; i++)
|
for (i = 0; i < indent; i++)
|
||||||
{
|
|
||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
}
|
|
||||||
appendStringInfo(str, " -> ");
|
appendStringInfo(str, " -> ");
|
||||||
explain_outNode(str, outerPlan(plan), indent + 3, es);
|
explain_outNode(str, outerPlan(plan), indent + 3, es);
|
||||||
}
|
}
|
||||||
|
@ -281,9 +273,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||||
if (innerPlan(plan))
|
if (innerPlan(plan))
|
||||||
{
|
{
|
||||||
for (i = 0; i < indent; i++)
|
for (i = 0; i < indent; i++)
|
||||||
{
|
|
||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
}
|
|
||||||
appendStringInfo(str, " -> ");
|
appendStringInfo(str, " -> ");
|
||||||
explain_outNode(str, innerPlan(plan), indent + 3, es);
|
explain_outNode(str, innerPlan(plan), indent + 3, es);
|
||||||
}
|
}
|
||||||
|
@ -295,17 +285,13 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||||
List *lst;
|
List *lst;
|
||||||
|
|
||||||
for (i = 0; i < indent; i++)
|
for (i = 0; i < indent; i++)
|
||||||
{
|
|
||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
}
|
|
||||||
appendStringInfo(str, " SubPlan\n");
|
appendStringInfo(str, " SubPlan\n");
|
||||||
foreach(lst, plan->subPlan)
|
foreach(lst, plan->subPlan)
|
||||||
{
|
{
|
||||||
es->rtable = ((SubPlan *) lfirst(lst))->rtable;
|
es->rtable = ((SubPlan *) lfirst(lst))->rtable;
|
||||||
for (i = 0; i < indent; i++)
|
for (i = 0; i < indent; i++)
|
||||||
{
|
|
||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
}
|
|
||||||
appendStringInfo(str, " -> ");
|
appendStringInfo(str, " -> ");
|
||||||
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, indent + 4, es);
|
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, indent + 4, es);
|
||||||
}
|
}
|
||||||
|
@ -336,9 +322,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||||
es->rtable = nth(whichplan, appendplan->unionrtables);
|
es->rtable = nth(whichplan, appendplan->unionrtables);
|
||||||
|
|
||||||
for (i = 0; i < indent; i++)
|
for (i = 0; i < indent; i++)
|
||||||
{
|
|
||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
}
|
|
||||||
appendStringInfo(str, " -> ");
|
appendStringInfo(str, " -> ");
|
||||||
|
|
||||||
explain_outNode(str, subnode, indent + 4, es);
|
explain_outNode(str, subnode, indent + 4, es);
|
||||||
|
@ -353,7 +337,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||||
static char *
|
static char *
|
||||||
Explain_PlanToString(Plan *plan, ExplainState *es)
|
Explain_PlanToString(Plan *plan, ExplainState *es)
|
||||||
{
|
{
|
||||||
StringInfoData str;
|
StringInfoData str;
|
||||||
|
|
||||||
/* see stringinfo.h for an explanation of this maneuver */
|
/* see stringinfo.h for an explanation of this maneuver */
|
||||||
initStringInfo(&str);
|
initStringInfo(&str);
|
||||||
|
@ -367,9 +351,9 @@ Explain_PlanToString(Plan *plan, ExplainState *es)
|
||||||
* This is a crock ... there shouldn't be an upper limit to what you can elog().
|
* This is a crock ... there shouldn't be an upper limit to what you can elog().
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
printLongNotice(const char * header, const char * message)
|
printLongNotice(const char *header, const char *message)
|
||||||
{
|
{
|
||||||
int len = strlen(message);
|
int len = strlen(message);
|
||||||
|
|
||||||
elog(NOTICE, "%.20s%.*s", header, ELOG_MAXLEN - 64, message);
|
elog(NOTICE, "%.20s%.*s", header, ELOG_MAXLEN - 64, message);
|
||||||
len -= ELOG_MAXLEN - 64;
|
len -= ELOG_MAXLEN - 64;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.3 1999/05/10 00:44:59 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.4 1999/05/25 16:08:24 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -53,7 +53,7 @@ static void NormIndexAttrs(List *attList, AttrNumber *attNumP,
|
||||||
static char *GetDefaultOpClass(Oid atttypid);
|
static char *GetDefaultOpClass(Oid atttypid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DefineIndex
|
* DefineIndex
|
||||||
* Creates a new index.
|
* Creates a new index.
|
||||||
*
|
*
|
||||||
* 'attributeList' is a list of IndexElem specifying either a functional
|
* 'attributeList' is a list of IndexElem specifying either a functional
|
||||||
|
@ -164,7 +164,7 @@ DefineIndex(char *heapRelationName,
|
||||||
if (nargs > INDEX_MAX_KEYS)
|
if (nargs > INDEX_MAX_KEYS)
|
||||||
{
|
{
|
||||||
elog(ERROR,
|
elog(ERROR,
|
||||||
"Too many args to function, limit of %d", INDEX_MAX_KEYS);
|
"Too many args to function, limit of %d", INDEX_MAX_KEYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
FIsetnArgs(&fInfo, nargs);
|
FIsetnArgs(&fInfo, nargs);
|
||||||
|
@ -207,7 +207,7 @@ DefineIndex(char *heapRelationName,
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ExtendIndex
|
* ExtendIndex
|
||||||
* Extends a partial index.
|
* Extends a partial index.
|
||||||
*
|
*
|
||||||
* Exceptions:
|
* Exceptions:
|
||||||
|
@ -304,7 +304,7 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
|
||||||
predInfo->oldPred = oldPred;
|
predInfo->oldPred = oldPred;
|
||||||
|
|
||||||
attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
|
attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
|
||||||
sizeof attributeNumberA[0]);
|
sizeof attributeNumberA[0]);
|
||||||
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof classObjectId[0]);
|
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof classObjectId[0]);
|
||||||
|
|
||||||
|
|
||||||
|
@ -501,7 +501,7 @@ NormIndexAttrs(List *attList, /* list of IndexElem's */
|
||||||
/* we just set the type name because that is all we need */
|
/* we just set the type name because that is all we need */
|
||||||
attribute->typename = makeNode(TypeName);
|
attribute->typename = makeNode(TypeName);
|
||||||
attribute->typename->name = nameout(&((Form_pg_type) GETSTRUCT(tuple))->typname);
|
attribute->typename->name = nameout(&((Form_pg_type) GETSTRUCT(tuple))->typname);
|
||||||
|
|
||||||
/* we all need the typmod for the char and varchar types. */
|
/* we all need the typmod for the char and varchar types. */
|
||||||
attribute->typename->typmod = attform->atttypmod;
|
attribute->typename->typmod = attform->atttypmod;
|
||||||
}
|
}
|
||||||
|
@ -547,7 +547,7 @@ GetDefaultOpClass(Oid atttypid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RemoveIndex
|
* RemoveIndex
|
||||||
* Deletes an index.
|
* Deletes an index.
|
||||||
*
|
*
|
||||||
* Exceptions:
|
* Exceptions:
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.32 1999/02/13 23:15:08 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.33 1999/05/25 16:08:25 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RemoveOperator
|
* RemoveOperator
|
||||||
* Deletes an operator.
|
* Deletes an operator.
|
||||||
*
|
*
|
||||||
* Exceptions:
|
* Exceptions:
|
||||||
|
@ -288,7 +288,7 @@ RemoveType(char *typeName) /* type name to be removed */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RemoveFunction
|
* RemoveFunction
|
||||||
* Deletes a function.
|
* Deletes a function.
|
||||||
*
|
*
|
||||||
* Exceptions:
|
* Exceptions:
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.24 1999/05/17 18:24:48 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.25 1999/05/25 16:08:26 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -142,7 +142,7 @@ renameatt(char *relname,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ((relid = RelnameFindRelid(relname)) == InvalidOid)
|
if ((relid = RelnameFindRelid(relname)) == InvalidOid)
|
||||||
elog(ERROR, "renameatt: relation \"%s\" nonexistent", relname);
|
elog(ERROR, "renameatt: relation \"%s\" nonexistent", relname);
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ renameatt(char *relname,
|
||||||
void
|
void
|
||||||
renamerel(char *oldrelname, char *newrelname)
|
renamerel(char *oldrelname, char *newrelname)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
Relation relrelation; /* for RELATION relation */
|
Relation relrelation; /* for RELATION relation */
|
||||||
HeapTuple oldreltup;
|
HeapTuple oldreltup;
|
||||||
char oldpath[MAXPGPATH],
|
char oldpath[MAXPGPATH],
|
||||||
|
@ -237,7 +237,7 @@ renamerel(char *oldrelname, char *newrelname)
|
||||||
{
|
{
|
||||||
sprintf(toldpath, "%s.%d", oldpath, i);
|
sprintf(toldpath, "%s.%d", oldpath, i);
|
||||||
sprintf(tnewpath, "%s.%d", newpath, i);
|
sprintf(tnewpath, "%s.%d", newpath, i);
|
||||||
if(rename(toldpath, tnewpath) < 0)
|
if (rename(toldpath, tnewpath) < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ static void init_params(CreateSeqStmt *seq, Form_pg_sequence new);
|
||||||
static int get_param(DefElem *def);
|
static int get_param(DefElem *def);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DefineSequence
|
* DefineSequence
|
||||||
* Creates a new sequence relation
|
* Creates a new sequence relation
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
@ -218,8 +218,8 @@ nextval(struct varlena * seqin)
|
||||||
return elm->last;
|
return elm->last;
|
||||||
}
|
}
|
||||||
|
|
||||||
seq = read_info("nextval", elm, &buf); /* lock page' buffer and read
|
seq = read_info("nextval", elm, &buf); /* lock page' buffer and
|
||||||
* tuple */
|
* read tuple */
|
||||||
|
|
||||||
next = result = seq->last_value;
|
next = result = seq->last_value;
|
||||||
incby = seq->increment_by;
|
incby = seq->increment_by;
|
||||||
|
@ -327,8 +327,8 @@ setval(struct varlena * seqin, int4 next)
|
||||||
|
|
||||||
/* open and AccessShareLock sequence */
|
/* open and AccessShareLock sequence */
|
||||||
elm = init_sequence("setval", seqname);
|
elm = init_sequence("setval", seqname);
|
||||||
seq = read_info("setval", elm, &buf); /* lock page' buffer and read
|
seq = read_info("setval", elm, &buf); /* lock page' buffer and
|
||||||
* tuple */
|
* read tuple */
|
||||||
|
|
||||||
if (seq->cache_value != 1)
|
if (seq->cache_value != 1)
|
||||||
{
|
{
|
||||||
|
@ -361,11 +361,11 @@ setval(struct varlena * seqin, int4 next)
|
||||||
static Form_pg_sequence
|
static Form_pg_sequence
|
||||||
read_info(char *caller, SeqTable elm, Buffer *buf)
|
read_info(char *caller, SeqTable elm, Buffer *buf)
|
||||||
{
|
{
|
||||||
PageHeader page;
|
PageHeader page;
|
||||||
ItemId lp;
|
ItemId lp;
|
||||||
HeapTupleData tuple;
|
HeapTupleData tuple;
|
||||||
sequence_magic *sm;
|
sequence_magic *sm;
|
||||||
Form_pg_sequence seq;
|
Form_pg_sequence seq;
|
||||||
|
|
||||||
if (RelationGetNumberOfBlocks(elm->rel) != 1)
|
if (RelationGetNumberOfBlocks(elm->rel) != 1)
|
||||||
elog(ERROR, "%s.%s: invalid number of blocks in sequence",
|
elog(ERROR, "%s.%s: invalid number of blocks in sequence",
|
||||||
|
@ -464,7 +464,7 @@ init_sequence(char *caller, char *name)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CloseSequences
|
* CloseSequences
|
||||||
* is calling by xact mgr at commit/abort.
|
* is calling by xact mgr at commit/abort.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
|
|
@ -362,9 +362,9 @@ RelationBuildTriggers(Relation relation)
|
||||||
Form_pg_trigger pg_trigger;
|
Form_pg_trigger pg_trigger;
|
||||||
Relation irel;
|
Relation irel;
|
||||||
ScanKeyData skey;
|
ScanKeyData skey;
|
||||||
HeapTupleData tuple;
|
HeapTupleData tuple;
|
||||||
IndexScanDesc sd;
|
IndexScanDesc sd;
|
||||||
RetrieveIndexResult indexRes;
|
RetrieveIndexResult indexRes;
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
struct varlena *val;
|
struct varlena *val;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
|
@ -659,14 +659,14 @@ ExecARInsertTriggers(Relation rel, HeapTuple trigtuple)
|
||||||
bool
|
bool
|
||||||
ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
|
ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
|
||||||
{
|
{
|
||||||
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
|
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
|
||||||
TriggerData *SaveTriggerData;
|
TriggerData *SaveTriggerData;
|
||||||
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
|
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE];
|
||||||
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
|
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE];
|
||||||
HeapTuple trigtuple;
|
HeapTuple trigtuple;
|
||||||
HeapTuple newtuple = NULL;
|
HeapTuple newtuple = NULL;
|
||||||
TupleTableSlot *newSlot;
|
TupleTableSlot *newSlot;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
|
trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
|
||||||
if (trigtuple == NULL)
|
if (trigtuple == NULL)
|
||||||
|
@ -697,7 +697,7 @@ ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid)
|
||||||
void
|
void
|
||||||
ExecARDeleteTriggers(EState *estate, ItemPointer tupleid)
|
ExecARDeleteTriggers(EState *estate, ItemPointer tupleid)
|
||||||
{
|
{
|
||||||
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
|
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
|
||||||
TriggerData *SaveTriggerData;
|
TriggerData *SaveTriggerData;
|
||||||
int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE];
|
int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE];
|
||||||
Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE];
|
Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE];
|
||||||
|
@ -727,23 +727,23 @@ ExecARDeleteTriggers(EState *estate, ItemPointer tupleid)
|
||||||
HeapTuple
|
HeapTuple
|
||||||
ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
|
ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
|
||||||
{
|
{
|
||||||
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
|
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
|
||||||
TriggerData *SaveTriggerData;
|
TriggerData *SaveTriggerData;
|
||||||
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
|
int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE];
|
||||||
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
|
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE];
|
||||||
HeapTuple trigtuple;
|
HeapTuple trigtuple;
|
||||||
HeapTuple oldtuple;
|
HeapTuple oldtuple;
|
||||||
HeapTuple intuple = newtuple;
|
HeapTuple intuple = newtuple;
|
||||||
TupleTableSlot *newSlot;
|
TupleTableSlot *newSlot;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
|
trigtuple = GetTupleForTrigger(estate, tupleid, &newSlot);
|
||||||
if (trigtuple == NULL)
|
if (trigtuple == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In READ COMMITTED isolevel it's possible that newtuple
|
* In READ COMMITTED isolevel it's possible that newtuple was changed
|
||||||
* was changed due to concurrent update.
|
* due to concurrent update.
|
||||||
*/
|
*/
|
||||||
if (newSlot != NULL)
|
if (newSlot != NULL)
|
||||||
intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
|
intuple = newtuple = ExecRemoveJunk(estate->es_junkFilter, newSlot);
|
||||||
|
@ -772,7 +772,7 @@ ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
|
||||||
void
|
void
|
||||||
ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
|
ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
|
||||||
{
|
{
|
||||||
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
|
Relation rel = estate->es_result_relation_info->ri_RelationDesc;
|
||||||
TriggerData *SaveTriggerData;
|
TriggerData *SaveTriggerData;
|
||||||
int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE];
|
int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE];
|
||||||
Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE];
|
Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE];
|
||||||
|
@ -799,22 +799,22 @@ ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid);
|
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid);
|
||||||
|
|
||||||
static HeapTuple
|
static HeapTuple
|
||||||
GetTupleForTrigger(EState *estate, ItemPointer tid, TupleTableSlot **newSlot)
|
GetTupleForTrigger(EState *estate, ItemPointer tid, TupleTableSlot **newSlot)
|
||||||
{
|
{
|
||||||
Relation relation = estate->es_result_relation_info->ri_RelationDesc;
|
Relation relation = estate->es_result_relation_info->ri_RelationDesc;
|
||||||
HeapTupleData tuple;
|
HeapTupleData tuple;
|
||||||
HeapTuple result;
|
HeapTuple result;
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
if (newSlot != NULL)
|
if (newSlot != NULL)
|
||||||
{
|
{
|
||||||
int test;
|
int test;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mark tuple for update
|
* mark tuple for update
|
||||||
*/
|
*/
|
||||||
*newSlot = NULL;
|
*newSlot = NULL;
|
||||||
tuple.t_self = *tid;
|
tuple.t_self = *tid;
|
||||||
|
@ -824,7 +824,7 @@ ltrmark:;
|
||||||
{
|
{
|
||||||
case HeapTupleSelfUpdated:
|
case HeapTupleSelfUpdated:
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
return(NULL);
|
return (NULL);
|
||||||
|
|
||||||
case HeapTupleMayBeUpdated:
|
case HeapTupleMayBeUpdated:
|
||||||
break;
|
break;
|
||||||
|
@ -835,9 +835,9 @@ ltrmark:;
|
||||||
elog(ERROR, "Can't serialize access due to concurrent update");
|
elog(ERROR, "Can't serialize access due to concurrent update");
|
||||||
else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
|
else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
|
||||||
{
|
{
|
||||||
TupleTableSlot *epqslot = EvalPlanQual(estate,
|
TupleTableSlot *epqslot = EvalPlanQual(estate,
|
||||||
estate->es_result_relation_info->ri_RangeTableIndex,
|
estate->es_result_relation_info->ri_RangeTableIndex,
|
||||||
&(tuple.t_self));
|
&(tuple.t_self));
|
||||||
|
|
||||||
if (!(TupIsNull(epqslot)))
|
if (!(TupIsNull(epqslot)))
|
||||||
{
|
{
|
||||||
|
@ -846,23 +846,23 @@ ltrmark:;
|
||||||
goto ltrmark;
|
goto ltrmark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* if tuple was deleted or PlanQual failed
|
/*
|
||||||
* for updated tuple - we have not process
|
* if tuple was deleted or PlanQual failed for updated
|
||||||
* this tuple!
|
* tuple - we have not process this tuple!
|
||||||
*/
|
*/
|
||||||
return(NULL);
|
return (NULL);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
elog(ERROR, "Unknown status %u from heap_mark4update", test);
|
elog(ERROR, "Unknown status %u from heap_mark4update", test);
|
||||||
return(NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PageHeader dp;
|
PageHeader dp;
|
||||||
ItemId lp;
|
ItemId lp;
|
||||||
|
|
||||||
buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
|
buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: user.c,v 1.27 1999/04/02 06:16:36 tgl Exp $
|
* $Id: user.c,v 1.28 1999/05/25 16:08:27 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
|
|
||||||
static void CheckPgUserAclNotNull(void);
|
static void CheckPgUserAclNotNull(void);
|
||||||
|
|
||||||
#define SQL_LENGTH 512
|
#define SQL_LENGTH 512
|
||||||
|
|
||||||
/*---------------------------------------------------------------------
|
/*---------------------------------------------------------------------
|
||||||
* UpdatePgPwdFile
|
* UpdatePgPwdFile
|
||||||
|
@ -49,9 +49,9 @@ void
|
||||||
UpdatePgPwdFile(char *sql, CommandDest dest)
|
UpdatePgPwdFile(char *sql, CommandDest dest)
|
||||||
{
|
{
|
||||||
|
|
||||||
char *filename,
|
char *filename,
|
||||||
*tempname;
|
*tempname;
|
||||||
int bufsize;
|
int bufsize;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a temporary filename to be renamed later. This prevents the
|
* Create a temporary filename to be renamed later. This prevents the
|
||||||
|
@ -68,9 +68,9 @@ UpdatePgPwdFile(char *sql, CommandDest dest)
|
||||||
* SEPCHAR character as the delimiter between fields. Then rename the
|
* SEPCHAR character as the delimiter between fields. Then rename the
|
||||||
* file to its final name.
|
* file to its final name.
|
||||||
*/
|
*/
|
||||||
snprintf(sql, SQL_LENGTH,
|
snprintf(sql, SQL_LENGTH,
|
||||||
"copy %s to '%s' using delimiters %s",
|
"copy %s to '%s' using delimiters %s",
|
||||||
ShadowRelationName, tempname, CRYPT_PWD_FILE_SEPCHAR);
|
ShadowRelationName, tempname, CRYPT_PWD_FILE_SEPCHAR);
|
||||||
pg_exec_query_dest(sql, dest, false);
|
pg_exec_query_dest(sql, dest, false);
|
||||||
rename(tempname, filename);
|
rename(tempname, filename);
|
||||||
pfree((void *) tempname);
|
pfree((void *) tempname);
|
||||||
|
@ -94,19 +94,19 @@ UpdatePgPwdFile(char *sql, CommandDest dest)
|
||||||
void
|
void
|
||||||
DefineUser(CreateUserStmt *stmt, CommandDest dest)
|
DefineUser(CreateUserStmt *stmt, CommandDest dest)
|
||||||
{
|
{
|
||||||
char *pg_shadow,
|
char *pg_shadow,
|
||||||
sql[SQL_LENGTH];
|
sql[SQL_LENGTH];
|
||||||
Relation pg_shadow_rel;
|
Relation pg_shadow_rel;
|
||||||
TupleDesc pg_shadow_dsc;
|
TupleDesc pg_shadow_dsc;
|
||||||
HeapScanDesc scan;
|
HeapScanDesc scan;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
Datum datum;
|
Datum datum;
|
||||||
bool exists = false,
|
bool exists = false,
|
||||||
n,
|
n,
|
||||||
inblock,
|
inblock,
|
||||||
havepassword,
|
havepassword,
|
||||||
havevaluntil;
|
havevaluntil;
|
||||||
int max_id = -1;
|
int max_id = -1;
|
||||||
|
|
||||||
havepassword = stmt->password && stmt->password[0];
|
havepassword = stmt->password && stmt->password[0];
|
||||||
havevaluntil = stmt->validUntil && stmt->validUntil[0];
|
havevaluntil = stmt->validUntil && stmt->validUntil[0];
|
||||||
|
@ -161,21 +161,21 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest)
|
||||||
UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
|
UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
|
||||||
heap_close(pg_shadow_rel);
|
heap_close(pg_shadow_rel);
|
||||||
UserAbortTransactionBlock();
|
UserAbortTransactionBlock();
|
||||||
elog(ERROR,
|
elog(ERROR,
|
||||||
"defineUser: user \"%s\" has already been created", stmt->user);
|
"defineUser: user \"%s\" has already been created", stmt->user);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build the insert statement to be executed.
|
* Build the insert statement to be executed.
|
||||||
*
|
*
|
||||||
* XXX Ugly as this code is, it still fails to cope with ' or \
|
* XXX Ugly as this code is, it still fails to cope with ' or \ in any of
|
||||||
* in any of the provided strings.
|
* the provided strings.
|
||||||
*/
|
*/
|
||||||
snprintf(sql, SQL_LENGTH,
|
snprintf(sql, SQL_LENGTH,
|
||||||
"insert into %s (usename,usesysid,usecreatedb,usetrace,"
|
"insert into %s (usename,usesysid,usecreatedb,usetrace,"
|
||||||
"usesuper,usecatupd,passwd,valuntil) "
|
"usesuper,usecatupd,passwd,valuntil) "
|
||||||
"values('%s',%d,'%c','t','%c','t',%s%s%s,%s%s%s)",
|
"values('%s',%d,'%c','t','%c','t',%s%s%s,%s%s%s)",
|
||||||
ShadowRelationName,
|
ShadowRelationName,
|
||||||
stmt->user,
|
stmt->user,
|
||||||
max_id + 1,
|
max_id + 1,
|
||||||
|
@ -216,12 +216,12 @@ extern void
|
||||||
AlterUser(AlterUserStmt *stmt, CommandDest dest)
|
AlterUser(AlterUserStmt *stmt, CommandDest dest)
|
||||||
{
|
{
|
||||||
|
|
||||||
char *pg_shadow,
|
char *pg_shadow,
|
||||||
sql[SQL_LENGTH];
|
sql[SQL_LENGTH];
|
||||||
Relation pg_shadow_rel;
|
Relation pg_shadow_rel;
|
||||||
TupleDesc pg_shadow_dsc;
|
TupleDesc pg_shadow_dsc;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
bool inblock;
|
bool inblock;
|
||||||
|
|
||||||
if (stmt->password)
|
if (stmt->password)
|
||||||
CheckPgUserAclNotNull();
|
CheckPgUserAclNotNull();
|
||||||
|
@ -272,34 +272,32 @@ AlterUser(AlterUserStmt *stmt, CommandDest dest)
|
||||||
snprintf(sql, SQL_LENGTH, "update %s set", ShadowRelationName);
|
snprintf(sql, SQL_LENGTH, "update %s set", ShadowRelationName);
|
||||||
|
|
||||||
if (stmt->password)
|
if (stmt->password)
|
||||||
{
|
|
||||||
snprintf(sql, SQL_LENGTH, "%s passwd = '%s'", pstrdup(sql), stmt->password);
|
snprintf(sql, SQL_LENGTH, "%s passwd = '%s'", pstrdup(sql), stmt->password);
|
||||||
}
|
|
||||||
|
|
||||||
if (stmt->createdb)
|
if (stmt->createdb)
|
||||||
{
|
{
|
||||||
snprintf(sql, SQL_LENGTH, "%s %susecreatedb='%s'",
|
snprintf(sql, SQL_LENGTH, "%s %susecreatedb='%s'",
|
||||||
pstrdup(sql), stmt->password ? "," : "",
|
pstrdup(sql), stmt->password ? "," : "",
|
||||||
*stmt->createdb ? "t" : "f");
|
*stmt->createdb ? "t" : "f");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stmt->createuser)
|
if (stmt->createuser)
|
||||||
{
|
{
|
||||||
snprintf(sql, SQL_LENGTH, "%s %susesuper='%s'",
|
snprintf(sql, SQL_LENGTH, "%s %susesuper='%s'",
|
||||||
pstrdup(sql), (stmt->password || stmt->createdb) ? "," : "",
|
pstrdup(sql), (stmt->password || stmt->createdb) ? "," : "",
|
||||||
*stmt->createuser ? "t" : "f");
|
*stmt->createuser ? "t" : "f");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stmt->validUntil)
|
if (stmt->validUntil)
|
||||||
{
|
{
|
||||||
snprintf(sql, SQL_LENGTH, "%s %svaluntil='%s'",
|
snprintf(sql, SQL_LENGTH, "%s %svaluntil='%s'",
|
||||||
pstrdup(sql),
|
pstrdup(sql),
|
||||||
(stmt->password || stmt->createdb || stmt->createuser) ? "," : "",
|
(stmt->password || stmt->createdb || stmt->createuser) ? "," : "",
|
||||||
stmt->validUntil);
|
stmt->validUntil);
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(sql, SQL_LENGTH, "%s where usename = '%s'",
|
snprintf(sql, SQL_LENGTH, "%s where usename = '%s'",
|
||||||
pstrdup(sql), stmt->user);
|
pstrdup(sql), stmt->user);
|
||||||
|
|
||||||
pg_exec_query_dest(sql, dest, false);
|
pg_exec_query_dest(sql, dest, false);
|
||||||
|
|
||||||
|
@ -393,8 +391,8 @@ RemoveUser(char *user, CommandDest dest)
|
||||||
datum = heap_getattr(tuple, Anum_pg_database_datname, pg_dsc, &n);
|
datum = heap_getattr(tuple, Anum_pg_database_datname, pg_dsc, &n);
|
||||||
if (memcmp((void *) datum, "template1", 9))
|
if (memcmp((void *) datum, "template1", 9))
|
||||||
{
|
{
|
||||||
dbase =
|
dbase =
|
||||||
(char **) repalloc((void *) dbase, sizeof(char *) * (ndbase + 1));
|
(char **) repalloc((void *) dbase, sizeof(char *) * (ndbase + 1));
|
||||||
dbase[ndbase] = (char *) palloc(NAMEDATALEN + 1);
|
dbase[ndbase] = (char *) palloc(NAMEDATALEN + 1);
|
||||||
memcpy((void *) dbase[ndbase], (void *) datum, NAMEDATALEN);
|
memcpy((void *) dbase[ndbase], (void *) datum, NAMEDATALEN);
|
||||||
dbase[ndbase++][NAMEDATALEN] = '\0';
|
dbase[ndbase++][NAMEDATALEN] = '\0';
|
||||||
|
@ -435,8 +433,8 @@ RemoveUser(char *user, CommandDest dest)
|
||||||
/*
|
/*
|
||||||
* Remove the user from the pg_shadow table
|
* Remove the user from the pg_shadow table
|
||||||
*/
|
*/
|
||||||
snprintf(sql, SQL_LENGTH,
|
snprintf(sql, SQL_LENGTH,
|
||||||
"delete from %s where usename = '%s'", ShadowRelationName, user);
|
"delete from %s where usename = '%s'", ShadowRelationName, user);
|
||||||
pg_exec_query_dest(sql, dest, false);
|
pg_exec_query_dest(sql, dest, false);
|
||||||
|
|
||||||
UpdatePgPwdFile(sql, dest);
|
UpdatePgPwdFile(sql, dest);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.103 1999/05/23 09:10:24 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.104 1999/05/25 16:08:27 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -66,7 +66,7 @@ static Portal vc_portal;
|
||||||
|
|
||||||
static int MESSAGE_LEVEL; /* message level */
|
static int MESSAGE_LEVEL; /* message level */
|
||||||
|
|
||||||
static TransactionId XmaxRecent;
|
static TransactionId XmaxRecent;
|
||||||
|
|
||||||
#define swapLong(a,b) {long tmp; tmp=a; a=b; b=tmp;}
|
#define swapLong(a,b) {long tmp; tmp=a; a=b; b=tmp;}
|
||||||
#define swapInt(a,b) {int tmp; tmp=a; a=b; b=tmp;}
|
#define swapInt(a,b) {int tmp; tmp=a; a=b; b=tmp;}
|
||||||
|
@ -101,8 +101,8 @@ static void vc_free(VRelList vrl);
|
||||||
static void vc_getindices(Oid relid, int *nindices, Relation **Irel);
|
static void vc_getindices(Oid relid, int *nindices, Relation **Irel);
|
||||||
static void vc_clsindices(int nindices, Relation *Irel);
|
static void vc_clsindices(int nindices, Relation *Irel);
|
||||||
static void vc_mkindesc(Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc);
|
static void vc_mkindesc(Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc);
|
||||||
static void *vc_find_eq(void *bot, int nelem, int size, void *elm,
|
static void *vc_find_eq(void *bot, int nelem, int size, void *elm,
|
||||||
int (*compar) (const void *, const void *));
|
int (*compar) (const void *, const void *));
|
||||||
static int vc_cmp_blk(const void *left, const void *right);
|
static int vc_cmp_blk(const void *left, const void *right);
|
||||||
static int vc_cmp_offno(const void *left, const void *right);
|
static int vc_cmp_offno(const void *left, const void *right);
|
||||||
static int vc_cmp_vtlinks(const void *left, const void *right);
|
static int vc_cmp_vtlinks(const void *left, const void *right);
|
||||||
|
@ -222,14 +222,15 @@ vc_shutdown()
|
||||||
{
|
{
|
||||||
/* on entry, we are not in a transaction */
|
/* on entry, we are not in a transaction */
|
||||||
|
|
||||||
/* Flush the init file that relcache.c uses to save startup time.
|
/*
|
||||||
* The next backend startup will rebuild the init file with up-to-date
|
* Flush the init file that relcache.c uses to save startup time. The
|
||||||
* information from pg_class. This lets the optimizer see the stats that
|
* next backend startup will rebuild the init file with up-to-date
|
||||||
* we've collected for certain critical system indexes. See relcache.c
|
* information from pg_class. This lets the optimizer see the stats
|
||||||
* for more details.
|
* that we've collected for certain critical system indexes. See
|
||||||
|
* relcache.c for more details.
|
||||||
*
|
*
|
||||||
* Ignore any failure to unlink the file, since it might not be there
|
* Ignore any failure to unlink the file, since it might not be there if
|
||||||
* if no backend has been started since the last vacuum...
|
* no backend has been started since the last vacuum...
|
||||||
*/
|
*/
|
||||||
unlink(RELCACHE_INIT_FILENAME);
|
unlink(RELCACHE_INIT_FILENAME);
|
||||||
|
|
||||||
|
@ -578,7 +579,7 @@ vc_vacone(Oid relid, bool analyze, List *va_cols)
|
||||||
|
|
||||||
/* update statistics in pg_class */
|
/* update statistics in pg_class */
|
||||||
vc_updstats(vacrelstats->relid, vacrelstats->num_pages,
|
vc_updstats(vacrelstats->relid, vacrelstats->num_pages,
|
||||||
vacrelstats->num_tuples, vacrelstats->hasindex, vacrelstats);
|
vacrelstats->num_tuples, vacrelstats->hasindex, vacrelstats);
|
||||||
|
|
||||||
/* next command frees attribute stats */
|
/* next command frees attribute stats */
|
||||||
CommitTransactionCommand();
|
CommitTransactionCommand();
|
||||||
|
@ -601,7 +602,7 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
blkno;
|
blkno;
|
||||||
ItemId itemid;
|
ItemId itemid;
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
HeapTupleData tuple;
|
HeapTupleData tuple;
|
||||||
Page page,
|
Page page,
|
||||||
tempPage = NULL;
|
tempPage = NULL;
|
||||||
OffsetNumber offnum,
|
OffsetNumber offnum,
|
||||||
|
@ -712,7 +713,7 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
else if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
|
else if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
|
||||||
{
|
{
|
||||||
if (TransactionIdDidCommit((TransactionId)
|
if (TransactionIdDidCommit((TransactionId)
|
||||||
tuple.t_data->t_cmin))
|
tuple.t_data->t_cmin))
|
||||||
{
|
{
|
||||||
tuple.t_data->t_infomask |= HEAP_XMIN_INVALID;
|
tuple.t_data->t_infomask |= HEAP_XMIN_INVALID;
|
||||||
tupgone = true;
|
tupgone = true;
|
||||||
|
@ -759,7 +760,7 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
elog(NOTICE, "Rel %s: TID %u/%u: InsertTransactionInProgress %u - can't shrink relation",
|
elog(NOTICE, "Rel %s: TID %u/%u: InsertTransactionInProgress %u - can't shrink relation",
|
||||||
relname, blkno, offnum, tuple.t_data->t_xmin);
|
relname, blkno, offnum, tuple.t_data->t_xmin);
|
||||||
do_shrinking = false;
|
do_shrinking = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -799,6 +800,7 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
}
|
}
|
||||||
else if (!TransactionIdIsInProgress(tuple.t_data->t_xmax))
|
else if (!TransactionIdIsInProgress(tuple.t_data->t_xmax))
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not Aborted, Not Committed, Not in Progress - so it
|
* Not Aborted, Not Committed, Not in Progress - so it
|
||||||
* from crashed process. - vadim 06/02/97
|
* from crashed process. - vadim 06/02/97
|
||||||
|
@ -812,11 +814,12 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
relname, blkno, offnum, tuple.t_data->t_xmax);
|
relname, blkno, offnum, tuple.t_data->t_xmax);
|
||||||
do_shrinking = false;
|
do_shrinking = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If tuple is recently deleted then
|
* If tuple is recently deleted then we must not remove it
|
||||||
* we must not remove it from relation.
|
* from relation.
|
||||||
*/
|
*/
|
||||||
if (tupgone && tuple.t_data->t_xmax >= XmaxRecent &&
|
if (tupgone && tuple.t_data->t_xmax >= XmaxRecent &&
|
||||||
tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED)
|
tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED)
|
||||||
{
|
{
|
||||||
tupgone = false;
|
tupgone = false;
|
||||||
|
@ -826,20 +829,21 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
tuple.t_data->t_infomask |= HEAP_XMAX_COMMITTED;
|
tuple.t_data->t_infomask |= HEAP_XMAX_COMMITTED;
|
||||||
pgchanged = true;
|
pgchanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we do shrinking and this tuple is updated one
|
* If we do shrinking and this tuple is updated one
|
||||||
* then remember it to construct updated tuple
|
* then remember it to construct updated tuple
|
||||||
* dependencies.
|
* dependencies.
|
||||||
*/
|
*/
|
||||||
if (do_shrinking && !(ItemPointerEquals(&(tuple.t_self),
|
if (do_shrinking && !(ItemPointerEquals(&(tuple.t_self),
|
||||||
&(tuple.t_data->t_ctid))))
|
&(tuple.t_data->t_ctid))))
|
||||||
{
|
{
|
||||||
if (free_vtlinks == 0)
|
if (free_vtlinks == 0)
|
||||||
{
|
{
|
||||||
free_vtlinks = 1000;
|
free_vtlinks = 1000;
|
||||||
vtlinks = (VTupleLink) repalloc(vtlinks,
|
vtlinks = (VTupleLink) repalloc(vtlinks,
|
||||||
(free_vtlinks + num_vtlinks) *
|
(free_vtlinks + num_vtlinks) *
|
||||||
sizeof(VTupleLinkData));
|
sizeof(VTupleLinkData));
|
||||||
}
|
}
|
||||||
vtlinks[num_vtlinks].new_tid = tuple.t_data->t_ctid;
|
vtlinks[num_vtlinks].new_tid = tuple.t_data->t_ctid;
|
||||||
vtlinks[num_vtlinks].this_tid = tuple.t_self;
|
vtlinks[num_vtlinks].this_tid = tuple.t_self;
|
||||||
|
@ -962,8 +966,8 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
|
|
||||||
if (usable_free_size > 0 && num_vtlinks > 0)
|
if (usable_free_size > 0 && num_vtlinks > 0)
|
||||||
{
|
{
|
||||||
qsort((char *) vtlinks, num_vtlinks, sizeof (VTupleLinkData),
|
qsort((char *) vtlinks, num_vtlinks, sizeof(VTupleLinkData),
|
||||||
vc_cmp_vtlinks);
|
vc_cmp_vtlinks);
|
||||||
vacrelstats->vtlinks = vtlinks;
|
vacrelstats->vtlinks = vtlinks;
|
||||||
vacrelstats->num_vtlinks = num_vtlinks;
|
vacrelstats->num_vtlinks = num_vtlinks;
|
||||||
}
|
}
|
||||||
|
@ -980,10 +984,10 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
Tup %u: Vac %u, Keep/VTL %u/%u, Crash %u, UnUsed %u, MinLen %u, MaxLen %u; \
|
Tup %u: Vac %u, Keep/VTL %u/%u, Crash %u, UnUsed %u, MinLen %u, MaxLen %u; \
|
||||||
Re-using: Free/Avail. Space %u/%u; EndEmpty/Avail. Pages %u/%u. \
|
Re-using: Free/Avail. Space %u/%u; EndEmpty/Avail. Pages %u/%u. \
|
||||||
Elapsed %u/%u sec.",
|
Elapsed %u/%u sec.",
|
||||||
nblocks, changed_pages, vacuum_pages->vpl_num_pages, empty_pages,
|
nblocks, changed_pages, vacuum_pages->vpl_num_pages, empty_pages,
|
||||||
new_pages, num_tuples, tups_vacuumed,
|
new_pages, num_tuples, tups_vacuumed,
|
||||||
nkeep, vacrelstats->num_vtlinks, ncrash,
|
nkeep, vacrelstats->num_vtlinks, ncrash,
|
||||||
nunused, min_tlen, max_tlen, free_size, usable_free_size,
|
nunused, min_tlen, max_tlen, free_size, usable_free_size,
|
||||||
empty_end_pages, fraged_pages->vpl_num_pages,
|
empty_end_pages, fraged_pages->vpl_num_pages,
|
||||||
ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
|
ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
|
||||||
ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
|
ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
|
||||||
|
@ -1019,8 +1023,8 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
max_offset;
|
max_offset;
|
||||||
ItemId itemid,
|
ItemId itemid,
|
||||||
newitemid;
|
newitemid;
|
||||||
HeapTupleData tuple,
|
HeapTupleData tuple,
|
||||||
newtup;
|
newtup;
|
||||||
TupleDesc tupdesc = NULL;
|
TupleDesc tupdesc = NULL;
|
||||||
Datum *idatum = NULL;
|
Datum *idatum = NULL;
|
||||||
char *inulls = NULL;
|
char *inulls = NULL;
|
||||||
|
@ -1128,7 +1132,8 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
else
|
else
|
||||||
Assert(!isempty);
|
Assert(!isempty);
|
||||||
|
|
||||||
chain_tuple_moved = false; /* no one chain-tuple was moved off this page, yet */
|
chain_tuple_moved = false; /* no one chain-tuple was moved
|
||||||
|
* off this page, yet */
|
||||||
vpc->vpd_blkno = blkno;
|
vpc->vpd_blkno = blkno;
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
for (offnum = FirstOffsetNumber;
|
for (offnum = FirstOffsetNumber;
|
||||||
|
@ -1146,28 +1151,30 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
|
|
||||||
if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED))
|
if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED))
|
||||||
{
|
{
|
||||||
if ((TransactionId)tuple.t_data->t_cmin != myXID)
|
if ((TransactionId) tuple.t_data->t_cmin != myXID)
|
||||||
elog(ERROR, "Invalid XID in t_cmin");
|
elog(ERROR, "Invalid XID in t_cmin");
|
||||||
if (tuple.t_data->t_infomask & HEAP_MOVED_IN)
|
if (tuple.t_data->t_infomask & HEAP_MOVED_IN)
|
||||||
elog(ERROR, "HEAP_MOVED_IN was not expected");
|
elog(ERROR, "HEAP_MOVED_IN was not expected");
|
||||||
/*
|
|
||||||
* If this (chain) tuple is moved by me already then
|
/*
|
||||||
* I have to check is it in vpc or not - i.e. is it
|
* If this (chain) tuple is moved by me already then I
|
||||||
* moved while cleaning this page or some previous one.
|
* have to check is it in vpc or not - i.e. is it moved
|
||||||
|
* while cleaning this page or some previous one.
|
||||||
*/
|
*/
|
||||||
if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
|
if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
|
||||||
{
|
{
|
||||||
if (keep_tuples == 0)
|
if (keep_tuples == 0)
|
||||||
continue;
|
continue;
|
||||||
if (chain_tuple_moved) /* some chains was moved while */
|
if (chain_tuple_moved) /* some chains was moved
|
||||||
{ /* cleaning this page */
|
* while */
|
||||||
|
{ /* cleaning this page */
|
||||||
Assert(vpc->vpd_offsets_free > 0);
|
Assert(vpc->vpd_offsets_free > 0);
|
||||||
for (i = 0; i < vpc->vpd_offsets_free; i++)
|
for (i = 0; i < vpc->vpd_offsets_free; i++)
|
||||||
{
|
{
|
||||||
if (vpc->vpd_offsets[i] == offnum)
|
if (vpc->vpd_offsets[i] == offnum)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i >= vpc->vpd_offsets_free) /* not found */
|
if (i >= vpc->vpd_offsets_free) /* not found */
|
||||||
{
|
{
|
||||||
vpc->vpd_offsets[vpc->vpd_offsets_free++] = offnum;
|
vpc->vpd_offsets[vpc->vpd_offsets_free++] = offnum;
|
||||||
keep_tuples--;
|
keep_tuples--;
|
||||||
|
@ -1184,29 +1191,29 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this tuple is in the chain of tuples created in
|
* If this tuple is in the chain of tuples created in updates
|
||||||
* updates by "recent" transactions then we have to
|
* by "recent" transactions then we have to move all chain of
|
||||||
* move all chain of tuples to another places.
|
* tuples to another places.
|
||||||
*/
|
*/
|
||||||
if ((tuple.t_data->t_infomask & HEAP_UPDATED &&
|
if ((tuple.t_data->t_infomask & HEAP_UPDATED &&
|
||||||
tuple.t_data->t_xmin >= XmaxRecent) ||
|
tuple.t_data->t_xmin >= XmaxRecent) ||
|
||||||
(!(tuple.t_data->t_infomask & HEAP_XMAX_INVALID) &&
|
(!(tuple.t_data->t_infomask & HEAP_XMAX_INVALID) &&
|
||||||
!(ItemPointerEquals(&(tuple.t_self), &(tuple.t_data->t_ctid)))))
|
!(ItemPointerEquals(&(tuple.t_self), &(tuple.t_data->t_ctid)))))
|
||||||
{
|
{
|
||||||
Buffer Cbuf = buf;
|
Buffer Cbuf = buf;
|
||||||
Page Cpage;
|
Page Cpage;
|
||||||
ItemId Citemid;
|
ItemId Citemid;
|
||||||
ItemPointerData Ctid;
|
ItemPointerData Ctid;
|
||||||
HeapTupleData tp = tuple;
|
HeapTupleData tp = tuple;
|
||||||
Size tlen = tuple_len;
|
Size tlen = tuple_len;
|
||||||
VTupleMove vtmove = (VTupleMove)
|
VTupleMove vtmove = (VTupleMove)
|
||||||
palloc(100 * sizeof(VTupleMoveData));
|
palloc(100 * sizeof(VTupleMoveData));
|
||||||
int num_vtmove = 0;
|
int num_vtmove = 0;
|
||||||
int free_vtmove = 100;
|
int free_vtmove = 100;
|
||||||
VPageDescr to_vpd = fraged_pages->vpl_pagedesc[0];
|
VPageDescr to_vpd = fraged_pages->vpl_pagedesc[0];
|
||||||
int to_item = 0;
|
int to_item = 0;
|
||||||
bool freeCbuf = false;
|
bool freeCbuf = false;
|
||||||
int ti;
|
int ti;
|
||||||
|
|
||||||
if (vacrelstats->vtlinks == NULL)
|
if (vacrelstats->vtlinks == NULL)
|
||||||
elog(ERROR, "No one parent tuple was found");
|
elog(ERROR, "No one parent tuple was found");
|
||||||
|
@ -1215,22 +1222,23 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
WriteBuffer(cur_buffer);
|
WriteBuffer(cur_buffer);
|
||||||
cur_buffer = InvalidBuffer;
|
cur_buffer = InvalidBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this tuple is in the begin/middle of the chain
|
* If this tuple is in the begin/middle of the chain then
|
||||||
* then we have to move to the end of chain.
|
* we have to move to the end of chain.
|
||||||
*/
|
*/
|
||||||
while (!(tp.t_data->t_infomask & HEAP_XMAX_INVALID) &&
|
while (!(tp.t_data->t_infomask & HEAP_XMAX_INVALID) &&
|
||||||
!(ItemPointerEquals(&(tp.t_self), &(tp.t_data->t_ctid))))
|
!(ItemPointerEquals(&(tp.t_self), &(tp.t_data->t_ctid))))
|
||||||
{
|
{
|
||||||
Ctid = tp.t_data->t_ctid;
|
Ctid = tp.t_data->t_ctid;
|
||||||
if (freeCbuf)
|
if (freeCbuf)
|
||||||
ReleaseBuffer(Cbuf);
|
ReleaseBuffer(Cbuf);
|
||||||
freeCbuf = true;
|
freeCbuf = true;
|
||||||
Cbuf = ReadBuffer(onerel,
|
Cbuf = ReadBuffer(onerel,
|
||||||
ItemPointerGetBlockNumber(&Ctid));
|
ItemPointerGetBlockNumber(&Ctid));
|
||||||
Cpage = BufferGetPage(Cbuf);
|
Cpage = BufferGetPage(Cbuf);
|
||||||
Citemid = PageGetItemId(Cpage,
|
Citemid = PageGetItemId(Cpage,
|
||||||
ItemPointerGetOffsetNumber(&Ctid));
|
ItemPointerGetOffsetNumber(&Ctid));
|
||||||
if (!ItemIdIsUsed(Citemid))
|
if (!ItemIdIsUsed(Citemid))
|
||||||
elog(ERROR, "Child itemid marked as unused");
|
elog(ERROR, "Child itemid marked as unused");
|
||||||
tp.t_data = (HeapTupleHeader) PageGetItem(Cpage, Citemid);
|
tp.t_data = (HeapTupleHeader) PageGetItem(Cpage, Citemid);
|
||||||
|
@ -1238,16 +1246,16 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
tlen = tp.t_len = ItemIdGetLength(Citemid);
|
tlen = tp.t_len = ItemIdGetLength(Citemid);
|
||||||
}
|
}
|
||||||
/* first, can chain be moved ? */
|
/* first, can chain be moved ? */
|
||||||
for ( ; ; )
|
for (;;)
|
||||||
{
|
{
|
||||||
if (!vc_enough_space(to_vpd, tlen))
|
if (!vc_enough_space(to_vpd, tlen))
|
||||||
{
|
{
|
||||||
if (to_vpd != last_fraged_page &&
|
if (to_vpd != last_fraged_page &&
|
||||||
!vc_enough_space(to_vpd, vacrelstats->min_tlen))
|
!vc_enough_space(to_vpd, vacrelstats->min_tlen))
|
||||||
{
|
{
|
||||||
Assert(num_fraged_pages > to_item + 1);
|
Assert(num_fraged_pages > to_item + 1);
|
||||||
memmove(fraged_pages->vpl_pagedesc + to_item,
|
memmove(fraged_pages->vpl_pagedesc + to_item,
|
||||||
fraged_pages->vpl_pagedesc + to_item + 1,
|
fraged_pages->vpl_pagedesc + to_item + 1,
|
||||||
sizeof(VPageDescr *) * (num_fraged_pages - to_item - 1));
|
sizeof(VPageDescr *) * (num_fraged_pages - to_item - 1));
|
||||||
num_fraged_pages--;
|
num_fraged_pages--;
|
||||||
Assert(last_fraged_page == fraged_pages->vpl_pagedesc[num_fraged_pages - 1]);
|
Assert(last_fraged_page == fraged_pages->vpl_pagedesc[num_fraged_pages - 1]);
|
||||||
|
@ -1257,7 +1265,8 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
if (vc_enough_space(fraged_pages->vpl_pagedesc[i], tlen))
|
if (vc_enough_space(fraged_pages->vpl_pagedesc[i], tlen))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i == num_fraged_pages) /* can't move item anywhere */
|
if (i == num_fraged_pages) /* can't move item
|
||||||
|
* anywhere */
|
||||||
{
|
{
|
||||||
for (i = 0; i < num_vtmove; i++)
|
for (i = 0; i < num_vtmove; i++)
|
||||||
{
|
{
|
||||||
|
@ -1277,9 +1286,9 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
if (free_vtmove == 0)
|
if (free_vtmove == 0)
|
||||||
{
|
{
|
||||||
free_vtmove = 1000;
|
free_vtmove = 1000;
|
||||||
vtmove = (VTupleMove) repalloc(vtmove,
|
vtmove = (VTupleMove) repalloc(vtmove,
|
||||||
(free_vtmove + num_vtmove) *
|
(free_vtmove + num_vtmove) *
|
||||||
sizeof(VTupleMoveData));
|
sizeof(VTupleMoveData));
|
||||||
}
|
}
|
||||||
vtmove[num_vtmove].tid = tp.t_self;
|
vtmove[num_vtmove].tid = tp.t_self;
|
||||||
vtmove[num_vtmove].vpd = to_vpd;
|
vtmove[num_vtmove].vpd = to_vpd;
|
||||||
|
@ -1289,56 +1298,59 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
vtmove[num_vtmove].cleanVpd = false;
|
vtmove[num_vtmove].cleanVpd = false;
|
||||||
free_vtmove--;
|
free_vtmove--;
|
||||||
num_vtmove++;
|
num_vtmove++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All done ?
|
* All done ?
|
||||||
*/
|
*/
|
||||||
if (!(tp.t_data->t_infomask & HEAP_UPDATED) ||
|
if (!(tp.t_data->t_infomask & HEAP_UPDATED) ||
|
||||||
tp.t_data->t_xmin < XmaxRecent)
|
tp.t_data->t_xmin < XmaxRecent)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Well, try to find tuple with old row version
|
* Well, try to find tuple with old row version
|
||||||
*/
|
*/
|
||||||
for ( ; ; )
|
for (;;)
|
||||||
{
|
{
|
||||||
Buffer Pbuf;
|
Buffer Pbuf;
|
||||||
Page Ppage;
|
Page Ppage;
|
||||||
ItemId Pitemid;
|
ItemId Pitemid;
|
||||||
HeapTupleData Ptp;
|
HeapTupleData Ptp;
|
||||||
VTupleLinkData vtld,
|
VTupleLinkData vtld,
|
||||||
*vtlp;
|
*vtlp;
|
||||||
|
|
||||||
vtld.new_tid = tp.t_self;
|
vtld.new_tid = tp.t_self;
|
||||||
vtlp = (VTupleLink)
|
vtlp = (VTupleLink)
|
||||||
vc_find_eq((void *) (vacrelstats->vtlinks),
|
vc_find_eq((void *) (vacrelstats->vtlinks),
|
||||||
vacrelstats->num_vtlinks,
|
vacrelstats->num_vtlinks,
|
||||||
sizeof(VTupleLinkData),
|
sizeof(VTupleLinkData),
|
||||||
(void *) &vtld,
|
(void *) &vtld,
|
||||||
vc_cmp_vtlinks);
|
vc_cmp_vtlinks);
|
||||||
if (vtlp == NULL)
|
if (vtlp == NULL)
|
||||||
elog(ERROR, "Parent tuple was not found");
|
elog(ERROR, "Parent tuple was not found");
|
||||||
tp.t_self = vtlp->this_tid;
|
tp.t_self = vtlp->this_tid;
|
||||||
Pbuf = ReadBuffer(onerel,
|
Pbuf = ReadBuffer(onerel,
|
||||||
ItemPointerGetBlockNumber(&(tp.t_self)));
|
ItemPointerGetBlockNumber(&(tp.t_self)));
|
||||||
Ppage = BufferGetPage(Pbuf);
|
Ppage = BufferGetPage(Pbuf);
|
||||||
Pitemid = PageGetItemId(Ppage,
|
Pitemid = PageGetItemId(Ppage,
|
||||||
ItemPointerGetOffsetNumber(&(tp.t_self)));
|
ItemPointerGetOffsetNumber(&(tp.t_self)));
|
||||||
if (!ItemIdIsUsed(Pitemid))
|
if (!ItemIdIsUsed(Pitemid))
|
||||||
elog(ERROR, "Parent itemid marked as unused");
|
elog(ERROR, "Parent itemid marked as unused");
|
||||||
Ptp.t_data = (HeapTupleHeader) PageGetItem(Ppage, Pitemid);
|
Ptp.t_data = (HeapTupleHeader) PageGetItem(Ppage, Pitemid);
|
||||||
Assert(Ptp.t_data->t_xmax == tp.t_data->t_xmin);
|
Assert(Ptp.t_data->t_xmax == tp.t_data->t_xmin);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this tuple is updated version of row and
|
* If this tuple is updated version of row and it
|
||||||
* it was created by the same transaction then
|
* was created by the same transaction then no one
|
||||||
* no one is interested in this tuple -
|
* is interested in this tuple - mark it as
|
||||||
* mark it as removed.
|
* removed.
|
||||||
*/
|
*/
|
||||||
if (Ptp.t_data->t_infomask & HEAP_UPDATED &&
|
if (Ptp.t_data->t_infomask & HEAP_UPDATED &&
|
||||||
Ptp.t_data->t_xmin == Ptp.t_data->t_xmax)
|
Ptp.t_data->t_xmin == Ptp.t_data->t_xmax)
|
||||||
{
|
{
|
||||||
TransactionIdStore(myXID,
|
TransactionIdStore(myXID,
|
||||||
(TransactionId*) &(Ptp.t_data->t_cmin));
|
(TransactionId *) &(Ptp.t_data->t_cmin));
|
||||||
Ptp.t_data->t_infomask &=
|
Ptp.t_data->t_infomask &=
|
||||||
~(HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID|HEAP_MOVED_IN);
|
~(HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_IN);
|
||||||
Ptp.t_data->t_infomask |= HEAP_MOVED_OFF;
|
Ptp.t_data->t_infomask |= HEAP_MOVED_OFF;
|
||||||
WriteBuffer(Pbuf);
|
WriteBuffer(Pbuf);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1354,7 +1366,7 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
}
|
}
|
||||||
if (freeCbuf)
|
if (freeCbuf)
|
||||||
ReleaseBuffer(Cbuf);
|
ReleaseBuffer(Cbuf);
|
||||||
if (num_vtmove == 0) /* chain can't be moved */
|
if (num_vtmove == 0) /* chain can't be moved */
|
||||||
{
|
{
|
||||||
pfree(vtmove);
|
pfree(vtmove);
|
||||||
break;
|
break;
|
||||||
|
@ -1364,19 +1376,20 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
{
|
{
|
||||||
/* Get tuple from chain */
|
/* Get tuple from chain */
|
||||||
tuple.t_self = vtmove[ti].tid;
|
tuple.t_self = vtmove[ti].tid;
|
||||||
Cbuf = ReadBuffer(onerel,
|
Cbuf = ReadBuffer(onerel,
|
||||||
ItemPointerGetBlockNumber(&(tuple.t_self)));
|
ItemPointerGetBlockNumber(&(tuple.t_self)));
|
||||||
Cpage = BufferGetPage(Cbuf);
|
Cpage = BufferGetPage(Cbuf);
|
||||||
Citemid = PageGetItemId(Cpage,
|
Citemid = PageGetItemId(Cpage,
|
||||||
ItemPointerGetOffsetNumber(&(tuple.t_self)));
|
ItemPointerGetOffsetNumber(&(tuple.t_self)));
|
||||||
tuple.t_data = (HeapTupleHeader) PageGetItem(Cpage, Citemid);
|
tuple.t_data = (HeapTupleHeader) PageGetItem(Cpage, Citemid);
|
||||||
tuple_len = tuple.t_len = ItemIdGetLength(Citemid);
|
tuple_len = tuple.t_len = ItemIdGetLength(Citemid);
|
||||||
/* Get page to move in */
|
/* Get page to move in */
|
||||||
cur_buffer = ReadBuffer(onerel, vtmove[ti].vpd->vpd_blkno);
|
cur_buffer = ReadBuffer(onerel, vtmove[ti].vpd->vpd_blkno);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We should LockBuffer(cur_buffer) but don't, at the
|
* We should LockBuffer(cur_buffer) but don't, at the
|
||||||
* moment. If you'll do LockBuffer then UNLOCK it
|
* moment. If you'll do LockBuffer then UNLOCK it
|
||||||
* before index_insert: unique btree-s call heap_fetch
|
* before index_insert: unique btree-s call heap_fetch
|
||||||
* to get t_infomask of inserted heap tuple !!!
|
* to get t_infomask of inserted heap tuple !!!
|
||||||
*/
|
*/
|
||||||
ToPage = BufferGetPage(cur_buffer);
|
ToPage = BufferGetPage(cur_buffer);
|
||||||
|
@ -1385,22 +1398,23 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
|
||||||
vc_vacpage(ToPage, vtmove[ti].vpd);
|
vc_vacpage(ToPage, vtmove[ti].vpd);
|
||||||
heap_copytuple_with_tuple(&tuple, &newtup);
|
heap_copytuple_with_tuple(&tuple, &newtup);
|
||||||
RelationInvalidateHeapTuple(onerel, &tuple);
|
RelationInvalidateHeapTuple(onerel, &tuple);
|
||||||
TransactionIdStore(myXID, (TransactionId*) &(newtup.t_data->t_cmin));
|
TransactionIdStore(myXID, (TransactionId *) &(newtup.t_data->t_cmin));
|
||||||
newtup.t_data->t_infomask &=
|
newtup.t_data->t_infomask &=
|
||||||
~(HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID|HEAP_MOVED_OFF);
|
~(HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_OFF);
|
||||||
newtup.t_data->t_infomask |= HEAP_MOVED_IN;
|
newtup.t_data->t_infomask |= HEAP_MOVED_IN;
|
||||||
newoff = PageAddItem(ToPage, (Item) newtup.t_data, tuple_len,
|
newoff = PageAddItem(ToPage, (Item) newtup.t_data, tuple_len,
|
||||||
InvalidOffsetNumber, LP_USED);
|
InvalidOffsetNumber, LP_USED);
|
||||||
if (newoff == InvalidOffsetNumber)
|
if (newoff == InvalidOffsetNumber)
|
||||||
{
|
{
|
||||||
elog(ERROR, "\
|
elog(ERROR, "\
|
||||||
moving chain: failed to add item with len = %u to page %u",
|
moving chain: failed to add item with len = %u to page %u",
|
||||||
tuple_len, vtmove[ti].vpd->vpd_blkno);
|
tuple_len, vtmove[ti].vpd->vpd_blkno);
|
||||||
}
|
}
|
||||||
newitemid = PageGetItemId(ToPage, newoff);
|
newitemid = PageGetItemId(ToPage, newoff);
|
||||||
pfree(newtup.t_data);
|
pfree(newtup.t_data);
|
||||||
newtup.t_data = (HeapTupleHeader) PageGetItem(ToPage, newitemid);
|
newtup.t_data = (HeapTupleHeader) PageGetItem(ToPage, newitemid);
|
||||||
ItemPointerSet(&(newtup.t_self), vtmove[ti].vpd->vpd_blkno, newoff);
|
ItemPointerSet(&(newtup.t_self), vtmove[ti].vpd->vpd_blkno, newoff);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set t_ctid pointing to itself for last tuple in
|
* Set t_ctid pointing to itself for last tuple in
|
||||||
* chain and to next tuple in chain otherwise.
|
* chain and to next tuple in chain otherwise.
|
||||||
|
@ -1411,19 +1425,20 @@ moving chain: failed to add item with len = %u to page %u",
|
||||||
newtup.t_data->t_ctid = Ctid;
|
newtup.t_data->t_ctid = Ctid;
|
||||||
Ctid = newtup.t_self;
|
Ctid = newtup.t_self;
|
||||||
|
|
||||||
TransactionIdStore(myXID, (TransactionId*) &(tuple.t_data->t_cmin));
|
TransactionIdStore(myXID, (TransactionId *) &(tuple.t_data->t_cmin));
|
||||||
tuple.t_data->t_infomask &=
|
tuple.t_data->t_infomask &=
|
||||||
~(HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID|HEAP_MOVED_IN);
|
~(HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_IN);
|
||||||
tuple.t_data->t_infomask |= HEAP_MOVED_OFF;
|
tuple.t_data->t_infomask |= HEAP_MOVED_OFF;
|
||||||
|
|
||||||
num_moved++;
|
num_moved++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remember that we moved tuple from the current page
|
* Remember that we moved tuple from the current page
|
||||||
* (corresponding index tuple will be cleaned).
|
* (corresponding index tuple will be cleaned).
|
||||||
*/
|
*/
|
||||||
if (Cbuf == buf)
|
if (Cbuf == buf)
|
||||||
vpc->vpd_offsets[vpc->vpd_offsets_free++] =
|
vpc->vpd_offsets[vpc->vpd_offsets_free++] =
|
||||||
ItemPointerGetOffsetNumber(&(tuple.t_self));
|
ItemPointerGetOffsetNumber(&(tuple.t_self));
|
||||||
else
|
else
|
||||||
keep_tuples++;
|
keep_tuples++;
|
||||||
|
|
||||||
|
@ -1432,12 +1447,12 @@ moving chain: failed to add item with len = %u to page %u",
|
||||||
for (i = 0, idcur = Idesc; i < nindices; i++, idcur++)
|
for (i = 0, idcur = Idesc; i < nindices; i++, idcur++)
|
||||||
{
|
{
|
||||||
FormIndexDatum(idcur->natts,
|
FormIndexDatum(idcur->natts,
|
||||||
(AttrNumber *) &(idcur->tform->indkey[0]),
|
(AttrNumber *) &(idcur->tform->indkey[0]),
|
||||||
&newtup,
|
&newtup,
|
||||||
tupdesc,
|
tupdesc,
|
||||||
idatum,
|
idatum,
|
||||||
inulls,
|
inulls,
|
||||||
idcur->finfoP);
|
idcur->finfoP);
|
||||||
iresult = index_insert(Irel[i],
|
iresult = index_insert(Irel[i],
|
||||||
idatum,
|
idatum,
|
||||||
inulls,
|
inulls,
|
||||||
|
@ -1507,13 +1522,13 @@ moving chain: failed to add item with len = %u to page %u",
|
||||||
|
|
||||||
RelationInvalidateHeapTuple(onerel, &tuple);
|
RelationInvalidateHeapTuple(onerel, &tuple);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mark new tuple as moved_in by vacuum and
|
* Mark new tuple as moved_in by vacuum and store vacuum XID
|
||||||
* store vacuum XID in t_cmin !!!
|
* in t_cmin !!!
|
||||||
*/
|
*/
|
||||||
TransactionIdStore(myXID, (TransactionId*) &(newtup.t_data->t_cmin));
|
TransactionIdStore(myXID, (TransactionId *) &(newtup.t_data->t_cmin));
|
||||||
newtup.t_data->t_infomask &=
|
newtup.t_data->t_infomask &=
|
||||||
~(HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID|HEAP_MOVED_OFF);
|
~(HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_OFF);
|
||||||
newtup.t_data->t_infomask |= HEAP_MOVED_IN;
|
newtup.t_data->t_infomask |= HEAP_MOVED_IN;
|
||||||
|
|
||||||
/* add tuple to the page */
|
/* add tuple to the page */
|
||||||
|
@ -1532,13 +1547,13 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
|
||||||
ItemPointerSet(&(newtup.t_data->t_ctid), cur_page->vpd_blkno, newoff);
|
ItemPointerSet(&(newtup.t_data->t_ctid), cur_page->vpd_blkno, newoff);
|
||||||
newtup.t_self = newtup.t_data->t_ctid;
|
newtup.t_self = newtup.t_data->t_ctid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mark old tuple as moved_off by vacuum and
|
* Mark old tuple as moved_off by vacuum and store vacuum XID
|
||||||
* store vacuum XID in t_cmin !!!
|
* in t_cmin !!!
|
||||||
*/
|
*/
|
||||||
TransactionIdStore(myXID, (TransactionId*) &(tuple.t_data->t_cmin));
|
TransactionIdStore(myXID, (TransactionId *) &(tuple.t_data->t_cmin));
|
||||||
tuple.t_data->t_infomask &=
|
tuple.t_data->t_infomask &=
|
||||||
~(HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID|HEAP_MOVED_IN);
|
~(HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_IN);
|
||||||
tuple.t_data->t_infomask |= HEAP_MOVED_OFF;
|
tuple.t_data->t_infomask |= HEAP_MOVED_OFF;
|
||||||
|
|
||||||
cur_page->vpd_offsets_used++;
|
cur_page->vpd_offsets_used++;
|
||||||
|
@ -1572,11 +1587,11 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
|
||||||
|
|
||||||
if (offnum < maxoff && keep_tuples > 0)
|
if (offnum < maxoff && keep_tuples > 0)
|
||||||
{
|
{
|
||||||
OffsetNumber off;
|
OffsetNumber off;
|
||||||
|
|
||||||
for (off = OffsetNumberNext(offnum);
|
for (off = OffsetNumberNext(offnum);
|
||||||
off <= maxoff;
|
off <= maxoff;
|
||||||
off = OffsetNumberNext(off))
|
off = OffsetNumberNext(off))
|
||||||
{
|
{
|
||||||
itemid = PageGetItemId(page, off);
|
itemid = PageGetItemId(page, off);
|
||||||
if (!ItemIdIsUsed(itemid))
|
if (!ItemIdIsUsed(itemid))
|
||||||
|
@ -1584,21 +1599,22 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
|
||||||
tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
|
tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
|
||||||
if (tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED)
|
if (tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED)
|
||||||
continue;
|
continue;
|
||||||
if ((TransactionId)tuple.t_data->t_cmin != myXID)
|
if ((TransactionId) tuple.t_data->t_cmin != myXID)
|
||||||
elog(ERROR, "Invalid XID in t_cmin (4)");
|
elog(ERROR, "Invalid XID in t_cmin (4)");
|
||||||
if (tuple.t_data->t_infomask & HEAP_MOVED_IN)
|
if (tuple.t_data->t_infomask & HEAP_MOVED_IN)
|
||||||
elog(ERROR, "HEAP_MOVED_IN was not expected (2)");
|
elog(ERROR, "HEAP_MOVED_IN was not expected (2)");
|
||||||
if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
|
if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
|
||||||
{
|
{
|
||||||
if (chain_tuple_moved) /* some chains was moved while */
|
if (chain_tuple_moved) /* some chains was moved
|
||||||
{ /* cleaning this page */
|
* while */
|
||||||
|
{ /* cleaning this page */
|
||||||
Assert(vpc->vpd_offsets_free > 0);
|
Assert(vpc->vpd_offsets_free > 0);
|
||||||
for (i = 0; i < vpc->vpd_offsets_free; i++)
|
for (i = 0; i < vpc->vpd_offsets_free; i++)
|
||||||
{
|
{
|
||||||
if (vpc->vpd_offsets[i] == off)
|
if (vpc->vpd_offsets[i] == off)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i >= vpc->vpd_offsets_free) /* not found */
|
if (i >= vpc->vpd_offsets_free) /* not found */
|
||||||
{
|
{
|
||||||
vpc->vpd_offsets[vpc->vpd_offsets_free++] = off;
|
vpc->vpd_offsets[vpc->vpd_offsets_free++] = off;
|
||||||
Assert(keep_tuples > 0);
|
Assert(keep_tuples > 0);
|
||||||
|
@ -1619,8 +1635,8 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
|
||||||
{
|
{
|
||||||
if (chain_tuple_moved) /* else - they are ordered */
|
if (chain_tuple_moved) /* else - they are ordered */
|
||||||
{
|
{
|
||||||
qsort((char *) (vpc->vpd_offsets), vpc->vpd_offsets_free,
|
qsort((char *) (vpc->vpd_offsets), vpc->vpd_offsets_free,
|
||||||
sizeof(OffsetNumber), vc_cmp_offno);
|
sizeof(OffsetNumber), vc_cmp_offno);
|
||||||
}
|
}
|
||||||
vc_reappage(&Nvpl, vpc);
|
vc_reappage(&Nvpl, vpc);
|
||||||
WriteBuffer(buf);
|
WriteBuffer(buf);
|
||||||
|
@ -1645,6 +1661,7 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
|
||||||
|
|
||||||
if (num_moved > 0)
|
if (num_moved > 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to commit our tuple' movings before we'll truncate
|
* We have to commit our tuple' movings before we'll truncate
|
||||||
* relation, but we shouldn't lose our locks. And so - quick hack:
|
* relation, but we shouldn't lose our locks. And so - quick hack:
|
||||||
|
@ -1657,8 +1674,8 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean uncleaned reapped pages from vacuum_pages list list and set xmin
|
* Clean uncleaned reapped pages from vacuum_pages list list and set
|
||||||
* committed for inserted tuples
|
* xmin committed for inserted tuples
|
||||||
*/
|
*/
|
||||||
checked_moved = 0;
|
checked_moved = 0;
|
||||||
for (i = 0, vpp = vacuum_pages->vpl_pagedesc; i < vacuumed_pages; i++, vpp++)
|
for (i = 0, vpp = vacuum_pages->vpl_pagedesc; i < vacuumed_pages; i++, vpp++)
|
||||||
|
@ -1671,7 +1688,8 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
|
||||||
if (!PageIsEmpty(page))
|
if (!PageIsEmpty(page))
|
||||||
vc_vacpage(page, *vpp);
|
vc_vacpage(page, *vpp);
|
||||||
}
|
}
|
||||||
else /* this page was used */
|
else
|
||||||
|
/* this page was used */
|
||||||
{
|
{
|
||||||
num_tuples = 0;
|
num_tuples = 0;
|
||||||
max_offset = PageGetMaxOffsetNumber(page);
|
max_offset = PageGetMaxOffsetNumber(page);
|
||||||
|
@ -1685,7 +1703,7 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
|
||||||
tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
|
tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
|
||||||
if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED))
|
if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED))
|
||||||
{
|
{
|
||||||
if ((TransactionId)tuple.t_data->t_cmin != myXID)
|
if ((TransactionId) tuple.t_data->t_cmin != myXID)
|
||||||
elog(ERROR, "Invalid XID in t_cmin (2)");
|
elog(ERROR, "Invalid XID in t_cmin (2)");
|
||||||
if (tuple.t_data->t_infomask & HEAP_MOVED_IN)
|
if (tuple.t_data->t_infomask & HEAP_MOVED_IN)
|
||||||
{
|
{
|
||||||
|
@ -1734,8 +1752,8 @@ Elapsed %u/%u sec.",
|
||||||
}
|
}
|
||||||
Assert(keep_tuples >= 0);
|
Assert(keep_tuples >= 0);
|
||||||
for (i = 0; i < nindices; i++)
|
for (i = 0; i < nindices; i++)
|
||||||
vc_vaconeind(&Nvpl, Irel[i],
|
vc_vaconeind(&Nvpl, Irel[i],
|
||||||
vacrelstats->num_tuples, keep_tuples);
|
vacrelstats->num_tuples, keep_tuples);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1757,7 +1775,7 @@ Elapsed %u/%u sec.",
|
||||||
|
|
||||||
if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED))
|
if (!(tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED))
|
||||||
{
|
{
|
||||||
if ((TransactionId)tuple.t_data->t_cmin != myXID)
|
if ((TransactionId) tuple.t_data->t_cmin != myXID)
|
||||||
elog(ERROR, "Invalid XID in t_cmin (3)");
|
elog(ERROR, "Invalid XID in t_cmin (3)");
|
||||||
if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
|
if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
|
||||||
{
|
{
|
||||||
|
@ -1998,7 +2016,7 @@ vc_vaconeind(VPageList vpl, Relation indrel, int num_tuples, int keep_tuples)
|
||||||
getrusage(RUSAGE_SELF, &ru1);
|
getrusage(RUSAGE_SELF, &ru1);
|
||||||
|
|
||||||
elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %u: Deleted %u. Elapsed %u/%u sec.",
|
elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %u: Deleted %u. Elapsed %u/%u sec.",
|
||||||
indrel->rd_rel->relname.data, num_pages,
|
indrel->rd_rel->relname.data, num_pages,
|
||||||
num_index_tuples - keep_tuples, tups_vacuumed,
|
num_index_tuples - keep_tuples, tups_vacuumed,
|
||||||
ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
|
ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
|
||||||
ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
|
ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
|
||||||
|
@ -2208,25 +2226,25 @@ vc_bucketcpy(Form_pg_attribute attr, Datum value, Datum *bucket, int16 *bucket_l
|
||||||
static void
|
static void
|
||||||
vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *vacrelstats)
|
vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *vacrelstats)
|
||||||
{
|
{
|
||||||
Relation rd,
|
Relation rd,
|
||||||
ad,
|
ad,
|
||||||
sd;
|
sd;
|
||||||
HeapScanDesc scan;
|
HeapScanDesc scan;
|
||||||
HeapTupleData rtup;
|
HeapTupleData rtup;
|
||||||
HeapTuple ctup,
|
HeapTuple ctup,
|
||||||
atup,
|
atup,
|
||||||
stup;
|
stup;
|
||||||
Form_pg_class pgcform;
|
Form_pg_class pgcform;
|
||||||
ScanKeyData askey;
|
ScanKeyData askey;
|
||||||
Form_pg_attribute attp;
|
Form_pg_attribute attp;
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* update number of tuples and number of pages in pg_class
|
* update number of tuples and number of pages in pg_class
|
||||||
*/
|
*/
|
||||||
ctup = SearchSysCacheTupleCopy(RELOID,
|
ctup = SearchSysCacheTupleCopy(RELOID,
|
||||||
ObjectIdGetDatum(relid),
|
ObjectIdGetDatum(relid),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
if (!HeapTupleIsValid(ctup))
|
if (!HeapTupleIsValid(ctup))
|
||||||
elog(ERROR, "pg_class entry for relid %u vanished during vacuuming",
|
elog(ERROR, "pg_class entry for relid %u vanished during vacuuming",
|
||||||
relid);
|
relid);
|
||||||
|
@ -2237,7 +2255,7 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
|
||||||
rtup.t_self = ctup->t_self;
|
rtup.t_self = ctup->t_self;
|
||||||
heap_fetch(rd, SnapshotNow, &rtup, &buffer);
|
heap_fetch(rd, SnapshotNow, &rtup, &buffer);
|
||||||
pfree(ctup);
|
pfree(ctup);
|
||||||
|
|
||||||
/* overwrite the existing statistics in the tuple */
|
/* overwrite the existing statistics in the tuple */
|
||||||
vc_setpagelock(rd, ItemPointerGetBlockNumber(&(rtup.t_self)));
|
vc_setpagelock(rd, ItemPointerGetBlockNumber(&(rtup.t_self)));
|
||||||
pgcform = (Form_pg_class) GETSTRUCT(&rtup);
|
pgcform = (Form_pg_class) GETSTRUCT(&rtup);
|
||||||
|
@ -2317,8 +2335,7 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
|
||||||
attp->attdisbursion = selratio;
|
attp->attdisbursion = selratio;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Invalidate the cache for the tuple
|
* Invalidate the cache for the tuple and write the buffer
|
||||||
* and write the buffer
|
|
||||||
*/
|
*/
|
||||||
RelationInvalidateHeapTuple(ad, atup);
|
RelationInvalidateHeapTuple(ad, atup);
|
||||||
WriteNoReleaseBuffer(abuffer);
|
WriteNoReleaseBuffer(abuffer);
|
||||||
|
@ -2375,8 +2392,7 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Invalidate the cached pg_class tuple and
|
* Invalidate the cached pg_class tuple and write the buffer
|
||||||
* write the buffer
|
|
||||||
*/
|
*/
|
||||||
RelationInvalidateHeapTuple(rd, &rtup);
|
RelationInvalidateHeapTuple(rd, &rtup);
|
||||||
|
|
||||||
|
@ -2504,8 +2520,8 @@ vc_free(VRelList vrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
vc_find_eq(void *bot, int nelem, int size, void *elm,
|
vc_find_eq(void *bot, int nelem, int size, void *elm,
|
||||||
int (*compar) (const void *, const void *))
|
int (*compar) (const void *, const void *))
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
int last = nelem - 1;
|
int last = nelem - 1;
|
||||||
|
@ -2527,16 +2543,16 @@ vc_find_eq(void *bot, int nelem, int size, void *elm,
|
||||||
}
|
}
|
||||||
if (last_move == true)
|
if (last_move == true)
|
||||||
{
|
{
|
||||||
res = compar(elm, (void *)((char *)bot + last * size));
|
res = compar(elm, (void *) ((char *) bot + last * size));
|
||||||
if (res > 0)
|
if (res > 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
return (void *)((char *)bot + last * size);
|
return (void *) ((char *) bot + last * size);
|
||||||
last_move = false;
|
last_move = false;
|
||||||
}
|
}
|
||||||
res = compar(elm, (void *)((char *)bot + celm * size));
|
res = compar(elm, (void *) ((char *) bot + celm * size));
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
return (void *)((char *)bot + celm * size);
|
return (void *) ((char *) bot + celm * size);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
if (celm == 0)
|
if (celm == 0)
|
||||||
|
@ -2551,7 +2567,7 @@ vc_find_eq(void *bot, int nelem, int size, void *elm,
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
last = last - celm - 1;
|
last = last - celm - 1;
|
||||||
bot = (void *)((char *)bot + (celm + 1) * size);
|
bot = (void *) ((char *) bot + (celm + 1) * size);
|
||||||
celm = (last + 1) / 2;
|
celm = (last + 1) / 2;
|
||||||
first_move = true;
|
first_move = true;
|
||||||
}
|
}
|
||||||
|
@ -2591,25 +2607,25 @@ static int
|
||||||
vc_cmp_vtlinks(const void *left, const void *right)
|
vc_cmp_vtlinks(const void *left, const void *right)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (((VTupleLink)left)->new_tid.ip_blkid.bi_hi <
|
if (((VTupleLink) left)->new_tid.ip_blkid.bi_hi <
|
||||||
((VTupleLink)right)->new_tid.ip_blkid.bi_hi)
|
((VTupleLink) right)->new_tid.ip_blkid.bi_hi)
|
||||||
return -1;
|
return -1;
|
||||||
if (((VTupleLink)left)->new_tid.ip_blkid.bi_hi >
|
if (((VTupleLink) left)->new_tid.ip_blkid.bi_hi >
|
||||||
((VTupleLink)right)->new_tid.ip_blkid.bi_hi)
|
((VTupleLink) right)->new_tid.ip_blkid.bi_hi)
|
||||||
return 1;
|
return 1;
|
||||||
/* bi_hi-es are equal */
|
/* bi_hi-es are equal */
|
||||||
if (((VTupleLink)left)->new_tid.ip_blkid.bi_lo <
|
if (((VTupleLink) left)->new_tid.ip_blkid.bi_lo <
|
||||||
((VTupleLink)right)->new_tid.ip_blkid.bi_lo)
|
((VTupleLink) right)->new_tid.ip_blkid.bi_lo)
|
||||||
return -1;
|
return -1;
|
||||||
if (((VTupleLink)left)->new_tid.ip_blkid.bi_lo >
|
if (((VTupleLink) left)->new_tid.ip_blkid.bi_lo >
|
||||||
((VTupleLink)right)->new_tid.ip_blkid.bi_lo)
|
((VTupleLink) right)->new_tid.ip_blkid.bi_lo)
|
||||||
return 1;
|
return 1;
|
||||||
/* bi_lo-es are equal */
|
/* bi_lo-es are equal */
|
||||||
if (((VTupleLink)left)->new_tid.ip_posid <
|
if (((VTupleLink) left)->new_tid.ip_posid <
|
||||||
((VTupleLink)right)->new_tid.ip_posid)
|
((VTupleLink) right)->new_tid.ip_posid)
|
||||||
return -1;
|
return -1;
|
||||||
if (((VTupleLink)left)->new_tid.ip_posid >
|
if (((VTupleLink) left)->new_tid.ip_posid >
|
||||||
((VTupleLink)right)->new_tid.ip_posid)
|
((VTupleLink) right)->new_tid.ip_posid)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* Routines for handling of 'SET var TO',
|
* Routines for handling of 'SET var TO',
|
||||||
* 'SHOW var' and 'RESET var' statements.
|
* 'SHOW var' and 'RESET var' statements.
|
||||||
*
|
*
|
||||||
* $Id: variable.c,v 1.19 1999/02/18 06:00:44 momjian Exp $
|
* $Id: variable.c,v 1.20 1999/05/25 16:08:28 momjian Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -45,10 +45,12 @@ static bool parse_ksqo(const char *);
|
||||||
static bool show_XactIsoLevel(void);
|
static bool show_XactIsoLevel(void);
|
||||||
static bool reset_XactIsoLevel(void);
|
static bool reset_XactIsoLevel(void);
|
||||||
static bool parse_XactIsoLevel(const char *);
|
static bool parse_XactIsoLevel(const char *);
|
||||||
|
|
||||||
#ifdef QUERY_LIMIT
|
#ifdef QUERY_LIMIT
|
||||||
static bool show_query_limit(void);
|
static bool show_query_limit(void);
|
||||||
static bool reset_query_limit(void);
|
static bool reset_query_limit(void);
|
||||||
static bool parse_query_limit(const char *);
|
static bool parse_query_limit(const char *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern Cost _cpu_page_wight_;
|
extern Cost _cpu_page_wight_;
|
||||||
|
@ -545,41 +547,41 @@ reset_timezone()
|
||||||
static bool
|
static bool
|
||||||
parse_query_limit(const char *value)
|
parse_query_limit(const char *value)
|
||||||
{
|
{
|
||||||
int32 limit;
|
int32 limit;
|
||||||
|
|
||||||
if (value == NULL) {
|
if (value == NULL)
|
||||||
reset_query_limit();
|
{
|
||||||
return(TRUE);
|
reset_query_limit();
|
||||||
}
|
return (TRUE);
|
||||||
/* why is pg_atoi's arg not declared "const char *" ? */
|
}
|
||||||
limit = pg_atoi((char *) value, sizeof(int32), '\0');
|
/* why is pg_atoi's arg not declared "const char *" ? */
|
||||||
if (limit <= -1) {
|
limit = pg_atoi((char *) value, sizeof(int32), '\0');
|
||||||
elog(ERROR, "Bad value for # of query limit (%s)", value);
|
if (limit <= -1)
|
||||||
}
|
elog(ERROR, "Bad value for # of query limit (%s)", value);
|
||||||
ExecutorLimit(limit);
|
ExecutorLimit(limit);
|
||||||
return(TRUE);
|
return (TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
show_query_limit(void)
|
show_query_limit(void)
|
||||||
{
|
{
|
||||||
int limit;
|
int limit;
|
||||||
|
|
||||||
limit = ExecutorGetLimit();
|
limit = ExecutorGetLimit();
|
||||||
if (limit == ALL_TUPLES) {
|
if (limit == ALL_TUPLES)
|
||||||
elog(NOTICE, "No query limit is set");
|
elog(NOTICE, "No query limit is set");
|
||||||
} else {
|
else
|
||||||
elog(NOTICE, "query limit is %d",limit);
|
elog(NOTICE, "query limit is %d", limit);
|
||||||
}
|
return (TRUE);
|
||||||
return(TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
reset_query_limit(void)
|
reset_query_limit(void)
|
||||||
{
|
{
|
||||||
ExecutorLimit(ALL_TUPLES);
|
ExecutorLimit(ALL_TUPLES);
|
||||||
return(TRUE);
|
return (TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
|
@ -685,10 +687,10 @@ ResetPGVariable(const char *name)
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------
|
/*-----------------------------------------------------------------------
|
||||||
KSQO code will one day be unnecessary when the optimizer makes use of
|
KSQO code will one day be unnecessary when the optimizer makes use of
|
||||||
indexes when multiple ORs are specified in the where clause.
|
indexes when multiple ORs are specified in the where clause.
|
||||||
See optimizer/prep/prepkeyset.c for more on this.
|
See optimizer/prep/prepkeyset.c for more on this.
|
||||||
daveh@insightdist.com 6/16/98
|
daveh@insightdist.com 6/16/98
|
||||||
-----------------------------------------------------------------------*/
|
-----------------------------------------------------------------------*/
|
||||||
static bool
|
static bool
|
||||||
parse_ksqo(const char *value)
|
parse_ksqo(const char *value)
|
||||||
|
@ -732,7 +734,7 @@ reset_ksqo()
|
||||||
static bool
|
static bool
|
||||||
parse_XactIsoLevel(const char *value)
|
parse_XactIsoLevel(const char *value)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
{
|
{
|
||||||
reset_XactIsoLevel();
|
reset_XactIsoLevel();
|
||||||
|
@ -770,7 +772,7 @@ show_XactIsoLevel()
|
||||||
static bool
|
static bool
|
||||||
reset_XactIsoLevel()
|
reset_XactIsoLevel()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (SerializableSnapshot != NULL)
|
if (SerializableSnapshot != NULL)
|
||||||
{
|
{
|
||||||
elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
|
elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: view.c,v 1.32 1999/02/13 23:15:12 momjian Exp $
|
* $Id: view.c,v 1.33 1999/05/25 16:08:28 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <postgres.h>
|
#include <postgres.h>
|
||||||
|
@ -230,9 +230,9 @@ UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
|
||||||
* table... CURRENT first, then NEW....
|
* table... CURRENT first, then NEW....
|
||||||
*/
|
*/
|
||||||
rt_entry1 = addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*",
|
rt_entry1 = addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*",
|
||||||
FALSE, FALSE);
|
FALSE, FALSE);
|
||||||
rt_entry2 = addRangeTableEntry(NULL, (char *) viewName, "*NEW*",
|
rt_entry2 = addRangeTableEntry(NULL, (char *) viewName, "*NEW*",
|
||||||
FALSE, FALSE);
|
FALSE, FALSE);
|
||||||
new_rt = lcons(rt_entry2, old_rt);
|
new_rt = lcons(rt_entry2, old_rt);
|
||||||
new_rt = lcons(rt_entry1, new_rt);
|
new_rt = lcons(rt_entry1, new_rt);
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,15 @@
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* This code provides support for a tee node, which allows
|
* This code provides support for a tee node, which allows
|
||||||
* multiple parent in a megaplan.
|
* multiple parent in a megaplan.
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
* ExecTee
|
* ExecTee
|
||||||
* ExecInitTee
|
* ExecInitTee
|
||||||
* ExecEndTee
|
* ExecEndTee
|
||||||
*
|
*
|
||||||
* $Id: nodeTee.c,v 1.1 1999/03/23 16:50:49 momjian Exp $
|
* $Id: nodeTee.c,v 1.2 1999/05/25 16:08:50 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -46,12 +46,12 @@
|
||||||
bool
|
bool
|
||||||
ExecInitTee(Tee *node, EState *currentEstate, Plan *parent)
|
ExecInitTee(Tee *node, EState *currentEstate, Plan *parent)
|
||||||
{
|
{
|
||||||
TeeState *teeState;
|
TeeState *teeState;
|
||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
int len;
|
int len;
|
||||||
Relation bufferRel;
|
Relation bufferRel;
|
||||||
TupleDesc tupType;
|
TupleDesc tupType;
|
||||||
EState *estate;
|
EState *estate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* it is possible that the Tee has already been initialized since it
|
* it is possible that the Tee has already been initialized since it
|
||||||
|
@ -167,7 +167,7 @@ ExecInitTee(Tee *node, EState *currentEstate, Plan *parent)
|
||||||
else
|
else
|
||||||
bufferRel = heap_open(
|
bufferRel = heap_open(
|
||||||
heap_create_with_catalog(teeState->tee_bufferRelname,
|
heap_create_with_catalog(teeState->tee_bufferRelname,
|
||||||
tupType, RELKIND_RELATION, false));
|
tupType, RELKIND_RELATION, false));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -176,7 +176,7 @@ ExecInitTee(Tee *node, EState *currentEstate, Plan *parent)
|
||||||
newoid());
|
newoid());
|
||||||
bufferRel = heap_open(
|
bufferRel = heap_open(
|
||||||
heap_create_with_catalog(teeState->tee_bufferRelname,
|
heap_create_with_catalog(teeState->tee_bufferRelname,
|
||||||
tupType, RELKIND_RELATION, false));
|
tupType, RELKIND_RELATION, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
teeState->tee_bufferRel = bufferRel;
|
teeState->tee_bufferRel = bufferRel;
|
||||||
|
@ -339,6 +339,7 @@ ExecTee(Tee *node, Plan *parent)
|
||||||
slot = ExecProcNode(childNode, (Plan *) node);
|
slot = ExecProcNode(childNode, (Plan *) node);
|
||||||
if (!TupIsNull(slot))
|
if (!TupIsNull(slot))
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* heap_insert changes something...
|
* heap_insert changes something...
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: execAmi.c,v 1.34 1999/05/10 00:45:05 momjian Exp $
|
* $Id: execAmi.c,v 1.35 1999/05/25 16:08:34 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
* ExecCreatR function to create temporary relations
|
* ExecCreatR function to create temporary relations
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.50 1999/03/20 02:07:31 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.51 1999/05/25 16:08:37 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -66,7 +66,7 @@ bool execConstByVal;
|
||||||
int execConstLen;
|
int execConstLen;
|
||||||
|
|
||||||
/* static functions decls */
|
/* static functions decls */
|
||||||
static Datum ExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull);
|
static Datum ExecEvalAggref(Aggref * aggref, ExprContext *econtext, bool *isNull);
|
||||||
static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext,
|
static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext,
|
||||||
bool *isNull, bool *isDone);
|
bool *isNull, bool *isDone);
|
||||||
static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull);
|
static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull);
|
||||||
|
@ -190,7 +190,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static Datum
|
static Datum
|
||||||
ExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull)
|
ExecEvalAggref(Aggref * aggref, ExprContext *econtext, bool *isNull)
|
||||||
{
|
{
|
||||||
*isNull = econtext->ecxt_nulls[aggref->aggno];
|
*isNull = econtext->ecxt_nulls[aggref->aggno];
|
||||||
return econtext->ecxt_values[aggref->aggno];
|
return econtext->ecxt_values[aggref->aggno];
|
||||||
|
@ -232,7 +232,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||||
int16 len;
|
int16 len;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get the slot we want
|
* get the slot we want
|
||||||
*/
|
*/
|
||||||
switch (variable->varno)
|
switch (variable->varno)
|
||||||
{
|
{
|
||||||
|
@ -251,7 +251,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* extract tuple information from the slot
|
* extract tuple information from the slot
|
||||||
*/
|
*/
|
||||||
heapTuple = slot->val;
|
heapTuple = slot->val;
|
||||||
tuple_type = slot->ttc_tupleDescriptor;
|
tuple_type = slot->ttc_tupleDescriptor;
|
||||||
|
@ -270,7 +270,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||||
* the entire tuple, we give back a whole slot so that callers know
|
* the entire tuple, we give back a whole slot so that callers know
|
||||||
* what the tuple looks like.
|
* what the tuple looks like.
|
||||||
*/
|
*/
|
||||||
if (attnum == InvalidAttrNumber)
|
if (attnum == InvalidAttrNumber)
|
||||||
{
|
{
|
||||||
TupleTableSlot *tempSlot;
|
TupleTableSlot *tempSlot;
|
||||||
TupleDesc td;
|
TupleDesc td;
|
||||||
|
@ -299,26 +299,25 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||||
isNull); /* return: is attribute null? */
|
isNull); /* return: is attribute null? */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* return null if att is null
|
* return null if att is null
|
||||||
*/
|
*/
|
||||||
if (*isNull)
|
if (*isNull)
|
||||||
return (Datum) NULL;
|
return (Datum) NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get length and type information..
|
* get length and type information.. ??? what should we do about
|
||||||
* ??? what should we do about variable length attributes
|
* variable length attributes - variable length attributes have their
|
||||||
* - variable length attributes have their length stored
|
* length stored in the first 4 bytes of the memory pointed to by the
|
||||||
* in the first 4 bytes of the memory pointed to by the
|
* returned value.. If we can determine that the type is a variable
|
||||||
* returned value.. If we can determine that the type
|
* length type, we can do the right thing. -cim 9/15/89
|
||||||
* is a variable length type, we can do the right thing.
|
|
||||||
* -cim 9/15/89
|
|
||||||
*/
|
*/
|
||||||
if (attnum < 0)
|
if (attnum < 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is a pseudo-att, we get the type and fake the length.
|
* If this is a pseudo-att, we get the type and fake the length.
|
||||||
* There ought to be a routine to return the real lengths, so
|
* There ought to be a routine to return the real lengths, so
|
||||||
* we'll mark this one ... XXX -mao
|
* we'll mark this one ... XXX -mao
|
||||||
*/
|
*/
|
||||||
len = heap_sysattrlen(attnum); /* XXX see -mao above */
|
len = heap_sysattrlen(attnum); /* XXX see -mao above */
|
||||||
byval = heap_sysattrbyval(attnum); /* XXX see -mao above */
|
byval = heap_sysattrbyval(attnum); /* XXX see -mao above */
|
||||||
|
@ -609,11 +608,11 @@ ExecEvalFuncArgs(FunctionCachePtr fcache,
|
||||||
i = 0;
|
i = 0;
|
||||||
foreach(arg, argList)
|
foreach(arg, argList)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* evaluate the expression, in general functions cannot take
|
* evaluate the expression, in general functions cannot take sets
|
||||||
* sets as arguments but we make an exception in the case of
|
* as arguments but we make an exception in the case of nested dot
|
||||||
* nested dot expressions. We have to watch out for this case
|
* expressions. We have to watch out for this case here.
|
||||||
* here.
|
|
||||||
*/
|
*/
|
||||||
argV[i] = (Datum)
|
argV[i] = (Datum)
|
||||||
ExecEvalExpr((Node *) lfirst(arg),
|
ExecEvalExpr((Node *) lfirst(arg),
|
||||||
|
@ -671,10 +670,10 @@ ExecMakeFunctionResult(Node *node,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* arguments is a list of expressions to evaluate
|
* arguments is a list of expressions to evaluate before passing to
|
||||||
* before passing to the function manager.
|
* the function manager. We collect the results of evaluating the
|
||||||
* We collect the results of evaluating the expressions
|
* expressions into a datum array (argV) and pass this array to
|
||||||
* into a datum array (argV) and pass this array to arrayFmgr()
|
* arrayFmgr()
|
||||||
*/
|
*/
|
||||||
if (fcache->nargs != 0)
|
if (fcache->nargs != 0)
|
||||||
{
|
{
|
||||||
|
@ -743,8 +742,8 @@ ExecMakeFunctionResult(Node *node,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* now return the value gotten by calling the function manager,
|
* now return the value gotten by calling the function manager,
|
||||||
* passing the function the evaluated parameter values.
|
* passing the function the evaluated parameter values.
|
||||||
*/
|
*/
|
||||||
if (fcache->language == SQLlanguageId)
|
if (fcache->language == SQLlanguageId)
|
||||||
{
|
{
|
||||||
|
@ -843,12 +842,12 @@ ExecEvalOper(Expr *opClause, ExprContext *econtext, bool *isNull)
|
||||||
bool isDone;
|
bool isDone;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* an opclause is a list (op args). (I think)
|
* an opclause is a list (op args). (I think)
|
||||||
*
|
*
|
||||||
* we extract the oid of the function associated with
|
* we extract the oid of the function associated with the op and then
|
||||||
* the op and then pass the work onto ExecMakeFunctionResult
|
* pass the work onto ExecMakeFunctionResult which evaluates the
|
||||||
* which evaluates the arguments and returns the result of
|
* arguments and returns the result of calling the function on the
|
||||||
* calling the function on the evaluated arguments.
|
* evaluated arguments.
|
||||||
*/
|
*/
|
||||||
op = (Oper *) opClause->oper;
|
op = (Oper *) opClause->oper;
|
||||||
argList = opClause->args;
|
argList = opClause->args;
|
||||||
|
@ -865,8 +864,8 @@ ExecEvalOper(Expr *opClause, ExprContext *econtext, bool *isNull)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call ExecMakeFunctionResult() with a dummy isDone that we ignore.
|
* call ExecMakeFunctionResult() with a dummy isDone that we ignore.
|
||||||
* We don't have operator whose arguments are sets.
|
* We don't have operator whose arguments are sets.
|
||||||
*/
|
*/
|
||||||
return ExecMakeFunctionResult((Node *) op, argList, econtext, isNull, &isDone);
|
return ExecMakeFunctionResult((Node *) op, argList, econtext, isNull, &isDone);
|
||||||
}
|
}
|
||||||
|
@ -887,14 +886,14 @@ ExecEvalFunc(Expr *funcClause,
|
||||||
FunctionCachePtr fcache;
|
FunctionCachePtr fcache;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* an funcclause is a list (func args). (I think)
|
* an funcclause is a list (func args). (I think)
|
||||||
*
|
*
|
||||||
* we extract the oid of the function associated with
|
* we extract the oid of the function associated with the func node and
|
||||||
* the func node and then pass the work onto ExecMakeFunctionResult
|
* then pass the work onto ExecMakeFunctionResult which evaluates the
|
||||||
* which evaluates the arguments and returns the result of
|
* arguments and returns the result of calling the function on the
|
||||||
* calling the function on the evaluated arguments.
|
* evaluated arguments.
|
||||||
*
|
*
|
||||||
* this is nearly identical to the ExecEvalOper code.
|
* this is nearly identical to the ExecEvalOper code.
|
||||||
*/
|
*/
|
||||||
func = (Func *) funcClause->oper;
|
func = (Func *) funcClause->oper;
|
||||||
argList = funcClause->args;
|
argList = funcClause->args;
|
||||||
|
@ -939,21 +938,21 @@ ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull)
|
||||||
clause = lfirst(notclause->args);
|
clause = lfirst(notclause->args);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't iterate over sets in the quals, so pass in an isDone
|
* We don't iterate over sets in the quals, so pass in an isDone flag,
|
||||||
* flag, but ignore it.
|
* but ignore it.
|
||||||
*/
|
*/
|
||||||
expr_value = ExecEvalExpr(clause, econtext, isNull, &isDone);
|
expr_value = ExecEvalExpr(clause, econtext, isNull, &isDone);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the expression evaluates to null, then we just
|
* if the expression evaluates to null, then we just cascade the null
|
||||||
* cascade the null back to whoever called us.
|
* back to whoever called us.
|
||||||
*/
|
*/
|
||||||
if (*isNull)
|
if (*isNull)
|
||||||
return expr_value;
|
return expr_value;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* evaluation of 'not' is simple.. expr is false, then
|
* evaluation of 'not' is simple.. expr is false, then return 'true'
|
||||||
* return 'true' and vice versa.
|
* and vice versa.
|
||||||
*/
|
*/
|
||||||
if (DatumGetInt32(expr_value) == 0)
|
if (DatumGetInt32(expr_value) == 0)
|
||||||
return (Datum) true;
|
return (Datum) true;
|
||||||
|
@ -978,22 +977,19 @@ ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull)
|
||||||
clauses = orExpr->args;
|
clauses = orExpr->args;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we use three valued logic functions here...
|
* we use three valued logic functions here... we evaluate each of the
|
||||||
* we evaluate each of the clauses in turn,
|
* clauses in turn, as soon as one is true we return that value. If
|
||||||
* as soon as one is true we return that
|
* none is true and none of the clauses evaluate to NULL we return
|
||||||
* value. If none is true and none of the
|
* the value of the last clause evaluated (which should be false) with
|
||||||
* clauses evaluate to NULL we return
|
* *isNull set to false else if none is true and at least one clause
|
||||||
* the value of the last clause evaluated (which
|
* evaluated to NULL we set *isNull flag to true -
|
||||||
* should be false) with *isNull set to false else
|
|
||||||
* if none is true and at least one clause evaluated
|
|
||||||
* to NULL we set *isNull flag to true -
|
|
||||||
*/
|
*/
|
||||||
foreach(clause, clauses)
|
foreach(clause, clauses)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't iterate over sets in the quals, so pass in an isDone
|
* We don't iterate over sets in the quals, so pass in an isDone
|
||||||
* flag, but ignore it.
|
* flag, but ignore it.
|
||||||
*/
|
*/
|
||||||
const_value = ExecEvalExpr((Node *) lfirst(clause),
|
const_value = ExecEvalExpr((Node *) lfirst(clause),
|
||||||
econtext,
|
econtext,
|
||||||
|
@ -1001,34 +997,32 @@ ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull)
|
||||||
&isDone);
|
&isDone);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the expression evaluates to null, then we
|
* if the expression evaluates to null, then we remember it in the
|
||||||
* remember it in the local IsNull flag, if none of the
|
* local IsNull flag, if none of the clauses are true then we need
|
||||||
* clauses are true then we need to set *isNull
|
* to set *isNull to true again.
|
||||||
* to true again.
|
|
||||||
*/
|
*/
|
||||||
if (*isNull)
|
if (*isNull)
|
||||||
{
|
{
|
||||||
IsNull = *isNull;
|
IsNull = *isNull;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Many functions don't (or can't!) check if an argument is NULL
|
* Many functions don't (or can't!) check if an argument is
|
||||||
* or NOT_NULL and may return TRUE (1) with *isNull TRUE
|
* NULL or NOT_NULL and may return TRUE (1) with *isNull TRUE
|
||||||
* (an_int4_column <> 1: int4ne returns TRUE for NULLs).
|
* (an_int4_column <> 1: int4ne returns TRUE for NULLs). Not
|
||||||
* Not having time to fix the function manager I want to fix OR:
|
* having time to fix the function manager I want to fix OR:
|
||||||
* if we had 'x <> 1 OR x isnull' then when x is NULL
|
* if we had 'x <> 1 OR x isnull' then when x is NULL TRUE was
|
||||||
* TRUE was returned by the 'x <> 1' clause ...
|
* returned by the 'x <> 1' clause ... but ExecQualClause says
|
||||||
* but ExecQualClause says that the qualification should *fail*
|
* that the qualification should *fail* if isnull is TRUE for
|
||||||
* if isnull is TRUE for any value returned by ExecEvalExpr.
|
* any value returned by ExecEvalExpr. So, force this rule
|
||||||
* So, force this rule here:
|
* here: if isnull is TRUE then the clause failed. Note:
|
||||||
* if isnull is TRUE then the clause failed.
|
* nullvalue() & nonnullvalue() always sets isnull to FALSE
|
||||||
* Note: nullvalue() & nonnullvalue() always sets isnull to FALSE for NULLs.
|
* for NULLs. - vadim 09/22/97
|
||||||
* - vadim 09/22/97
|
|
||||||
*/
|
*/
|
||||||
const_value = 0;
|
const_value = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we have a true result, then we return it.
|
* if we have a true result, then we return it.
|
||||||
*/
|
*/
|
||||||
if (DatumGetInt32(const_value) != 0)
|
if (DatumGetInt32(const_value) != 0)
|
||||||
return const_value;
|
return const_value;
|
||||||
|
@ -1057,18 +1051,16 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
|
||||||
clauses = andExpr->args;
|
clauses = andExpr->args;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we evaluate each of the clauses in turn,
|
* we evaluate each of the clauses in turn, as soon as one is false we
|
||||||
* as soon as one is false we return that
|
* return that value. If none are false or NULL then we return the
|
||||||
* value. If none are false or NULL then we return
|
* value of the last clause evaluated, which should be true.
|
||||||
* the value of the last clause evaluated, which
|
|
||||||
* should be true.
|
|
||||||
*/
|
*/
|
||||||
foreach(clause, clauses)
|
foreach(clause, clauses)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't iterate over sets in the quals, so pass in an isDone
|
* We don't iterate over sets in the quals, so pass in an isDone
|
||||||
* flag, but ignore it.
|
* flag, but ignore it.
|
||||||
*/
|
*/
|
||||||
const_value = ExecEvalExpr((Node *) lfirst(clause),
|
const_value = ExecEvalExpr((Node *) lfirst(clause),
|
||||||
econtext,
|
econtext,
|
||||||
|
@ -1076,17 +1068,16 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
|
||||||
&isDone);
|
&isDone);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the expression evaluates to null, then we
|
* if the expression evaluates to null, then we remember it in
|
||||||
* remember it in IsNull, if none of the clauses after
|
* IsNull, if none of the clauses after this evaluates to false we
|
||||||
* this evaluates to false we will have to set *isNull
|
* will have to set *isNull to true again.
|
||||||
* to true again.
|
|
||||||
*/
|
*/
|
||||||
if (*isNull)
|
if (*isNull)
|
||||||
IsNull = *isNull;
|
IsNull = *isNull;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we have a false result, then we return it, since the
|
* if we have a false result, then we return it, since the
|
||||||
* conjunction must be false.
|
* conjunction must be false.
|
||||||
*/
|
*/
|
||||||
if (DatumGetInt32(const_value) == 0)
|
if (DatumGetInt32(const_value) == 0)
|
||||||
return const_value;
|
return const_value;
|
||||||
|
@ -1106,7 +1097,7 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static Datum
|
static Datum
|
||||||
ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
|
ExecEvalCase(CaseExpr * caseExpr, ExprContext *econtext, bool *isNull)
|
||||||
{
|
{
|
||||||
List *clauses;
|
List *clauses;
|
||||||
List *clause;
|
List *clause;
|
||||||
|
@ -1117,17 +1108,16 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
|
||||||
clauses = caseExpr->args;
|
clauses = caseExpr->args;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we evaluate each of the WHEN clauses in turn,
|
* we evaluate each of the WHEN clauses in turn, as soon as one is
|
||||||
* as soon as one is true we return the corresponding
|
* true we return the corresponding result. If none are true then we
|
||||||
* result. If none are true then we return the value
|
* return the value of the default clause, or NULL.
|
||||||
* of the default clause, or NULL.
|
|
||||||
*/
|
*/
|
||||||
foreach(clause, clauses)
|
foreach(clause, clauses)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't iterate over sets in the quals, so pass in an isDone
|
* We don't iterate over sets in the quals, so pass in an isDone
|
||||||
* flag, but ignore it.
|
* flag, but ignore it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
wclause = lfirst(clause);
|
wclause = lfirst(clause);
|
||||||
|
@ -1137,8 +1127,8 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
|
||||||
&isDone);
|
&isDone);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we have a true test, then we return the result,
|
* if we have a true test, then we return the result, since the
|
||||||
* since the case statement is satisfied.
|
* case statement is satisfied.
|
||||||
*/
|
*/
|
||||||
if (DatumGetInt32(const_value) != 0)
|
if (DatumGetInt32(const_value) != 0)
|
||||||
{
|
{
|
||||||
|
@ -1159,9 +1149,7 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
|
||||||
&isDone);
|
&isDone);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
*isNull = true;
|
*isNull = true;
|
||||||
}
|
|
||||||
|
|
||||||
return const_value;
|
return const_value;
|
||||||
}
|
}
|
||||||
|
@ -1204,8 +1192,8 @@ ExecEvalExpr(Node *expression,
|
||||||
*isDone = true;
|
*isDone = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* here we dispatch the work to the appropriate type
|
* here we dispatch the work to the appropriate type of function given
|
||||||
* of function given the type of our expression.
|
* the type of our expression.
|
||||||
*/
|
*/
|
||||||
if (expression == NULL)
|
if (expression == NULL)
|
||||||
{
|
{
|
||||||
|
@ -1287,7 +1275,7 @@ ExecEvalExpr(Node *expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
return retDatum;
|
return retDatum;
|
||||||
} /* ExecEvalExpr() */
|
} /* ExecEvalExpr() */
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
|
@ -1325,16 +1313,15 @@ ExecQualClause(Node *clause, ExprContext *econtext)
|
||||||
ExecEvalExpr(clause, econtext, &isNull, &isDone);
|
ExecEvalExpr(clause, econtext, &isNull, &isDone);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this is interesting behaviour here. When a clause evaluates
|
* this is interesting behaviour here. When a clause evaluates to
|
||||||
* to null, then we consider this as passing the qualification.
|
* null, then we consider this as passing the qualification. it seems
|
||||||
* it seems kind of like, if the qual is NULL, then there's no
|
* kind of like, if the qual is NULL, then there's no qual..
|
||||||
* qual..
|
|
||||||
*/
|
*/
|
||||||
if (isNull)
|
if (isNull)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* remember, we return true when the qualification fails..
|
* remember, we return true when the qualification fails..
|
||||||
*/
|
*/
|
||||||
if (DatumGetInt32(expr_value) == 0)
|
if (DatumGetInt32(expr_value) == 0)
|
||||||
return true;
|
return true;
|
||||||
|
@ -1356,7 +1343,7 @@ ExecQual(List *qual, ExprContext *econtext)
|
||||||
bool result;
|
bool result;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* debugging stuff
|
* debugging stuff
|
||||||
*/
|
*/
|
||||||
EV_printf("ExecQual: qual is ");
|
EV_printf("ExecQual: qual is ");
|
||||||
EV_nodeDisplay(qual);
|
EV_nodeDisplay(qual);
|
||||||
|
@ -1365,18 +1352,18 @@ ExecQual(List *qual, ExprContext *econtext)
|
||||||
IncrProcessed();
|
IncrProcessed();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* return true immediately if no qual
|
* return true immediately if no qual
|
||||||
*/
|
*/
|
||||||
if (qual == NIL)
|
if (qual == NIL)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* a "qual" is a list of clauses. To evaluate the
|
* a "qual" is a list of clauses. To evaluate the qual, we evaluate
|
||||||
* qual, we evaluate each of the clauses in the list.
|
* each of the clauses in the list.
|
||||||
*
|
*
|
||||||
* ExecQualClause returns true when we know the qualification
|
* ExecQualClause returns true when we know the qualification *failed* so
|
||||||
* *failed* so we just pass each clause in qual to it until
|
* we just pass each clause in qual to it until we know the qual
|
||||||
* we know the qual failed or there are no more clauses.
|
* failed or there are no more clauses.
|
||||||
*/
|
*/
|
||||||
result = false;
|
result = false;
|
||||||
|
|
||||||
|
@ -1388,9 +1375,9 @@ ExecQual(List *qual, ExprContext *econtext)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if result is true, then it means a clause failed so we
|
* if result is true, then it means a clause failed so we return
|
||||||
* return false. if result is false then it means no clause
|
* false. if result is false then it means no clause failed so we
|
||||||
* failed so we return true.
|
* return true.
|
||||||
*/
|
*/
|
||||||
if (result == true)
|
if (result == true)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1447,48 +1434,46 @@ ExecTargetList(List *targetlist,
|
||||||
bool isNull;
|
bool isNull;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* debugging stuff
|
* debugging stuff
|
||||||
*/
|
*/
|
||||||
EV_printf("ExecTargetList: tl is ");
|
EV_printf("ExecTargetList: tl is ");
|
||||||
EV_nodeDisplay(targetlist);
|
EV_nodeDisplay(targetlist);
|
||||||
EV_printf("\n");
|
EV_printf("\n");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return a dummy tuple if the targetlist is empty.
|
* Return a dummy tuple if the targetlist is empty. the dummy tuple is
|
||||||
* the dummy tuple is necessary to differentiate
|
* necessary to differentiate between passing and failing the
|
||||||
* between passing and failing the qualification.
|
* qualification.
|
||||||
*/
|
*/
|
||||||
if (targetlist == NIL)
|
if (targetlist == NIL)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* I now think that the only time this makes
|
* I now think that the only time this makes any sense is when we
|
||||||
* any sense is when we run a delete query. Then
|
* run a delete query. Then we need to return something other
|
||||||
* we need to return something other than nil
|
* than nil so we know to delete the tuple associated with the
|
||||||
* so we know to delete the tuple associated
|
* saved tupleid.. see what ExecutePlan does with the returned
|
||||||
* with the saved tupleid.. see what ExecutePlan
|
* tuple.. -cim 9/21/89
|
||||||
* does with the returned tuple.. -cim 9/21/89
|
|
||||||
*
|
*
|
||||||
* It could also happen in queries like:
|
* It could also happen in queries like: retrieve (foo.all) where
|
||||||
* retrieve (foo.all) where bar.a = 3
|
* bar.a = 3
|
||||||
*
|
*
|
||||||
* is this a new phenomenon? it might cause bogus behavior
|
* is this a new phenomenon? it might cause bogus behavior if we try
|
||||||
* if we try to free this tuple later!! I put a hook in
|
* to free this tuple later!! I put a hook in ExecProject to watch
|
||||||
* ExecProject to watch out for this case -mer 24 Aug 1992
|
* out for this case -mer 24 Aug 1992
|
||||||
*
|
*
|
||||||
* We must return dummy tuple!!! Try
|
* We must return dummy tuple!!! Try select t1.x from t1, t2 where
|
||||||
* select t1.x from t1, t2 where t1.y = 1 and t2.y = 1
|
* t1.y = 1 and t2.y = 1 - t2 scan target list will be empty and
|
||||||
* - t2 scan target list will be empty and so no one tuple
|
* so no one tuple will be returned! But Mer was right - dummy
|
||||||
* will be returned! But Mer was right - dummy tuple
|
* tuple must be palloced... - vadim 03/01/1999
|
||||||
* must be palloced... - vadim 03/01/1999
|
|
||||||
*/
|
*/
|
||||||
*isDone = true;
|
*isDone = true;
|
||||||
return (HeapTuple) palloc(1);
|
return (HeapTuple) palloc(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* allocate an array of char's to hold the "null" information
|
* allocate an array of char's to hold the "null" information only if
|
||||||
* only if we have a really large targetlist. otherwise we use
|
* we have a really large targetlist. otherwise we use the stack.
|
||||||
* the stack.
|
|
||||||
*/
|
*/
|
||||||
if (nodomains > 64)
|
if (nodomains > 64)
|
||||||
{
|
{
|
||||||
|
@ -1502,20 +1487,21 @@ ExecTargetList(List *targetlist,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* evaluate all the expressions in the target list
|
* evaluate all the expressions in the target list
|
||||||
*/
|
*/
|
||||||
EV_printf("ExecTargetList: setting target list values\n");
|
EV_printf("ExecTargetList: setting target list values\n");
|
||||||
|
|
||||||
*isDone = true;
|
*isDone = true;
|
||||||
foreach(tl, targetlist)
|
foreach(tl, targetlist)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* remember, a target list is a list of lists:
|
* remember, a target list is a list of lists:
|
||||||
*
|
*
|
||||||
* ((<resdom | fjoin> expr) (<resdom | fjoin> expr) ...)
|
* ((<resdom | fjoin> expr) (<resdom | fjoin> expr) ...)
|
||||||
*
|
*
|
||||||
* tl is a pointer to successive cdr's of the targetlist
|
* tl is a pointer to successive cdr's of the targetlist tle is a
|
||||||
* tle is a pointer to the target list entry in tl
|
* pointer to the target list entry in tl
|
||||||
*/
|
*/
|
||||||
tle = lfirst(tl);
|
tle = lfirst(tl);
|
||||||
|
|
||||||
|
@ -1572,7 +1558,7 @@ ExecTargetList(List *targetlist,
|
||||||
curNode < nNodes;
|
curNode < nNodes;
|
||||||
curNode++, fjTlist = lnext(fjTlist))
|
curNode++, fjTlist = lnext(fjTlist))
|
||||||
{
|
{
|
||||||
#ifdef NOT_USED /* what is this?? */
|
#ifdef NOT_USED /* what is this?? */
|
||||||
Node *outernode = lfirst(fjTlist);
|
Node *outernode = lfirst(fjTlist);
|
||||||
|
|
||||||
fjRes = (Resdom *) outernode->iterexpr;
|
fjRes = (Resdom *) outernode->iterexpr;
|
||||||
|
@ -1590,19 +1576,19 @@ ExecTargetList(List *targetlist,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* form the new result tuple (in the "normal" context)
|
* form the new result tuple (in the "normal" context)
|
||||||
*/
|
*/
|
||||||
newTuple = (HeapTuple) heap_formtuple(targettype, values, null_head);
|
newTuple = (HeapTuple) heap_formtuple(targettype, values, null_head);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free the nulls array if we allocated one..
|
* free the nulls array if we allocated one..
|
||||||
*/
|
*/
|
||||||
if (nodomains > 64)
|
if (nodomains > 64)
|
||||||
{
|
{
|
||||||
pfree(null_head);
|
pfree(null_head);
|
||||||
pfree(fjIsNull);
|
pfree(fjIsNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
return newTuple;
|
return newTuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1631,13 +1617,13 @@ ExecProject(ProjectionInfo *projInfo, bool *isDone)
|
||||||
HeapTuple newTuple;
|
HeapTuple newTuple;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
*/
|
*/
|
||||||
if (projInfo == NULL)
|
if (projInfo == NULL)
|
||||||
return (TupleTableSlot *) NULL;
|
return (TupleTableSlot *) NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get the projection info we want
|
* get the projection info we want
|
||||||
*/
|
*/
|
||||||
slot = projInfo->pi_slot;
|
slot = projInfo->pi_slot;
|
||||||
targetlist = projInfo->pi_targetlist;
|
targetlist = projInfo->pi_targetlist;
|
||||||
|
@ -1648,7 +1634,7 @@ ExecProject(ProjectionInfo *projInfo, bool *isDone)
|
||||||
econtext = projInfo->pi_exprContext;
|
econtext = projInfo->pi_exprContext;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* form a new (result) tuple
|
* form a new (result) tuple
|
||||||
*/
|
*/
|
||||||
newTuple = ExecTargetList(targetlist,
|
newTuple = ExecTargetList(targetlist,
|
||||||
len,
|
len,
|
||||||
|
@ -1658,11 +1644,10 @@ ExecProject(ProjectionInfo *projInfo, bool *isDone)
|
||||||
isDone);
|
isDone);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* store the tuple in the projection slot and return the slot.
|
* store the tuple in the projection slot and return the slot.
|
||||||
*
|
*
|
||||||
* If there's no projection target list we don't want to pfree
|
* If there's no projection target list we don't want to pfree the bogus
|
||||||
* the bogus tuple that ExecTargetList passes back to us.
|
* tuple that ExecTargetList passes back to us. -mer 24 Aug 1992
|
||||||
* -mer 24 Aug 1992
|
|
||||||
*/
|
*/
|
||||||
return (TupleTableSlot *)
|
return (TupleTableSlot *)
|
||||||
ExecStoreTuple(newTuple,/* tuple to store */
|
ExecStoreTuple(newTuple,/* tuple to store */
|
||||||
|
@ -1670,4 +1655,3 @@ ExecProject(ProjectionInfo *projInfo, bool *isDone)
|
||||||
InvalidBuffer, /* tuple has no buffer */
|
InvalidBuffer, /* tuple has no buffer */
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.24 1999/03/23 16:50:48 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.25 1999/05/25 16:08:39 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -467,6 +467,7 @@ ExecSetSlotPolicy(TupleTableSlot *slot, /* slot to change */
|
||||||
|
|
||||||
return old_shouldFree;
|
return old_shouldFree;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
|
@ -650,6 +651,7 @@ ExecInitMarkedTupleSlot(EState *estate, MergeJoinState *mergestate)
|
||||||
INIT_SLOT_ALLOC;
|
INIT_SLOT_ALLOC;
|
||||||
mergestate->mj_MarkedTupleSlot = (TupleTableSlot *) slot;
|
mergestate->mj_MarkedTupleSlot = (TupleTableSlot *) slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.44 1999/03/20 01:13:22 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.45 1999/05/25 16:08:39 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -402,7 +402,7 @@ ExecFreeExprContext(CommonState *commonstate)
|
||||||
void
|
void
|
||||||
ExecFreeTypeInfo(CommonState *commonstate)
|
ExecFreeTypeInfo(CommonState *commonstate)
|
||||||
{
|
{
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
|
|
||||||
tupDesc = commonstate->cs_ResultTupleSlot->ttc_tupleDescriptor;
|
tupDesc = commonstate->cs_ResultTupleSlot->ttc_tupleDescriptor;
|
||||||
if (tupDesc == NULL)
|
if (tupDesc == NULL)
|
||||||
|
@ -498,12 +498,12 @@ ExecAssignScanTypeFromOuterPlan(Plan *node, CommonScanState *csstate)
|
||||||
* Routines dealing with the structure 'attribute' which conatains
|
* Routines dealing with the structure 'attribute' which conatains
|
||||||
* the type information about attributes in a tuple:
|
* the type information about attributes in a tuple:
|
||||||
*
|
*
|
||||||
* ExecMakeTypeInfo(noType)
|
* ExecMakeTypeInfo(noType)
|
||||||
* returns pointer to array of 'noType' structure 'attribute'.
|
* returns pointer to array of 'noType' structure 'attribute'.
|
||||||
* ExecSetTypeInfo(index, typeInfo, attNum, attLen)
|
* ExecSetTypeInfo(index, typeInfo, attNum, attLen)
|
||||||
* sets the element indexed by 'index' in typeInfo with
|
* sets the element indexed by 'index' in typeInfo with
|
||||||
* the values: attNum, attLen.
|
* the values: attNum, attLen.
|
||||||
* ExecFreeTypeInfo(typeInfo)
|
* ExecFreeTypeInfo(typeInfo)
|
||||||
* frees the structure 'typeInfo'.
|
* frees the structure 'typeInfo'.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -677,7 +677,7 @@ ExecGetIndexKeyInfo(Form_pg_index indexTuple,
|
||||||
*/
|
*/
|
||||||
numKeys = 0;
|
numKeys = 0;
|
||||||
for (i = 0; i < INDEX_MAX_KEYS &&
|
for (i = 0; i < INDEX_MAX_KEYS &&
|
||||||
indexTuple->indkey[i] != InvalidAttrNumber; i++)
|
indexTuple->indkey[i] != InvalidAttrNumber; i++)
|
||||||
numKeys++;
|
numKeys++;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -711,7 +711,7 @@ ExecGetIndexKeyInfo(Form_pg_index indexTuple,
|
||||||
*/
|
*/
|
||||||
CXT1_printf("ExecGetIndexKeyInfo: context is %d\n", CurrentMemoryContext);
|
CXT1_printf("ExecGetIndexKeyInfo: context is %d\n", CurrentMemoryContext);
|
||||||
|
|
||||||
attKeys = (AttrNumber *)palloc(numKeys * sizeof(AttrNumber));
|
attKeys = (AttrNumber *) palloc(numKeys * sizeof(AttrNumber));
|
||||||
|
|
||||||
for (i = 0; i < numKeys; i++)
|
for (i = 0; i < numKeys; i++)
|
||||||
attKeys[i] = indexTuple->indkey[i];
|
attKeys[i] = indexTuple->indkey[i];
|
||||||
|
@ -917,19 +917,20 @@ ExecOpenIndices(Oid resultRelationOid,
|
||||||
if (indexDesc != NULL)
|
if (indexDesc != NULL)
|
||||||
{
|
{
|
||||||
relationDescs[i++] = indexDesc;
|
relationDescs[i++] = indexDesc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hack for not btree and hash indices: they use relation level
|
* Hack for not btree and hash indices: they use relation
|
||||||
* exclusive locking on updation (i.e. - they are not ready
|
* level exclusive locking on updation (i.e. - they are
|
||||||
* for MVCC) and so we have to exclusively lock indices here
|
* not ready for MVCC) and so we have to exclusively lock
|
||||||
* to prevent deadlocks if we will scan them - index_beginscan
|
* indices here to prevent deadlocks if we will scan them
|
||||||
* places AccessShareLock, indices update methods don't use
|
* - index_beginscan places AccessShareLock, indices
|
||||||
* locks at all. We release this lock in ExecCloseIndices.
|
* update methods don't use locks at all. We release this
|
||||||
* Note, that hashes use page level locking - i.e. are not
|
* lock in ExecCloseIndices. Note, that hashes use page
|
||||||
* deadlock-free, - let's them be on their way -:))
|
* level locking - i.e. are not deadlock-free, - let's
|
||||||
* vadim 03-12-1998
|
* them be on their way -:)) vadim 03-12-1998
|
||||||
*/
|
*/
|
||||||
if (indexDesc->rd_rel->relam != BTREE_AM_OID &&
|
if (indexDesc->rd_rel->relam != BTREE_AM_OID &&
|
||||||
indexDesc->rd_rel->relam != HASH_AM_OID)
|
indexDesc->rd_rel->relam != HASH_AM_OID)
|
||||||
LockRelation(indexDesc, AccessExclusiveLock);
|
LockRelation(indexDesc, AccessExclusiveLock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1014,15 +1015,17 @@ ExecCloseIndices(RelationInfo *resultRelationInfo)
|
||||||
{
|
{
|
||||||
if (relationDescs[i] == NULL)
|
if (relationDescs[i] == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Notes in ExecOpenIndices.
|
* Notes in ExecOpenIndices.
|
||||||
*/
|
*/
|
||||||
if (relationDescs[i]->rd_rel->relam != BTREE_AM_OID &&
|
if (relationDescs[i]->rd_rel->relam != BTREE_AM_OID &&
|
||||||
relationDescs[i]->rd_rel->relam != HASH_AM_OID)
|
relationDescs[i]->rd_rel->relam != HASH_AM_OID)
|
||||||
UnlockRelation(relationDescs[i], AccessExclusiveLock);
|
UnlockRelation(relationDescs[i], AccessExclusiveLock);
|
||||||
|
|
||||||
index_close(relationDescs[i]);
|
index_close(relationDescs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX should free indexInfo array here too.
|
* XXX should free indexInfo array here too.
|
||||||
*/
|
*/
|
||||||
|
@ -1210,7 +1213,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
|
||||||
result = index_insert(relationDescs[i], /* index relation */
|
result = index_insert(relationDescs[i], /* index relation */
|
||||||
datum, /* array of heaptuple Datums */
|
datum, /* array of heaptuple Datums */
|
||||||
nulls, /* info on nulls */
|
nulls, /* info on nulls */
|
||||||
&(heapTuple->t_self), /* tid of heap tuple */
|
&(heapTuple->t_self), /* tid of heap tuple */
|
||||||
heapRelation);
|
heapRelation);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.25 1999/05/13 07:28:29 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.26 1999/05/25 16:08:39 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -107,9 +107,9 @@ init_execution_state(FunctionCachePtr fcache,
|
||||||
preves = (execution_state *) NULL;
|
preves = (execution_state *) NULL;
|
||||||
|
|
||||||
planTree_list = pg_parse_and_plan(fcache->src, fcache->argOidVect,
|
planTree_list = pg_parse_and_plan(fcache->src, fcache->argOidVect,
|
||||||
nargs, &queryTree_list, None, FALSE);
|
nargs, &queryTree_list, None, FALSE);
|
||||||
|
|
||||||
foreach (qtl_item, queryTree_list)
|
foreach(qtl_item, queryTree_list)
|
||||||
{
|
{
|
||||||
Query *queryTree = lfirst(qtl_item);
|
Query *queryTree = lfirst(qtl_item);
|
||||||
Plan *planTree = lfirst(planTree_list);
|
Plan *planTree = lfirst(planTree_list);
|
||||||
|
@ -199,7 +199,7 @@ postquel_getnext(execution_state *es)
|
||||||
|
|
||||||
feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
|
feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
|
||||||
|
|
||||||
return ExecutorRun(es->qd, es->estate, feature, (Node *)NULL, (Node *)NULL);
|
return ExecutorRun(es->qd, es->estate, feature, (Node *) NULL, (Node *) NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -45,7 +45,7 @@ typedef struct AggFuncInfo
|
||||||
FmgrInfo finalfn;
|
FmgrInfo finalfn;
|
||||||
} AggFuncInfo;
|
} AggFuncInfo;
|
||||||
|
|
||||||
static Datum aggGetAttr(TupleTableSlot *tuple, Aggref *aggref, bool *isNull);
|
static Datum aggGetAttr(TupleTableSlot *tuple, Aggref * aggref, bool *isNull);
|
||||||
|
|
||||||
|
|
||||||
/* ---------------------------------------
|
/* ---------------------------------------
|
||||||
|
@ -121,7 +121,8 @@ ExecAgg(Agg *node)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We loop retrieving groups until we find one matching node->plan.qual
|
* We loop retrieving groups until we find one matching
|
||||||
|
* node->plan.qual
|
||||||
*/
|
*/
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -133,7 +134,7 @@ ExecAgg(Agg *node)
|
||||||
econtext = aggstate->csstate.cstate.cs_ExprContext;
|
econtext = aggstate->csstate.cstate.cs_ExprContext;
|
||||||
|
|
||||||
nagg = length(node->aggs);
|
nagg = length(node->aggs);
|
||||||
|
|
||||||
value1 = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_values;
|
value1 = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_values;
|
||||||
nulls = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_nulls;
|
nulls = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_nulls;
|
||||||
|
|
||||||
|
@ -163,7 +164,7 @@ ExecAgg(Agg *node)
|
||||||
finalfn_oid;
|
finalfn_oid;
|
||||||
|
|
||||||
aggref->aggno = ++aggno;
|
aggref->aggno = ++aggno;
|
||||||
|
|
||||||
/* ---------------------
|
/* ---------------------
|
||||||
* find transfer functions of all the aggregates and initialize
|
* find transfer functions of all the aggregates and initialize
|
||||||
* their initial values
|
* their initial values
|
||||||
|
@ -172,7 +173,7 @@ ExecAgg(Agg *node)
|
||||||
aggname = aggref->aggname;
|
aggname = aggref->aggname;
|
||||||
aggTuple = SearchSysCacheTuple(AGGNAME,
|
aggTuple = SearchSysCacheTuple(AGGNAME,
|
||||||
PointerGetDatum(aggname),
|
PointerGetDatum(aggname),
|
||||||
ObjectIdGetDatum(aggref->basetype),
|
ObjectIdGetDatum(aggref->basetype),
|
||||||
0, 0);
|
0, 0);
|
||||||
if (!HeapTupleIsValid(aggTuple))
|
if (!HeapTupleIsValid(aggTuple))
|
||||||
elog(ERROR, "ExecAgg: cache lookup failed for aggregate \"%s\"(%s)",
|
elog(ERROR, "ExecAgg: cache lookup failed for aggregate \"%s\"(%s)",
|
||||||
|
@ -195,9 +196,9 @@ ExecAgg(Agg *node)
|
||||||
fmgr_info(xfn2_oid, &aggFuncInfo[aggno].xfn2);
|
fmgr_info(xfn2_oid, &aggFuncInfo[aggno].xfn2);
|
||||||
aggFuncInfo[aggno].xfn2_oid = xfn2_oid;
|
aggFuncInfo[aggno].xfn2_oid = xfn2_oid;
|
||||||
value2[aggno] = (Datum) AggNameGetInitVal((char *) aggname,
|
value2[aggno] = (Datum) AggNameGetInitVal((char *) aggname,
|
||||||
aggp->aggbasetype,
|
aggp->aggbasetype,
|
||||||
2,
|
2,
|
||||||
&isNull2);
|
&isNull2);
|
||||||
/* ------------------------------------------
|
/* ------------------------------------------
|
||||||
* If there is a second transition function, its initial
|
* If there is a second transition function, its initial
|
||||||
* value must exist -- as it does not depend on data values,
|
* value must exist -- as it does not depend on data values,
|
||||||
|
@ -213,9 +214,9 @@ ExecAgg(Agg *node)
|
||||||
fmgr_info(xfn1_oid, &aggFuncInfo[aggno].xfn1);
|
fmgr_info(xfn1_oid, &aggFuncInfo[aggno].xfn1);
|
||||||
aggFuncInfo[aggno].xfn1_oid = xfn1_oid;
|
aggFuncInfo[aggno].xfn1_oid = xfn1_oid;
|
||||||
value1[aggno] = (Datum) AggNameGetInitVal((char *) aggname,
|
value1[aggno] = (Datum) AggNameGetInitVal((char *) aggname,
|
||||||
aggp->aggbasetype,
|
aggp->aggbasetype,
|
||||||
1,
|
1,
|
||||||
&isNull1);
|
&isNull1);
|
||||||
|
|
||||||
/* ------------------------------------------
|
/* ------------------------------------------
|
||||||
* If the initial value for the first transition function
|
* If the initial value for the first transition function
|
||||||
|
@ -245,6 +246,7 @@ ExecAgg(Agg *node)
|
||||||
outerslot = ExecProcNode(outerPlan, (Plan *) node);
|
outerslot = ExecProcNode(outerPlan, (Plan *) node);
|
||||||
if (TupIsNull(outerslot))
|
if (TupIsNull(outerslot))
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* when the outerplan doesn't return a single tuple,
|
* when the outerplan doesn't return a single tuple,
|
||||||
* create a dummy heaptuple anyway because we still need
|
* create a dummy heaptuple anyway because we still need
|
||||||
|
@ -299,27 +301,29 @@ ExecAgg(Agg *node)
|
||||||
{
|
{
|
||||||
if (noInitValue[aggno])
|
if (noInitValue[aggno])
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* value1 has not been initialized.
|
* value1 has not been initialized. This is the
|
||||||
* This is the first non-NULL input value.
|
* first non-NULL input value. We use it as the
|
||||||
* We use it as the initial value for value1.
|
* initial value for value1.
|
||||||
*
|
*
|
||||||
* But we can't just use it straight, we have to
|
* But we can't just use it straight, we have to make
|
||||||
* make a copy of it since the tuple from which it
|
* a copy of it since the tuple from which it came
|
||||||
* came will be freed on the next iteration of the
|
* will be freed on the next iteration of the
|
||||||
* scan. This requires finding out how to copy
|
* scan. This requires finding out how to copy
|
||||||
* the Datum. We assume the datum is of the agg's
|
* the Datum. We assume the datum is of the agg's
|
||||||
* basetype, or at least binary compatible with it.
|
* basetype, or at least binary compatible with
|
||||||
|
* it.
|
||||||
*/
|
*/
|
||||||
Type aggBaseType = typeidType(aggref->basetype);
|
Type aggBaseType = typeidType(aggref->basetype);
|
||||||
int attlen = typeLen(aggBaseType);
|
int attlen = typeLen(aggBaseType);
|
||||||
bool byVal = typeByVal(aggBaseType);
|
bool byVal = typeByVal(aggBaseType);
|
||||||
|
|
||||||
if (byVal)
|
if (byVal)
|
||||||
value1[aggno] = newVal;
|
value1[aggno] = newVal;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (attlen == -1) /* variable length */
|
if (attlen == -1) /* variable length */
|
||||||
attlen = VARSIZE((struct varlena *) newVal);
|
attlen = VARSIZE((struct varlena *) newVal);
|
||||||
value1[aggno] = (Datum) palloc(attlen);
|
value1[aggno] = (Datum) palloc(attlen);
|
||||||
memcpy((char *) (value1[aggno]), (char *) newVal,
|
memcpy((char *) (value1[aggno]), (char *) newVal,
|
||||||
|
@ -330,13 +334,14 @@ ExecAgg(Agg *node)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* apply the transition functions.
|
* apply the transition functions.
|
||||||
*/
|
*/
|
||||||
args[0] = value1[aggno];
|
args[0] = value1[aggno];
|
||||||
args[1] = newVal;
|
args[1] = newVal;
|
||||||
value1[aggno] = (Datum) fmgr_c(&aggfns->xfn1,
|
value1[aggno] = (Datum) fmgr_c(&aggfns->xfn1,
|
||||||
(FmgrValues *) args, &isNull1);
|
(FmgrValues *) args, &isNull1);
|
||||||
Assert(!isNull1);
|
Assert(!isNull1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -344,8 +349,8 @@ ExecAgg(Agg *node)
|
||||||
if (aggfns->xfn2.fn_addr != NULL)
|
if (aggfns->xfn2.fn_addr != NULL)
|
||||||
{
|
{
|
||||||
args[0] = value2[aggno];
|
args[0] = value2[aggno];
|
||||||
value2[aggno] = (Datum) fmgr_c(&aggfns->xfn2,
|
value2[aggno] = (Datum) fmgr_c(&aggfns->xfn2,
|
||||||
(FmgrValues *) args, &isNull2);
|
(FmgrValues *) args, &isNull2);
|
||||||
Assert(!isNull2);
|
Assert(!isNull2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,7 +400,7 @@ ExecAgg(Agg *node)
|
||||||
else
|
else
|
||||||
elog(NOTICE, "ExecAgg: no valid transition functions??");
|
elog(NOTICE, "ExecAgg: no valid transition functions??");
|
||||||
value1[aggno] = (Datum) fmgr_c(&aggfns->finalfn,
|
value1[aggno] = (Datum) fmgr_c(&aggfns->finalfn,
|
||||||
(FmgrValues *) args, &(nulls[aggno]));
|
(FmgrValues *) args, &(nulls[aggno]));
|
||||||
}
|
}
|
||||||
else if (aggfns->xfn1.fn_addr != NULL)
|
else if (aggfns->xfn1.fn_addr != NULL)
|
||||||
{
|
{
|
||||||
|
@ -441,10 +446,11 @@ ExecAgg(Agg *node)
|
||||||
* As long as the retrieved group does not match the
|
* As long as the retrieved group does not match the
|
||||||
* qualifications it is ignored and the next group is fetched
|
* qualifications it is ignored and the next group is fetched
|
||||||
*/
|
*/
|
||||||
if(node->plan.qual != NULL)
|
if (node->plan.qual != NULL)
|
||||||
qual_result = ExecQual(fix_opids(node->plan.qual), econtext);
|
qual_result = ExecQual(fix_opids(node->plan.qual), econtext);
|
||||||
else qual_result = false;
|
else
|
||||||
|
qual_result = false;
|
||||||
|
|
||||||
if (oneTuple)
|
if (oneTuple)
|
||||||
pfree(oneTuple);
|
pfree(oneTuple);
|
||||||
}
|
}
|
||||||
|
@ -466,7 +472,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||||
AggState *aggstate;
|
AggState *aggstate;
|
||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assign the node's execution state
|
* assign the node's execution state
|
||||||
*/
|
*/
|
||||||
|
@ -478,7 +484,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||||
aggstate = makeNode(AggState);
|
aggstate = makeNode(AggState);
|
||||||
node->aggstate = aggstate;
|
node->aggstate = aggstate;
|
||||||
aggstate->agg_done = FALSE;
|
aggstate->agg_done = FALSE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assign node's base id and create expression context
|
* assign node's base id and create expression context
|
||||||
*/
|
*/
|
||||||
|
@ -494,7 +500,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||||
ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
|
ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
|
||||||
|
|
||||||
econtext = aggstate->csstate.cstate.cs_ExprContext;
|
econtext = aggstate->csstate.cstate.cs_ExprContext;
|
||||||
econtext->ecxt_values = (Datum *) palloc(sizeof(Datum) * length(node->aggs));
|
econtext->ecxt_values = (Datum *) palloc(sizeof(Datum) * length(node->aggs));
|
||||||
MemSet(econtext->ecxt_values, 0, sizeof(Datum) * length(node->aggs));
|
MemSet(econtext->ecxt_values, 0, sizeof(Datum) * length(node->aggs));
|
||||||
econtext->ecxt_nulls = (char *) palloc(sizeof(char) * length(node->aggs));
|
econtext->ecxt_nulls = (char *) palloc(sizeof(char) * length(node->aggs));
|
||||||
MemSet(econtext->ecxt_nulls, 0, sizeof(char) * length(node->aggs));
|
MemSet(econtext->ecxt_nulls, 0, sizeof(char) * length(node->aggs));
|
||||||
|
@ -538,8 +544,8 @@ int
|
||||||
ExecCountSlotsAgg(Agg *node)
|
ExecCountSlotsAgg(Agg *node)
|
||||||
{
|
{
|
||||||
return ExecCountSlotsNode(outerPlan(node)) +
|
return ExecCountSlotsNode(outerPlan(node)) +
|
||||||
ExecCountSlotsNode(innerPlan(node)) +
|
ExecCountSlotsNode(innerPlan(node)) +
|
||||||
AGG_NSLOTS;
|
AGG_NSLOTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------
|
/* ------------------------
|
||||||
|
@ -576,7 +582,7 @@ ExecEndAgg(Agg *node)
|
||||||
*/
|
*/
|
||||||
static Datum
|
static Datum
|
||||||
aggGetAttr(TupleTableSlot *slot,
|
aggGetAttr(TupleTableSlot *slot,
|
||||||
Aggref *aggref,
|
Aggref * aggref,
|
||||||
bool *isNull)
|
bool *isNull)
|
||||||
{
|
{
|
||||||
Datum result;
|
Datum result;
|
||||||
|
@ -622,10 +628,11 @@ aggGetAttr(TupleTableSlot *slot,
|
||||||
return (Datum) tempSlot;
|
return (Datum) tempSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = heap_getattr(heapTuple, /* tuple containing attribute */
|
result = heap_getattr(heapTuple, /* tuple containing attribute */
|
||||||
attnum, /* attribute number of desired attribute */
|
attnum, /* attribute number of desired
|
||||||
tuple_type,/* tuple descriptor of tuple */
|
* attribute */
|
||||||
isNull); /* return: is attribute null? */
|
tuple_type, /* tuple descriptor of tuple */
|
||||||
|
isNull); /* return: is attribute null? */
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* return null if att is null
|
* return null if att is null
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.18 1999/02/21 03:48:40 scrappy Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.19 1999/05/25 16:08:40 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -151,7 +151,7 @@ exec_append_initialize_next(Append *node)
|
||||||
if (appendstate->as_junkFilter_list)
|
if (appendstate->as_junkFilter_list)
|
||||||
{
|
{
|
||||||
estate->es_junkFilter = (JunkFilter *) nth(whichplan,
|
estate->es_junkFilter = (JunkFilter *) nth(whichplan,
|
||||||
appendstate->as_junkFilter_list);
|
appendstate->as_junkFilter_list);
|
||||||
}
|
}
|
||||||
if (appendstate->as_result_relation_info_list)
|
if (appendstate->as_result_relation_info_list)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* columns. (ie. tuples from the same group are consecutive)
|
* columns. (ie. tuples from the same group are consecutive)
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.25 1999/02/13 23:15:21 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.26 1999/05/25 16:08:41 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -193,8 +193,8 @@ ExecGroupOneTuple(Group *node)
|
||||||
grpstate->grp_done = TRUE;
|
grpstate->grp_done = TRUE;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
grpstate->grp_firstTuple = firsttuple =
|
grpstate->grp_firstTuple = firsttuple =
|
||||||
heap_copytuple(outerslot->val);
|
heap_copytuple(outerslot->val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* $Id: nodeHash.c,v 1.35 1999/05/18 21:33:06 tgl Exp $
|
* $Id: nodeHash.c,v 1.36 1999/05/25 16:08:41 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -80,7 +80,8 @@ ExecHash(Hash *node)
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < nbatch; i++)
|
for (i = 0; i < nbatch; i++)
|
||||||
{
|
{
|
||||||
File tfile = OpenTemporaryFile();
|
File tfile = OpenTemporaryFile();
|
||||||
|
|
||||||
Assert(tfile >= 0);
|
Assert(tfile >= 0);
|
||||||
hashtable->innerBatchFile[i] = BufFileCreate(tfile);
|
hashtable->innerBatchFile[i] = BufFileCreate(tfile);
|
||||||
}
|
}
|
||||||
|
@ -247,30 +248,33 @@ ExecHashTableCreate(Hash *node)
|
||||||
int i;
|
int i;
|
||||||
Portal myPortal;
|
Portal myPortal;
|
||||||
char myPortalName[64];
|
char myPortalName[64];
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Get information about the size of the relation to be hashed
|
* Get information about the size of the relation to be hashed
|
||||||
* (it's the "outer" subtree of this node, but the inner relation of
|
* (it's the "outer" subtree of this node, but the inner relation of
|
||||||
* the hashjoin).
|
* the hashjoin).
|
||||||
* Caution: this is only the planner's estimates, and so
|
* Caution: this is only the planner's estimates, and so
|
||||||
* can't be trusted too far. Apply a healthy fudge factor.
|
* can't be trusted too far. Apply a healthy fudge factor.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
outerNode = outerPlan(node);
|
outerNode = outerPlan(node);
|
||||||
ntuples = outerNode->plan_size;
|
ntuples = outerNode->plan_size;
|
||||||
if (ntuples <= 0) /* force a plausible size if no info */
|
if (ntuples <= 0) /* force a plausible size if no info */
|
||||||
ntuples = 1000;
|
ntuples = 1000;
|
||||||
/* estimate tupsize based on footprint of tuple in hashtable...
|
|
||||||
* but what about palloc overhead?
|
/*
|
||||||
|
* estimate tupsize based on footprint of tuple in hashtable... but
|
||||||
|
* what about palloc overhead?
|
||||||
*/
|
*/
|
||||||
tupsize = MAXALIGN(outerNode->plan_width) +
|
tupsize = MAXALIGN(outerNode->plan_width) +
|
||||||
MAXALIGN(sizeof(HashJoinTupleData));
|
MAXALIGN(sizeof(HashJoinTupleData));
|
||||||
inner_rel_bytes = (double) ntuples * tupsize * FUDGE_FAC;
|
inner_rel_bytes = (double) ntuples *tupsize * FUDGE_FAC;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Target hashtable size is SortMem kilobytes, but not less than
|
* Target hashtable size is SortMem kilobytes, but not less than
|
||||||
* sqrt(estimated inner rel size), so as to avoid horrible performance.
|
* sqrt(estimated inner rel size), so as to avoid horrible
|
||||||
|
* performance.
|
||||||
*/
|
*/
|
||||||
hash_table_bytes = sqrt(inner_rel_bytes);
|
hash_table_bytes = sqrt(inner_rel_bytes);
|
||||||
if (hash_table_bytes < (SortMem * 1024L))
|
if (hash_table_bytes < (SortMem * 1024L))
|
||||||
|
@ -278,17 +282,19 @@ ExecHashTableCreate(Hash *node)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Count the number of hash buckets we want for the whole relation,
|
* Count the number of hash buckets we want for the whole relation,
|
||||||
* for an average bucket load of NTUP_PER_BUCKET (per virtual bucket!).
|
* for an average bucket load of NTUP_PER_BUCKET (per virtual
|
||||||
|
* bucket!).
|
||||||
*/
|
*/
|
||||||
totalbuckets = (int) ceil((double) ntuples * FUDGE_FAC / NTUP_PER_BUCKET);
|
totalbuckets = (int) ceil((double) ntuples * FUDGE_FAC / NTUP_PER_BUCKET);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Count the number of buckets we think will actually fit in the
|
* Count the number of buckets we think will actually fit in the
|
||||||
* target memory size, at a loading of NTUP_PER_BUCKET (physical buckets).
|
* target memory size, at a loading of NTUP_PER_BUCKET (physical
|
||||||
* NOTE: FUDGE_FAC here determines the fraction of the hashtable space
|
* buckets). NOTE: FUDGE_FAC here determines the fraction of the
|
||||||
* reserved to allow for nonuniform distribution of hash values.
|
* hashtable space reserved to allow for nonuniform distribution of
|
||||||
* Perhaps this should be a different number from the other uses of
|
* hash values. Perhaps this should be a different number from the
|
||||||
* FUDGE_FAC, but since we have no real good way to pick either one...
|
* other uses of FUDGE_FAC, but since we have no real good way to pick
|
||||||
|
* either one...
|
||||||
*/
|
*/
|
||||||
bucketsize = NTUP_PER_BUCKET * tupsize;
|
bucketsize = NTUP_PER_BUCKET * tupsize;
|
||||||
nbuckets = (int) (hash_table_bytes / (bucketsize * FUDGE_FAC));
|
nbuckets = (int) (hash_table_bytes / (bucketsize * FUDGE_FAC));
|
||||||
|
@ -297,21 +303,25 @@ ExecHashTableCreate(Hash *node)
|
||||||
|
|
||||||
if (totalbuckets <= nbuckets)
|
if (totalbuckets <= nbuckets)
|
||||||
{
|
{
|
||||||
/* We have enough space, so no batching. In theory we could
|
|
||||||
* even reduce nbuckets, but since that could lead to poor
|
/*
|
||||||
* behavior if estimated ntuples is much less than reality,
|
* We have enough space, so no batching. In theory we could even
|
||||||
* it seems better to make more buckets instead of fewer.
|
* reduce nbuckets, but since that could lead to poor behavior if
|
||||||
|
* estimated ntuples is much less than reality, it seems better to
|
||||||
|
* make more buckets instead of fewer.
|
||||||
*/
|
*/
|
||||||
totalbuckets = nbuckets;
|
totalbuckets = nbuckets;
|
||||||
nbatch = 0;
|
nbatch = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Need to batch; compute how many batches we want to use.
|
|
||||||
* Note that nbatch doesn't have to have anything to do with
|
/*
|
||||||
* the ratio totalbuckets/nbuckets; in fact, it is the number
|
* Need to batch; compute how many batches we want to use. Note
|
||||||
* of groups we will use for the part of the data that doesn't
|
* that nbatch doesn't have to have anything to do with the ratio
|
||||||
* fall into the first nbuckets hash buckets.
|
* totalbuckets/nbuckets; in fact, it is the number of groups we
|
||||||
|
* will use for the part of the data that doesn't fall into the
|
||||||
|
* first nbuckets hash buckets.
|
||||||
*/
|
*/
|
||||||
nbatch = (int) ceil((inner_rel_bytes - hash_table_bytes) /
|
nbatch = (int) ceil((inner_rel_bytes - hash_table_bytes) /
|
||||||
hash_table_bytes);
|
hash_table_bytes);
|
||||||
|
@ -319,16 +329,17 @@ ExecHashTableCreate(Hash *node)
|
||||||
nbatch = 1;
|
nbatch = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now, totalbuckets is the number of (virtual) hashbuckets for the
|
/*
|
||||||
|
* Now, totalbuckets is the number of (virtual) hashbuckets for the
|
||||||
* whole relation, and nbuckets is the number of physical hashbuckets
|
* whole relation, and nbuckets is the number of physical hashbuckets
|
||||||
* we will use in the first pass. Data falling into the first nbuckets
|
* we will use in the first pass. Data falling into the first
|
||||||
* virtual hashbuckets gets handled in the first pass; everything else
|
* nbuckets virtual hashbuckets gets handled in the first pass;
|
||||||
* gets divided into nbatch batches to be processed in additional
|
* everything else gets divided into nbatch batches to be processed in
|
||||||
* passes.
|
* additional passes.
|
||||||
*/
|
*/
|
||||||
#ifdef HJDEBUG
|
#ifdef HJDEBUG
|
||||||
printf("nbatch = %d, totalbuckets = %d, nbuckets = %d\n",
|
printf("nbatch = %d, totalbuckets = %d, nbuckets = %d\n",
|
||||||
nbatch, totalbuckets, nbuckets);
|
nbatch, totalbuckets, nbuckets);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -353,14 +364,16 @@ ExecHashTableCreate(Hash *node)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
i = 0;
|
i = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
i++;
|
i++;
|
||||||
sprintf(myPortalName, "<hashtable %d>", i);
|
sprintf(myPortalName, "<hashtable %d>", i);
|
||||||
myPortal = GetPortalByName(myPortalName);
|
myPortal = GetPortalByName(myPortalName);
|
||||||
} while (PortalIsValid(myPortal));
|
} while (PortalIsValid(myPortal));
|
||||||
myPortal = CreatePortal(myPortalName);
|
myPortal = CreatePortal(myPortalName);
|
||||||
Assert(PortalIsValid(myPortal));
|
Assert(PortalIsValid(myPortal));
|
||||||
hashtable->myPortal = (void*) myPortal; /* kluge for circular includes */
|
hashtable->myPortal = (void *) myPortal; /* kluge for circular
|
||||||
|
* includes */
|
||||||
hashtable->hashCxt = (MemoryContext) PortalGetVariableMemory(myPortal);
|
hashtable->hashCxt = (MemoryContext) PortalGetVariableMemory(myPortal);
|
||||||
hashtable->batchCxt = (MemoryContext) PortalGetHeapMemory(myPortal);
|
hashtable->batchCxt = (MemoryContext) PortalGetHeapMemory(myPortal);
|
||||||
|
|
||||||
|
@ -392,8 +405,9 @@ ExecHashTableCreate(Hash *node)
|
||||||
/* The files will not be opened until later... */
|
/* The files will not be opened until later... */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare portal for the first-scan space allocations;
|
/*
|
||||||
* allocate the hashbucket array therein, and set each bucket "empty".
|
* Prepare portal for the first-scan space allocations; allocate the
|
||||||
|
* hashbucket array therein, and set each bucket "empty".
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(hashtable->batchCxt);
|
MemoryContextSwitchTo(hashtable->batchCxt);
|
||||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||||
|
@ -405,9 +419,7 @@ ExecHashTableCreate(Hash *node)
|
||||||
elog(ERROR, "Insufficient memory for hash table.");
|
elog(ERROR, "Insufficient memory for hash table.");
|
||||||
|
|
||||||
for (i = 0; i < nbuckets; i++)
|
for (i = 0; i < nbuckets; i++)
|
||||||
{
|
|
||||||
hashtable->buckets[i] = NULL;
|
hashtable->buckets[i] = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
|
||||||
|
@ -436,7 +448,7 @@ ExecHashTableDestroy(HashJoinTable hashtable)
|
||||||
|
|
||||||
/* Destroy the portal to release all working memory */
|
/* Destroy the portal to release all working memory */
|
||||||
/* cast here is a kluge for circular includes... */
|
/* cast here is a kluge for circular includes... */
|
||||||
PortalDestroy((Portal*) & hashtable->myPortal);
|
PortalDestroy((Portal *) &hashtable->myPortal);
|
||||||
|
|
||||||
/* And drop the control block */
|
/* And drop the control block */
|
||||||
pfree(hashtable);
|
pfree(hashtable);
|
||||||
|
@ -468,15 +480,15 @@ ExecHashTableInsert(HashJoinTable hashtable,
|
||||||
* put the tuple in hash table
|
* put the tuple in hash table
|
||||||
* ---------------
|
* ---------------
|
||||||
*/
|
*/
|
||||||
HashJoinTuple hashTuple;
|
HashJoinTuple hashTuple;
|
||||||
int hashTupleSize;
|
int hashTupleSize;
|
||||||
|
|
||||||
hashTupleSize = MAXALIGN(sizeof(*hashTuple)) + heapTuple->t_len;
|
hashTupleSize = MAXALIGN(sizeof(*hashTuple)) + heapTuple->t_len;
|
||||||
hashTuple = (HashJoinTuple) MemoryContextAlloc(hashtable->batchCxt,
|
hashTuple = (HashJoinTuple) MemoryContextAlloc(hashtable->batchCxt,
|
||||||
hashTupleSize);
|
hashTupleSize);
|
||||||
if (hashTuple == NULL)
|
if (hashTuple == NULL)
|
||||||
elog(ERROR, "Insufficient memory for hash table.");
|
elog(ERROR, "Insufficient memory for hash table.");
|
||||||
memcpy((char *) & hashTuple->htup,
|
memcpy((char *) &hashTuple->htup,
|
||||||
(char *) heapTuple,
|
(char *) heapTuple,
|
||||||
sizeof(hashTuple->htup));
|
sizeof(hashTuple->htup));
|
||||||
hashTuple->htup.t_data = (HeapTupleHeader)
|
hashTuple->htup.t_data = (HeapTupleHeader)
|
||||||
|
@ -493,8 +505,9 @@ ExecHashTableInsert(HashJoinTable hashtable,
|
||||||
* put the tuple into a tmp file for other batches
|
* put the tuple into a tmp file for other batches
|
||||||
* -----------------
|
* -----------------
|
||||||
*/
|
*/
|
||||||
int batchno = (hashtable->nbatch * (bucketno - hashtable->nbuckets)) /
|
int batchno = (hashtable->nbatch * (bucketno - hashtable->nbuckets)) /
|
||||||
(hashtable->totalbuckets - hashtable->nbuckets);
|
(hashtable->totalbuckets - hashtable->nbuckets);
|
||||||
|
|
||||||
hashtable->innerBatchSize[batchno]++;
|
hashtable->innerBatchSize[batchno]++;
|
||||||
ExecHashJoinSaveTuple(heapTuple,
|
ExecHashJoinSaveTuple(heapTuple,
|
||||||
hashtable->innerBatchFile[batchno]);
|
hashtable->innerBatchFile[batchno]);
|
||||||
|
@ -563,26 +576,23 @@ ExecScanHashBucket(HashJoinState *hjstate,
|
||||||
List *hjclauses,
|
List *hjclauses,
|
||||||
ExprContext *econtext)
|
ExprContext *econtext)
|
||||||
{
|
{
|
||||||
HashJoinTable hashtable = hjstate->hj_HashTable;
|
HashJoinTable hashtable = hjstate->hj_HashTable;
|
||||||
HashJoinTuple hashTuple = hjstate->hj_CurTuple;
|
HashJoinTuple hashTuple = hjstate->hj_CurTuple;
|
||||||
|
|
||||||
/* hj_CurTuple is NULL to start scanning a new bucket, or the address
|
/*
|
||||||
|
* hj_CurTuple is NULL to start scanning a new bucket, or the address
|
||||||
* of the last tuple returned from the current bucket.
|
* of the last tuple returned from the current bucket.
|
||||||
*/
|
*/
|
||||||
if (hashTuple == NULL)
|
if (hashTuple == NULL)
|
||||||
{
|
|
||||||
hashTuple = hashtable->buckets[hjstate->hj_CurBucketNo];
|
hashTuple = hashtable->buckets[hjstate->hj_CurBucketNo];
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
hashTuple = hashTuple->next;
|
hashTuple = hashTuple->next;
|
||||||
}
|
|
||||||
|
|
||||||
while (hashTuple != NULL)
|
while (hashTuple != NULL)
|
||||||
{
|
{
|
||||||
HeapTuple heapTuple = & hashTuple->htup;
|
HeapTuple heapTuple = &hashTuple->htup;
|
||||||
TupleTableSlot *inntuple;
|
TupleTableSlot *inntuple;
|
||||||
bool qualResult;
|
bool qualResult;
|
||||||
|
|
||||||
/* insert hashtable's tuple into exec slot so ExecQual sees it */
|
/* insert hashtable's tuple into exec slot so ExecQual sees it */
|
||||||
inntuple = ExecStoreTuple(heapTuple, /* tuple to store */
|
inntuple = ExecStoreTuple(heapTuple, /* tuple to store */
|
||||||
|
@ -618,28 +628,34 @@ ExecScanHashBucket(HashJoinState *hjstate,
|
||||||
static int
|
static int
|
||||||
hashFunc(Datum key, int len, bool byVal)
|
hashFunc(Datum key, int len, bool byVal)
|
||||||
{
|
{
|
||||||
unsigned int h = 0;
|
unsigned int h = 0;
|
||||||
unsigned char *k;
|
unsigned char *k;
|
||||||
|
|
||||||
|
if (byVal)
|
||||||
|
{
|
||||||
|
|
||||||
if (byVal) {
|
|
||||||
/*
|
/*
|
||||||
* If it's a by-value data type, use the 'len' least significant bytes
|
* If it's a by-value data type, use the 'len' least significant
|
||||||
* of the Datum value. This should do the right thing on either
|
* bytes of the Datum value. This should do the right thing on
|
||||||
* bigendian or littleendian hardware --- see the Datum access
|
* either bigendian or littleendian hardware --- see the Datum
|
||||||
* macros in c.h.
|
* access macros in c.h.
|
||||||
*/
|
*/
|
||||||
while (len-- > 0) {
|
while (len-- > 0)
|
||||||
|
{
|
||||||
h = (h * PRIME1) ^ (key & 0xFF);
|
h = (h * PRIME1) ^ (key & 0xFF);
|
||||||
key >>= 8;
|
key >>= 8;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is a variable length type, then 'k' points to a "struct
|
* If this is a variable length type, then 'k' points to a "struct
|
||||||
* varlena" and len == -1. NOTE: VARSIZE returns the "real" data
|
* varlena" and len == -1. NOTE: VARSIZE returns the "real" data
|
||||||
* length plus the sizeof the "vl_len" attribute of varlena (the
|
* length plus the sizeof the "vl_len" attribute of varlena (the
|
||||||
* length information). 'k' points to the beginning of the varlena
|
* length information). 'k' points to the beginning of the varlena
|
||||||
* struct, so we have to use "VARDATA" to find the beginning of the
|
* struct, so we have to use "VARDATA" to find the beginning of
|
||||||
* "real" data.
|
* the "real" data.
|
||||||
*/
|
*/
|
||||||
if (len == -1)
|
if (len == -1)
|
||||||
{
|
{
|
||||||
|
@ -647,9 +663,7 @@ hashFunc(Datum key, int len, bool byVal)
|
||||||
k = (unsigned char *) VARDATA(key);
|
k = (unsigned char *) VARDATA(key);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
k = (unsigned char *) key;
|
k = (unsigned char *) key;
|
||||||
}
|
|
||||||
while (len-- > 0)
|
while (len-- > 0)
|
||||||
h = (h * PRIME1) ^ (*k++);
|
h = (h * PRIME1) ^ (*k++);
|
||||||
}
|
}
|
||||||
|
@ -669,7 +683,7 @@ hashFunc(Datum key, int len, bool byVal)
|
||||||
void
|
void
|
||||||
ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
||||||
{
|
{
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
int nbuckets = hashtable->nbuckets;
|
int nbuckets = hashtable->nbuckets;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -682,13 +696,14 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
||||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We still use the same number of physical buckets as in the first pass.
|
* We still use the same number of physical buckets as in the first
|
||||||
* (It could be different; but we already decided how many buckets would
|
* pass. (It could be different; but we already decided how many
|
||||||
* be appropriate for the allowed memory, so stick with that number.)
|
* buckets would be appropriate for the allowed memory, so stick with
|
||||||
* We MUST set totalbuckets to equal nbuckets, because from now on
|
* that number.) We MUST set totalbuckets to equal nbuckets, because
|
||||||
* no tuples will go out to temp files; there are no more virtual buckets,
|
* from now on no tuples will go out to temp files; there are no more
|
||||||
* only real buckets. (This implies that tuples will go into different
|
* virtual buckets, only real buckets. (This implies that tuples will
|
||||||
* bucket numbers than they did on the first pass, but that's OK.)
|
* go into different bucket numbers than they did on the first pass,
|
||||||
|
* but that's OK.)
|
||||||
*/
|
*/
|
||||||
hashtable->totalbuckets = nbuckets;
|
hashtable->totalbuckets = nbuckets;
|
||||||
|
|
||||||
|
@ -700,9 +715,7 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
||||||
elog(ERROR, "Insufficient memory for hash table.");
|
elog(ERROR, "Insufficient memory for hash table.");
|
||||||
|
|
||||||
for (i = 0; i < nbuckets; i++)
|
for (i = 0; i < nbuckets; i++)
|
||||||
{
|
|
||||||
hashtable->buckets[i] = NULL;
|
hashtable->buckets[i] = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
}
|
}
|
||||||
|
@ -710,6 +723,7 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
||||||
void
|
void
|
||||||
ExecReScanHash(Hash *node, ExprContext *exprCtxt, Plan *parent)
|
ExecReScanHash(Hash *node, ExprContext *exprCtxt, Plan *parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||||
* first ExecProcNode.
|
* first ExecProcNode.
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.20 1999/05/18 21:33:06 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.21 1999/05/25 16:08:42 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -23,10 +23,10 @@
|
||||||
#include "optimizer/clauses.h" /* for get_leftop */
|
#include "optimizer/clauses.h" /* for get_leftop */
|
||||||
|
|
||||||
static TupleTableSlot *ExecHashJoinOuterGetTuple(Plan *node, Plan *parent,
|
static TupleTableSlot *ExecHashJoinOuterGetTuple(Plan *node, Plan *parent,
|
||||||
HashJoinState *hjstate);
|
HashJoinState *hjstate);
|
||||||
static TupleTableSlot *ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
|
static TupleTableSlot *ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
|
||||||
BufFile *file,
|
BufFile * file,
|
||||||
TupleTableSlot *tupleSlot);
|
TupleTableSlot *tupleSlot);
|
||||||
static int ExecHashJoinGetBatch(int bucketno, HashJoinTable hashtable);
|
static int ExecHashJoinGetBatch(int bucketno, HashJoinTable hashtable);
|
||||||
static int ExecHashJoinNewBatch(HashJoinState *hjstate);
|
static int ExecHashJoinNewBatch(HashJoinState *hjstate);
|
||||||
|
|
||||||
|
@ -132,7 +132,8 @@ ExecHashJoin(HashJoin *node)
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < hashtable->nbatch; i++)
|
for (i = 0; i < hashtable->nbatch; i++)
|
||||||
{
|
{
|
||||||
File tfile = OpenTemporaryFile();
|
File tfile = OpenTemporaryFile();
|
||||||
|
|
||||||
Assert(tfile >= 0);
|
Assert(tfile >= 0);
|
||||||
hashtable->outerBatchFile[i] = BufFileCreate(tfile);
|
hashtable->outerBatchFile[i] = BufFileCreate(tfile);
|
||||||
}
|
}
|
||||||
|
@ -149,6 +150,7 @@ ExecHashJoin(HashJoin *node)
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the current outer tuple is nil, get a new one
|
* if the current outer tuple is nil, get a new one
|
||||||
*/
|
*/
|
||||||
|
@ -159,6 +161,7 @@ ExecHashJoin(HashJoin *node)
|
||||||
hjstate);
|
hjstate);
|
||||||
if (TupIsNull(outerTupleSlot))
|
if (TupIsNull(outerTupleSlot))
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* when the last batch runs out, clean up and exit
|
* when the last batch runs out, clean up and exit
|
||||||
*/
|
*/
|
||||||
|
@ -168,8 +171,8 @@ ExecHashJoin(HashJoin *node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* now we have an outer tuple, find the corresponding bucket for
|
* now we have an outer tuple, find the corresponding bucket
|
||||||
* this tuple from the hash table
|
* for this tuple from the hash table
|
||||||
*/
|
*/
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
hjstate->hj_CurBucketNo = ExecHashGetBucket(hashtable, econtext,
|
hjstate->hj_CurBucketNo = ExecHashGetBucket(hashtable, econtext,
|
||||||
|
@ -184,20 +187,23 @@ ExecHashJoin(HashJoin *node)
|
||||||
*/
|
*/
|
||||||
if (hashtable->curbatch == 0)
|
if (hashtable->curbatch == 0)
|
||||||
{
|
{
|
||||||
int batch = ExecHashJoinGetBatch(hjstate->hj_CurBucketNo,
|
int batch = ExecHashJoinGetBatch(hjstate->hj_CurBucketNo,
|
||||||
hashtable);
|
hashtable);
|
||||||
|
|
||||||
if (batch > 0)
|
if (batch > 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need to postpone this outer tuple to a later batch.
|
* Need to postpone this outer tuple to a later batch.
|
||||||
* Save it in the corresponding outer-batch file.
|
* Save it in the corresponding outer-batch file.
|
||||||
*/
|
*/
|
||||||
int batchno = batch - 1;
|
int batchno = batch - 1;
|
||||||
|
|
||||||
hashtable->outerBatchSize[batchno]++;
|
hashtable->outerBatchSize[batchno]++;
|
||||||
ExecHashJoinSaveTuple(outerTupleSlot->val,
|
ExecHashJoinSaveTuple(outerTupleSlot->val,
|
||||||
hashtable->outerBatchFile[batchno]);
|
hashtable->outerBatchFile[batchno]);
|
||||||
ExecClearTuple(outerTupleSlot);
|
ExecClearTuple(outerTupleSlot);
|
||||||
continue; /* loop around for a new outer tuple */
|
continue; /* loop around for a new outer tuple */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,6 +218,7 @@ ExecHashJoin(HashJoin *node)
|
||||||
econtext);
|
econtext);
|
||||||
if (curtuple == NULL)
|
if (curtuple == NULL)
|
||||||
break; /* out of matches */
|
break; /* out of matches */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we've got a match, but still need to test qpqual
|
* we've got a match, but still need to test qpqual
|
||||||
*/
|
*/
|
||||||
|
@ -427,32 +434,33 @@ ExecEndHashJoin(HashJoin *node)
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
ExecHashJoinOuterGetTuple(Plan *node, Plan *parent, HashJoinState *hjstate)
|
ExecHashJoinOuterGetTuple(Plan *node, Plan *parent, HashJoinState *hjstate)
|
||||||
{
|
{
|
||||||
HashJoinTable hashtable = hjstate->hj_HashTable;
|
HashJoinTable hashtable = hjstate->hj_HashTable;
|
||||||
int curbatch = hashtable->curbatch;
|
int curbatch = hashtable->curbatch;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
|
|
||||||
if (curbatch == 0)
|
if (curbatch == 0)
|
||||||
{ /* if it is the first pass */
|
{ /* if it is the first pass */
|
||||||
slot = ExecProcNode(node, parent);
|
slot = ExecProcNode(node, parent);
|
||||||
if (! TupIsNull(slot))
|
if (!TupIsNull(slot))
|
||||||
return slot;
|
return slot;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have just reached the end of the first pass.
|
* We have just reached the end of the first pass. Try to switch
|
||||||
* Try to switch to a saved batch.
|
* to a saved batch.
|
||||||
*/
|
*/
|
||||||
curbatch = ExecHashJoinNewBatch(hjstate);
|
curbatch = ExecHashJoinNewBatch(hjstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to read from a temp file.
|
* Try to read from a temp file. Loop allows us to advance to new
|
||||||
* Loop allows us to advance to new batch as needed.
|
* batch as needed.
|
||||||
*/
|
*/
|
||||||
while (curbatch <= hashtable->nbatch)
|
while (curbatch <= hashtable->nbatch)
|
||||||
{
|
{
|
||||||
slot = ExecHashJoinGetSavedTuple(hjstate,
|
slot = ExecHashJoinGetSavedTuple(hjstate,
|
||||||
hashtable->outerBatchFile[curbatch-1],
|
hashtable->outerBatchFile[curbatch - 1],
|
||||||
hjstate->hj_OuterTupleSlot);
|
hjstate->hj_OuterTupleSlot);
|
||||||
if (! TupIsNull(slot))
|
if (!TupIsNull(slot))
|
||||||
return slot;
|
return slot;
|
||||||
curbatch = ExecHashJoinNewBatch(hjstate);
|
curbatch = ExecHashJoinNewBatch(hjstate);
|
||||||
}
|
}
|
||||||
|
@ -470,12 +478,12 @@ ExecHashJoinOuterGetTuple(Plan *node, Plan *parent, HashJoinState *hjstate)
|
||||||
|
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
|
ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
|
||||||
BufFile *file,
|
BufFile * file,
|
||||||
TupleTableSlot *tupleSlot)
|
TupleTableSlot *tupleSlot)
|
||||||
{
|
{
|
||||||
HeapTupleData htup;
|
HeapTupleData htup;
|
||||||
size_t nread;
|
size_t nread;
|
||||||
HeapTuple heapTuple;
|
HeapTuple heapTuple;
|
||||||
|
|
||||||
nread = BufFileRead(file, (void *) &htup, sizeof(HeapTupleData));
|
nread = BufFileRead(file, (void *) &htup, sizeof(HeapTupleData));
|
||||||
if (nread == 0)
|
if (nread == 0)
|
||||||
|
@ -484,8 +492,8 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
|
||||||
elog(ERROR, "Read from hashjoin temp file failed");
|
elog(ERROR, "Read from hashjoin temp file failed");
|
||||||
heapTuple = palloc(HEAPTUPLESIZE + htup.t_len);
|
heapTuple = palloc(HEAPTUPLESIZE + htup.t_len);
|
||||||
memcpy((char *) heapTuple, (char *) &htup, sizeof(HeapTupleData));
|
memcpy((char *) heapTuple, (char *) &htup, sizeof(HeapTupleData));
|
||||||
heapTuple->t_data = (HeapTupleHeader)
|
heapTuple->t_data = (HeapTupleHeader)
|
||||||
((char *) heapTuple + HEAPTUPLESIZE);
|
((char *) heapTuple + HEAPTUPLESIZE);
|
||||||
nread = BufFileRead(file, (void *) heapTuple->t_data, htup.t_len);
|
nread = BufFileRead(file, (void *) heapTuple->t_data, htup.t_len);
|
||||||
if (nread != (size_t) htup.t_len)
|
if (nread != (size_t) htup.t_len)
|
||||||
elog(ERROR, "Read from hashjoin temp file failed");
|
elog(ERROR, "Read from hashjoin temp file failed");
|
||||||
|
@ -506,16 +514,17 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
|
||||||
int newbatch = hashtable->curbatch + 1;
|
int newbatch = hashtable->curbatch + 1;
|
||||||
long *innerBatchSize = hashtable->innerBatchSize;
|
long *innerBatchSize = hashtable->innerBatchSize;
|
||||||
long *outerBatchSize = hashtable->outerBatchSize;
|
long *outerBatchSize = hashtable->outerBatchSize;
|
||||||
BufFile *innerFile;
|
BufFile *innerFile;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
Var *innerhashkey;
|
Var *innerhashkey;
|
||||||
|
|
||||||
if (newbatch > 1)
|
if (newbatch > 1)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We no longer need the previous outer batch file;
|
* We no longer need the previous outer batch file; close it right
|
||||||
* close it right away to free disk space.
|
* away to free disk space.
|
||||||
*/
|
*/
|
||||||
BufFileClose(hashtable->outerBatchFile[newbatch - 2]);
|
BufFileClose(hashtable->outerBatchFile[newbatch - 2]);
|
||||||
hashtable->outerBatchFile[newbatch - 2] = NULL;
|
hashtable->outerBatchFile[newbatch - 2] = NULL;
|
||||||
|
@ -541,8 +550,8 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
|
||||||
return newbatch; /* no more batches */
|
return newbatch; /* no more batches */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Rewind inner and outer batch files for this batch,
|
* Rewind inner and outer batch files for this batch, so that we can
|
||||||
* so that we can start reading them.
|
* start reading them.
|
||||||
*/
|
*/
|
||||||
if (BufFileSeek(hashtable->outerBatchFile[newbatch - 1], 0L,
|
if (BufFileSeek(hashtable->outerBatchFile[newbatch - 1], 0L,
|
||||||
SEEK_SET) != 0L)
|
SEEK_SET) != 0L)
|
||||||
|
@ -571,7 +580,8 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* after we build the hash table, the inner batch file is no longer needed
|
* after we build the hash table, the inner batch file is no longer
|
||||||
|
* needed
|
||||||
*/
|
*/
|
||||||
BufFileClose(innerFile);
|
BufFileClose(innerFile);
|
||||||
hashtable->innerBatchFile[newbatch - 1] = NULL;
|
hashtable->innerBatchFile[newbatch - 1] = NULL;
|
||||||
|
@ -615,9 +625,9 @@ ExecHashJoinGetBatch(int bucketno, HashJoinTable hashtable)
|
||||||
|
|
||||||
void
|
void
|
||||||
ExecHashJoinSaveTuple(HeapTuple heapTuple,
|
ExecHashJoinSaveTuple(HeapTuple heapTuple,
|
||||||
BufFile *file)
|
BufFile * file)
|
||||||
{
|
{
|
||||||
size_t written;
|
size_t written;
|
||||||
|
|
||||||
written = BufFileWrite(file, (void *) heapTuple, sizeof(HeapTupleData));
|
written = BufFileWrite(file, (void *) heapTuple, sizeof(HeapTupleData));
|
||||||
if (written != sizeof(HeapTupleData))
|
if (written != sizeof(HeapTupleData))
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.35 1999/05/10 00:45:06 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.36 1999/05/25 16:08:43 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -91,13 +91,14 @@ IndexNext(IndexScan *node)
|
||||||
IndexScanDesc scandesc;
|
IndexScanDesc scandesc;
|
||||||
Relation heapRelation;
|
Relation heapRelation;
|
||||||
RetrieveIndexResult result;
|
RetrieveIndexResult result;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
Buffer buffer = InvalidBuffer;
|
Buffer buffer = InvalidBuffer;
|
||||||
int numIndices;
|
int numIndices;
|
||||||
|
|
||||||
bool bBackward;
|
bool bBackward;
|
||||||
int indexNumber;
|
int indexNumber;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* extract necessary information from index scan node
|
* extract necessary information from index scan node
|
||||||
* ----------------
|
* ----------------
|
||||||
|
@ -114,14 +115,14 @@ IndexNext(IndexScan *node)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if we are evaluating PlanQual for tuple of this relation.
|
* Check if we are evaluating PlanQual for tuple of this relation.
|
||||||
* Additional checking is not good, but no other way for now.
|
* Additional checking is not good, but no other way for now. We could
|
||||||
* We could introduce new nodes for this case and handle
|
* introduce new nodes for this case and handle IndexScan --> NewNode
|
||||||
* IndexScan --> NewNode switching in Init/ReScan plan...
|
* switching in Init/ReScan plan...
|
||||||
*/
|
*/
|
||||||
if (estate->es_evTuple != NULL &&
|
if (estate->es_evTuple != NULL &&
|
||||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
||||||
{
|
{
|
||||||
int iptr;
|
int iptr;
|
||||||
|
|
||||||
slot->ttc_buffer = InvalidBuffer;
|
slot->ttc_buffer = InvalidBuffer;
|
||||||
slot->ttc_shouldFree = false;
|
slot->ttc_shouldFree = false;
|
||||||
|
@ -138,7 +139,7 @@ IndexNext(IndexScan *node)
|
||||||
scanstate->cstate.cs_ExprContext))
|
scanstate->cstate.cs_ExprContext))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (iptr == numIndices) /* would not be returned by indices */
|
if (iptr == numIndices) /* would not be returned by indices */
|
||||||
slot->val = NULL;
|
slot->val = NULL;
|
||||||
/* Flag for the next call that no more tuples */
|
/* Flag for the next call that no more tuples */
|
||||||
estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
|
estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
|
||||||
|
@ -153,26 +154,26 @@ IndexNext(IndexScan *node)
|
||||||
* appropriate heap tuple.. else return NULL.
|
* appropriate heap tuple.. else return NULL.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
bBackward = ScanDirectionIsBackward(direction);
|
bBackward = ScanDirectionIsBackward(direction);
|
||||||
if (bBackward)
|
if (bBackward)
|
||||||
{
|
{
|
||||||
indexNumber = numIndices - indexstate->iss_IndexPtr - 1;
|
indexNumber = numIndices - indexstate->iss_IndexPtr - 1;
|
||||||
if (indexNumber < 0)
|
if (indexNumber < 0)
|
||||||
{
|
{
|
||||||
indexNumber = 0;
|
indexNumber = 0;
|
||||||
indexstate->iss_IndexPtr = numIndices - 1;
|
indexstate->iss_IndexPtr = numIndices - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((indexNumber = indexstate->iss_IndexPtr) < 0)
|
if ((indexNumber = indexstate->iss_IndexPtr) < 0)
|
||||||
{
|
{
|
||||||
indexNumber = 0;
|
indexNumber = 0;
|
||||||
indexstate->iss_IndexPtr = 0;
|
indexstate->iss_IndexPtr = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (indexNumber < numIndices)
|
while (indexNumber < numIndices)
|
||||||
{
|
{
|
||||||
scandesc = scanDescs[indexstate->iss_IndexPtr];
|
scandesc = scanDescs[indexstate->iss_IndexPtr];
|
||||||
while ((result = index_getnext(scandesc, direction)) != NULL)
|
while ((result = index_getnext(scandesc, direction)) != NULL)
|
||||||
{
|
{
|
||||||
|
@ -224,14 +225,14 @@ IndexNext(IndexScan *node)
|
||||||
if (BufferIsValid(buffer))
|
if (BufferIsValid(buffer))
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
}
|
}
|
||||||
if (indexNumber < numIndices)
|
if (indexNumber < numIndices)
|
||||||
{
|
{
|
||||||
indexNumber++;
|
indexNumber++;
|
||||||
if (bBackward)
|
if (bBackward)
|
||||||
indexstate->iss_IndexPtr--;
|
indexstate->iss_IndexPtr--;
|
||||||
else
|
else
|
||||||
indexstate->iss_IndexPtr++;
|
indexstate->iss_IndexPtr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* if we get here it means the index scan failed so we
|
* if we get here it means the index scan failed so we
|
||||||
|
@ -323,7 +324,7 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||||
indexstate->iss_IndexPtr = -1;
|
indexstate->iss_IndexPtr = -1;
|
||||||
|
|
||||||
/* If this is re-scanning of PlanQual ... */
|
/* If this is re-scanning of PlanQual ... */
|
||||||
if (estate->es_evTuple != NULL &&
|
if (estate->es_evTuple != NULL &&
|
||||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
||||||
{
|
{
|
||||||
estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
|
estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
|
||||||
|
@ -703,7 +704,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||||
run_keys = (n_keys <= 0) ? NULL :
|
run_keys = (n_keys <= 0) ? NULL :
|
||||||
(int *) palloc(n_keys * sizeof(int));
|
(int *) palloc(n_keys * sizeof(int));
|
||||||
|
|
||||||
CXT1_printf("ExecInitIndexScan: context is %d\n",CurrentMemoryContext);
|
CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* for each opclause in the given qual,
|
* for each opclause in the given qual,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.21 1999/02/13 23:15:24 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.22 1999/05/25 16:08:44 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -116,7 +116,7 @@ ExecMaterial(Material *node)
|
||||||
|
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* heap_insert changes something...
|
* heap_insert changes something...
|
||||||
*/
|
*/
|
||||||
|
@ -124,12 +124,12 @@ ExecMaterial(Material *node)
|
||||||
heapTuple = heap_copytuple(slot->val);
|
heapTuple = heap_copytuple(slot->val);
|
||||||
else
|
else
|
||||||
heapTuple = slot->val;
|
heapTuple = slot->val;
|
||||||
|
|
||||||
heap_insert(tempRelation, heapTuple);
|
heap_insert(tempRelation, heapTuple);
|
||||||
|
|
||||||
if (slot->ttc_buffer != InvalidBuffer)
|
if (slot->ttc_buffer != InvalidBuffer)
|
||||||
pfree(heapTuple);
|
pfree(heapTuple);
|
||||||
|
|
||||||
ExecClearTuple(slot);
|
ExecClearTuple(slot);
|
||||||
}
|
}
|
||||||
currentRelation = tempRelation;
|
currentRelation = tempRelation;
|
||||||
|
@ -360,8 +360,8 @@ ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
matstate->csstate.css_currentScanDesc = ExecReScanR(matstate->csstate.css_currentRelation,
|
matstate->csstate.css_currentScanDesc = ExecReScanR(matstate->csstate.css_currentRelation,
|
||||||
matstate->csstate.css_currentScanDesc,
|
matstate->csstate.css_currentScanDesc,
|
||||||
node->plan.state->es_direction, 0, NULL);
|
node->plan.state->es_direction, 0, NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.26 1999/05/10 00:45:07 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.27 1999/05/25 16:08:45 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -103,7 +103,7 @@ static bool MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static List *
|
static List *
|
||||||
MJFormSkipQual(List *qualList, char * replaceopname)
|
MJFormSkipQual(List *qualList, char *replaceopname)
|
||||||
{
|
{
|
||||||
List *qualCopy;
|
List *qualCopy;
|
||||||
List *qualcdr;
|
List *qualcdr;
|
||||||
|
@ -148,14 +148,14 @@ MJFormSkipQual(List *qualList, char * replaceopname)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
optup = get_operator_tuple(op->opno);
|
optup = get_operator_tuple(op->opno);
|
||||||
if (!HeapTupleIsValid(optup)) /* shouldn't happen */
|
if (!HeapTupleIsValid(optup)) /* shouldn't happen */
|
||||||
elog(ERROR, "MJFormSkipQual: operator %u not found", op->opno);
|
elog(ERROR, "MJFormSkipQual: operator %u not found", op->opno);
|
||||||
opform = (Form_pg_operator) GETSTRUCT(optup);
|
opform = (Form_pg_operator) GETSTRUCT(optup);
|
||||||
oprleft = opform->oprleft;
|
oprleft = opform->oprleft;
|
||||||
oprright = opform->oprright;
|
oprright = opform->oprright;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Now look up the matching "<" or ">" operator. If there isn't one,
|
* Now look up the matching "<" or ">" operator. If there isn't one,
|
||||||
* whoever marked the "=" operator mergejoinable was a loser.
|
* whoever marked the "=" operator mergejoinable was a loser.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
@ -166,7 +166,7 @@ MJFormSkipQual(List *qualList, char * replaceopname)
|
||||||
CharGetDatum('b'));
|
CharGetDatum('b'));
|
||||||
if (!HeapTupleIsValid(optup))
|
if (!HeapTupleIsValid(optup))
|
||||||
elog(ERROR,
|
elog(ERROR,
|
||||||
"MJFormSkipQual: mergejoin operator %u has no matching %s op",
|
"MJFormSkipQual: mergejoin operator %u has no matching %s op",
|
||||||
op->opno, replaceopname);
|
op->opno, replaceopname);
|
||||||
opform = (Form_pg_operator) GETSTRUCT(optup);
|
opform = (Form_pg_operator) GETSTRUCT(optup);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
* SeqScan (emp.all)
|
* SeqScan (emp.all)
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.10 1999/03/20 01:13:22 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.11 1999/05/25 16:08:46 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -263,8 +263,8 @@ ExecEndResult(Result *node)
|
||||||
* is freed at end-transaction time. -cim 6/2/91
|
* is freed at end-transaction time. -cim 6/2/91
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
ExecFreeExprContext(&resstate->cstate); /* XXX - new for us - er1p */
|
ExecFreeExprContext(&resstate->cstate); /* XXX - new for us - er1p */
|
||||||
ExecFreeTypeInfo(&resstate->cstate); /* XXX - new for us - er1p */
|
ExecFreeTypeInfo(&resstate->cstate); /* XXX - new for us - er1p */
|
||||||
ExecFreeProjectionInfo(&resstate->cstate);
|
ExecFreeProjectionInfo(&resstate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -278,7 +278,8 @@ ExecEndResult(Result *node)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
|
ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
|
||||||
pfree(resstate); node->resstate = NULL; /* XXX - new for us - er1p */
|
pfree(resstate);
|
||||||
|
node->resstate = NULL; /* XXX - new for us - er1p */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.17 1999/02/13 23:15:26 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.18 1999/05/25 16:08:46 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -68,11 +68,11 @@ SeqNext(SeqScan *node)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if we are evaluating PlanQual for tuple of this relation.
|
* Check if we are evaluating PlanQual for tuple of this relation.
|
||||||
* Additional checking is not good, but no other way for now.
|
* Additional checking is not good, but no other way for now. We could
|
||||||
* We could introduce new nodes for this case and handle
|
* introduce new nodes for this case and handle SeqScan --> NewNode
|
||||||
* SeqScan --> NewNode switching in Init/ReScan plan...
|
* switching in Init/ReScan plan...
|
||||||
*/
|
*/
|
||||||
if (estate->es_evTuple != NULL &&
|
if (estate->es_evTuple != NULL &&
|
||||||
estate->es_evTuple[node->scanrelid - 1] != NULL)
|
estate->es_evTuple[node->scanrelid - 1] != NULL)
|
||||||
{
|
{
|
||||||
slot->ttc_buffer = InvalidBuffer;
|
slot->ttc_buffer = InvalidBuffer;
|
||||||
|
@ -83,10 +83,11 @@ SeqNext(SeqScan *node)
|
||||||
return (slot);
|
return (slot);
|
||||||
}
|
}
|
||||||
slot->val = estate->es_evTuple[node->scanrelid - 1];
|
slot->val = estate->es_evTuple[node->scanrelid - 1];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that unlike IndexScan, SeqScan never use keys
|
* Note that unlike IndexScan, SeqScan never use keys in
|
||||||
* in heap_beginscan (and this is very bad) - so, here
|
* heap_beginscan (and this is very bad) - so, here we have not
|
||||||
* we have not check are keys ok or not.
|
* check are keys ok or not.
|
||||||
*/
|
*/
|
||||||
/* Flag for the next call that no more tuples */
|
/* Flag for the next call that no more tuples */
|
||||||
estate->es_evTupleNull[node->scanrelid - 1] = true;
|
estate->es_evTupleNull[node->scanrelid - 1] = true;
|
||||||
|
@ -401,10 +402,11 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan((Plan *) node);
|
||||||
ExecReScan(outerPlan, exprCtxt, parent);
|
ExecReScan(outerPlan, exprCtxt, parent);
|
||||||
}
|
}
|
||||||
else /* otherwise, we are scanning a relation */
|
else
|
||||||
|
/* otherwise, we are scanning a relation */
|
||||||
{
|
{
|
||||||
/* If this is re-scanning of PlanQual ... */
|
/* If this is re-scanning of PlanQual ... */
|
||||||
if (estate->es_evTuple != NULL &&
|
if (estate->es_evTuple != NULL &&
|
||||||
estate->es_evTuple[node->scanrelid - 1] != NULL)
|
estate->es_evTuple[node->scanrelid - 1] != NULL)
|
||||||
{
|
{
|
||||||
estate->es_evTupleNull[node->scanrelid - 1] = false;
|
estate->es_evTupleNull[node->scanrelid - 1] = false;
|
||||||
|
|
|
@ -58,15 +58,16 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
|
||||||
ExecReScan(plan, (ExprContext *) NULL, plan);
|
ExecReScan(plan, (ExprContext *) NULL, plan);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For all sublink types except EXPR_SUBLINK, the result type is boolean,
|
* For all sublink types except EXPR_SUBLINK, the result type is
|
||||||
* and we have a fairly clear idea of how to combine multiple subitems
|
* boolean, and we have a fairly clear idea of how to combine multiple
|
||||||
* and deal with NULL values or an empty subplan result.
|
* subitems and deal with NULL values or an empty subplan result.
|
||||||
*
|
*
|
||||||
* For EXPR_SUBLINK, the result type is whatever the combining operator
|
* For EXPR_SUBLINK, the result type is whatever the combining operator
|
||||||
* returns. We have no way to deal with more than one column in the
|
* returns. We have no way to deal with more than one column in the
|
||||||
* subplan result --- hopefully the parser forbids that. More seriously,
|
* subplan result --- hopefully the parser forbids that. More
|
||||||
* it's unclear what to do with NULL values or an empty subplan result.
|
* seriously, it's unclear what to do with NULL values or an empty
|
||||||
* For now, we error out, but should something else happen?
|
* subplan result. For now, we error out, but should something else
|
||||||
|
* happen?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (slot = ExecProcNode(plan, plan);
|
for (slot = ExecProcNode(plan, plan);
|
||||||
|
@ -105,14 +106,14 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
|
||||||
}
|
}
|
||||||
if (subLinkType != EXPR_SUBLINK)
|
if (subLinkType != EXPR_SUBLINK)
|
||||||
{
|
{
|
||||||
if ((! (bool) result && !(sublink->useor)) ||
|
if ((!(bool) result && !(sublink->useor)) ||
|
||||||
((bool) result && sublink->useor))
|
((bool) result && sublink->useor))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subLinkType == ALL_SUBLINK && ! (bool) result)
|
if (subLinkType == ALL_SUBLINK && !(bool) result)
|
||||||
break;
|
break;
|
||||||
if (subLinkType == ANY_SUBLINK && (bool) result)
|
if (subLinkType == ANY_SUBLINK && (bool) result)
|
||||||
break;
|
break;
|
||||||
|
@ -120,7 +121,7 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
/* deal with empty subplan result. Note default result is 'false' */
|
/* deal with empty subplan result. Note default result is 'false' */
|
||||||
if (subLinkType == ALL_SUBLINK)
|
if (subLinkType == ALL_SUBLINK)
|
||||||
result = (Datum) true;
|
result = (Datum) true;
|
||||||
else if (subLinkType == EXPR_SUBLINK)
|
else if (subLinkType == EXPR_SUBLINK)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* spi.c
|
* spi.c
|
||||||
* Server Programming Interface
|
* Server Programming Interface
|
||||||
*
|
*
|
||||||
* $Id: spi.c,v 1.37 1999/05/13 07:28:30 tgl Exp $
|
* $Id: spi.c,v 1.38 1999/05/25 16:08:48 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -19,9 +19,9 @@ static _SPI_connection *_SPI_current = NULL;
|
||||||
static int _SPI_connected = -1;
|
static int _SPI_connected = -1;
|
||||||
static int _SPI_curid = -1;
|
static int _SPI_curid = -1;
|
||||||
|
|
||||||
DLLIMPORT uint32 SPI_processed = 0;
|
DLLIMPORT uint32 SPI_processed = 0;
|
||||||
DLLIMPORT SPITupleTable *SPI_tuptable;
|
DLLIMPORT SPITupleTable *SPI_tuptable;
|
||||||
DLLIMPORT int SPI_result;
|
DLLIMPORT int SPI_result;
|
||||||
|
|
||||||
static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
|
static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
|
||||||
static int _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount);
|
static int _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount);
|
||||||
|
@ -49,8 +49,8 @@ extern void ShowUsage(void);
|
||||||
int
|
int
|
||||||
SPI_connect()
|
SPI_connect()
|
||||||
{
|
{
|
||||||
char pname[64];
|
char pname[64];
|
||||||
PortalVariableMemory pvmem;
|
PortalVariableMemory pvmem;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It's possible on startup and after commit/abort. In future we'll
|
* It's possible on startup and after commit/abort. In future we'll
|
||||||
|
@ -345,8 +345,8 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
|
||||||
mtuple = heap_formtuple(rel->rd_att, v, n);
|
mtuple = heap_formtuple(rel->rd_att, v, n);
|
||||||
infomask = mtuple->t_data->t_infomask;
|
infomask = mtuple->t_data->t_infomask;
|
||||||
memmove(&(mtuple->t_data->t_oid), &(tuple->t_data->t_oid),
|
memmove(&(mtuple->t_data->t_oid), &(tuple->t_data->t_oid),
|
||||||
((char *) &(tuple->t_data->t_hoff) -
|
((char *) &(tuple->t_data->t_hoff) -
|
||||||
(char *) &(tuple->t_data->t_oid)));
|
(char *) &(tuple->t_data->t_oid)));
|
||||||
mtuple->t_data->t_infomask = infomask;
|
mtuple->t_data->t_infomask = infomask;
|
||||||
mtuple->t_data->t_natts = numberOfAttributes;
|
mtuple->t_data->t_natts = numberOfAttributes;
|
||||||
}
|
}
|
||||||
|
@ -411,8 +411,8 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
|
||||||
val = heap_getattr(tuple, fnumber, tupdesc, &isnull);
|
val = heap_getattr(tuple, fnumber, tupdesc, &isnull);
|
||||||
if (isnull)
|
if (isnull)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (! getTypeOutAndElem((Oid) tupdesc->attrs[fnumber - 1]->atttypid,
|
if (!getTypeOutAndElem((Oid) tupdesc->attrs[fnumber - 1]->atttypid,
|
||||||
&foutoid, &typelem))
|
&foutoid, &typelem))
|
||||||
{
|
{
|
||||||
SPI_result = SPI_ERROR_NOOUTFUNC;
|
SPI_result = SPI_ERROR_NOOUTFUNC;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -549,13 +549,13 @@ SPI_pfree(void *pointer)
|
||||||
/* =================== private functions =================== */
|
/* =================== private functions =================== */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* spi_printtup
|
* spi_printtup
|
||||||
* store tuple retrieved by Executor into SPITupleTable
|
* store tuple retrieved by Executor into SPITupleTable
|
||||||
* of current SPI procedure
|
* of current SPI procedure
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
spi_printtup(HeapTuple tuple, TupleDesc tupdesc, DestReceiver* self)
|
spi_printtup(HeapTuple tuple, TupleDesc tupdesc, DestReceiver * self)
|
||||||
{
|
{
|
||||||
SPITupleTable *tuptable;
|
SPITupleTable *tuptable;
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
@ -633,12 +633,13 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
||||||
|
|
||||||
_SPI_current->qtlist = queryTree_list;
|
_SPI_current->qtlist = queryTree_list;
|
||||||
|
|
||||||
foreach (queryTree_list_item, queryTree_list)
|
foreach(queryTree_list_item, queryTree_list)
|
||||||
{
|
{
|
||||||
queryTree = (Query *) lfirst(queryTree_list_item);
|
queryTree = (Query *) lfirst(queryTree_list_item);
|
||||||
planTree = lfirst(planTree_list);
|
planTree = lfirst(planTree_list);
|
||||||
planTree_list = lnext(planTree_list);
|
planTree_list = lnext(planTree_list);
|
||||||
islastquery = (planTree_list == NIL); /* assume lists are same len */
|
islastquery = (planTree_list == NIL); /* assume lists are same
|
||||||
|
* len */
|
||||||
|
|
||||||
if (queryTree->commandType == CMD_UTILITY)
|
if (queryTree->commandType == CMD_UTILITY)
|
||||||
{
|
{
|
||||||
|
@ -658,7 +659,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
||||||
if (plan == NULL)
|
if (plan == NULL)
|
||||||
{
|
{
|
||||||
ProcessUtility(queryTree->utilityStmt, None);
|
ProcessUtility(queryTree->utilityStmt, None);
|
||||||
if (! islastquery)
|
if (!islastquery)
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
else
|
else
|
||||||
return res;
|
return res;
|
||||||
|
@ -717,17 +718,18 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
|
||||||
_SPI_current->tuptable = NULL;
|
_SPI_current->tuptable = NULL;
|
||||||
_SPI_current->qtlist = NULL;
|
_SPI_current->qtlist = NULL;
|
||||||
|
|
||||||
foreach (queryTree_list_item, queryTree_list)
|
foreach(queryTree_list_item, queryTree_list)
|
||||||
{
|
{
|
||||||
queryTree = (Query *) lfirst(queryTree_list_item);
|
queryTree = (Query *) lfirst(queryTree_list_item);
|
||||||
planTree = lfirst(planTree_list);
|
planTree = lfirst(planTree_list);
|
||||||
planTree_list = lnext(planTree_list);
|
planTree_list = lnext(planTree_list);
|
||||||
islastquery = (planTree_list == NIL); /* assume lists are same len */
|
islastquery = (planTree_list == NIL); /* assume lists are same
|
||||||
|
* len */
|
||||||
|
|
||||||
if (queryTree->commandType == CMD_UTILITY)
|
if (queryTree->commandType == CMD_UTILITY)
|
||||||
{
|
{
|
||||||
ProcessUtility(queryTree->utilityStmt, None);
|
ProcessUtility(queryTree->utilityStmt, None);
|
||||||
if (! islastquery)
|
if (!islastquery)
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
else
|
else
|
||||||
return SPI_OK_UTILITY;
|
return SPI_OK_UTILITY;
|
||||||
|
@ -777,7 +779,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
||||||
char *intoName = NULL;
|
char *intoName = NULL;
|
||||||
int res;
|
int res;
|
||||||
Const tcount_const;
|
Const tcount_const;
|
||||||
Node *count = NULL;
|
Node *count = NULL;
|
||||||
|
|
||||||
switch (operation)
|
switch (operation)
|
||||||
{
|
{
|
||||||
|
@ -833,18 +835,18 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
memset(&tcount_const, 0, sizeof(tcount_const));
|
memset(&tcount_const, 0, sizeof(tcount_const));
|
||||||
tcount_const.type = T_Const;
|
tcount_const.type = T_Const;
|
||||||
tcount_const.consttype = INT4OID;
|
tcount_const.consttype = INT4OID;
|
||||||
tcount_const.constlen = sizeof(int4);
|
tcount_const.constlen = sizeof(int4);
|
||||||
tcount_const.constvalue = (Datum)tcount;
|
tcount_const.constvalue = (Datum) tcount;
|
||||||
tcount_const.constisnull = FALSE;
|
tcount_const.constisnull = FALSE;
|
||||||
tcount_const.constbyval = TRUE;
|
tcount_const.constbyval = TRUE;
|
||||||
tcount_const.constisset = FALSE;
|
tcount_const.constisset = FALSE;
|
||||||
tcount_const.constiscast = FALSE;
|
tcount_const.constiscast = FALSE;
|
||||||
|
|
||||||
count = (Node *)&tcount_const;
|
count = (Node *) &tcount_const;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == NULL) /* plan preparation */
|
if (state == NULL) /* plan preparation */
|
||||||
return res;
|
return res;
|
||||||
#ifdef SPI_EXECUTOR_STATS
|
#ifdef SPI_EXECUTOR_STATS
|
||||||
|
@ -922,7 +924,7 @@ _SPI_procmem()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* _SPI_begin_call
|
* _SPI_begin_call
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/lib/Attic/fstack.c,v 1.10 1999/02/13 23:15:34 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/lib/Attic/fstack.c,v 1.11 1999/05/25 16:08:52 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -20,20 +20,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FixedItemIsValid
|
* FixedItemIsValid
|
||||||
* True iff item is valid.
|
* True iff item is valid.
|
||||||
*/
|
*/
|
||||||
#define FixedItemIsValid(item) PointerIsValid(item)
|
#define FixedItemIsValid(item) PointerIsValid(item)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FixedStackGetItemBase
|
* FixedStackGetItemBase
|
||||||
* Returns base of enclosing structure.
|
* Returns base of enclosing structure.
|
||||||
*/
|
*/
|
||||||
#define FixedStackGetItemBase(stack, item) \
|
#define FixedStackGetItemBase(stack, item) \
|
||||||
((Pointer)((char *)(item) - (stack)->offset))
|
((Pointer)((char *)(item) - (stack)->offset))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FixedStackGetItem
|
* FixedStackGetItem
|
||||||
* Returns item of given pointer to enclosing structure.
|
* Returns item of given pointer to enclosing structure.
|
||||||
*/
|
*/
|
||||||
#define FixedStackGetItem(stack, pointer) \
|
#define FixedStackGetItem(stack, pointer) \
|
||||||
|
@ -84,7 +84,7 @@ FixedStackPush(FixedStack stack, Pointer pointer)
|
||||||
|
|
||||||
#ifdef USE_ASSERT_CHECKING
|
#ifdef USE_ASSERT_CHECKING
|
||||||
/*
|
/*
|
||||||
* FixedStackContains
|
* FixedStackContains
|
||||||
* True iff ordered stack contains given element.
|
* True iff ordered stack contains given element.
|
||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: stringinfo.c,v 1.15 1999/04/25 03:19:25 tgl Exp $
|
* $Id: stringinfo.c,v 1.16 1999/05/25 16:08:53 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -67,17 +67,18 @@ initStringInfo(StringInfo str)
|
||||||
static void
|
static void
|
||||||
enlargeStringInfo(StringInfo str, int needed)
|
enlargeStringInfo(StringInfo str, int needed)
|
||||||
{
|
{
|
||||||
int newlen;
|
int newlen;
|
||||||
char *newdata;
|
char *newdata;
|
||||||
|
|
||||||
needed += str->len + 1; /* total space required now */
|
needed += str->len + 1; /* total space required now */
|
||||||
if (needed <= str->maxlen)
|
if (needed <= str->maxlen)
|
||||||
return; /* got enough space already */
|
return; /* got enough space already */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't want to allocate just a little more space with each append;
|
* We don't want to allocate just a little more space with each
|
||||||
* for efficiency, double the buffer size each time it overflows.
|
* append; for efficiency, double the buffer size each time it
|
||||||
* Actually, we might need to more than double it if 'needed' is big...
|
* overflows. Actually, we might need to more than double it if
|
||||||
|
* 'needed' is big...
|
||||||
*/
|
*/
|
||||||
newlen = 2 * str->maxlen;
|
newlen = 2 * str->maxlen;
|
||||||
while (needed > newlen)
|
while (needed > newlen)
|
||||||
|
@ -86,7 +87,7 @@ enlargeStringInfo(StringInfo str, int needed)
|
||||||
newdata = palloc(newlen);
|
newdata = palloc(newlen);
|
||||||
if (newdata == NULL)
|
if (newdata == NULL)
|
||||||
elog(ERROR,
|
elog(ERROR,
|
||||||
"enlargeStringInfo: Out of memory (%d bytes requested)", newlen);
|
"enlargeStringInfo: Out of memory (%d bytes requested)", newlen);
|
||||||
|
|
||||||
/* OK, transfer data into new buffer, and release old buffer */
|
/* OK, transfer data into new buffer, and release old buffer */
|
||||||
memcpy(newdata, str->data, str->len + 1);
|
memcpy(newdata, str->data, str->len + 1);
|
||||||
|
@ -107,11 +108,11 @@ enlargeStringInfo(StringInfo str, int needed)
|
||||||
* generated in a single call (not on the total string length).
|
* generated in a single call (not on the total string length).
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
appendStringInfo(StringInfo str, const char *fmt, ...)
|
appendStringInfo(StringInfo str, const char *fmt,...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
int buflen;
|
int buflen;
|
||||||
|
|
||||||
Assert(str != NULL);
|
Assert(str != NULL);
|
||||||
|
|
||||||
|
@ -164,7 +165,8 @@ appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
|
||||||
memcpy(str->data + str->len, data, datalen);
|
memcpy(str->data + str->len, data, datalen);
|
||||||
str->len += datalen;
|
str->len += datalen;
|
||||||
|
|
||||||
/* Keep a trailing null in place, even though it's probably useless
|
/*
|
||||||
|
* Keep a trailing null in place, even though it's probably useless
|
||||||
* for binary data...
|
* for binary data...
|
||||||
*/
|
*/
|
||||||
str->data[str->len] = '\0';
|
str->data[str->len] = '\0';
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.35 1999/04/16 04:59:03 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.36 1999/05/25 16:08:55 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -75,13 +75,13 @@ static int map_old_to_new(Port *port, UserAuth old, int status);
|
||||||
static int
|
static int
|
||||||
pg_krb4_recvauth(Port *port)
|
pg_krb4_recvauth(Port *port)
|
||||||
{
|
{
|
||||||
long krbopts = 0; /* one-way authentication */
|
long krbopts = 0; /* one-way authentication */
|
||||||
KTEXT_ST clttkt;
|
KTEXT_ST clttkt;
|
||||||
char instance[INST_SZ+1],
|
char instance[INST_SZ + 1],
|
||||||
version[KRB_SENDAUTH_VLEN+1];
|
version[KRB_SENDAUTH_VLEN + 1];
|
||||||
AUTH_DAT auth_data;
|
AUTH_DAT auth_data;
|
||||||
Key_schedule key_sched;
|
Key_schedule key_sched;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
strcpy(instance, "*"); /* don't care, but arg gets expanded
|
strcpy(instance, "*"); /* don't care, but arg gets expanded
|
||||||
* anyway */
|
* anyway */
|
||||||
|
@ -99,7 +99,7 @@ pg_krb4_recvauth(Port *port)
|
||||||
if (status != KSUCCESS)
|
if (status != KSUCCESS)
|
||||||
{
|
{
|
||||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||||
"pg_krb4_recvauth: kerberos error: %s\n", krb_err_txt[status]);
|
"pg_krb4_recvauth: kerberos error: %s\n", krb_err_txt[status]);
|
||||||
fputs(PQerrormsg, stderr);
|
fputs(PQerrormsg, stderr);
|
||||||
pqdebug("%s", PQerrormsg);
|
pqdebug("%s", PQerrormsg);
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
|
@ -107,7 +107,7 @@ pg_krb4_recvauth(Port *port)
|
||||||
if (strncmp(version, PG_KRB4_VERSION, KRB_SENDAUTH_VLEN))
|
if (strncmp(version, PG_KRB4_VERSION, KRB_SENDAUTH_VLEN))
|
||||||
{
|
{
|
||||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||||
"pg_krb4_recvauth: protocol version != \"%s\"\n", PG_KRB4_VERSION);
|
"pg_krb4_recvauth: protocol version != \"%s\"\n", PG_KRB4_VERSION);
|
||||||
fputs(PQerrormsg, stderr);
|
fputs(PQerrormsg, stderr);
|
||||||
pqdebug("%s", PQerrormsg);
|
pqdebug("%s", PQerrormsg);
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
|
@ -115,8 +115,8 @@ pg_krb4_recvauth(Port *port)
|
||||||
if (strncmp(port->user, auth_data.pname, SM_USER))
|
if (strncmp(port->user, auth_data.pname, SM_USER))
|
||||||
{
|
{
|
||||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||||
"pg_krb4_recvauth: name \"%s\" != \"%s\"\n",
|
"pg_krb4_recvauth: name \"%s\" != \"%s\"\n",
|
||||||
port->user, auth_data.pname);
|
port->user, auth_data.pname);
|
||||||
fputs(PQerrormsg, stderr);
|
fputs(PQerrormsg, stderr);
|
||||||
pqdebug("%s", PQerrormsg);
|
pqdebug("%s", PQerrormsg);
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
|
@ -129,7 +129,7 @@ static int
|
||||||
pg_krb4_recvauth(Port *port)
|
pg_krb4_recvauth(Port *port)
|
||||||
{
|
{
|
||||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||||
"pg_krb4_recvauth: Kerberos not implemented on this server.\n");
|
"pg_krb4_recvauth: Kerberos not implemented on this server.\n");
|
||||||
fputs(PQerrormsg, stderr);
|
fputs(PQerrormsg, stderr);
|
||||||
pqdebug("%s", PQerrormsg);
|
pqdebug("%s", PQerrormsg);
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ pg_krb5_recvauth(Port *port)
|
||||||
if (code = krb5_parse_name(servbuf, &server))
|
if (code = krb5_parse_name(servbuf, &server))
|
||||||
{
|
{
|
||||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||||
"pg_krb5_recvauth: Kerberos error %d in krb5_parse_name\n", code);
|
"pg_krb5_recvauth: Kerberos error %d in krb5_parse_name\n", code);
|
||||||
com_err("pg_krb5_recvauth", code, "in krb5_parse_name");
|
com_err("pg_krb5_recvauth", code, "in krb5_parse_name");
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,7 @@ pg_krb5_recvauth(Port *port)
|
||||||
(krb5_authenticator **) NULL))
|
(krb5_authenticator **) NULL))
|
||||||
{
|
{
|
||||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||||
"pg_krb5_recvauth: Kerberos error %d in krb5_recvauth\n", code);
|
"pg_krb5_recvauth: Kerberos error %d in krb5_recvauth\n", code);
|
||||||
com_err("pg_krb5_recvauth", code, "in krb5_recvauth");
|
com_err("pg_krb5_recvauth", code, "in krb5_recvauth");
|
||||||
krb5_free_principal(server);
|
krb5_free_principal(server);
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
|
@ -271,7 +271,7 @@ pg_krb5_recvauth(Port *port)
|
||||||
if ((code = krb5_unparse_name(client, &kusername)))
|
if ((code = krb5_unparse_name(client, &kusername)))
|
||||||
{
|
{
|
||||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||||
"pg_krb5_recvauth: Kerberos error %d in krb5_unparse_name\n", code);
|
"pg_krb5_recvauth: Kerberos error %d in krb5_unparse_name\n", code);
|
||||||
com_err("pg_krb5_recvauth", code, "in krb5_unparse_name");
|
com_err("pg_krb5_recvauth", code, "in krb5_unparse_name");
|
||||||
krb5_free_principal(client);
|
krb5_free_principal(client);
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
|
@ -280,7 +280,7 @@ pg_krb5_recvauth(Port *port)
|
||||||
if (!kusername)
|
if (!kusername)
|
||||||
{
|
{
|
||||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||||
"pg_krb5_recvauth: could not decode username\n");
|
"pg_krb5_recvauth: could not decode username\n");
|
||||||
fputs(PQerrormsg, stderr);
|
fputs(PQerrormsg, stderr);
|
||||||
pqdebug("%s", PQerrormsg);
|
pqdebug("%s", PQerrormsg);
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
|
@ -289,7 +289,7 @@ pg_krb5_recvauth(Port *port)
|
||||||
if (strncmp(username, kusername, SM_USER))
|
if (strncmp(username, kusername, SM_USER))
|
||||||
{
|
{
|
||||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||||
"pg_krb5_recvauth: name \"%s\" != \"%s\"\n", port->user, kusername);
|
"pg_krb5_recvauth: name \"%s\" != \"%s\"\n", port->user, kusername);
|
||||||
fputs(PQerrormsg, stderr);
|
fputs(PQerrormsg, stderr);
|
||||||
pqdebug("%s", PQerrormsg);
|
pqdebug("%s", PQerrormsg);
|
||||||
pfree(kusername);
|
pfree(kusername);
|
||||||
|
@ -304,7 +304,7 @@ static int
|
||||||
pg_krb5_recvauth(Port *port)
|
pg_krb5_recvauth(Port *port)
|
||||||
{
|
{
|
||||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||||
"pg_krb5_recvauth: Kerberos not implemented on this server.\n");
|
"pg_krb5_recvauth: Kerberos not implemented on this server.\n");
|
||||||
fputs(PQerrormsg, stderr);
|
fputs(PQerrormsg, stderr);
|
||||||
pqdebug("%s", PQerrormsg);
|
pqdebug("%s", PQerrormsg);
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt)
|
||||||
if (user == NULL || password == NULL)
|
if (user == NULL || password == NULL)
|
||||||
{
|
{
|
||||||
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
snprintf(PQerrormsg, ERROR_MSG_LENGTH,
|
||||||
"pg_password_recvauth: badly formed password packet.\n");
|
"pg_password_recvauth: badly formed password packet.\n");
|
||||||
fputs(PQerrormsg, stderr);
|
fputs(PQerrormsg, stderr);
|
||||||
pqdebug("%s", PQerrormsg);
|
pqdebug("%s", PQerrormsg);
|
||||||
|
|
||||||
|
@ -405,7 +405,7 @@ pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt)
|
||||||
void
|
void
|
||||||
auth_failed(Port *port)
|
auth_failed(Port *port)
|
||||||
{
|
{
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
const char *authmethod = "Unknown auth method:";
|
const char *authmethod = "Unknown auth method:";
|
||||||
|
|
||||||
switch (port->auth_method)
|
switch (port->auth_method)
|
||||||
|
@ -449,9 +449,9 @@ be_recvauth(Port *port)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the authentication method to use for this frontend/database
|
* Get the authentication method to use for this frontend/database
|
||||||
* combination. Note: a failure return indicates a problem with
|
* combination. Note: a failure return indicates a problem with the
|
||||||
* the hba config file, not with the request. hba.c should have
|
* hba config file, not with the request. hba.c should have dropped
|
||||||
* dropped an error message into the postmaster logfile if it failed.
|
* an error message into the postmaster logfile if it failed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (hba_getauthmethod(&port->raddr, port->user, port->database,
|
if (hba_getauthmethod(&port->raddr, port->user, port->database,
|
||||||
|
@ -470,27 +470,28 @@ be_recvauth(Port *port)
|
||||||
{
|
{
|
||||||
/* Handle new style authentication. */
|
/* Handle new style authentication. */
|
||||||
|
|
||||||
AuthRequest areq = AUTH_REQ_OK;
|
AuthRequest areq = AUTH_REQ_OK;
|
||||||
PacketDoneProc auth_handler = NULL;
|
PacketDoneProc auth_handler = NULL;
|
||||||
|
|
||||||
switch (port->auth_method)
|
switch (port->auth_method)
|
||||||
{
|
{
|
||||||
case uaReject:
|
case uaReject:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This could have come from an explicit "reject" entry
|
* This could have come from an explicit "reject" entry in
|
||||||
* in pg_hba.conf, but more likely it means there was no
|
* pg_hba.conf, but more likely it means there was no
|
||||||
* matching entry. Take pity on the poor user and issue
|
* matching entry. Take pity on the poor user and issue a
|
||||||
* a helpful error message. NOTE: this is not a security
|
* helpful error message. NOTE: this is not a security
|
||||||
* breach, because all the info reported here is known
|
* breach, because all the info reported here is known at
|
||||||
* at the frontend and must be assumed known to bad guys.
|
* the frontend and must be assumed known to bad guys.
|
||||||
* We're merely helping out the less clueful good guys.
|
* We're merely helping out the less clueful good guys.
|
||||||
* NOTE 2: libpq-be.h defines the maximum error message
|
* NOTE 2: libpq-be.h defines the maximum error message
|
||||||
* length as 99 characters. It probably wouldn't hurt
|
* length as 99 characters. It probably wouldn't hurt
|
||||||
* anything to increase it, but there might be some
|
* anything to increase it, but there might be some client
|
||||||
* client out there that will fail. So, be terse.
|
* out there that will fail. So, be terse.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
const char *hostinfo = "localhost";
|
const char *hostinfo = "localhost";
|
||||||
|
|
||||||
if (port->raddr.sa.sa_family == AF_INET)
|
if (port->raddr.sa.sa_family == AF_INET)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue