mirror of
https://github.com/postgres/postgres.git
synced 2025-12-02 23:42:46 +03:00
Remove dashes in comments that don't need them, rewrap with pgindent.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
/* -------------------------------------------------------------------------
|
/* -------------------------------------------------------------------------
|
||||||
* pg_dumplo
|
* pg_dumplo
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/contrib/pg_dumplo/Attic/lo_export.c,v 1.6 2001/03/22 03:59:10 momjian Exp $
|
* $Header: /cvsroot/pgsql/contrib/pg_dumplo/Attic/lo_export.c,v 1.7 2001/03/22 06:16:06 momjian Exp $
|
||||||
*
|
*
|
||||||
* Karel Zak 1999-2000
|
* Karel Zak 1999-2000
|
||||||
* -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
@@ -32,7 +32,7 @@ load_lolist(LODumpMaster * pgLO)
|
|||||||
int i;
|
int i;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Now find any candidate tables who have columns of type oid.
|
* Now find any candidate tables who have columns of type oid.
|
||||||
*
|
*
|
||||||
* NOTE: System tables including pg_largeobject will be ignored.
|
* NOTE: System tables including pg_largeobject will be ignored.
|
||||||
@@ -40,7 +40,6 @@ load_lolist(LODumpMaster * pgLO)
|
|||||||
*
|
*
|
||||||
* NOTE: the system oid column is ignored, as it has attnum < 1.
|
* NOTE: the system oid column is ignored, as it has attnum < 1.
|
||||||
* This shouldn't matter for correctness, but it saves time.
|
* This shouldn't matter for correctness, but it saves time.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
pgLO->res = PQexec(pgLO->conn,
|
pgLO->res = PQexec(pgLO->conn,
|
||||||
"SELECT c.relname, a.attname "
|
"SELECT c.relname, a.attname "
|
||||||
@@ -109,9 +108,8 @@ pglo_export(LODumpMaster * pgLO)
|
|||||||
for (ll = pgLO->lolist; ll->lo_table != NULL; ll++)
|
for (ll = pgLO->lolist; ll->lo_table != NULL; ll++)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Query: find the LOs referenced by this column
|
* Query: find the LOs referenced by this column
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
sprintf(Qbuff, "SELECT DISTINCT l.loid FROM \"%s\" x, pg_largeobject l WHERE x.\"%s\" = l.loid",
|
sprintf(Qbuff, "SELECT DISTINCT l.loid FROM \"%s\" x, pg_largeobject l WHERE x.\"%s\" = l.loid",
|
||||||
ll->lo_table, ll->lo_attr);
|
ll->lo_table, ll->lo_attr);
|
||||||
@@ -137,9 +135,8 @@ pglo_export(LODumpMaster * pgLO)
|
|||||||
int t;
|
int t;
|
||||||
char *val;
|
char *val;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Create DIR/FILE
|
* Create DIR/FILE
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (pgLO->action != ACTION_SHOW)
|
if (pgLO->action != ACTION_SHOW)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* -------------------------------------------------------------------------
|
/* -------------------------------------------------------------------------
|
||||||
* pg_dumplo
|
* pg_dumplo
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/contrib/pg_dumplo/Attic/lo_import.c,v 1.4 2001/03/22 03:59:10 momjian Exp $
|
* $Header: /cvsroot/pgsql/contrib/pg_dumplo/Attic/lo_import.c,v 1.5 2001/03/22 06:16:06 momjian Exp $
|
||||||
*
|
*
|
||||||
* Karel Zak 1999-2000
|
* Karel Zak 1999-2000
|
||||||
* -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
@@ -50,9 +50,8 @@ pglo_import(LODumpMaster * pgLO)
|
|||||||
|
|
||||||
sprintf(lo_path, "%s/%s", pgLO->space, path);
|
sprintf(lo_path, "%s/%s", pgLO->space, path);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Import LO
|
* Import LO
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if ((new_oid = lo_import(pgLO->conn, lo_path)) == 0)
|
if ((new_oid = lo_import(pgLO->conn, lo_path)) == 0)
|
||||||
{
|
{
|
||||||
@@ -79,9 +78,8 @@ pglo_import(LODumpMaster * pgLO)
|
|||||||
|
|
||||||
pgLO->counter++;
|
pgLO->counter++;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* UPDATE oid in tab
|
* UPDATE oid in tab
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
sprintf(Qbuff, "UPDATE \"%s\" SET \"%s\"=%u WHERE \"%s\"=%u",
|
sprintf(Qbuff, "UPDATE \"%s\" SET \"%s\"=%u WHERE \"%s\"=%u",
|
||||||
loa.lo_table, loa.lo_attr, new_oid, loa.lo_attr, loa.lo_oid);
|
loa.lo_table, loa.lo_attr, new_oid, loa.lo_attr, loa.lo_oid);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* -------------------------------------------------------------------------
|
/* -------------------------------------------------------------------------
|
||||||
* pg_dumplo
|
* pg_dumplo
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/contrib/pg_dumplo/Attic/main.c,v 1.7 2001/03/22 03:59:10 momjian Exp $
|
* $Header: /cvsroot/pgsql/contrib/pg_dumplo/Attic/main.c,v 1.8 2001/03/22 06:16:06 momjian Exp $
|
||||||
*
|
*
|
||||||
* Karel Zak 1999-2000
|
* Karel Zak 1999-2000
|
||||||
* -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
@@ -65,9 +65,8 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
progname = argv[0];
|
progname = argv[0];
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Parse ARGV
|
* Parse ARGV
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
{
|
{
|
||||||
@@ -153,9 +152,8 @@ main(int argc, char **argv)
|
|||||||
exit(RE_ERROR);
|
exit(RE_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Check space
|
* Check space
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (!pgLO->space && !pgLO->action == ACTION_SHOW)
|
if (!pgLO->space && !pgLO->action == ACTION_SHOW)
|
||||||
{
|
{
|
||||||
@@ -172,9 +170,8 @@ main(int argc, char **argv)
|
|||||||
exit(RE_ERROR);
|
exit(RE_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Make connection
|
* Make connection
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
pgLO->conn = PQsetdbLogin(pgLO->host, NULL, NULL, NULL, pgLO->db,
|
pgLO->conn = PQsetdbLogin(pgLO->host, NULL, NULL, NULL, pgLO->db,
|
||||||
pgLO->user, pwd);
|
pgLO->user, pwd);
|
||||||
@@ -189,9 +186,8 @@ main(int argc, char **argv)
|
|||||||
pgLO->user = PQuser(pgLO->conn);
|
pgLO->user = PQuser(pgLO->conn);
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Init index file
|
* Init index file
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (pgLO->action != ACTION_SHOW)
|
if (pgLO->action != ACTION_SHOW)
|
||||||
index_file(pgLO);
|
index_file(pgLO);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.70 2001/03/22 03:59:11 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.71 2001/03/22 06:16:06 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The old interface functions have been converted to macros
|
* The old interface functions have been converted to macros
|
||||||
@@ -246,9 +246,8 @@ nocachegetattr(HeapTuple tuple,
|
|||||||
* there's a null somewhere in the tuple
|
* there's a null somewhere in the tuple
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* check to see if desired att is null
|
* check to see if desired att is null
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef IN_MACRO
|
#ifdef IN_MACRO
|
||||||
@@ -261,9 +260,8 @@ nocachegetattr(HeapTuple tuple,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Now check to see if any preceding bits are null...
|
* Now check to see if any preceding bits are null...
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
int byte = attnum >> 3;
|
int byte = attnum >> 3;
|
||||||
@@ -658,9 +656,8 @@ heap_modifytuple(HeapTuple tuple,
|
|||||||
HeapTuple newTuple;
|
HeapTuple newTuple;
|
||||||
uint8 infomask;
|
uint8 infomask;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(HeapTupleIsValid(tuple));
|
Assert(HeapTupleIsValid(tuple));
|
||||||
Assert(RelationIsValid(relation));
|
Assert(RelationIsValid(relation));
|
||||||
@@ -670,10 +667,9 @@ heap_modifytuple(HeapTuple tuple,
|
|||||||
|
|
||||||
numberOfAttributes = RelationGetForm(relation)->relnatts;
|
numberOfAttributes = RelationGetForm(relation)->relnatts;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* allocate and fill *value and *nulls arrays from either
|
* allocate and fill *value and *nulls arrays from either the tuple or
|
||||||
* the tuple or the repl information, as appropriate.
|
* the repl information, as appropriate.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
value = (Datum *) palloc(numberOfAttributes * sizeof *value);
|
value = (Datum *) palloc(numberOfAttributes * sizeof *value);
|
||||||
nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
|
nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
|
||||||
@@ -701,17 +697,16 @@ heap_modifytuple(HeapTuple tuple,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create a new tuple from the *values and *nulls arrays
|
* create a new tuple from the *values and *nulls arrays
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newTuple = heap_formtuple(RelationGetDescr(relation),
|
newTuple = heap_formtuple(RelationGetDescr(relation),
|
||||||
value,
|
value,
|
||||||
nulls);
|
nulls);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy the header except for t_len, t_natts, t_hoff, t_bits, t_infomask
|
* copy the header except for t_len, t_natts, t_hoff, t_bits,
|
||||||
* ----------------
|
* t_infomask
|
||||||
*/
|
*/
|
||||||
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 */
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.53 2001/03/22 03:59:11 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.54 2001/03/22 06:16:06 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -165,9 +165,8 @@ index_formtuple(TupleDesc tupleDescriptor,
|
|||||||
|
|
||||||
infomask |= size;
|
infomask |= size;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize metadata
|
* initialize metadata
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tuple->t_info = infomask;
|
tuple->t_info = infomask;
|
||||||
return tuple;
|
return tuple;
|
||||||
@@ -205,9 +204,9 @@ nocache_index_getattr(IndexTuple tup,
|
|||||||
int data_off; /* tuple data offset */
|
int data_off; /* tuple data offset */
|
||||||
|
|
||||||
(void) isnull; /* not used */
|
(void) isnull; /* not used */
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@@ -246,9 +245,9 @@ nocache_index_getattr(IndexTuple tup,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ /* there's a null somewhere in the tuple */
|
{ /* there's a null somewhere in the tuple */
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* check to see if desired att is null
|
* check to see if desired att is null
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* XXX "knows" t_bits are just after fixed tuple header! */
|
/* XXX "knows" t_bits are just after fixed tuple header! */
|
||||||
@@ -264,9 +263,8 @@ nocache_index_getattr(IndexTuple tup,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Now check to see if any preceding bits are null...
|
* Now check to see if any preceding bits are null...
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
int byte = attnum >> 3;
|
int byte = attnum >> 3;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.58 2001/03/22 03:59:11 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.59 2001/03/22 06:16:06 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -155,16 +155,14 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||||||
if (myState->attrinfo != typeinfo || myState->nattrs != natts)
|
if (myState->attrinfo != typeinfo || myState->nattrs != natts)
|
||||||
printtup_prepare_info(myState, typeinfo, natts);
|
printtup_prepare_info(myState, typeinfo, natts);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* tell the frontend to expect new tuple data (in ASCII style)
|
* tell the frontend to expect new tuple data (in ASCII style)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pq_beginmessage(&buf);
|
pq_beginmessage(&buf);
|
||||||
pq_sendbyte(&buf, 'D');
|
pq_sendbyte(&buf, 'D');
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* send a bitmap of which attributes are not null
|
* send a bitmap of which attributes are not null
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
j = 0;
|
j = 0;
|
||||||
k = 1 << 7;
|
k = 1 << 7;
|
||||||
@@ -183,9 +181,8 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||||||
if (k != (1 << 7)) /* flush last partial byte */
|
if (k != (1 << 7)) /* flush last partial byte */
|
||||||
pq_sendint(&buf, j, 1);
|
pq_sendint(&buf, j, 1);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* send the attributes of this tuple
|
* send the attributes of this tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < natts; ++i)
|
for (i = 0; i < natts; ++i)
|
||||||
{
|
{
|
||||||
@@ -357,16 +354,14 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||||||
if (myState->attrinfo != typeinfo || myState->nattrs != natts)
|
if (myState->attrinfo != typeinfo || myState->nattrs != natts)
|
||||||
printtup_prepare_info(myState, typeinfo, natts);
|
printtup_prepare_info(myState, typeinfo, natts);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* tell the frontend to expect new tuple data (in binary style)
|
* tell the frontend to expect new tuple data (in binary style)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pq_beginmessage(&buf);
|
pq_beginmessage(&buf);
|
||||||
pq_sendbyte(&buf, 'B');
|
pq_sendbyte(&buf, 'B');
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* send a bitmap of which attributes are not null
|
* send a bitmap of which attributes are not null
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
j = 0;
|
j = 0;
|
||||||
k = 1 << 7;
|
k = 1 << 7;
|
||||||
@@ -385,9 +380,8 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||||||
if (k != (1 << 7)) /* flush last partial byte */
|
if (k != (1 << 7)) /* flush last partial byte */
|
||||||
pq_sendint(&buf, j, 1);
|
pq_sendint(&buf, j, 1);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* send the attributes of this tuple
|
* send the attributes of this tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
#ifdef IPORTAL_DEBUG
|
#ifdef IPORTAL_DEBUG
|
||||||
fprintf(stderr, "sending tuple with %d atts\n", natts);
|
fprintf(stderr, "sending tuple with %d atts\n", natts);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.72 2001/03/22 03:59:11 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.73 2001/03/22 06:16:06 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
|
||||||
@@ -37,17 +37,15 @@ CreateTemplateTupleDesc(int natts)
|
|||||||
uint32 size;
|
uint32 size;
|
||||||
TupleDesc desc;
|
TupleDesc desc;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
AssertArg(natts >= 1);
|
AssertArg(natts >= 1);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* allocate enough memory for the tuple descriptor and
|
* allocate enough memory for the tuple descriptor and zero it as
|
||||||
* zero it as TupleDescInitEntry assumes that the descriptor
|
* TupleDescInitEntry assumes that the descriptor is filled with NULL
|
||||||
* is filled with NULL pointers.
|
* pointers.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
size = natts * sizeof(Form_pg_attribute);
|
size = natts * sizeof(Form_pg_attribute);
|
||||||
desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
|
desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
|
||||||
@@ -71,9 +69,8 @@ CreateTupleDesc(int natts, Form_pg_attribute *attrs)
|
|||||||
{
|
{
|
||||||
TupleDesc desc;
|
TupleDesc desc;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
AssertArg(natts >= 1);
|
AssertArg(natts >= 1);
|
||||||
|
|
||||||
@@ -337,9 +334,8 @@ TupleDescInitEntry(TupleDesc desc,
|
|||||||
Form_pg_type typeForm;
|
Form_pg_type typeForm;
|
||||||
Form_pg_attribute att;
|
Form_pg_attribute att;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
AssertArg(PointerIsValid(desc));
|
AssertArg(PointerIsValid(desc));
|
||||||
AssertArg(attributeNumber >= 1);
|
AssertArg(attributeNumber >= 1);
|
||||||
@@ -352,17 +348,15 @@ TupleDescInitEntry(TupleDesc desc,
|
|||||||
|
|
||||||
AssertArg(!PointerIsValid(desc->attrs[attributeNumber - 1]));
|
AssertArg(!PointerIsValid(desc->attrs[attributeNumber - 1]));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* allocate storage for this attribute
|
* allocate storage for this attribute
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
att = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
|
att = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
|
||||||
desc->attrs[attributeNumber - 1] = att;
|
desc->attrs[attributeNumber - 1] = att;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize the attribute fields
|
* initialize the attribute fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
att->attrelid = 0; /* dummy value */
|
att->attrelid = 0; /* dummy value */
|
||||||
|
|
||||||
@@ -404,10 +398,10 @@ TupleDescInitEntry(TupleDesc desc,
|
|||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
if (!HeapTupleIsValid(tuple))
|
if (!HeapTupleIsValid(tuple))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* here type info does not exist yet so we just fill
|
/*
|
||||||
* the attribute with dummy information and return false.
|
* here type info does not exist yet so we just fill the attribute
|
||||||
* ----------------
|
* with dummy information and return false.
|
||||||
*/
|
*/
|
||||||
att->atttypid = InvalidOid;
|
att->atttypid = InvalidOid;
|
||||||
att->attlen = (int16) 0;
|
att->attlen = (int16) 0;
|
||||||
@@ -417,32 +411,30 @@ TupleDescInitEntry(TupleDesc desc,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* type info exists so we initialize our attribute
|
* type info exists so we initialize our attribute information from
|
||||||
* information from the type tuple we found..
|
* the type tuple we found..
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
typeForm = (Form_pg_type) GETSTRUCT(tuple);
|
typeForm = (Form_pg_type) GETSTRUCT(tuple);
|
||||||
|
|
||||||
att->atttypid = tuple->t_data->t_oid;
|
att->atttypid = tuple->t_data->t_oid;
|
||||||
|
|
||||||
/*------------------------
|
/*
|
||||||
* There are a couple of cases where we must override the information
|
* There are a couple of cases where we must override the information
|
||||||
* stored in pg_type.
|
* stored in pg_type.
|
||||||
*
|
*
|
||||||
* First: if this attribute is a set, what is really stored in the
|
* First: if this attribute is a set, what is really stored in the
|
||||||
* attribute is the OID of a tuple in the pg_proc catalog.
|
* attribute is the OID of a tuple in the pg_proc catalog. The pg_proc
|
||||||
* The pg_proc tuple contains the query string which defines
|
* tuple contains the query string which defines this set - i.e., the
|
||||||
* this set - i.e., the query to run to get the set.
|
* query to run to get the set. So the atttypid (just assigned above)
|
||||||
* So the atttypid (just assigned above) refers to the type returned
|
* refers to the type returned by this query, but the actual length of
|
||||||
* by this query, but the actual length of this attribute is the
|
* this attribute is the length (size) of an OID.
|
||||||
* length (size) of an OID.
|
|
||||||
*
|
*
|
||||||
* (Why not just make the atttypid point to the OID type, instead
|
* (Why not just make the atttypid point to the OID type, instead of the
|
||||||
* of the type the query returns? Because the executor uses the atttypid
|
* type the query returns? Because the executor uses the atttypid to
|
||||||
* to tell the front end what type will be returned (in BeginCommand),
|
* tell the front end what type will be returned (in BeginCommand),
|
||||||
* and in the end the type returned will be the result of the query, not
|
* and in the end the type returned will be the result of the query,
|
||||||
* an OID.)
|
* not an OID.)
|
||||||
*
|
*
|
||||||
* (Why not wait until the return type of the set is known (i.e., the
|
* (Why not wait until the return type of the set is known (i.e., the
|
||||||
* recursive call to the executor to execute the set has returned)
|
* recursive call to the executor to execute the set has returned)
|
||||||
@@ -460,7 +452,6 @@ TupleDescInitEntry(TupleDesc desc,
|
|||||||
*
|
*
|
||||||
* A set of complex type is first and foremost a set, so its
|
* A set of complex type is first and foremost a set, so its
|
||||||
* representation is Oid not pointer. So, test that case first.
|
* representation is Oid not pointer. So, test that case first.
|
||||||
*-----------------------------------------
|
|
||||||
*/
|
*/
|
||||||
if (attisset)
|
if (attisset)
|
||||||
{
|
{
|
||||||
@@ -550,9 +541,8 @@ BuildDescForRelation(List *schema, char *relname)
|
|||||||
int ndef = 0;
|
int ndef = 0;
|
||||||
bool attisset;
|
bool attisset;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* allocate a new tuple descriptor
|
* allocate a new tuple descriptor
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
natts = length(schema);
|
natts = length(schema);
|
||||||
desc = CreateTemplateTupleDesc(natts);
|
desc = CreateTemplateTupleDesc(natts);
|
||||||
@@ -565,11 +555,10 @@ BuildDescForRelation(List *schema, char *relname)
|
|||||||
ColumnDef *entry = lfirst(p);
|
ColumnDef *entry = lfirst(p);
|
||||||
List *arry;
|
List *arry;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* for each entry in the list, get the name and type
|
* for each entry in the list, get the name and type information
|
||||||
* information from the list and have TupleDescInitEntry
|
* from the list and have TupleDescInitEntry fill in the attribute
|
||||||
* fill in the attribute information we need.
|
* information we need.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
attnum++;
|
attnum++;
|
||||||
|
|
||||||
@@ -595,12 +584,12 @@ BuildDescForRelation(List *schema, char *relname)
|
|||||||
typenameTypeId(typename),
|
typenameTypeId(typename),
|
||||||
atttypmod, attdim, attisset))
|
atttypmod, attdim, attisset))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* if TupleDescInitEntry() fails, it means there is
|
/*
|
||||||
* no type in the system catalogs. So now we check if
|
* if TupleDescInitEntry() fails, it means there is no type in
|
||||||
* the type name equals the relation name. If so we
|
* the system catalogs. So now we check if the type name
|
||||||
* have a self reference, otherwise it's an error.
|
* equals the relation name. If so we have a self reference,
|
||||||
* ----------------
|
* otherwise it's an error.
|
||||||
*/
|
*/
|
||||||
if (strcmp(typename, relname) == 0)
|
if (strcmp(typename, relname) == 0)
|
||||||
TupleDescMakeSelfReference(desc, attnum, relname);
|
TupleDescMakeSelfReference(desc, attnum, relname);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.111 2001/03/22 03:59:13 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.112 2001/03/22 06:16:07 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@@ -116,20 +116,20 @@ initscan(HeapScanDesc scan,
|
|||||||
unsigned nkeys,
|
unsigned nkeys,
|
||||||
ScanKey key)
|
ScanKey key)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* Make sure we have up-to-date idea of number of blocks in relation.
|
* Make sure we have up-to-date idea of number of blocks in relation.
|
||||||
* It is sufficient to do this once at scan start, since any tuples
|
* It is sufficient to do this once at scan start, since any tuples
|
||||||
* added while the scan is in progress will be invisible to my
|
* added while the scan is in progress will be invisible to my
|
||||||
* transaction anyway...
|
* transaction anyway...
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
relation->rd_nblocks = RelationGetNumberOfBlocks(relation);
|
relation->rd_nblocks = RelationGetNumberOfBlocks(relation);
|
||||||
|
|
||||||
if (relation->rd_nblocks == 0)
|
if (relation->rd_nblocks == 0)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* relation is empty
|
* relation is empty
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
scan->rs_ntup.t_datamcxt = scan->rs_ctup.t_datamcxt =
|
scan->rs_ntup.t_datamcxt = scan->rs_ctup.t_datamcxt =
|
||||||
scan->rs_ptup.t_datamcxt = NULL;
|
scan->rs_ptup.t_datamcxt = NULL;
|
||||||
@@ -139,9 +139,9 @@ initscan(HeapScanDesc scan,
|
|||||||
}
|
}
|
||||||
else if (atend)
|
else if (atend)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* reverse scan
|
* reverse scan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
scan->rs_ntup.t_datamcxt = scan->rs_ctup.t_datamcxt = NULL;
|
scan->rs_ntup.t_datamcxt = scan->rs_ctup.t_datamcxt = NULL;
|
||||||
scan->rs_ntup.t_data = scan->rs_ctup.t_data = NULL;
|
scan->rs_ntup.t_data = scan->rs_ctup.t_data = NULL;
|
||||||
@@ -152,9 +152,9 @@ initscan(HeapScanDesc scan,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* forward scan
|
* forward scan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
scan->rs_ctup.t_datamcxt = scan->rs_ptup.t_datamcxt = NULL;
|
scan->rs_ctup.t_datamcxt = scan->rs_ptup.t_datamcxt = NULL;
|
||||||
scan->rs_ctup.t_data = scan->rs_ptup.t_data = NULL;
|
scan->rs_ctup.t_data = scan->rs_ptup.t_data = NULL;
|
||||||
@@ -170,9 +170,8 @@ initscan(HeapScanDesc scan,
|
|||||||
ItemPointerSetInvalid(&(scan->rs_mntid));
|
ItemPointerSetInvalid(&(scan->rs_mntid));
|
||||||
ItemPointerSetInvalid(&(scan->rs_mcd));
|
ItemPointerSetInvalid(&(scan->rs_mcd));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy the scan key, if appropriate
|
* copy the scan key, if appropriate
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (key != NULL)
|
if (key != NULL)
|
||||||
memmove(scan->rs_key, key, nkeys * sizeof(ScanKeyData));
|
memmove(scan->rs_key, key, nkeys * sizeof(ScanKeyData));
|
||||||
@@ -188,11 +187,9 @@ unpinscan(HeapScanDesc scan)
|
|||||||
if (BufferIsValid(scan->rs_pbuf))
|
if (BufferIsValid(scan->rs_pbuf))
|
||||||
ReleaseBuffer(scan->rs_pbuf);
|
ReleaseBuffer(scan->rs_pbuf);
|
||||||
|
|
||||||
/* ------------------------------------
|
/*
|
||||||
* Scan will pin buffer once for each non-NULL tuple pointer
|
* Scan will pin buffer once for each non-NULL tuple pointer (ptup,
|
||||||
* (ptup, ctup, ntup), so they have to be unpinned multiple
|
* ctup, ntup), so they have to be unpinned multiple times.
|
||||||
* times.
|
|
||||||
* ------------------------------------
|
|
||||||
*/
|
*/
|
||||||
if (BufferIsValid(scan->rs_cbuf))
|
if (BufferIsValid(scan->rs_cbuf))
|
||||||
ReleaseBuffer(scan->rs_cbuf);
|
ReleaseBuffer(scan->rs_cbuf);
|
||||||
@@ -251,19 +248,17 @@ heapgettup(Relation relation,
|
|||||||
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
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_heapgettup);
|
IncrHeapAccessStat(local_heapgettup);
|
||||||
IncrHeapAccessStat(global_heapgettup);
|
IncrHeapAccessStat(global_heapgettup);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* debugging stuff
|
* debugging stuff
|
||||||
*
|
*
|
||||||
* check validity of arguments, here and for other functions too
|
* check validity of arguments, here and for other functions too Note: no
|
||||||
* Note: no locking manipulations needed--this is a local function
|
* locking manipulations needed--this is a local function
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
#ifdef HEAPDEBUGALL
|
#ifdef HEAPDEBUGALL
|
||||||
if (ItemPointerIsValid(tid))
|
if (ItemPointerIsValid(tid))
|
||||||
@@ -289,9 +284,8 @@ heapgettup(Relation relation,
|
|||||||
|
|
||||||
tuple->t_tableOid = relation->rd_id;
|
tuple->t_tableOid = relation->rd_id;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* return null immediately if relation is empty
|
* return null immediately if relation is empty
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!(pages = relation->rd_nblocks))
|
if (!(pages = relation->rd_nblocks))
|
||||||
{
|
{
|
||||||
@@ -300,15 +294,14 @@ heapgettup(Relation relation,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* calculate next starting lineoff, given scan direction
|
* calculate next starting lineoff, given scan direction
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!dir)
|
if (!dir)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* ``no movement'' scan direction
|
* ``no movement'' scan direction
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
/* assume it is a valid TID XXX */
|
/* assume it is a valid TID XXX */
|
||||||
if (ItemPointerIsValid(tid) == false)
|
if (ItemPointerIsValid(tid) == false)
|
||||||
@@ -340,9 +333,9 @@ heapgettup(Relation relation,
|
|||||||
}
|
}
|
||||||
else if (dir < 0)
|
else if (dir < 0)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* reverse scan direction
|
* reverse scan direction
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (ItemPointerIsValid(tid) == false)
|
if (ItemPointerIsValid(tid) == false)
|
||||||
tid = NULL;
|
tid = NULL;
|
||||||
@@ -383,9 +376,9 @@ heapgettup(Relation relation,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* forward scan direction
|
* forward scan direction
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (ItemPointerIsValid(tid) == false)
|
if (ItemPointerIsValid(tid) == false)
|
||||||
{
|
{
|
||||||
@@ -420,10 +413,9 @@ heapgettup(Relation relation,
|
|||||||
|
|
||||||
/* 'dir' is now non-zero */
|
/* 'dir' is now non-zero */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* calculate line pointer and number of remaining items
|
* calculate line pointer and number of remaining items to check on
|
||||||
* to check on this page.
|
* this page.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
lpp = PageGetItemId(dp, lineoff);
|
lpp = PageGetItemId(dp, lineoff);
|
||||||
if (dir < 0)
|
if (dir < 0)
|
||||||
@@ -431,10 +423,9 @@ heapgettup(Relation relation,
|
|||||||
else
|
else
|
||||||
linesleft = lines - lineoff;
|
linesleft = lines - lineoff;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* advance the scan until we find a qualifying tuple or
|
* advance the scan until we find a qualifying tuple or run out of
|
||||||
* run out of stuff to scan
|
* stuff to scan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@@ -446,9 +437,9 @@ heapgettup(Relation relation,
|
|||||||
tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
|
tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
|
||||||
tuple->t_len = ItemIdGetLength(lpp);
|
tuple->t_len = ItemIdGetLength(lpp);
|
||||||
ItemPointerSet(&(tuple->t_self), page, lineoff);
|
ItemPointerSet(&(tuple->t_self), page, lineoff);
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* if current tuple qualifies, return it.
|
* if current tuple qualifies, return it.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
HeapTupleSatisfies(tuple, relation, *buffer, (PageHeader) dp,
|
HeapTupleSatisfies(tuple, relation, *buffer, (PageHeader) dp,
|
||||||
snapshot, nkeys, key);
|
snapshot, nkeys, key);
|
||||||
@@ -459,9 +450,8 @@ heapgettup(Relation relation,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* otherwise move to the next item on the page
|
* otherwise move to the next item on the page
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
--linesleft;
|
--linesleft;
|
||||||
if (dir < 0)
|
if (dir < 0)
|
||||||
@@ -477,17 +467,15 @@ heapgettup(Relation relation,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if we get here, it means we've exhausted the items on
|
* if we get here, it means we've exhausted the items on this page
|
||||||
* this page and it's time to move to the next..
|
* and it's time to move to the next..
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
|
||||||
page = nextpage(page, dir);
|
page = nextpage(page, dir);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* return NULL if we've exhausted all the pages..
|
* return NULL if we've exhausted all the pages..
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (page < 0 || page >= pages)
|
if (page < 0 || page >= pages)
|
||||||
{
|
{
|
||||||
@@ -588,9 +576,8 @@ heap_open(Oid relationId, LOCKMODE lockmode)
|
|||||||
|
|
||||||
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
|
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_open);
|
IncrHeapAccessStat(local_open);
|
||||||
IncrHeapAccessStat(global_open);
|
IncrHeapAccessStat(global_open);
|
||||||
@@ -626,9 +613,8 @@ heap_openr(const char *relationName, LOCKMODE lockmode)
|
|||||||
|
|
||||||
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
|
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_openr);
|
IncrHeapAccessStat(local_openr);
|
||||||
IncrHeapAccessStat(global_openr);
|
IncrHeapAccessStat(global_openr);
|
||||||
@@ -663,9 +649,8 @@ heap_open_nofail(Oid relationId)
|
|||||||
{
|
{
|
||||||
Relation r;
|
Relation r;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_open);
|
IncrHeapAccessStat(local_open);
|
||||||
IncrHeapAccessStat(global_open);
|
IncrHeapAccessStat(global_open);
|
||||||
@@ -694,9 +679,8 @@ heap_openr_nofail(const char *relationName)
|
|||||||
{
|
{
|
||||||
Relation r;
|
Relation r;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_openr);
|
IncrHeapAccessStat(local_openr);
|
||||||
IncrHeapAccessStat(global_openr);
|
IncrHeapAccessStat(global_openr);
|
||||||
@@ -724,9 +708,8 @@ heap_close(Relation relation, LOCKMODE lockmode)
|
|||||||
{
|
{
|
||||||
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
|
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_close);
|
IncrHeapAccessStat(local_close);
|
||||||
IncrHeapAccessStat(global_close);
|
IncrHeapAccessStat(global_close);
|
||||||
@@ -752,27 +735,24 @@ heap_beginscan(Relation relation,
|
|||||||
{
|
{
|
||||||
HeapScanDesc scan;
|
HeapScanDesc scan;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_beginscan);
|
IncrHeapAccessStat(local_beginscan);
|
||||||
IncrHeapAccessStat(global_beginscan);
|
IncrHeapAccessStat(global_beginscan);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!RelationIsValid(relation))
|
if (!RelationIsValid(relation))
|
||||||
elog(ERROR, "heap_beginscan: !RelationIsValid(relation)");
|
elog(ERROR, "heap_beginscan: !RelationIsValid(relation)");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* increment relation ref count while scanning relation
|
* increment relation ref count while scanning relation
|
||||||
*
|
*
|
||||||
* This is just to make really sure the relcache entry won't go away
|
* This is just to make really sure the relcache entry won't go away
|
||||||
* while the scan has a pointer to it. Caller should be holding the
|
* while the scan has a pointer to it. Caller should be holding the
|
||||||
* rel open anyway, so this is redundant in all normal scenarios...
|
* rel open anyway, so this is redundant in all normal scenarios...
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
RelationIncrementReferenceCount(relation);
|
RelationIncrementReferenceCount(relation);
|
||||||
|
|
||||||
@@ -780,9 +760,8 @@ heap_beginscan(Relation relation,
|
|||||||
if (relation->rd_rel->relkind == RELKIND_UNCATALOGED)
|
if (relation->rd_rel->relkind == RELKIND_UNCATALOGED)
|
||||||
snapshot = SnapshotSelf;
|
snapshot = SnapshotSelf;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* allocate and initialize scan descriptor
|
* allocate and initialize scan descriptor
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
scan = (HeapScanDesc) palloc(sizeof(HeapScanDescData));
|
scan = (HeapScanDesc) palloc(sizeof(HeapScanDescData));
|
||||||
|
|
||||||
@@ -814,22 +793,20 @@ heap_rescan(HeapScanDesc scan,
|
|||||||
bool scanFromEnd,
|
bool scanFromEnd,
|
||||||
ScanKey key)
|
ScanKey key)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_rescan);
|
IncrHeapAccessStat(local_rescan);
|
||||||
IncrHeapAccessStat(global_rescan);
|
IncrHeapAccessStat(global_rescan);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* unpin scan buffers
|
* unpin scan buffers
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
unpinscan(scan);
|
unpinscan(scan);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* reinitialize scan descriptor
|
* reinitialize scan descriptor
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
scan->rs_atend = scanFromEnd;
|
scan->rs_atend = scanFromEnd;
|
||||||
initscan(scan, scan->rs_rd, scanFromEnd, scan->rs_nkeys, key);
|
initscan(scan, scan->rs_rd, scanFromEnd, scan->rs_nkeys, key);
|
||||||
@@ -845,24 +822,22 @@ heap_rescan(HeapScanDesc scan,
|
|||||||
void
|
void
|
||||||
heap_endscan(HeapScanDesc scan)
|
heap_endscan(HeapScanDesc scan)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_endscan);
|
IncrHeapAccessStat(local_endscan);
|
||||||
IncrHeapAccessStat(global_endscan);
|
IncrHeapAccessStat(global_endscan);
|
||||||
|
|
||||||
/* Note: no locking manipulations needed */
|
/* Note: no locking manipulations needed */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* unpin scan buffers
|
* unpin scan buffers
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
unpinscan(scan);
|
unpinscan(scan);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* decrement relation reference count and free scan descriptor storage
|
* decrement relation reference count and free scan descriptor storage
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
RelationDecrementReferenceCount(scan->rs_rd);
|
RelationDecrementReferenceCount(scan->rs_rd);
|
||||||
|
|
||||||
@@ -919,34 +894,31 @@ heap_getnext(HeapScanDesc scandesc, int backw)
|
|||||||
{
|
{
|
||||||
HeapScanDesc scan = scandesc;
|
HeapScanDesc scan = scandesc;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_getnext);
|
IncrHeapAccessStat(local_getnext);
|
||||||
IncrHeapAccessStat(global_getnext);
|
IncrHeapAccessStat(global_getnext);
|
||||||
|
|
||||||
/* Note: no locking manipulations needed */
|
/* Note: no locking manipulations needed */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* argument checks
|
* argument checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (scan == NULL)
|
if (scan == NULL)
|
||||||
elog(ERROR, "heap_getnext: NULL relscan");
|
elog(ERROR, "heap_getnext: NULL relscan");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize return buffer to InvalidBuffer
|
* initialize return buffer to InvalidBuffer
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HEAPDEBUG_1; /* heap_getnext( info ) */
|
HEAPDEBUG_1; /* heap_getnext( info ) */
|
||||||
|
|
||||||
if (backw)
|
if (backw)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* handle reverse scan
|
* handle reverse scan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
HEAPDEBUG_2; /* heap_getnext called with backw */
|
HEAPDEBUG_2; /* heap_getnext called with backw */
|
||||||
|
|
||||||
@@ -1020,9 +992,9 @@ heap_getnext(HeapScanDesc scandesc, int backw)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* handle forward scan
|
* handle forward scan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (scan->rs_ctup.t_data == scan->rs_ntup.t_data &&
|
if (scan->rs_ctup.t_data == scan->rs_ntup.t_data &&
|
||||||
BufferIsInvalid(scan->rs_nbuf))
|
BufferIsInvalid(scan->rs_nbuf))
|
||||||
@@ -1097,10 +1069,9 @@ heap_getnext(HeapScanDesc scandesc, int backw)
|
|||||||
scan->rs_nbuf = UnknownBuffer;
|
scan->rs_nbuf = UnknownBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if we get here it means we have a new current scan tuple, so
|
* if we get here it means we have a new current scan tuple, so point
|
||||||
* point to the proper return buffer and return the tuple.
|
* to the proper return buffer and return the tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HEAPDEBUG_7; /* heap_getnext returning tuple */
|
HEAPDEBUG_7; /* heap_getnext returning tuple */
|
||||||
@@ -1133,17 +1104,15 @@ heap_fetch(Relation relation,
|
|||||||
ItemPointer tid = &(tuple->t_self);
|
ItemPointer tid = &(tuple->t_self);
|
||||||
OffsetNumber offnum;
|
OffsetNumber offnum;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_fetch);
|
IncrHeapAccessStat(local_fetch);
|
||||||
IncrHeapAccessStat(global_fetch);
|
IncrHeapAccessStat(global_fetch);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the buffer from the relation descriptor
|
* get the buffer from the relation descriptor Note that this does a
|
||||||
* Note that this does a buffer pin.
|
* buffer pin.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
|
buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
|
||||||
@@ -1154,17 +1123,15 @@ heap_fetch(Relation relation,
|
|||||||
|
|
||||||
LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the item line pointer corresponding to the requested tid
|
* get the item line pointer corresponding to the requested tid
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
dp = (PageHeader) BufferGetPage(buffer);
|
dp = (PageHeader) BufferGetPage(buffer);
|
||||||
offnum = ItemPointerGetOffsetNumber(tid);
|
offnum = ItemPointerGetOffsetNumber(tid);
|
||||||
lp = PageGetItemId(dp, offnum);
|
lp = PageGetItemId(dp, offnum);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* more sanity checks
|
* more sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!ItemIdIsUsed(lp))
|
if (!ItemIdIsUsed(lp))
|
||||||
@@ -1182,9 +1149,8 @@ heap_fetch(Relation relation,
|
|||||||
tuple->t_len = ItemIdGetLength(lp);
|
tuple->t_len = ItemIdGetLength(lp);
|
||||||
tuple->t_tableOid = relation->rd_id;
|
tuple->t_tableOid = relation->rd_id;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* check time qualification of tid
|
* check time qualification of tid
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HeapTupleSatisfies(tuple, relation, buffer, dp,
|
HeapTupleSatisfies(tuple, relation, buffer, dp,
|
||||||
@@ -1229,10 +1195,9 @@ heap_get_latest_tid(Relation relation,
|
|||||||
bool invalidBlock,
|
bool invalidBlock,
|
||||||
linkend;
|
linkend;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the buffer from the relation descriptor
|
* get the buffer from the relation descriptor Note that this does a
|
||||||
* Note that this does a buffer pin.
|
* buffer pin.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
|
buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
|
||||||
@@ -1243,9 +1208,8 @@ heap_get_latest_tid(Relation relation,
|
|||||||
|
|
||||||
LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the item line pointer corresponding to the requested tid
|
* get the item line pointer corresponding to the requested tid
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
dp = (PageHeader) BufferGetPage(buffer);
|
dp = (PageHeader) BufferGetPage(buffer);
|
||||||
offnum = ItemPointerGetOffsetNumber(tid);
|
offnum = ItemPointerGetOffsetNumber(tid);
|
||||||
@@ -1263,9 +1227,8 @@ heap_get_latest_tid(Relation relation,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* more sanity checks
|
* more sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
tp.t_datamcxt = NULL;
|
tp.t_datamcxt = NULL;
|
||||||
@@ -1274,9 +1237,8 @@ heap_get_latest_tid(Relation relation,
|
|||||||
tp.t_self = *tid;
|
tp.t_self = *tid;
|
||||||
ctid = tp.t_data->t_ctid;
|
ctid = tp.t_data->t_ctid;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* check time qualification of tid
|
* check time qualification of tid
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HeapTupleSatisfies(&tp, relation, buffer, dp,
|
HeapTupleSatisfies(&tp, relation, buffer, dp,
|
||||||
@@ -1323,15 +1285,13 @@ heap_insert(Relation relation, HeapTuple tup)
|
|||||||
IncrHeapAccessStat(local_insert);
|
IncrHeapAccessStat(local_insert);
|
||||||
IncrHeapAccessStat(global_insert);
|
IncrHeapAccessStat(global_insert);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* If the object id of this tuple has already been assigned, trust
|
* If the object id of this tuple has already been assigned, trust the
|
||||||
* the caller. There are a couple of ways this can happen. At initial
|
* caller. There are a couple of ways this can happen. At initial db
|
||||||
* db creation, the backend program sets oids for tuples. When we
|
* creation, the backend program sets oids for tuples. When we define
|
||||||
* define an index, we set the oid. Finally, in the future, we may
|
* an index, we set the oid. Finally, in the future, we may allow
|
||||||
* allow users to set their own object ids in order to support a
|
* users to set their own object ids in order to support a persistent
|
||||||
* persistent object store (objects need to contain pointers to one
|
* object store (objects need to contain pointers to one another).
|
||||||
* another).
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!OidIsValid(tup->t_data->t_oid))
|
if (!OidIsValid(tup->t_data->t_oid))
|
||||||
tup->t_data->t_oid = newoid();
|
tup->t_data->t_oid = newoid();
|
||||||
@@ -1346,10 +1306,10 @@ heap_insert(Relation relation, HeapTuple tup)
|
|||||||
tup->t_tableOid = relation->rd_id;
|
tup->t_tableOid = relation->rd_id;
|
||||||
|
|
||||||
#ifdef TUPLE_TOASTER_ACTIVE
|
#ifdef TUPLE_TOASTER_ACTIVE
|
||||||
/* ----------
|
|
||||||
* If the new tuple is too big for storage or contains already
|
/*
|
||||||
* toasted attributes from some other relation, invoke the toaster.
|
* If the new tuple is too big for storage or contains already toasted
|
||||||
* ----------
|
* attributes from some other relation, invoke the toaster.
|
||||||
*/
|
*/
|
||||||
if (HeapTupleHasExtended(tup) ||
|
if (HeapTupleHasExtended(tup) ||
|
||||||
(MAXALIGN(tup->t_len) > TOAST_TUPLE_THRESHOLD))
|
(MAXALIGN(tup->t_len) > TOAST_TUPLE_THRESHOLD))
|
||||||
@@ -1540,12 +1500,12 @@ l1:
|
|||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
|
||||||
#ifdef TUPLE_TOASTER_ACTIVE
|
#ifdef TUPLE_TOASTER_ACTIVE
|
||||||
/* ----------
|
|
||||||
* If the relation has toastable attributes, we need to delete
|
/*
|
||||||
* no longer needed items there too. We have to do this before
|
* If the relation has toastable attributes, we need to delete no
|
||||||
|
* longer needed items there too. We have to do this before
|
||||||
* WriteBuffer because we need to look at the contents of the tuple,
|
* WriteBuffer because we need to look at the contents of the tuple,
|
||||||
* but it's OK to release the context lock on the buffer first.
|
* but it's OK to release the context lock on the buffer first.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (HeapTupleHasExtended(&tp))
|
if (HeapTupleHasExtended(&tp))
|
||||||
heap_tuple_toast_attrs(relation, NULL, &(tp));
|
heap_tuple_toast_attrs(relation, NULL, &(tp));
|
||||||
@@ -1977,9 +1937,8 @@ void
|
|||||||
heap_markpos(HeapScanDesc scan)
|
heap_markpos(HeapScanDesc scan)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_markpos);
|
IncrHeapAccessStat(local_markpos);
|
||||||
IncrHeapAccessStat(global_markpos);
|
IncrHeapAccessStat(global_markpos);
|
||||||
@@ -2012,9 +1971,8 @@ heap_markpos(HeapScanDesc scan)
|
|||||||
scan->rs_key);
|
scan->rs_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Should not unpin the buffer pages. They may still be in use.
|
* Should not unpin the buffer pages. They may still be in use.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (scan->rs_ptup.t_data != NULL)
|
if (scan->rs_ptup.t_data != NULL)
|
||||||
scan->rs_mptid = scan->rs_ptup.t_self;
|
scan->rs_mptid = scan->rs_ptup.t_self;
|
||||||
@@ -2054,9 +2012,9 @@ heap_markpos(HeapScanDesc scan)
|
|||||||
void
|
void
|
||||||
heap_restrpos(HeapScanDesc scan)
|
heap_restrpos(HeapScanDesc scan)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_restrpos);
|
IncrHeapAccessStat(local_restrpos);
|
||||||
IncrHeapAccessStat(global_restrpos);
|
IncrHeapAccessStat(global_restrpos);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Id: hio.c,v 1.36 2001/03/22 03:59:13 momjian Exp $
|
* $Id: hio.c,v 1.37 2001/03/22 06:16:07 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -37,9 +37,8 @@ RelationPutHeapTuple(Relation relation,
|
|||||||
ItemId itemId;
|
ItemId itemId;
|
||||||
Item item;
|
Item item;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* increment access statistics
|
* increment access statistics
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrHeapAccessStat(local_RelationPutHeapTuple);
|
IncrHeapAccessStat(local_RelationPutHeapTuple);
|
||||||
IncrHeapAccessStat(global_RelationPutHeapTuple);
|
IncrHeapAccessStat(global_RelationPutHeapTuple);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/Attic/stats.c,v 1.23 2001/01/24 19:42:48 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/heap/Attic/stats.c,v 1.24 2001/03/22 06:16:07 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* initam should be moved someplace else.
|
* initam should be moved someplace else.
|
||||||
@@ -37,25 +37,22 @@ InitHeapAccessStatistics()
|
|||||||
MemoryContext oldContext;
|
MemoryContext oldContext;
|
||||||
HeapAccessStatistics stats;
|
HeapAccessStatistics stats;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* make sure we don't initialize things twice
|
* make sure we don't initialize things twice
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (heap_access_stats != NULL)
|
if (heap_access_stats != NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* allocate statistics structure from the top memory context
|
* allocate statistics structure from the top memory context
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
oldContext = MemoryContextSwitchTo(TopMemoryContext);
|
oldContext = MemoryContextSwitchTo(TopMemoryContext);
|
||||||
|
|
||||||
stats = (HeapAccessStatistics)
|
stats = (HeapAccessStatistics)
|
||||||
palloc(sizeof(HeapAccessStatisticsData));
|
palloc(sizeof(HeapAccessStatisticsData));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize fields to default values
|
* initialize fields to default values
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
stats->global_open = 0;
|
stats->global_open = 0;
|
||||||
stats->global_openr = 0;
|
stats->global_openr = 0;
|
||||||
@@ -103,17 +100,15 @@ InitHeapAccessStatistics()
|
|||||||
stats->local_RelationNameGetRelation = 0;
|
stats->local_RelationNameGetRelation = 0;
|
||||||
stats->global_RelationNameGetRelation = 0;
|
stats->global_RelationNameGetRelation = 0;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* record init times
|
* record init times
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
time(&stats->init_global_timestamp);
|
time(&stats->init_global_timestamp);
|
||||||
time(&stats->local_reset_timestamp);
|
time(&stats->local_reset_timestamp);
|
||||||
time(&stats->last_request_timestamp);
|
time(&stats->last_request_timestamp);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* return to old memory context
|
* return to old memory context
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(oldContext);
|
MemoryContextSwitchTo(oldContext);
|
||||||
|
|
||||||
@@ -130,18 +125,16 @@ ResetHeapAccessStatistics()
|
|||||||
{
|
{
|
||||||
HeapAccessStatistics stats;
|
HeapAccessStatistics stats;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* do nothing if stats aren't initialized
|
* do nothing if stats aren't initialized
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (heap_access_stats == NULL)
|
if (heap_access_stats == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
stats = heap_access_stats;
|
stats = heap_access_stats;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* reset local counts
|
* reset local counts
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
stats->local_open = 0;
|
stats->local_open = 0;
|
||||||
stats->local_openr = 0;
|
stats->local_openr = 0;
|
||||||
@@ -165,9 +158,8 @@ ResetHeapAccessStatistics()
|
|||||||
stats->local_RelationPutHeapTuple = 0;
|
stats->local_RelationPutHeapTuple = 0;
|
||||||
stats->local_RelationPutLongHeapTuple = 0;
|
stats->local_RelationPutLongHeapTuple = 0;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* reset local timestamps
|
* reset local timestamps
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
time(&stats->local_reset_timestamp);
|
time(&stats->local_reset_timestamp);
|
||||||
time(&stats->last_request_timestamp);
|
time(&stats->last_request_timestamp);
|
||||||
@@ -185,22 +177,19 @@ GetHeapAccessStatistics()
|
|||||||
{
|
{
|
||||||
HeapAccessStatistics stats;
|
HeapAccessStatistics stats;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* return nothing if stats aren't initialized
|
* return nothing if stats aren't initialized
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (heap_access_stats == NULL)
|
if (heap_access_stats == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* record the current request time
|
* record the current request time
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
time(&heap_access_stats->last_request_timestamp);
|
time(&heap_access_stats->last_request_timestamp);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* allocate a copy of the stats and return it to the caller.
|
* allocate a copy of the stats and return it to the caller.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
stats = (HeapAccessStatistics)
|
stats = (HeapAccessStatistics)
|
||||||
palloc(sizeof(HeapAccessStatisticsData));
|
palloc(sizeof(HeapAccessStatisticsData));
|
||||||
@@ -222,9 +211,9 @@ GetHeapAccessStatistics()
|
|||||||
void
|
void
|
||||||
PrintHeapAccessStatistics(HeapAccessStatistics stats)
|
PrintHeapAccessStatistics(HeapAccessStatistics stats)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* return nothing if stats aren't valid
|
* return nothing if stats aren't valid
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (stats == NULL)
|
if (stats == NULL)
|
||||||
return;
|
return;
|
||||||
@@ -342,9 +331,9 @@ PrintAndFreeHeapAccessStatistics(HeapAccessStatistics stats)
|
|||||||
void
|
void
|
||||||
initam(void)
|
initam(void)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* initialize heap statistics.
|
* initialize heap statistics.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
InitHeapAccessStatistics();
|
InitHeapAccessStatistics();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.18 2001/03/22 03:59:13 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.19 2001/03/22 06:16:07 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@@ -81,17 +81,18 @@ heap_tuple_fetch_attr(varattrib *attr)
|
|||||||
|
|
||||||
if (VARATT_IS_EXTERNAL(attr))
|
if (VARATT_IS_EXTERNAL(attr))
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* This is an external stored plain value
|
* This is an external stored plain value
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
result = toast_fetch_datum(attr);
|
result = toast_fetch_datum(attr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* This is a plain value inside of the main tuple - why am I called?
|
/*
|
||||||
* ----------
|
* This is a plain value inside of the main tuple - why am I
|
||||||
|
* called?
|
||||||
*/
|
*/
|
||||||
result = attr;
|
result = attr;
|
||||||
}
|
}
|
||||||
@@ -134,18 +135,18 @@ heap_tuple_untoast_attr(varattrib *attr)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* This is an external stored plain value
|
* This is an external stored plain value
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
result = toast_fetch_datum(attr);
|
result = toast_fetch_datum(attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (VARATT_IS_COMPRESSED(attr))
|
else if (VARATT_IS_COMPRESSED(attr))
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* This is a compressed value inside of the main tuple
|
* This is a compressed value inside of the main tuple
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
result = (varattrib *) palloc(attr->va_content.va_compressed.va_rawsize
|
result = (varattrib *) palloc(attr->va_content.va_compressed.va_rawsize
|
||||||
+ VARHDRSZ);
|
+ VARHDRSZ);
|
||||||
@@ -154,9 +155,10 @@ heap_tuple_untoast_attr(varattrib *attr)
|
|||||||
pglz_decompress((PGLZ_Header *) attr, VARATT_DATA(result));
|
pglz_decompress((PGLZ_Header *) attr, VARATT_DATA(result));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* ----------
|
|
||||||
* This is a plain value inside of the main tuple - why am I called?
|
/*
|
||||||
* ----------
|
* This is a plain value inside of the main tuple - why am I
|
||||||
|
* called?
|
||||||
*/
|
*/
|
||||||
return attr;
|
return attr;
|
||||||
|
|
||||||
@@ -180,19 +182,16 @@ toast_delete(Relation rel, HeapTuple oldtup)
|
|||||||
Datum value;
|
Datum value;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the tuple descriptor, the number of and attribute
|
* Get the tuple descriptor, the number of and attribute descriptors.
|
||||||
* descriptors.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
tupleDesc = rel->rd_att;
|
tupleDesc = rel->rd_att;
|
||||||
numAttrs = tupleDesc->natts;
|
numAttrs = tupleDesc->natts;
|
||||||
att = tupleDesc->attrs;
|
att = tupleDesc->attrs;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Check for external stored attributes and delete them
|
* Check for external stored attributes and delete them from the
|
||||||
* from the secondary relation.
|
* secondary relation.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < numAttrs; i++)
|
for (i = 0; i < numAttrs; i++)
|
||||||
{
|
{
|
||||||
@@ -237,10 +236,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
bool toast_free[MaxHeapAttributeNumber];
|
bool toast_free[MaxHeapAttributeNumber];
|
||||||
bool toast_delold[MaxHeapAttributeNumber];
|
bool toast_delold[MaxHeapAttributeNumber];
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the tuple descriptor, the number of and attribute
|
* Get the tuple descriptor, the number of and attribute descriptors
|
||||||
* descriptors and the location of the tuple values.
|
* and the location of the tuple values.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
tupleDesc = rel->rd_att;
|
tupleDesc = rel->rd_att;
|
||||||
numAttrs = tupleDesc->natts;
|
numAttrs = tupleDesc->natts;
|
||||||
@@ -266,9 +264,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
|
|
||||||
if (oldtup != NULL)
|
if (oldtup != NULL)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* For UPDATE get the old and new values of this attribute
|
* For UPDATE get the old and new values of this attribute
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
old_value = (varattrib *) DatumGetPointer(
|
old_value = (varattrib *) DatumGetPointer(
|
||||||
heap_getattr(oldtup, i + 1, tupleDesc, &old_isnull));
|
heap_getattr(oldtup, i + 1, tupleDesc, &old_isnull));
|
||||||
@@ -276,10 +274,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
heap_getattr(newtup, i + 1, tupleDesc, &new_isnull);
|
heap_getattr(newtup, i + 1, tupleDesc, &new_isnull);
|
||||||
new_value = (varattrib *) DatumGetPointer(toast_values[i]);
|
new_value = (varattrib *) DatumGetPointer(toast_values[i]);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If the old value is an external stored one, check if it
|
* If the old value is an external stored one, check if it has
|
||||||
* has changed so we have to delete it later.
|
* changed so we have to delete it later.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (!old_isnull && att[i]->attlen == -1 &&
|
if (!old_isnull && att[i]->attlen == -1 &&
|
||||||
VARATT_IS_EXTERNAL(old_value))
|
VARATT_IS_EXTERNAL(old_value))
|
||||||
@@ -290,21 +287,21 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
old_value->va_content.va_external.va_attno !=
|
old_value->va_content.va_external.va_attno !=
|
||||||
new_value->va_content.va_external.va_attno)
|
new_value->va_content.va_external.va_attno)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* The old external store value isn't needed any
|
/*
|
||||||
* more after the update
|
* The old external store value isn't needed any more
|
||||||
* ----------
|
* after the update
|
||||||
*/
|
*/
|
||||||
toast_delold[i] = true;
|
toast_delold[i] = true;
|
||||||
need_delold = true;
|
need_delold = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* This attribute isn't changed by this update
|
/*
|
||||||
* so we reuse the original reference to the old
|
* This attribute isn't changed by this update so we
|
||||||
* value in the new tuple.
|
* reuse the original reference to the old value in
|
||||||
* ----------
|
* the new tuple.
|
||||||
*/
|
*/
|
||||||
toast_action[i] = 'p';
|
toast_action[i] = 'p';
|
||||||
toast_sizes[i] = VARATT_SIZE(toast_values[i]);
|
toast_sizes[i] = VARATT_SIZE(toast_values[i]);
|
||||||
@@ -314,17 +311,16 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* For INSERT simply get the new value
|
* For INSERT simply get the new value
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
toast_values[i] =
|
toast_values[i] =
|
||||||
heap_getattr(newtup, i + 1, tupleDesc, &new_isnull);
|
heap_getattr(newtup, i + 1, tupleDesc, &new_isnull);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NULL attributes
|
* Handle NULL attributes
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (new_isnull)
|
if (new_isnull)
|
||||||
{
|
{
|
||||||
@@ -334,24 +330,22 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Now look at varsize attributes
|
* Now look at varsize attributes
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (att[i]->attlen == -1)
|
if (att[i]->attlen == -1)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* If the table's attribute says PLAIN always, force it so.
|
* If the table's attribute says PLAIN always, force it so.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (att[i]->attstorage == 'p')
|
if (att[i]->attstorage == 'p')
|
||||||
toast_action[i] = 'p';
|
toast_action[i] = 'p';
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* We took care of UPDATE above, so any external value we find
|
* We took care of UPDATE above, so any external value we find
|
||||||
* still in the tuple must be someone else's we cannot reuse.
|
* still in the tuple must be someone else's we cannot reuse.
|
||||||
* Expand it to plain (and, probably, toast it again below).
|
* Expand it to plain (and, probably, toast it again below).
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (VARATT_IS_EXTERNAL(DatumGetPointer(toast_values[i])))
|
if (VARATT_IS_EXTERNAL(DatumGetPointer(toast_values[i])))
|
||||||
{
|
{
|
||||||
@@ -362,17 +356,16 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
need_free = true;
|
need_free = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Remember the size of this attribute
|
* Remember the size of this attribute
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
toast_sizes[i] = VARATT_SIZE(DatumGetPointer(toast_values[i]));
|
toast_sizes[i] = VARATT_SIZE(DatumGetPointer(toast_values[i]));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Not a variable size attribute, plain storage always
|
* Not a variable size attribute, plain storage always
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
toast_action[i] = 'p';
|
toast_action[i] = 'p';
|
||||||
toast_sizes[i] = att[i]->attlen;
|
toast_sizes[i] = att[i]->attlen;
|
||||||
@@ -393,9 +386,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
maxDataLen += BITMAPLEN(numAttrs);
|
maxDataLen += BITMAPLEN(numAttrs);
|
||||||
maxDataLen = TOAST_TUPLE_TARGET - MAXALIGN(maxDataLen);
|
maxDataLen = TOAST_TUPLE_TARGET - MAXALIGN(maxDataLen);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Look for attributes with attstorage 'x' to compress
|
* Look for attributes with attstorage 'x' to compress
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >
|
while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >
|
||||||
maxDataLen)
|
maxDataLen)
|
||||||
@@ -405,9 +397,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
Datum old_value;
|
Datum old_value;
|
||||||
Datum new_value;
|
Datum new_value;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Search for the biggest yet uncompressed internal attribute
|
* Search for the biggest yet uncompressed internal attribute
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < numAttrs; i++)
|
for (i = 0; i < numAttrs; i++)
|
||||||
{
|
{
|
||||||
@@ -427,9 +418,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
if (biggest_attno < 0)
|
if (biggest_attno < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Attempt to compress it inline
|
* Attempt to compress it inline
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
i = biggest_attno;
|
i = biggest_attno;
|
||||||
old_value = toast_values[i];
|
old_value = toast_values[i];
|
||||||
@@ -457,10 +447,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Second we look for attributes of attstorage 'x' or 'e' that
|
* Second we look for attributes of attstorage 'x' or 'e' that are
|
||||||
* are still inline.
|
* still inline.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >
|
while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >
|
||||||
maxDataLen && rel->rd_rel->reltoastrelid != InvalidOid)
|
maxDataLen && rel->rd_rel->reltoastrelid != InvalidOid)
|
||||||
@@ -469,10 +458,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
int32 biggest_size = MAXALIGN(sizeof(varattrib));
|
int32 biggest_size = MAXALIGN(sizeof(varattrib));
|
||||||
Datum old_value;
|
Datum old_value;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Search for the biggest yet inlined attribute with
|
* Search for the biggest yet inlined attribute with attstorage =
|
||||||
* attstorage = 'x' or 'e'
|
* 'x' or 'e'
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < numAttrs; i++)
|
for (i = 0; i < numAttrs; i++)
|
||||||
{
|
{
|
||||||
@@ -492,9 +480,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
if (biggest_attno < 0)
|
if (biggest_attno < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Store this external
|
* Store this external
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
i = biggest_attno;
|
i = biggest_attno;
|
||||||
old_value = toast_values[i];
|
old_value = toast_values[i];
|
||||||
@@ -513,10 +500,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
need_free = true;
|
need_free = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Round 3 - this time we take attributes with storage
|
* Round 3 - this time we take attributes with storage 'm' into
|
||||||
* 'm' into compression
|
* compression
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >
|
while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >
|
||||||
maxDataLen)
|
maxDataLen)
|
||||||
@@ -526,9 +512,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
Datum old_value;
|
Datum old_value;
|
||||||
Datum new_value;
|
Datum new_value;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Search for the biggest yet uncompressed internal attribute
|
* Search for the biggest yet uncompressed internal attribute
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < numAttrs; i++)
|
for (i = 0; i < numAttrs; i++)
|
||||||
{
|
{
|
||||||
@@ -548,9 +533,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
if (biggest_attno < 0)
|
if (biggest_attno < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Attempt to compress it inline
|
* Attempt to compress it inline
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
i = biggest_attno;
|
i = biggest_attno;
|
||||||
old_value = toast_values[i];
|
old_value = toast_values[i];
|
||||||
@@ -578,9 +562,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Finally we store attributes of type 'm' external
|
* Finally we store attributes of type 'm' external
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >
|
while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >
|
||||||
maxDataLen && rel->rd_rel->reltoastrelid != InvalidOid)
|
maxDataLen && rel->rd_rel->reltoastrelid != InvalidOid)
|
||||||
@@ -589,10 +572,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
int32 biggest_size = MAXALIGN(sizeof(varattrib));
|
int32 biggest_size = MAXALIGN(sizeof(varattrib));
|
||||||
Datum old_value;
|
Datum old_value;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Search for the biggest yet inlined attribute with
|
* Search for the biggest yet inlined attribute with attstorage =
|
||||||
* attstorage = 'm'
|
* 'm'
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < numAttrs; i++)
|
for (i = 0; i < numAttrs; i++)
|
||||||
{
|
{
|
||||||
@@ -612,9 +594,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
if (biggest_attno < 0)
|
if (biggest_attno < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Store this external
|
* Store this external
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
i = biggest_attno;
|
i = biggest_attno;
|
||||||
old_value = toast_values[i];
|
old_value = toast_values[i];
|
||||||
@@ -633,10 +614,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
need_free = true;
|
need_free = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* In the case we toasted any values, we need to build
|
* In the case we toasted any values, we need to build a new heap
|
||||||
* a new heap tuple with the changed values.
|
* tuple with the changed values.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (need_change)
|
if (need_change)
|
||||||
{
|
{
|
||||||
@@ -645,9 +625,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
HeapTupleHeader olddata;
|
HeapTupleHeader olddata;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Calculate the new size of the tuple
|
* Calculate the new size of the tuple
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
new_len = offsetof(HeapTupleHeaderData, t_bits);
|
new_len = offsetof(HeapTupleHeaderData, t_bits);
|
||||||
if (has_nulls)
|
if (has_nulls)
|
||||||
@@ -655,19 +634,17 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
new_len = MAXALIGN(new_len);
|
new_len = MAXALIGN(new_len);
|
||||||
new_len += ComputeDataSize(tupleDesc, toast_values, toast_nulls);
|
new_len += ComputeDataSize(tupleDesc, toast_values, toast_nulls);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Remember the old memory location of the tuple (for below),
|
* Remember the old memory location of the tuple (for below),
|
||||||
* switch to the memory context of the HeapTuple structure
|
* switch to the memory context of the HeapTuple structure and
|
||||||
* and allocate the new tuple.
|
* allocate the new tuple.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
olddata = newtup->t_data;
|
olddata = newtup->t_data;
|
||||||
oldcxt = MemoryContextSwitchTo(newtup->t_datamcxt);
|
oldcxt = MemoryContextSwitchTo(newtup->t_datamcxt);
|
||||||
new_data = palloc(new_len);
|
new_data = palloc(new_len);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Put the tuple header and the changed values into place
|
* Put the tuple header and the changed values into place
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
memcpy(new_data, newtup->t_data, newtup->t_data->t_hoff);
|
memcpy(new_data, newtup->t_data, newtup->t_data->t_hoff);
|
||||||
newtup->t_data = (HeapTupleHeader) new_data;
|
newtup->t_data = (HeapTupleHeader) new_data;
|
||||||
@@ -682,33 +659,29 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
|||||||
&(newtup->t_data->t_infomask),
|
&(newtup->t_data->t_infomask),
|
||||||
has_nulls ? newtup->t_data->t_bits : NULL);
|
has_nulls ? newtup->t_data->t_bits : NULL);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* In the case we modified a previously modified tuple again,
|
* In the case we modified a previously modified tuple again, free
|
||||||
* free the memory from the previous run
|
* the memory from the previous run
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if ((char *) olddata != ((char *) newtup + HEAPTUPLESIZE))
|
if ((char *) olddata != ((char *) newtup + HEAPTUPLESIZE))
|
||||||
pfree(olddata);
|
pfree(olddata);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Switch back to the old memory context
|
* Switch back to the old memory context
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Free allocated temp values
|
* Free allocated temp values
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (need_free)
|
if (need_free)
|
||||||
for (i = 0; i < numAttrs; i++)
|
for (i = 0; i < numAttrs; i++)
|
||||||
if (toast_free[i])
|
if (toast_free[i])
|
||||||
pfree(DatumGetPointer(toast_values[i]));
|
pfree(DatumGetPointer(toast_values[i]));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Delete external values from the old tuple
|
* Delete external values from the old tuple
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (need_delold)
|
if (need_delold)
|
||||||
for (i = 0; i < numAttrs; i++)
|
for (i = 0; i < numAttrs; i++)
|
||||||
@@ -776,9 +749,8 @@ toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
|
|||||||
char *data_p;
|
char *data_p;
|
||||||
int32 data_todo;
|
int32 data_todo;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Create the varattrib reference
|
* Create the varattrib reference
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
result = (varattrib *) palloc(sizeof(varattrib));
|
result = (varattrib *) palloc(sizeof(varattrib));
|
||||||
|
|
||||||
@@ -802,9 +774,8 @@ toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
|
|||||||
result->va_content.va_external.va_rowid = mainoid;
|
result->va_content.va_external.va_rowid = mainoid;
|
||||||
result->va_content.va_external.va_attno = attno;
|
result->va_content.va_external.va_attno = attno;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Initialize constant parts of the tuple data
|
* Initialize constant parts of the tuple data
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
t_values[0] = ObjectIdGetDatum(result->va_content.va_external.va_valueid);
|
t_values[0] = ObjectIdGetDatum(result->va_content.va_external.va_valueid);
|
||||||
t_values[2] = PointerGetDatum(chunk_data);
|
t_values[2] = PointerGetDatum(chunk_data);
|
||||||
@@ -812,36 +783,32 @@ toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
|
|||||||
t_nulls[1] = ' ';
|
t_nulls[1] = ' ';
|
||||||
t_nulls[2] = ' ';
|
t_nulls[2] = ' ';
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the data to process
|
* Get the data to process
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
data_p = VARATT_DATA(value);
|
data_p = VARATT_DATA(value);
|
||||||
data_todo = VARATT_SIZE(value) - VARHDRSZ;
|
data_todo = VARATT_SIZE(value) - VARHDRSZ;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Open the toast relation
|
* Open the toast relation
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
|
toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
|
||||||
toasttupDesc = toastrel->rd_att;
|
toasttupDesc = toastrel->rd_att;
|
||||||
toastidx = index_open(rel->rd_rel->reltoastidxid);
|
toastidx = index_open(rel->rd_rel->reltoastidxid);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Split up the item into chunks
|
* Split up the item into chunks
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
while (data_todo > 0)
|
while (data_todo > 0)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Calculate the size of this chunk
|
* Calculate the size of this chunk
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
chunk_size = Min(TOAST_MAX_CHUNK_SIZE, data_todo);
|
chunk_size = Min(TOAST_MAX_CHUNK_SIZE, data_todo);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Build a tuple
|
* Build a tuple
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
t_values[1] = Int32GetDatum(chunk_seq++);
|
t_values[1] = Int32GetDatum(chunk_seq++);
|
||||||
VARATT_SIZEP(chunk_data) = chunk_size + VARHDRSZ;
|
VARATT_SIZEP(chunk_data) = chunk_size + VARHDRSZ;
|
||||||
@@ -850,9 +817,8 @@ toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
|
|||||||
if (!HeapTupleIsValid(toasttup))
|
if (!HeapTupleIsValid(toasttup))
|
||||||
elog(ERROR, "Failed to build TOAST tuple");
|
elog(ERROR, "Failed to build TOAST tuple");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Store it and create the index entry
|
* Store it and create the index entry
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
heap_insert(toastrel, toasttup);
|
heap_insert(toastrel, toasttup);
|
||||||
idxres = index_insert(toastidx, t_values, t_nulls,
|
idxres = index_insert(toastidx, t_values, t_nulls,
|
||||||
@@ -861,24 +827,21 @@ toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
|
|||||||
if (idxres == NULL)
|
if (idxres == NULL)
|
||||||
elog(ERROR, "Failed to insert index entry for TOAST tuple");
|
elog(ERROR, "Failed to insert index entry for TOAST tuple");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Free memory
|
* Free memory
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
heap_freetuple(toasttup);
|
heap_freetuple(toasttup);
|
||||||
pfree(idxres);
|
pfree(idxres);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Move on to next chunk
|
* Move on to next chunk
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
data_todo -= chunk_size;
|
data_todo -= chunk_size;
|
||||||
data_p += chunk_size;
|
data_p += chunk_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Done - close toast relation and return the reference
|
* Done - close toast relation and return the reference
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
index_close(toastidx);
|
index_close(toastidx);
|
||||||
heap_close(toastrel, RowExclusiveLock);
|
heap_close(toastrel, RowExclusiveLock);
|
||||||
@@ -908,17 +871,15 @@ toast_delete_datum(Relation rel, Datum value)
|
|||||||
if (!VARATT_IS_EXTERNAL(attr))
|
if (!VARATT_IS_EXTERNAL(attr))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Open the toast relation and it's index
|
* Open the toast relation and it's index
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
|
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
|
||||||
RowExclusiveLock);
|
RowExclusiveLock);
|
||||||
toastidx = index_open(attr->va_content.va_external.va_toastidxid);
|
toastidx = index_open(attr->va_content.va_external.va_toastidxid);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Setup a scan key to fetch from the index by va_valueid
|
* Setup a scan key to fetch from the index by va_valueid
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ScanKeyEntryInitialize(&toastkey,
|
ScanKeyEntryInitialize(&toastkey,
|
||||||
(bits16) 0,
|
(bits16) 0,
|
||||||
@@ -926,9 +887,8 @@ toast_delete_datum(Relation rel, Datum value)
|
|||||||
(RegProcedure) F_OIDEQ,
|
(RegProcedure) F_OIDEQ,
|
||||||
ObjectIdGetDatum(attr->va_content.va_external.va_valueid));
|
ObjectIdGetDatum(attr->va_content.va_external.va_valueid));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Read the chunks by index
|
* Read the chunks by index
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
toastscan = index_beginscan(toastidx, false, 1, &toastkey);
|
toastscan = index_beginscan(toastidx, false, 1, &toastkey);
|
||||||
while ((indexRes = index_getnext(toastscan, ForwardScanDirection)) != NULL)
|
while ((indexRes = index_getnext(toastscan, ForwardScanDirection)) != NULL)
|
||||||
@@ -940,18 +900,16 @@ toast_delete_datum(Relation rel, Datum value)
|
|||||||
if (!toasttup.t_data)
|
if (!toasttup.t_data)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Have a chunk, delete it
|
* Have a chunk, delete it
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
simple_heap_delete(toastrel, &toasttup.t_self);
|
simple_heap_delete(toastrel, &toasttup.t_self);
|
||||||
|
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* End scan and close relations
|
* End scan and close relations
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
index_endscan(toastscan);
|
index_endscan(toastscan);
|
||||||
index_close(toastidx);
|
index_close(toastidx);
|
||||||
@@ -1003,18 +961,16 @@ toast_fetch_datum(varattrib *attr)
|
|||||||
if (VARATT_IS_COMPRESSED(attr))
|
if (VARATT_IS_COMPRESSED(attr))
|
||||||
VARATT_SIZEP(result) |= VARATT_FLAG_COMPRESSED;
|
VARATT_SIZEP(result) |= VARATT_FLAG_COMPRESSED;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Open the toast relation and it's index
|
* Open the toast relation and it's index
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
|
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
|
||||||
AccessShareLock);
|
AccessShareLock);
|
||||||
toasttupDesc = toastrel->rd_att;
|
toasttupDesc = toastrel->rd_att;
|
||||||
toastidx = index_open(attr->va_content.va_external.va_toastidxid);
|
toastidx = index_open(attr->va_content.va_external.va_toastidxid);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Setup a scan key to fetch from the index by va_valueid
|
* Setup a scan key to fetch from the index by va_valueid
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ScanKeyEntryInitialize(&toastkey,
|
ScanKeyEntryInitialize(&toastkey,
|
||||||
(bits16) 0,
|
(bits16) 0,
|
||||||
@@ -1022,11 +978,10 @@ toast_fetch_datum(varattrib *attr)
|
|||||||
(RegProcedure) F_OIDEQ,
|
(RegProcedure) F_OIDEQ,
|
||||||
ObjectIdGetDatum(attr->va_content.va_external.va_valueid));
|
ObjectIdGetDatum(attr->va_content.va_external.va_valueid));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Read the chunks by index
|
* Read the chunks by index
|
||||||
*
|
*
|
||||||
* Note we will not necessarily see the chunks in sequence-number order.
|
* Note we will not necessarily see the chunks in sequence-number order.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
toastscan = index_beginscan(toastidx, false, 1, &toastkey);
|
toastscan = index_beginscan(toastidx, false, 1, &toastkey);
|
||||||
while ((indexRes = index_getnext(toastscan, ForwardScanDirection)) != NULL)
|
while ((indexRes = index_getnext(toastscan, ForwardScanDirection)) != NULL)
|
||||||
@@ -1039,9 +994,8 @@ toast_fetch_datum(varattrib *attr)
|
|||||||
continue;
|
continue;
|
||||||
ttup = &toasttup;
|
ttup = &toasttup;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Have a chunk, extract the sequence number and the data
|
* Have a chunk, extract the sequence number and the data
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
residx = DatumGetInt32(heap_getattr(ttup, 2, toasttupDesc, &isnull));
|
residx = DatumGetInt32(heap_getattr(ttup, 2, toasttupDesc, &isnull));
|
||||||
Assert(!isnull);
|
Assert(!isnull);
|
||||||
@@ -1049,9 +1003,8 @@ toast_fetch_datum(varattrib *attr)
|
|||||||
Assert(!isnull);
|
Assert(!isnull);
|
||||||
chunksize = VARATT_SIZE(chunk) - VARHDRSZ;
|
chunksize = VARATT_SIZE(chunk) - VARHDRSZ;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Some checks on the data we've found
|
* Some checks on the data we've found
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (residx < 0 || residx >= numchunks)
|
if (residx < 0 || residx >= numchunks)
|
||||||
elog(ERROR, "unexpected chunk number %d for toast value %d",
|
elog(ERROR, "unexpected chunk number %d for toast value %d",
|
||||||
@@ -1076,9 +1029,8 @@ toast_fetch_datum(varattrib *attr)
|
|||||||
residx,
|
residx,
|
||||||
attr->va_content.va_external.va_valueid);
|
attr->va_content.va_external.va_valueid);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Copy the data into proper place in our result
|
* Copy the data into proper place in our result
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
memcpy(((char *) VARATT_DATA(result)) + residx * TOAST_MAX_CHUNK_SIZE,
|
memcpy(((char *) VARATT_DATA(result)) + residx * TOAST_MAX_CHUNK_SIZE,
|
||||||
VARATT_DATA(chunk),
|
VARATT_DATA(chunk),
|
||||||
@@ -1087,9 +1039,8 @@ toast_fetch_datum(varattrib *attr)
|
|||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Final checks that we successfully fetched the datum
|
* Final checks that we successfully fetched the datum
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (memcmp(chunks_found, chunks_expected, numchunks) != 0)
|
if (memcmp(chunks_found, chunks_expected, numchunks) != 0)
|
||||||
elog(ERROR, "not all toast chunks found for value %d",
|
elog(ERROR, "not all toast chunks found for value %d",
|
||||||
@@ -1097,9 +1048,8 @@ toast_fetch_datum(varattrib *attr)
|
|||||||
pfree(chunks_expected);
|
pfree(chunks_expected);
|
||||||
pfree(chunks_found);
|
pfree(chunks_found);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* End scan and close relations
|
* End scan and close relations
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
index_endscan(toastscan);
|
index_endscan(toastscan);
|
||||||
index_close(toastidx);
|
index_close(toastidx);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.47 2001/01/24 19:42:48 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.48 2001/03/22 06:16:07 momjian Exp $
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
* index_open - open an index relation by relationId
|
* index_open - open an index relation by relationId
|
||||||
@@ -190,9 +190,8 @@ index_insert(Relation relation,
|
|||||||
RELATION_CHECKS;
|
RELATION_CHECKS;
|
||||||
GET_REL_PROCEDURE(insert, aminsert);
|
GET_REL_PROCEDURE(insert, aminsert);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* have the am's insert proc do all the work.
|
* have the am's insert proc do all the work.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
specificResult = (InsertIndexResult)
|
specificResult = (InsertIndexResult)
|
||||||
DatumGetPointer(OidFunctionCall5(procedure,
|
DatumGetPointer(OidFunctionCall5(procedure,
|
||||||
@@ -241,13 +240,12 @@ index_beginscan(Relation relation,
|
|||||||
|
|
||||||
RelationIncrementReferenceCount(relation);
|
RelationIncrementReferenceCount(relation);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Acquire AccessShareLock for the duration of the scan
|
* Acquire AccessShareLock for the duration of the scan
|
||||||
*
|
*
|
||||||
* Note: we could get an SI inval message here and consequently have
|
* Note: we could get an SI inval message here and consequently have to
|
||||||
* to rebuild the relcache entry. The refcount increment above
|
* rebuild the relcache entry. The refcount increment above ensures
|
||||||
* ensures that we will rebuild it and not just flush it...
|
* that we will rebuild it and not just flush it...
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
LockRelation(relation, AccessShareLock);
|
LockRelation(relation, AccessShareLock);
|
||||||
|
|
||||||
@@ -347,9 +345,8 @@ index_getnext(IndexScanDesc scan,
|
|||||||
|
|
||||||
SCAN_CHECKS;
|
SCAN_CHECKS;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Look up the access procedure only once per scan.
|
* Look up the access procedure only once per scan.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (scan->fn_getnext.fn_oid == InvalidOid)
|
if (scan->fn_getnext.fn_oid == InvalidOid)
|
||||||
{
|
{
|
||||||
@@ -359,9 +356,8 @@ index_getnext(IndexScanDesc scan,
|
|||||||
fmgr_info(procedure, &scan->fn_getnext);
|
fmgr_info(procedure, &scan->fn_getnext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* have the am's gettuple proc do all the work.
|
* have the am's gettuple proc do all the work.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
result = (RetrieveIndexResult)
|
result = (RetrieveIndexResult)
|
||||||
DatumGetPointer(FunctionCall2(&scan->fn_getnext,
|
DatumGetPointer(FunctionCall2(&scan->fn_getnext,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.64 2001/03/22 03:59:15 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.65 2001/03/22 06:16:07 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -238,21 +238,19 @@ _bt_binsrch(Relation rel,
|
|||||||
high = mid;
|
high = mid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------
|
/*
|
||||||
* At this point we have high == low, but be careful: they could point
|
* At this point we have high == low, but be careful: they could point
|
||||||
* past the last slot on the page.
|
* past the last slot on the page.
|
||||||
*
|
*
|
||||||
* On a leaf page, we always return the first key >= scan key
|
* On a leaf page, we always return the first key >= scan key (which
|
||||||
* (which could be the last slot + 1).
|
* could be the last slot + 1).
|
||||||
*--------------------
|
|
||||||
*/
|
*/
|
||||||
if (P_ISLEAF(opaque))
|
if (P_ISLEAF(opaque))
|
||||||
return low;
|
return low;
|
||||||
|
|
||||||
/*--------------------
|
/*
|
||||||
* On a non-leaf page, return the last key < scan key.
|
* On a non-leaf page, return the last key < scan key. There must be
|
||||||
* There must be one if _bt_compare() is playing by the rules.
|
* one if _bt_compare() is playing by the rules.
|
||||||
*--------------------
|
|
||||||
*/
|
*/
|
||||||
Assert(low > P_FIRSTDATAKEY(opaque));
|
Assert(low > P_FIRSTDATAKEY(opaque));
|
||||||
|
|
||||||
@@ -584,21 +582,20 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
|||||||
|
|
||||||
ItemPointerSet(current, blkno, offnum);
|
ItemPointerSet(current, blkno, offnum);
|
||||||
|
|
||||||
/*----------
|
/*
|
||||||
* At this point we are positioned at the first item >= scan key,
|
* At this point we are positioned at the first item >= scan key, or
|
||||||
* or possibly at the end of a page on which all the existing items
|
* possibly at the end of a page on which all the existing items are <
|
||||||
* are < scan key and we know that everything on later pages is
|
* scan key and we know that everything on later pages is >= scan key.
|
||||||
* >= scan key. We could step forward in the latter case, but that'd
|
* We could step forward in the latter case, but that'd be a waste of
|
||||||
* be a waste of time if we want to scan backwards. So, it's now time to
|
* time if we want to scan backwards. So, it's now time to examine
|
||||||
* examine the scan strategy to find the exact place to start the scan.
|
* the scan strategy to find the exact place to start the scan.
|
||||||
*
|
*
|
||||||
* Note: if _bt_step fails (meaning we fell off the end of the index
|
* Note: if _bt_step fails (meaning we fell off the end of the index in
|
||||||
* in one direction or the other), we either return NULL (no matches) or
|
* one direction or the other), we either return NULL (no matches) or
|
||||||
* call _bt_endpoint() to set up a scan starting at that index endpoint,
|
* call _bt_endpoint() to set up a scan starting at that index
|
||||||
* as appropriate for the desired scan type.
|
* endpoint, as appropriate for the desired scan type.
|
||||||
*
|
*
|
||||||
* it's yet other place to add some code later for is(not)null ...
|
* it's yet other place to add some code later for is(not)null ...
|
||||||
*----------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
switch (strat_total)
|
switch (strat_total)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.42 2001/03/22 03:59:17 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.43 2001/03/22 06:16:10 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
|
||||||
@@ -124,30 +124,25 @@ TransactionLogTest(TransactionId transactionId, /* transaction id to test */
|
|||||||
XidStatus xidstatus; /* recorded status of xid */
|
XidStatus xidstatus; /* recorded status of xid */
|
||||||
bool fail = false; /* success/failure */
|
bool fail = false; /* success/failure */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* during initialization consider all transactions
|
* during initialization consider all transactions as having been
|
||||||
* as having been committed
|
* committed
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!RelationIsValid(LogRelation))
|
if (!RelationIsValid(LogRelation))
|
||||||
return (bool) (status == XID_COMMIT);
|
return (bool) (status == XID_COMMIT);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* before going to the buffer manager, check our single
|
* before going to the buffer manager, check our single item cache to
|
||||||
* item cache to see if we didn't just check the transaction
|
* see if we didn't just check the transaction status a moment ago.
|
||||||
* status a moment ago.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (TransactionIdEquals(transactionId, cachedTestXid))
|
if (TransactionIdEquals(transactionId, cachedTestXid))
|
||||||
return (bool)
|
return (bool)
|
||||||
(status == cachedTestXidStatus);
|
(status == cachedTestXidStatus);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* compute the item pointer corresponding to the
|
* compute the item pointer corresponding to the page containing our
|
||||||
* page containing our transaction id. We save the item in
|
* transaction id. We save the item in our cache to speed up things
|
||||||
* our cache to speed up things if we happen to ask for the
|
* if we happen to ask for the same xid's status more than once.
|
||||||
* same xid's status more than once.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
TransComputeBlockNumber(LogRelation, transactionId, &blockNumber);
|
TransComputeBlockNumber(LogRelation, transactionId, &blockNumber);
|
||||||
xidstatus = TransBlockNumberGetXidStatus(LogRelation,
|
xidstatus = TransBlockNumberGetXidStatus(LogRelation,
|
||||||
@@ -169,9 +164,8 @@ TransactionLogTest(TransactionId transactionId, /* transaction id to test */
|
|||||||
return (bool) (status == xidstatus);
|
return (bool) (status == xidstatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* here the block didn't contain the information we wanted
|
* here the block didn't contain the information we wanted
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "TransactionLogTest: failed to get xidstatus");
|
elog(ERROR, "TransactionLogTest: failed to get xidstatus");
|
||||||
|
|
||||||
@@ -192,16 +186,14 @@ TransactionLogUpdate(TransactionId transactionId, /* trans id to update */
|
|||||||
BlockNumber blockNumber;
|
BlockNumber blockNumber;
|
||||||
bool fail = false; /* success/failure */
|
bool fail = false; /* success/failure */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* during initialization we don't record any updates.
|
* during initialization we don't record any updates.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!RelationIsValid(LogRelation))
|
if (!RelationIsValid(LogRelation))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* update the log relation
|
* update the log relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
TransComputeBlockNumber(LogRelation, transactionId, &blockNumber);
|
TransComputeBlockNumber(LogRelation, transactionId, &blockNumber);
|
||||||
TransBlockNumberSetXidStatus(LogRelation,
|
TransBlockNumberSetXidStatus(LogRelation,
|
||||||
@@ -292,43 +284,38 @@ static void
|
|||||||
TransRecover(Relation logRelation)
|
TransRecover(Relation logRelation)
|
||||||
{
|
{
|
||||||
#ifdef NOT_USED
|
#ifdef NOT_USED
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* first get the last recorded transaction in the log.
|
* first get the last recorded transaction in the log.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
TransGetLastRecordedTransaction(logRelation, logLastXid, &fail);
|
TransGetLastRecordedTransaction(logRelation, logLastXid, &fail);
|
||||||
if (fail == true)
|
if (fail == true)
|
||||||
elog(ERROR, "TransRecover: failed TransGetLastRecordedTransaction");
|
elog(ERROR, "TransRecover: failed TransGetLastRecordedTransaction");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* next get the "last" and "next" variables
|
* next get the "last" and "next" variables
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
VariableRelationGetLastXid(&varLastXid);
|
VariableRelationGetLastXid(&varLastXid);
|
||||||
VariableRelationGetNextXid(&varNextXid);
|
VariableRelationGetNextXid(&varNextXid);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* intregity test (1)
|
* intregity test (1)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (TransactionIdIsLessThan(varNextXid, logLastXid))
|
if (TransactionIdIsLessThan(varNextXid, logLastXid))
|
||||||
elog(ERROR, "TransRecover: varNextXid < logLastXid");
|
elog(ERROR, "TransRecover: varNextXid < logLastXid");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* intregity test (2)
|
* intregity test (2)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* intregity test (3)
|
* intregity test (3)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* here we have a valid "
|
* here we have a valid "
|
||||||
*
|
*
|
||||||
* **** RESUME HERE ****
|
**** RESUME HERE ****
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
varNextXid = TransactionIdDup(varLastXid);
|
varNextXid = TransactionIdDup(varLastXid);
|
||||||
TransactionIdIncrement(&varNextXid);
|
TransactionIdIncrement(&varNextXid);
|
||||||
@@ -375,51 +362,45 @@ InitializeTransactionLog(void)
|
|||||||
Relation logRelation;
|
Relation logRelation;
|
||||||
MemoryContext oldContext;
|
MemoryContext oldContext;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* don't do anything during bootstrapping
|
* don't do anything during bootstrapping
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (AMI_OVERRIDE)
|
if (AMI_OVERRIDE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* disable the transaction system so the access methods
|
* disable the transaction system so the access methods don't
|
||||||
* don't interfere during initialization.
|
* interfere during initialization.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
OverrideTransactionSystem(true);
|
OverrideTransactionSystem(true);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* make sure allocations occur within the top memory context
|
* make sure allocations occur within the top memory context so that
|
||||||
* so that our log management structures are protected from
|
* our log management structures are protected from garbage collection
|
||||||
* garbage collection at the end of every transaction.
|
* at the end of every transaction.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
oldContext = MemoryContextSwitchTo(TopMemoryContext);
|
oldContext = MemoryContextSwitchTo(TopMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* first open the log and time relations
|
* first open the log and time relations (these are created by amiint
|
||||||
* (these are created by amiint so they are guaranteed to exist)
|
* so they are guaranteed to exist)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
logRelation = heap_openr(LogRelationName, NoLock);
|
logRelation = heap_openr(LogRelationName, NoLock);
|
||||||
VariableRelation = heap_openr(VariableRelationName, NoLock);
|
VariableRelation = heap_openr(VariableRelationName, NoLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* XXX TransactionLogUpdate requires that LogRelation
|
* XXX TransactionLogUpdate requires that LogRelation is valid so we
|
||||||
* is valid so we temporarily set it so we can initialize
|
* temporarily set it so we can initialize things properly. This could
|
||||||
* things properly. This could be done cleaner.
|
* be done cleaner.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
LogRelation = logRelation;
|
LogRelation = logRelation;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if we have a virgin database, we initialize the log
|
* if we have a virgin database, we initialize the log relation by
|
||||||
* relation by committing the AmiTransactionId (id 512) and we
|
* committing the AmiTransactionId (id 512) and we initialize the
|
||||||
* initialize the variable relation by setting the next available
|
* variable relation by setting the next available transaction id to
|
||||||
* transaction id to FirstTransactionId (id 514). OID initialization
|
* FirstTransactionId (id 514). OID initialization happens as a side
|
||||||
* happens as a side effect of bootstrapping in varsup.c.
|
* effect of bootstrapping in varsup.c.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
SpinAcquire(OidGenLockId);
|
SpinAcquire(OidGenLockId);
|
||||||
if (!TransactionIdDidCommit(AmiTransactionId))
|
if (!TransactionIdDidCommit(AmiTransactionId))
|
||||||
@@ -433,33 +414,30 @@ InitializeTransactionLog(void)
|
|||||||
}
|
}
|
||||||
else if (RecoveryCheckingEnabled())
|
else if (RecoveryCheckingEnabled())
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* if we have a pre-initialized database and if the
|
/*
|
||||||
* perform recovery checking flag was passed then we
|
* if we have a pre-initialized database and if the perform
|
||||||
* do our database integrity checking.
|
* recovery checking flag was passed then we do our database
|
||||||
* ----------------
|
* integrity checking.
|
||||||
*/
|
*/
|
||||||
TransRecover(logRelation);
|
TransRecover(logRelation);
|
||||||
}
|
}
|
||||||
LogRelation = (Relation) NULL;
|
LogRelation = (Relation) NULL;
|
||||||
SpinRelease(OidGenLockId);
|
SpinRelease(OidGenLockId);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now re-enable the transaction system
|
* now re-enable the transaction system
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
OverrideTransactionSystem(false);
|
OverrideTransactionSystem(false);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* instantiate the global variables
|
* instantiate the global variables
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
LogRelation = logRelation;
|
LogRelation = logRelation;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* restore the memory context to the previous context
|
* restore the memory context to the previous context before we return
|
||||||
* before we return from initialization.
|
* from initialization.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(oldContext);
|
MemoryContextSwitchTo(oldContext);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/transsup.c,v 1.29 2001/03/22 03:59:17 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/transsup.c,v 1.30 2001/03/22 06:16:10 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* This file contains support functions for the high
|
* This file contains support functions for the high
|
||||||
@@ -56,11 +56,9 @@ TransComputeBlockNumber(Relation relation, /* relation to test */
|
|||||||
{
|
{
|
||||||
long itemsPerBlock = 0;
|
long itemsPerBlock = 0;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* we calculate the block number of our transaction
|
* we calculate the block number of our transaction by dividing the
|
||||||
* by dividing the transaction id by the number of
|
* transaction id by the number of transaction things per block.
|
||||||
* transaction things per block.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (relation == LogRelation)
|
if (relation == LogRelation)
|
||||||
itemsPerBlock = TP_NumXidStatusPerBlock;
|
itemsPerBlock = TP_NumXidStatusPerBlock;
|
||||||
@@ -109,18 +107,16 @@ TransBlockGetLastTransactionIdStatus(Block tblock,
|
|||||||
BitIndex offset;
|
BitIndex offset;
|
||||||
XidStatus xstatus;
|
XidStatus xstatus;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity check
|
* sanity check
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert((tblock != NULL));
|
Assert((tblock != NULL));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* search downward from the top of the block data, looking
|
* search downward from the top of the block data, looking for the
|
||||||
* for the first Non-in progress transaction status. Since we
|
* first Non-in progress transaction status. Since we are scanning
|
||||||
* are scanning backward, this will be last recorded transaction
|
* backward, this will be last recorded transaction status on the
|
||||||
* status on the block.
|
* block.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
maxIndex = TP_NumXidStatusPerBlock;
|
maxIndex = TP_NumXidStatusPerBlock;
|
||||||
for (index = maxIndex; index > 0; index--)
|
for (index = maxIndex; index > 0; index--)
|
||||||
@@ -131,11 +127,10 @@ TransBlockGetLastTransactionIdStatus(Block tblock,
|
|||||||
|
|
||||||
xstatus = (bit1 | bit2);
|
xstatus = (bit1 | bit2);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* here we have the status of some transaction, so test
|
* here we have the status of some transaction, so test if the
|
||||||
* if the status is recorded as "in progress". If so, then
|
* status is recorded as "in progress". If so, then we save the
|
||||||
* we save the transaction id in the place specified by the caller.
|
* transaction id in the place specified by the caller.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (xstatus != XID_INPROGRESS)
|
if (xstatus != XID_INPROGRESS)
|
||||||
{
|
{
|
||||||
@@ -148,12 +143,11 @@ TransBlockGetLastTransactionIdStatus(Block tblock,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if we get here and index is 0 it means we couldn't find
|
* if we get here and index is 0 it means we couldn't find a
|
||||||
* a non-inprogress transaction on the block. For now we just
|
* non-inprogress transaction on the block. For now we just return
|
||||||
* return this info to the user. They can check if the return
|
* this info to the user. They can check if the return status is "in
|
||||||
* status is "in progress" to know this condition has arisen.
|
* progress" to know this condition has arisen.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
{
|
{
|
||||||
@@ -161,9 +155,8 @@ TransBlockGetLastTransactionIdStatus(Block tblock,
|
|||||||
TransactionIdStore(baseXid, returnXidP);
|
TransactionIdStore(baseXid, returnXidP);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* return the status to the user
|
* return the status to the user
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
return xstatus;
|
return xstatus;
|
||||||
}
|
}
|
||||||
@@ -200,17 +193,15 @@ TransBlockGetXidStatus(Block tblock,
|
|||||||
*/
|
*/
|
||||||
index = transactionId % TP_NumXidStatusPerBlock;
|
index = transactionId % TP_NumXidStatusPerBlock;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the data at the specified index
|
* get the data at the specified index
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
offset = BitIndexOf(index);
|
offset = BitIndexOf(index);
|
||||||
bit1 = ((bits8) BitArrayBitIsSet((BitArray) tblock, offset++)) << 1;
|
bit1 = ((bits8) BitArrayBitIsSet((BitArray) tblock, offset++)) << 1;
|
||||||
bit2 = (bits8) BitArrayBitIsSet((BitArray) tblock, offset);
|
bit2 = (bits8) BitArrayBitIsSet((BitArray) tblock, offset);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* return the transaction status to the caller
|
* return the transaction status to the caller
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
return (XidStatus) (bit1 | bit2);
|
return (XidStatus) (bit1 | bit2);
|
||||||
}
|
}
|
||||||
@@ -245,9 +236,8 @@ TransBlockSetXidStatus(Block tblock,
|
|||||||
|
|
||||||
offset = BitIndexOf(index);
|
offset = BitIndexOf(index);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* store the transaction value at the specified offset
|
* store the transaction value at the specified offset
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
switch (xstatus)
|
switch (xstatus)
|
||||||
{
|
{
|
||||||
@@ -291,18 +281,16 @@ TransBlockNumberGetXidStatus(Relation relation,
|
|||||||
XidStatus xstatus; /* recorded status of xid */
|
XidStatus xstatus; /* recorded status of xid */
|
||||||
bool localfail; /* bool used if failP = NULL */
|
bool localfail; /* bool used if failP = NULL */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the page containing the transaction information
|
* get the page containing the transaction information
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
buffer = ReadBuffer(relation, blockNumber);
|
buffer = ReadBuffer(relation, blockNumber);
|
||||||
LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
||||||
block = BufferGetBlock(buffer);
|
block = BufferGetBlock(buffer);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the status from the block. note, for now we always
|
* get the status from the block. note, for now we always return
|
||||||
* return false in failP.
|
* false in failP.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (failP == NULL)
|
if (failP == NULL)
|
||||||
failP = &localfail;
|
failP = &localfail;
|
||||||
@@ -310,9 +298,8 @@ TransBlockNumberGetXidStatus(Relation relation,
|
|||||||
|
|
||||||
xstatus = TransBlockGetXidStatus(block, xid);
|
xstatus = TransBlockGetXidStatus(block, xid);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* release the buffer and return the status
|
* release the buffer and return the status
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
@@ -335,19 +322,17 @@ TransBlockNumberSetXidStatus(Relation relation,
|
|||||||
Block block; /* block containing xstatus */
|
Block block; /* block containing xstatus */
|
||||||
bool localfail; /* bool used if failP = NULL */
|
bool localfail; /* bool used if failP = NULL */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the block containing the transaction status
|
* get the block containing the transaction status
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
buffer = ReadBuffer(relation, blockNumber);
|
buffer = ReadBuffer(relation, blockNumber);
|
||||||
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
||||||
block = BufferGetBlock(buffer);
|
block = BufferGetBlock(buffer);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* attempt to update the status of the transaction on the block.
|
* attempt to update the status of the transaction on the block. if we
|
||||||
* if we are successful, write the block. otherwise release the buffer.
|
* are successful, write the block. otherwise release the buffer.
|
||||||
* note, for now we always return false in failP.
|
* note, for now we always return false in failP.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (failP == NULL)
|
if (failP == NULL)
|
||||||
failP = &localfail;
|
failP = &localfail;
|
||||||
@@ -381,22 +366,20 @@ TransGetLastRecordedTransaction(Relation relation,
|
|||||||
|
|
||||||
(*failP) = false;
|
(*failP) = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* SOMEDAY gain exclusive access to the log relation
|
* SOMEDAY gain exclusive access to the log relation
|
||||||
*
|
*
|
||||||
* That someday is today 5 Aug. 1991 -mer
|
* That someday is today 5 Aug. 1991 -mer It looks to me like we only
|
||||||
* It looks to me like we only need to set a read lock here, despite
|
* need to set a read lock here, despite the above comment about
|
||||||
* the above comment about exclusive access. The block is never
|
* exclusive access. The block is never actually written into, we
|
||||||
* actually written into, we only check status bits.
|
* only check status bits.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
RelationSetLockForRead(relation);
|
RelationSetLockForRead(relation);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* we assume the last block of the log contains the last
|
* we assume the last block of the log contains the last recorded
|
||||||
* recorded transaction. If the relation is empty we return
|
* transaction. If the relation is empty we return failure to the
|
||||||
* failure to the user.
|
* user.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
n = RelationGetNumberOfBlocks(relation);
|
n = RelationGetNumberOfBlocks(relation);
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
@@ -405,17 +388,15 @@ TransGetLastRecordedTransaction(Relation relation,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the block containing the transaction information
|
* get the block containing the transaction information
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
blockNumber = n - 1;
|
blockNumber = n - 1;
|
||||||
buffer = ReadBuffer(relation, blockNumber);
|
buffer = ReadBuffer(relation, blockNumber);
|
||||||
block = BufferGetBlock(buffer);
|
block = BufferGetBlock(buffer);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the last xid on the block
|
* get the last xid on the block
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
baseXid = blockNumber * TP_NumXidStatusPerBlock;
|
baseXid = blockNumber * TP_NumXidStatusPerBlock;
|
||||||
|
|
||||||
@@ -424,9 +405,8 @@ TransGetLastRecordedTransaction(Relation relation,
|
|||||||
|
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* SOMEDAY release our lock on the log relation
|
* SOMEDAY release our lock on the log relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
RelationUnsetLockForRead(relation);
|
RelationUnsetLockForRead(relation);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.100 2001/03/22 03:59:18 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.101 2001/03/22 06:16:10 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Transaction aborts can now occur two ways:
|
* Transaction aborts can now occur two ways:
|
||||||
@@ -396,17 +396,15 @@ GetCurrentTransactionId(void)
|
|||||||
{
|
{
|
||||||
TransactionState s = CurrentTransactionState;
|
TransactionState s = CurrentTransactionState;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if the transaction system is disabled, we return
|
* if the transaction system is disabled, we return the special
|
||||||
* the special "disabled" transaction id.
|
* "disabled" transaction id.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (s->state == TRANS_DISABLED)
|
if (s->state == TRANS_DISABLED)
|
||||||
return (TransactionId) DisabledTransactionId;
|
return (TransactionId) DisabledTransactionId;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* otherwise return the current transaction id.
|
* otherwise return the current transaction id.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
return (TransactionId) s->transactionIdData;
|
return (TransactionId) s->transactionIdData;
|
||||||
}
|
}
|
||||||
@@ -421,10 +419,9 @@ GetCurrentCommandId(void)
|
|||||||
{
|
{
|
||||||
TransactionState s = CurrentTransactionState;
|
TransactionState s = CurrentTransactionState;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if the transaction system is disabled, we return
|
* if the transaction system is disabled, we return the special
|
||||||
* the special "disabled" command id.
|
* "disabled" command id.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (s->state == TRANS_DISABLED)
|
if (s->state == TRANS_DISABLED)
|
||||||
return (CommandId) DisabledCommandId;
|
return (CommandId) DisabledCommandId;
|
||||||
@@ -437,10 +434,9 @@ GetScanCommandId(void)
|
|||||||
{
|
{
|
||||||
TransactionState s = CurrentTransactionState;
|
TransactionState s = CurrentTransactionState;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if the transaction system is disabled, we return
|
* if the transaction system is disabled, we return the special
|
||||||
* the special "disabled" command id.
|
* "disabled" command id.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (s->state == TRANS_DISABLED)
|
if (s->state == TRANS_DISABLED)
|
||||||
return (CommandId) DisabledCommandId;
|
return (CommandId) DisabledCommandId;
|
||||||
@@ -458,10 +454,9 @@ GetCurrentTransactionStartTime(void)
|
|||||||
{
|
{
|
||||||
TransactionState s = CurrentTransactionState;
|
TransactionState s = CurrentTransactionState;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if the transaction system is disabled, we return
|
* if the transaction system is disabled, we return the special
|
||||||
* the special "disabled" starting time.
|
* "disabled" starting time.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (s->state == TRANS_DISABLED)
|
if (s->state == TRANS_DISABLED)
|
||||||
return (AbsoluteTime) DisabledStartTime;
|
return (AbsoluteTime) DisabledStartTime;
|
||||||
@@ -608,16 +603,15 @@ AtStart_Locks(void)
|
|||||||
static void
|
static void
|
||||||
AtStart_Memory(void)
|
AtStart_Memory(void)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* We shouldn't have any transaction contexts already.
|
* We shouldn't have any transaction contexts already.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(TopTransactionContext == NULL);
|
Assert(TopTransactionContext == NULL);
|
||||||
Assert(TransactionCommandContext == NULL);
|
Assert(TransactionCommandContext == NULL);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Create a toplevel context for the transaction.
|
* Create a toplevel context for the transaction.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
TopTransactionContext =
|
TopTransactionContext =
|
||||||
AllocSetContextCreate(TopMemoryContext,
|
AllocSetContextCreate(TopMemoryContext,
|
||||||
@@ -626,9 +620,8 @@ AtStart_Memory(void)
|
|||||||
ALLOCSET_DEFAULT_INITSIZE,
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Create a statement-level context and make it active.
|
* Create a statement-level context and make it active.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
TransactionCommandContext =
|
TransactionCommandContext =
|
||||||
AllocSetContextCreate(TopTransactionContext,
|
AllocSetContextCreate(TopTransactionContext,
|
||||||
@@ -732,9 +725,9 @@ RecordTransactionCommit()
|
|||||||
static void
|
static void
|
||||||
AtCommit_Cache(void)
|
AtCommit_Cache(void)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* Make catalog changes visible to all backend.
|
* Make catalog changes visible to all backend.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
RegisterInvalid(true);
|
RegisterInvalid(true);
|
||||||
}
|
}
|
||||||
@@ -746,9 +739,9 @@ AtCommit_Cache(void)
|
|||||||
static void
|
static void
|
||||||
AtCommit_LocalCache(void)
|
AtCommit_LocalCache(void)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* Make catalog changes visible to me for the next command.
|
* Make catalog changes visible to me for the next command.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ImmediateLocalInvalidation(true);
|
ImmediateLocalInvalidation(true);
|
||||||
}
|
}
|
||||||
@@ -760,11 +753,11 @@ AtCommit_LocalCache(void)
|
|||||||
static void
|
static void
|
||||||
AtCommit_Locks(void)
|
AtCommit_Locks(void)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* XXX What if ProcReleaseLocks fails? (race condition?)
|
* XXX What if ProcReleaseLocks fails? (race condition?)
|
||||||
*
|
*
|
||||||
* Then you're up a creek! -mer 5/24/92
|
* Then you're up a creek! -mer 5/24/92
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ProcReleaseLocks(true);
|
ProcReleaseLocks(true);
|
||||||
}
|
}
|
||||||
@@ -776,17 +769,16 @@ AtCommit_Locks(void)
|
|||||||
static void
|
static void
|
||||||
AtCommit_Memory(void)
|
AtCommit_Memory(void)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* Now that we're "out" of a transaction, have the
|
/*
|
||||||
* system allocate things in the top memory context instead
|
* Now that we're "out" of a transaction, have the system allocate
|
||||||
* of per-transaction contexts.
|
* things in the top memory context instead of per-transaction
|
||||||
* ----------------
|
* contexts.
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(TopMemoryContext);
|
MemoryContextSwitchTo(TopMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Release all transaction-local memory.
|
* Release all transaction-local memory.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(TopTransactionContext != NULL);
|
Assert(TopTransactionContext != NULL);
|
||||||
MemoryContextDelete(TopTransactionContext);
|
MemoryContextDelete(TopTransactionContext);
|
||||||
@@ -862,11 +854,11 @@ AtAbort_Cache(void)
|
|||||||
static void
|
static void
|
||||||
AtAbort_Locks(void)
|
AtAbort_Locks(void)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* XXX What if ProcReleaseLocks() fails? (race condition?)
|
* XXX What if ProcReleaseLocks() fails? (race condition?)
|
||||||
*
|
*
|
||||||
* Then you're up a creek without a paddle! -mer
|
* Then you're up a creek without a paddle! -mer
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ProcReleaseLocks(false);
|
ProcReleaseLocks(false);
|
||||||
}
|
}
|
||||||
@@ -879,21 +871,20 @@ AtAbort_Locks(void)
|
|||||||
static void
|
static void
|
||||||
AtAbort_Memory(void)
|
AtAbort_Memory(void)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* Make sure we are in a valid context (not a child of
|
* Make sure we are in a valid context (not a child of
|
||||||
* TransactionCommandContext...). Note that it is possible
|
* TransactionCommandContext...). Note that it is possible for this
|
||||||
* for this code to be called when we aren't in a transaction
|
* code to be called when we aren't in a transaction at all; go
|
||||||
* at all; go directly to TopMemoryContext in that case.
|
* directly to TopMemoryContext in that case.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (TransactionCommandContext != NULL)
|
if (TransactionCommandContext != NULL)
|
||||||
{
|
{
|
||||||
MemoryContextSwitchTo(TransactionCommandContext);
|
MemoryContextSwitchTo(TransactionCommandContext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* We do not want to destroy transaction contexts yet,
|
* We do not want to destroy transaction contexts yet, but it
|
||||||
* but it should be OK to delete any command-local memory.
|
* should be OK to delete any command-local memory.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
MemoryContextResetAndDeleteChildren(TransactionCommandContext);
|
MemoryContextResetAndDeleteChildren(TransactionCommandContext);
|
||||||
}
|
}
|
||||||
@@ -914,17 +905,16 @@ AtAbort_Memory(void)
|
|||||||
static void
|
static void
|
||||||
AtCleanup_Memory(void)
|
AtCleanup_Memory(void)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* Now that we're "out" of a transaction, have the
|
/*
|
||||||
* system allocate things in the top memory context instead
|
* Now that we're "out" of a transaction, have the system allocate
|
||||||
* of per-transaction contexts.
|
* things in the top memory context instead of per-transaction
|
||||||
* ----------------
|
* contexts.
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(TopMemoryContext);
|
MemoryContextSwitchTo(TopMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Release all transaction-local memory.
|
* Release all transaction-local memory.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (TopTransactionContext != NULL)
|
if (TopTransactionContext != NULL)
|
||||||
MemoryContextDelete(TopTransactionContext);
|
MemoryContextDelete(TopTransactionContext);
|
||||||
@@ -951,61 +941,54 @@ StartTransaction(void)
|
|||||||
FreeXactSnapshot();
|
FreeXactSnapshot();
|
||||||
XactIsoLevel = DefaultXactIsoLevel;
|
XactIsoLevel = DefaultXactIsoLevel;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Check the current transaction state. If the transaction system
|
* Check the current transaction state. If the transaction system is
|
||||||
* is switched off, or if we're already in a transaction, do nothing.
|
* switched off, or if we're already in a transaction, do nothing.
|
||||||
* We're already in a transaction when the monitor sends a null
|
* We're already in a transaction when the monitor sends a null
|
||||||
* command to the backend to flush the comm channel. This is a
|
* command to the backend to flush the comm channel. This is a hacky
|
||||||
* hacky fix to a communications problem, and we keep having to
|
* fix to a communications problem, and we keep having to deal with it
|
||||||
* deal with it here. We should fix the comm channel code. mao 080891
|
* here. We should fix the comm channel code. mao 080891
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (s->state == TRANS_DISABLED || s->state == TRANS_INPROGRESS)
|
if (s->state == TRANS_DISABLED || s->state == TRANS_INPROGRESS)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* set the current transaction state information
|
* set the current transaction state information appropriately during
|
||||||
* appropriately during start processing
|
* start processing
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
s->state = TRANS_START;
|
s->state = TRANS_START;
|
||||||
|
|
||||||
SetReindexProcessing(false);
|
SetReindexProcessing(false);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* generate a new transaction id
|
* generate a new transaction id
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
GetNewTransactionId(&(s->transactionIdData));
|
GetNewTransactionId(&(s->transactionIdData));
|
||||||
|
|
||||||
XactLockTableInsert(s->transactionIdData);
|
XactLockTableInsert(s->transactionIdData);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize current transaction state fields
|
* initialize current transaction state fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
s->commandId = FirstCommandId;
|
s->commandId = FirstCommandId;
|
||||||
s->scanCommandId = FirstCommandId;
|
s->scanCommandId = FirstCommandId;
|
||||||
s->startTime = GetCurrentAbsoluteTime();
|
s->startTime = GetCurrentAbsoluteTime();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize the various transaction subsystems
|
* initialize the various transaction subsystems
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
AtStart_Memory();
|
AtStart_Memory();
|
||||||
AtStart_Cache();
|
AtStart_Cache();
|
||||||
AtStart_Locks();
|
AtStart_Locks();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Tell the trigger manager to we're starting a transaction
|
* Tell the trigger manager to we're starting a transaction
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
DeferredTriggerBeginXact();
|
DeferredTriggerBeginXact();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* done with start processing, set current transaction
|
* done with start processing, set current transaction state to "in
|
||||||
* state to "in progress"
|
* progress"
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
s->state = TRANS_INPROGRESS;
|
s->state = TRANS_INPROGRESS;
|
||||||
|
|
||||||
@@ -1034,9 +1017,8 @@ CommitTransaction(void)
|
|||||||
{
|
{
|
||||||
TransactionState s = CurrentTransactionState;
|
TransactionState s = CurrentTransactionState;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* check the current transaction state
|
* check the current transaction state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (s->state == TRANS_DISABLED)
|
if (s->state == TRANS_DISABLED)
|
||||||
return;
|
return;
|
||||||
@@ -1047,24 +1029,21 @@ CommitTransaction(void)
|
|||||||
/* Prevent cancel/die interrupt while cleaning up */
|
/* Prevent cancel/die interrupt while cleaning up */
|
||||||
HOLD_INTERRUPTS();
|
HOLD_INTERRUPTS();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Tell the trigger manager that this transaction is about to be
|
* Tell the trigger manager that this transaction is about to be
|
||||||
* committed. He'll invoke all trigger deferred until XACT before
|
* committed. He'll invoke all trigger deferred until XACT before we
|
||||||
* we really start on committing the transaction.
|
* really start on committing the transaction.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
DeferredTriggerEndXact();
|
DeferredTriggerEndXact();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* set the current transaction state information
|
* set the current transaction state information appropriately during
|
||||||
* appropriately during the abort processing
|
* the abort processing
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
s->state = TRANS_COMMIT;
|
s->state = TRANS_COMMIT;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* do commit processing
|
* do commit processing
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* handle commit for large objects [ PA, 7/17/98 ] */
|
/* handle commit for large objects [ PA, 7/17/98 ] */
|
||||||
@@ -1109,10 +1088,9 @@ CommitTransaction(void)
|
|||||||
|
|
||||||
SharedBufferChanged = false;/* safest place to do it */
|
SharedBufferChanged = false;/* safest place to do it */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* done with commit processing, set current transaction
|
* done with commit processing, set current transaction state back to
|
||||||
* state back to default
|
* default
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
s->state = TRANS_DEFAULT;
|
s->state = TRANS_DEFAULT;
|
||||||
|
|
||||||
@@ -1157,9 +1135,8 @@ AbortTransaction(void)
|
|||||||
*/
|
*/
|
||||||
LockWaitCancel();
|
LockWaitCancel();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* check the current transaction state
|
* check the current transaction state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (s->state == TRANS_DISABLED)
|
if (s->state == TRANS_DISABLED)
|
||||||
{
|
{
|
||||||
@@ -1170,10 +1147,9 @@ AbortTransaction(void)
|
|||||||
if (s->state != TRANS_INPROGRESS)
|
if (s->state != TRANS_INPROGRESS)
|
||||||
elog(NOTICE, "AbortTransaction and not in in-progress state");
|
elog(NOTICE, "AbortTransaction and not in in-progress state");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* set the current transaction state information
|
* set the current transaction state information appropriately during
|
||||||
* appropriately during the abort processing
|
* the abort processing
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
s->state = TRANS_ABORT;
|
s->state = TRANS_ABORT;
|
||||||
|
|
||||||
@@ -1182,9 +1158,8 @@ AbortTransaction(void)
|
|||||||
*/
|
*/
|
||||||
SetUserId(GetSessionUserId());
|
SetUserId(GetSessionUserId());
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* do abort processing
|
* do abort processing
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
DeferredTriggerAbortXact();
|
DeferredTriggerAbortXact();
|
||||||
lo_commit(false); /* 'false' means it's abort */
|
lo_commit(false); /* 'false' means it's abort */
|
||||||
@@ -1207,9 +1182,8 @@ AbortTransaction(void)
|
|||||||
|
|
||||||
SharedBufferChanged = false;/* safest place to do it */
|
SharedBufferChanged = false;/* safest place to do it */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* State remains TRANS_ABORT until CleanupTransaction().
|
* State remains TRANS_ABORT until CleanupTransaction().
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
RESUME_INTERRUPTS();
|
RESUME_INTERRUPTS();
|
||||||
}
|
}
|
||||||
@@ -1227,23 +1201,20 @@ CleanupTransaction(void)
|
|||||||
if (s->state == TRANS_DISABLED)
|
if (s->state == TRANS_DISABLED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* State should still be TRANS_ABORT from AbortTransaction().
|
* State should still be TRANS_ABORT from AbortTransaction().
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (s->state != TRANS_ABORT)
|
if (s->state != TRANS_ABORT)
|
||||||
elog(FATAL, "CleanupTransaction and not in abort state");
|
elog(FATAL, "CleanupTransaction and not in abort state");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* do abort cleanup processing
|
* do abort cleanup processing
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
AtCleanup_Memory();
|
AtCleanup_Memory();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* done with abort processing, set current transaction
|
* done with abort processing, set current transaction state back to
|
||||||
* state back to default
|
* default
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
s->state = TRANS_DEFAULT;
|
s->state = TRANS_DEFAULT;
|
||||||
}
|
}
|
||||||
@@ -1259,44 +1230,41 @@ StartTransactionCommand(void)
|
|||||||
|
|
||||||
switch (s->blockState)
|
switch (s->blockState)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* if we aren't in a transaction block, we
|
/*
|
||||||
* just do our usual start transaction.
|
* if we aren't in a transaction block, we just do our usual
|
||||||
* ----------------
|
* start transaction.
|
||||||
*/
|
*/
|
||||||
case TBLOCK_DEFAULT:
|
case TBLOCK_DEFAULT:
|
||||||
StartTransaction();
|
StartTransaction();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* We should never experience this -- if we do it
|
* We should never experience this -- if we do it means the
|
||||||
* means the BEGIN state was not changed in the previous
|
* BEGIN state was not changed in the previous
|
||||||
* CommitTransactionCommand(). If we get it, we print
|
* CommitTransactionCommand(). If we get it, we print a
|
||||||
* a warning and change to the in-progress state.
|
* warning and change to the in-progress state.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_BEGIN:
|
case TBLOCK_BEGIN:
|
||||||
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
|
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
|
||||||
s->blockState = TBLOCK_INPROGRESS;
|
s->blockState = TBLOCK_INPROGRESS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* This is the case when are somewhere in a transaction
|
* This is the case when are somewhere in a transaction block
|
||||||
* block and about to start a new command. For now we
|
* and about to start a new command. For now we do nothing
|
||||||
* do nothing but someday we may do command-local resource
|
* but someday we may do command-local resource
|
||||||
* initialization.
|
* initialization.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_INPROGRESS:
|
case TBLOCK_INPROGRESS:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* As with BEGIN, we should never experience this
|
* As with BEGIN, we should never experience this if we do it
|
||||||
* if we do it means the END state was not changed in the
|
* means the END state was not changed in the previous
|
||||||
* previous CommitTransactionCommand(). If we get it, we
|
* CommitTransactionCommand(). If we get it, we print a
|
||||||
* print a warning, commit the transaction, start a new
|
* warning, commit the transaction, start a new transaction
|
||||||
* transaction and change to the default state.
|
* and change to the default state.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_END:
|
case TBLOCK_END:
|
||||||
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_END");
|
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_END");
|
||||||
@@ -1305,23 +1273,21 @@ StartTransactionCommand(void)
|
|||||||
StartTransaction();
|
StartTransaction();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Here we are in the middle of a transaction block but
|
* Here we are in the middle of a transaction block but one of
|
||||||
* one of the commands caused an abort so we do nothing
|
* the commands caused an abort so we do nothing but remain in
|
||||||
* but remain in the abort state. Eventually we will get
|
* the abort state. Eventually we will get to the "END
|
||||||
* to the "END TRANSACTION" which will set things straight.
|
* TRANSACTION" which will set things straight.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_ABORT:
|
case TBLOCK_ABORT:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* This means we somehow aborted and the last call to
|
* This means we somehow aborted and the last call to
|
||||||
* CommitTransactionCommand() didn't clear the state so
|
* CommitTransactionCommand() didn't clear the state so we
|
||||||
* we remain in the ENDABORT state and maybe next time
|
* remain in the ENDABORT state and maybe next time we get to
|
||||||
* we get to CommitTransactionCommand() the state will
|
* CommitTransactionCommand() the state will get reset to
|
||||||
* get reset to default.
|
* default.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_ENDABORT:
|
case TBLOCK_ENDABORT:
|
||||||
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
|
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
|
||||||
@@ -1347,68 +1313,62 @@ CommitTransactionCommand(void)
|
|||||||
|
|
||||||
switch (s->blockState)
|
switch (s->blockState)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* if we aren't in a transaction block, we
|
/*
|
||||||
* just do our usual transaction commit
|
* if we aren't in a transaction block, we just do our usual
|
||||||
* ----------------
|
* transaction commit
|
||||||
*/
|
*/
|
||||||
case TBLOCK_DEFAULT:
|
case TBLOCK_DEFAULT:
|
||||||
CommitTransaction();
|
CommitTransaction();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* This is the case right after we get a "BEGIN TRANSACTION"
|
* This is the case right after we get a "BEGIN TRANSACTION"
|
||||||
* command, but the user hasn't done anything else yet, so
|
* command, but the user hasn't done anything else yet, so we
|
||||||
* we change to the "transaction block in progress" state
|
* change to the "transaction block in progress" state and
|
||||||
* and return.
|
* return.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_BEGIN:
|
case TBLOCK_BEGIN:
|
||||||
s->blockState = TBLOCK_INPROGRESS;
|
s->blockState = TBLOCK_INPROGRESS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* This is the case when we have finished executing a command
|
* This is the case when we have finished executing a command
|
||||||
* someplace within a transaction block. We increment the
|
* someplace within a transaction block. We increment the
|
||||||
* command counter and return. Someday we may free resources
|
* command counter and return. Someday we may free resources
|
||||||
* local to the command.
|
* local to the command.
|
||||||
*
|
*
|
||||||
* That someday is today, at least for memory allocated in
|
* That someday is today, at least for memory allocated in
|
||||||
* TransactionCommandContext.
|
* TransactionCommandContext. - vadim 03/25/97
|
||||||
* - vadim 03/25/97
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_INPROGRESS:
|
case TBLOCK_INPROGRESS:
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
MemoryContextResetAndDeleteChildren(TransactionCommandContext);
|
MemoryContextResetAndDeleteChildren(TransactionCommandContext);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* This is the case when we just got the "END TRANSACTION"
|
* This is the case when we just got the "END TRANSACTION"
|
||||||
* statement, so we commit the transaction and go back to
|
* statement, so we commit the transaction and go back to the
|
||||||
* the default state.
|
* default state.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_END:
|
case TBLOCK_END:
|
||||||
CommitTransaction();
|
CommitTransaction();
|
||||||
s->blockState = TBLOCK_DEFAULT;
|
s->blockState = TBLOCK_DEFAULT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Here we are in the middle of a transaction block but
|
* Here we are in the middle of a transaction block but one of
|
||||||
* one of the commands caused an abort so we do nothing
|
* the commands caused an abort so we do nothing but remain in
|
||||||
* but remain in the abort state. Eventually we will get
|
* the abort state. Eventually we will get to the "END
|
||||||
* to the "END TRANSACTION" which will set things straight.
|
* TRANSACTION" which will set things straight.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_ABORT:
|
case TBLOCK_ABORT:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Here we were in an aborted transaction block which
|
* Here we were in an aborted transaction block which just
|
||||||
* just processed the "END TRANSACTION" command from the
|
* processed the "END TRANSACTION" command from the user, so
|
||||||
* user, so clean up and return to the default state.
|
* clean up and return to the default state.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_ENDABORT:
|
case TBLOCK_ENDABORT:
|
||||||
CleanupTransaction();
|
CleanupTransaction();
|
||||||
@@ -1428,22 +1388,21 @@ AbortCurrentTransaction(void)
|
|||||||
|
|
||||||
switch (s->blockState)
|
switch (s->blockState)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* if we aren't in a transaction block, we
|
/*
|
||||||
* just do the basic abort & cleanup transaction.
|
* if we aren't in a transaction block, we just do the basic
|
||||||
* ----------------
|
* abort & cleanup transaction.
|
||||||
*/
|
*/
|
||||||
case TBLOCK_DEFAULT:
|
case TBLOCK_DEFAULT:
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
CleanupTransaction();
|
CleanupTransaction();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* If we are in the TBLOCK_BEGIN it means something
|
* If we are in the TBLOCK_BEGIN it means something screwed up
|
||||||
* screwed up right after reading "BEGIN TRANSACTION"
|
* right after reading "BEGIN TRANSACTION" so we enter the
|
||||||
* so we enter the abort state. Eventually an "END
|
* abort state. Eventually an "END TRANSACTION" will fix
|
||||||
* TRANSACTION" will fix things.
|
* things.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_BEGIN:
|
case TBLOCK_BEGIN:
|
||||||
s->blockState = TBLOCK_ABORT;
|
s->blockState = TBLOCK_ABORT;
|
||||||
@@ -1451,12 +1410,11 @@ AbortCurrentTransaction(void)
|
|||||||
/* CleanupTransaction happens when we exit TBLOCK_ABORT */
|
/* CleanupTransaction happens when we exit TBLOCK_ABORT */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* This is the case when are somewhere in a transaction
|
* This is the case when are somewhere in a transaction block
|
||||||
* block which aborted so we abort the transaction and
|
* which aborted so we abort the transaction and set the ABORT
|
||||||
* set the ABORT state. Eventually an "END TRANSACTION"
|
* state. Eventually an "END TRANSACTION" will fix things and
|
||||||
* will fix things and restore us to a normal state.
|
* restore us to a normal state.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_INPROGRESS:
|
case TBLOCK_INPROGRESS:
|
||||||
s->blockState = TBLOCK_ABORT;
|
s->blockState = TBLOCK_ABORT;
|
||||||
@@ -1464,12 +1422,10 @@ AbortCurrentTransaction(void)
|
|||||||
/* CleanupTransaction happens when we exit TBLOCK_ABORT */
|
/* CleanupTransaction happens when we exit TBLOCK_ABORT */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Here, the system was fouled up just after the
|
* Here, the system was fouled up just after the user wanted
|
||||||
* user wanted to end the transaction block so we
|
* to end the transaction block so we abort the transaction
|
||||||
* abort the transaction and put us back into the
|
* and put us back into the default state.
|
||||||
* default state.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_END:
|
case TBLOCK_END:
|
||||||
s->blockState = TBLOCK_DEFAULT;
|
s->blockState = TBLOCK_DEFAULT;
|
||||||
@@ -1477,22 +1433,20 @@ AbortCurrentTransaction(void)
|
|||||||
CleanupTransaction();
|
CleanupTransaction();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Here, we are already in an aborted transaction
|
* Here, we are already in an aborted transaction state and
|
||||||
* state and are waiting for an "END TRANSACTION" to
|
* are waiting for an "END TRANSACTION" to come along and lo
|
||||||
* come along and lo and behold, we abort again!
|
* and behold, we abort again! So we just remain in the abort
|
||||||
* So we just remain in the abort state.
|
* state.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_ABORT:
|
case TBLOCK_ABORT:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Here we were in an aborted transaction block which
|
* Here we were in an aborted transaction block which just
|
||||||
* just processed the "END TRANSACTION" command but somehow
|
* processed the "END TRANSACTION" command but somehow aborted
|
||||||
* aborted again.. since we must have done the abort
|
* again.. since we must have done the abort processing, we
|
||||||
* processing, we clean up and return to the default state.
|
* clean up and return to the default state.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case TBLOCK_ENDABORT:
|
case TBLOCK_ENDABORT:
|
||||||
CleanupTransaction();
|
CleanupTransaction();
|
||||||
@@ -1514,9 +1468,8 @@ BeginTransactionBlock(void)
|
|||||||
{
|
{
|
||||||
TransactionState s = CurrentTransactionState;
|
TransactionState s = CurrentTransactionState;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* check the current transaction state
|
* check the current transaction state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (s->state == TRANS_DISABLED)
|
if (s->state == TRANS_DISABLED)
|
||||||
return;
|
return;
|
||||||
@@ -1524,21 +1477,18 @@ BeginTransactionBlock(void)
|
|||||||
if (s->blockState != TBLOCK_DEFAULT)
|
if (s->blockState != TBLOCK_DEFAULT)
|
||||||
elog(NOTICE, "BEGIN: already a transaction in progress");
|
elog(NOTICE, "BEGIN: already a transaction in progress");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* set the current transaction block state information
|
* set the current transaction block state information appropriately
|
||||||
* appropriately during begin processing
|
* during begin processing
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
s->blockState = TBLOCK_BEGIN;
|
s->blockState = TBLOCK_BEGIN;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* do begin processing
|
* do begin processing
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* done with begin processing, set block state to inprogress
|
* done with begin processing, set block state to inprogress
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
s->blockState = TBLOCK_INPROGRESS;
|
s->blockState = TBLOCK_INPROGRESS;
|
||||||
}
|
}
|
||||||
@@ -1552,22 +1502,20 @@ EndTransactionBlock(void)
|
|||||||
{
|
{
|
||||||
TransactionState s = CurrentTransactionState;
|
TransactionState s = CurrentTransactionState;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* check the current transaction state
|
* check the current transaction state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (s->state == TRANS_DISABLED)
|
if (s->state == TRANS_DISABLED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (s->blockState == TBLOCK_INPROGRESS)
|
if (s->blockState == TBLOCK_INPROGRESS)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* here we are in a transaction block which should commit
|
/*
|
||||||
* when we get to the upcoming CommitTransactionCommand()
|
* here we are in a transaction block which should commit when we
|
||||||
* so we set the state to "END". CommitTransactionCommand()
|
* get to the upcoming CommitTransactionCommand() so we set the
|
||||||
* will recognize this and commit the transaction and return
|
* state to "END". CommitTransactionCommand() will recognize this
|
||||||
* us to the default state
|
* and commit the transaction and return us to the default state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
s->blockState = TBLOCK_END;
|
s->blockState = TBLOCK_END;
|
||||||
return;
|
return;
|
||||||
@@ -1575,25 +1523,23 @@ EndTransactionBlock(void)
|
|||||||
|
|
||||||
if (s->blockState == TBLOCK_ABORT)
|
if (s->blockState == TBLOCK_ABORT)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* here, we are in a transaction block which aborted
|
/*
|
||||||
* and since the AbortTransaction() was already done,
|
* here, we are in a transaction block which aborted and since the
|
||||||
* we do whatever is needed and change to the special
|
* AbortTransaction() was already done, we do whatever is needed
|
||||||
* "END ABORT" state. The upcoming CommitTransactionCommand()
|
* and change to the special "END ABORT" state. The upcoming
|
||||||
* will recognise this and then put us back in the default
|
* CommitTransactionCommand() will recognise this and then put us
|
||||||
* state.
|
* back in the default state.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
s->blockState = TBLOCK_ENDABORT;
|
s->blockState = TBLOCK_ENDABORT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* here, the user issued COMMIT when not inside a transaction.
|
* here, the user issued COMMIT when not inside a transaction. Issue a
|
||||||
* Issue a notice and go to abort state. The upcoming call to
|
* notice and go to abort state. The upcoming call to
|
||||||
* CommitTransactionCommand() will then put us back into the
|
* CommitTransactionCommand() will then put us back into the default
|
||||||
* default state.
|
* state.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
elog(NOTICE, "COMMIT: no transaction in progress");
|
elog(NOTICE, "COMMIT: no transaction in progress");
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
@@ -1610,34 +1556,31 @@ AbortTransactionBlock(void)
|
|||||||
{
|
{
|
||||||
TransactionState s = CurrentTransactionState;
|
TransactionState s = CurrentTransactionState;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* check the current transaction state
|
* check the current transaction state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (s->state == TRANS_DISABLED)
|
if (s->state == TRANS_DISABLED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (s->blockState == TBLOCK_INPROGRESS)
|
if (s->blockState == TBLOCK_INPROGRESS)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* here we were inside a transaction block something
|
/*
|
||||||
* screwed up inside the system so we enter the abort state,
|
* here we were inside a transaction block something screwed up
|
||||||
* do the abort processing and then return.
|
* inside the system so we enter the abort state, do the abort
|
||||||
* We remain in the abort state until we see an
|
* processing and then return. We remain in the abort state until
|
||||||
* END TRANSACTION command.
|
* we see an END TRANSACTION command.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
s->blockState = TBLOCK_ABORT;
|
s->blockState = TBLOCK_ABORT;
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* here, the user issued ABORT when not inside a transaction.
|
* here, the user issued ABORT when not inside a transaction. Issue a
|
||||||
* Issue a notice and go to abort state. The upcoming call to
|
* notice and go to abort state. The upcoming call to
|
||||||
* CommitTransactionCommand() will then put us back into the
|
* CommitTransactionCommand() will then put us back into the default
|
||||||
* default state.
|
* state.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
elog(NOTICE, "ROLLBACK: no transaction in progress");
|
elog(NOTICE, "ROLLBACK: no transaction in progress");
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
@@ -1655,9 +1598,8 @@ UserAbortTransactionBlock(void)
|
|||||||
{
|
{
|
||||||
TransactionState s = CurrentTransactionState;
|
TransactionState s = CurrentTransactionState;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* check the current transaction state
|
* check the current transaction state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (s->state == TRANS_DISABLED)
|
if (s->state == TRANS_DISABLED)
|
||||||
return;
|
return;
|
||||||
@@ -1675,14 +1617,13 @@ UserAbortTransactionBlock(void)
|
|||||||
|
|
||||||
if (s->blockState == TBLOCK_INPROGRESS)
|
if (s->blockState == TBLOCK_INPROGRESS)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* here we were inside a transaction block and we
|
/*
|
||||||
* got an abort command from the user, so we move to
|
* here we were inside a transaction block and we got an abort
|
||||||
* the abort state, do the abort processing and
|
* command from the user, so we move to the abort state, do the
|
||||||
* then change to the ENDABORT state so we will end up
|
* abort processing and then change to the ENDABORT state so we
|
||||||
* in the default state after the upcoming
|
* will end up in the default state after the upcoming
|
||||||
* CommitTransactionCommand().
|
* CommitTransactionCommand().
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
s->blockState = TBLOCK_ABORT;
|
s->blockState = TBLOCK_ABORT;
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
@@ -1690,12 +1631,11 @@ UserAbortTransactionBlock(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* here, the user issued ABORT when not inside a transaction.
|
* here, the user issued ABORT when not inside a transaction. Issue a
|
||||||
* Issue a notice and go to abort state. The upcoming call to
|
* notice and go to abort state. The upcoming call to
|
||||||
* CommitTransactionCommand() will then put us back into the
|
* CommitTransactionCommand() will then put us back into the default
|
||||||
* default state.
|
* state.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
elog(NOTICE, "ROLLBACK: no transaction in progress");
|
elog(NOTICE, "ROLLBACK: no transaction in progress");
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.105 2001/03/13 01:17:05 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.106 2001/03/22 06:16:10 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -218,9 +218,8 @@ BootstrapMain(int argc, char *argv[])
|
|||||||
int xlogop = BS_XLOG_NOP;
|
int xlogop = BS_XLOG_NOP;
|
||||||
char *potential_DataDir = NULL;
|
char *potential_DataDir = NULL;
|
||||||
|
|
||||||
/* --------------------
|
/*
|
||||||
* initialize globals
|
* initialize globals
|
||||||
* -------------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MyProcPid = getpid();
|
MyProcPid = getpid();
|
||||||
@@ -236,9 +235,8 @@ BootstrapMain(int argc, char *argv[])
|
|||||||
MemoryContextInit();
|
MemoryContextInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* process command arguments
|
* process command arguments
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Set defaults, to be overriden by explicit options below */
|
/* Set defaults, to be overriden by explicit options below */
|
||||||
@@ -248,7 +246,8 @@ BootstrapMain(int argc, char *argv[])
|
|||||||
if (!IsUnderPostmaster)
|
if (!IsUnderPostmaster)
|
||||||
{
|
{
|
||||||
ResetAllOptions();
|
ResetAllOptions();
|
||||||
potential_DataDir = getenv("PGDATA"); /* Null if no PGDATA variable */
|
potential_DataDir = getenv("PGDATA"); /* Null if no PGDATA
|
||||||
|
* variable */
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((flag = getopt(argc, argv, "D:dCQx:pB:F")) != EOF)
|
while ((flag = getopt(argc, argv, "D:dCQx:pB:F")) != EOF)
|
||||||
@@ -319,6 +318,7 @@ BootstrapMain(int argc, char *argv[])
|
|||||||
|
|
||||||
if (IsUnderPostmaster)
|
if (IsUnderPostmaster)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Properly accept or ignore signals the postmaster might send us
|
* Properly accept or ignore signals the postmaster might send us
|
||||||
*/
|
*/
|
||||||
@@ -328,6 +328,7 @@ BootstrapMain(int argc, char *argv[])
|
|||||||
pqsignal(SIGQUIT, quickdie);
|
pqsignal(SIGQUIT, quickdie);
|
||||||
pqsignal(SIGUSR1, SIG_IGN);
|
pqsignal(SIGUSR1, SIG_IGN);
|
||||||
pqsignal(SIGUSR2, SIG_IGN);
|
pqsignal(SIGUSR2, SIG_IGN);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset some signals that are accepted by postmaster but not here
|
* Reset some signals that are accepted by postmaster but not here
|
||||||
*/
|
*/
|
||||||
@@ -336,8 +337,10 @@ BootstrapMain(int argc, char *argv[])
|
|||||||
pqsignal(SIGTTOU, SIG_DFL);
|
pqsignal(SIGTTOU, SIG_DFL);
|
||||||
pqsignal(SIGCONT, SIG_DFL);
|
pqsignal(SIGCONT, SIG_DFL);
|
||||||
pqsignal(SIGWINCH, SIG_DFL);
|
pqsignal(SIGWINCH, SIG_DFL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unblock signals (they were blocked when the postmaster forked us)
|
* Unblock signals (they were blocked when the postmaster forked
|
||||||
|
* us)
|
||||||
*/
|
*/
|
||||||
PG_SETMASK(&UnBlockSig);
|
PG_SETMASK(&UnBlockSig);
|
||||||
}
|
}
|
||||||
@@ -408,9 +411,8 @@ BootstrapMain(int argc, char *argv[])
|
|||||||
for (i = 0; i < HASHTABLESIZE; ++i)
|
for (i = 0; i < HASHTABLESIZE; ++i)
|
||||||
hashtable[i] = NULL;
|
hashtable[i] = NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* abort processing resumes here
|
* abort processing resumes here
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (sigsetjmp(Warn_restart, 1) != 0)
|
if (sigsetjmp(Warn_restart, 1) != 0)
|
||||||
{
|
{
|
||||||
@@ -418,9 +420,8 @@ BootstrapMain(int argc, char *argv[])
|
|||||||
AbortCurrentTransaction();
|
AbortCurrentTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* process input.
|
* process input.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.161 2001/03/22 03:59:19 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.162 2001/03/22 06:16:10 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@@ -186,9 +186,8 @@ heap_create(char *relname,
|
|||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
Oid tblNode = MyDatabaseId;
|
Oid tblNode = MyDatabaseId;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
AssertArg(natts > 0);
|
AssertArg(natts > 0);
|
||||||
|
|
||||||
@@ -200,10 +199,9 @@ heap_create(char *relname,
|
|||||||
relname);
|
relname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* real ugly stuff to assign the proper relid in the relation
|
* real ugly stuff to assign the proper relid in the relation
|
||||||
* descriptor follows.
|
* descriptor follows.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (relname && IsSystemRelationName(relname))
|
if (relname && IsSystemRelationName(relname))
|
||||||
{
|
{
|
||||||
@@ -279,18 +277,16 @@ heap_create(char *relname,
|
|||||||
(int) MyProcPid, uniqueId++);
|
(int) MyProcPid, uniqueId++);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* switch to the cache context to create the relcache entry.
|
* switch to the cache context to create the relcache entry.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!CacheMemoryContext)
|
if (!CacheMemoryContext)
|
||||||
CreateCacheMemoryContext();
|
CreateCacheMemoryContext();
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* allocate a new relation descriptor.
|
* allocate a new relation descriptor.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
rel = (Relation) palloc(sizeof(RelationData));
|
rel = (Relation) palloc(sizeof(RelationData));
|
||||||
MemSet((char *) rel, 0, sizeof(RelationData));
|
MemSet((char *) rel, 0, sizeof(RelationData));
|
||||||
@@ -303,18 +299,16 @@ heap_create(char *relname,
|
|||||||
*/
|
*/
|
||||||
rel->rd_att = CreateTupleDescCopyConstr(tupDesc);
|
rel->rd_att = CreateTupleDescCopyConstr(tupDesc);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* nail the reldesc if this is a bootstrap create reln and
|
* nail the reldesc if this is a bootstrap create reln and we may need
|
||||||
* we may need it in the cache later on in the bootstrap
|
* it in the cache later on in the bootstrap process so we don't ever
|
||||||
* process so we don't ever want it kicked out. e.g. pg_attribute!!!
|
* want it kicked out. e.g. pg_attribute!!!
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (nailme)
|
if (nailme)
|
||||||
rel->rd_isnailed = true;
|
rel->rd_isnailed = true;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize the fields of our new relation descriptor
|
* initialize the fields of our new relation descriptor
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
rel->rd_rel = (Form_pg_class) palloc(sizeof *rel->rd_rel);
|
rel->rd_rel = (Form_pg_class) palloc(sizeof *rel->rd_rel);
|
||||||
MemSet((char *) rel->rd_rel, 0, sizeof *rel->rd_rel);
|
MemSet((char *) rel->rd_rel, 0, sizeof *rel->rd_rel);
|
||||||
@@ -334,15 +328,13 @@ heap_create(char *relname,
|
|||||||
rel->rd_node.relNode = relid;
|
rel->rd_node.relNode = relid;
|
||||||
rel->rd_rel->relfilenode = relid;
|
rel->rd_rel->relfilenode = relid;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* done building relcache entry.
|
* done building relcache entry.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* have the storage manager create the relation.
|
* have the storage manager create the relation.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (storage_create)
|
if (storage_create)
|
||||||
heap_storage_create(rel);
|
heap_storage_create(rel);
|
||||||
@@ -432,13 +424,11 @@ CheckAttributeNames(TupleDesc tupdesc)
|
|||||||
int j;
|
int j;
|
||||||
int natts = tupdesc->natts;
|
int natts = tupdesc->natts;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* first check for collision with system attribute names
|
* first check for collision with system attribute names
|
||||||
* ----------------
|
|
||||||
*
|
*
|
||||||
* also, warn user if attribute to be created has
|
* also, warn user if attribute to be created has an unknown typid
|
||||||
* an unknown typid (usually as a result of a 'retrieve into'
|
* (usually as a result of a 'retrieve into' - jolly
|
||||||
* - jolly
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < natts; i++)
|
for (i = 0; i < natts; i++)
|
||||||
{
|
{
|
||||||
@@ -460,9 +450,8 @@ CheckAttributeNames(TupleDesc tupdesc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* next check for repeated attribute names
|
* next check for repeated attribute names
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 1; i < natts; i++)
|
for (i = 1; i < natts; i++)
|
||||||
{
|
{
|
||||||
@@ -508,10 +497,9 @@ RelnameFindRelid(const char *relname)
|
|||||||
|
|
||||||
pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
|
pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* At bootstrap time, we have to do this the hard way. Form the
|
* At bootstrap time, we have to do this the hard way. Form the
|
||||||
* scan key.
|
* scan key.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ScanKeyEntryInitialize(&key,
|
ScanKeyEntryInitialize(&key,
|
||||||
0,
|
0,
|
||||||
@@ -519,9 +507,8 @@ RelnameFindRelid(const char *relname)
|
|||||||
(RegProcedure) F_NAMEEQ,
|
(RegProcedure) F_NAMEEQ,
|
||||||
(Datum) relname);
|
(Datum) relname);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* begin the scan
|
* begin the scan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_class_scan = heap_beginscan(pg_class_desc,
|
pg_class_scan = heap_beginscan(pg_class_desc,
|
||||||
0,
|
0,
|
||||||
@@ -529,10 +516,9 @@ RelnameFindRelid(const char *relname)
|
|||||||
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
|
||||||
* didn't find an existing relation.
|
* an existing relation.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tuple = heap_getnext(pg_class_scan, 0);
|
tuple = heap_getnext(pg_class_scan, 0);
|
||||||
|
|
||||||
@@ -567,23 +553,20 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
|||||||
Relation idescs[Num_pg_attr_indices];
|
Relation idescs[Num_pg_attr_indices];
|
||||||
int natts = tupdesc->natts;
|
int natts = tupdesc->natts;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open pg_attribute
|
* open pg_attribute
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
rel = heap_openr(AttributeRelationName, RowExclusiveLock);
|
rel = heap_openr(AttributeRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
/* -----------------
|
/*
|
||||||
* Check if we have any indices defined on pg_attribute.
|
* Check if we have any indices defined on pg_attribute.
|
||||||
* -----------------
|
|
||||||
*/
|
*/
|
||||||
hasindex = RelationGetForm(rel)->relhasindex;
|
hasindex = RelationGetForm(rel)->relhasindex;
|
||||||
if (hasindex)
|
if (hasindex)
|
||||||
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
|
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* first we add the user attributes..
|
* first we add the user attributes..
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
dpp = tupdesc->attrs;
|
dpp = tupdesc->attrs;
|
||||||
for (i = 0; i < natts; i++)
|
for (i = 0; i < natts; i++)
|
||||||
@@ -607,9 +590,8 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
|||||||
dpp++;
|
dpp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* next we add the system attributes..
|
* next we add the system attributes..
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
dpp = HeapAtt;
|
dpp = HeapAtt;
|
||||||
for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++)
|
for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++)
|
||||||
@@ -663,31 +645,29 @@ AddNewRelationTuple(Relation pg_class_desc,
|
|||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
Relation idescs[Num_pg_class_indices];
|
Relation idescs[Num_pg_class_indices];
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* first we update some of the information in our
|
* first we update some of the information in our uncataloged
|
||||||
* uncataloged relation's relation descriptor.
|
* relation's relation descriptor.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
new_rel_reltup = new_rel_desc->rd_rel;
|
new_rel_reltup = new_rel_desc->rd_rel;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Here we insert bogus estimates of the size of the new relation.
|
* Here we insert bogus estimates of the size of the new relation. In
|
||||||
* In reality, of course, the new relation has 0 tuples and pages,
|
* reality, of course, the new relation has 0 tuples and pages, and if
|
||||||
* and if we were tracking these statistics accurately then we'd
|
* we were tracking these statistics accurately then we'd set the
|
||||||
* set the fields that way. But at present the stats will be updated
|
* fields that way. But at present the stats will be updated only by
|
||||||
* only by VACUUM or CREATE INDEX, and the user might insert a lot of
|
* VACUUM or CREATE INDEX, and the user might insert a lot of tuples
|
||||||
* tuples before he gets around to doing either of those. So, instead
|
* before he gets around to doing either of those. So, instead of
|
||||||
* of saying the relation is empty, we insert guesstimates. The point
|
* saying the relation is empty, we insert guesstimates. The point is
|
||||||
* is to keep the optimizer from making really stupid choices on
|
* to keep the optimizer from making really stupid choices on
|
||||||
* never-yet-vacuumed tables; so the estimates need only be large
|
* never-yet-vacuumed tables; so the estimates need only be large
|
||||||
* enough to discourage the optimizer from using nested-loop plans.
|
* enough to discourage the optimizer from using nested-loop plans.
|
||||||
* With this hack, nested-loop plans will be preferred only after
|
* With this hack, nested-loop plans will be preferred only after the
|
||||||
* the table has been proven to be small by VACUUM or CREATE INDEX.
|
* table has been proven to be small by VACUUM or CREATE INDEX.
|
||||||
* Maintaining the stats on-the-fly would solve the problem more cleanly,
|
* Maintaining the stats on-the-fly would solve the problem more
|
||||||
* but the overhead of that would likely cost more than it'd save.
|
* cleanly, but the overhead of that would likely cost more than it'd
|
||||||
* (NOTE: CREATE INDEX inserts the same bogus estimates if it finds the
|
* save. (NOTE: CREATE INDEX inserts the same bogus estimates if it
|
||||||
* relation has 0 rows and pages. See index.c.)
|
* finds the relation has 0 rows and pages. See index.c.)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
new_rel_reltup->relpages = 10; /* bogus estimates */
|
new_rel_reltup->relpages = 10; /* bogus estimates */
|
||||||
new_rel_reltup->reltuples = 1000;
|
new_rel_reltup->reltuples = 1000;
|
||||||
@@ -792,9 +772,8 @@ heap_create_with_catalog(char *relname,
|
|||||||
int natts = tupdesc->natts;
|
int natts = tupdesc->natts;
|
||||||
char *temp_relname = NULL;
|
char *temp_relname = NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode());
|
Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode());
|
||||||
if (natts <= 0 || natts > MaxHeapAttributeNumber)
|
if (natts <= 0 || natts > MaxHeapAttributeNumber)
|
||||||
@@ -817,17 +796,16 @@ heap_create_with_catalog(char *relname,
|
|||||||
strcpy(relname, temp_relname); /* heap_create will change this */
|
strcpy(relname, temp_relname); /* heap_create will change this */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Tell heap_create not to create a physical file; we'll do that
|
* Tell heap_create not to create a physical file; we'll do that below
|
||||||
* below after all our catalog updates are done. (This isn't really
|
* after all our catalog updates are done. (This isn't really
|
||||||
* necessary anymore, but we may as well avoid the cycles of creating
|
* necessary anymore, but we may as well avoid the cycles of creating
|
||||||
* and deleting the file in case we fail.)
|
* and deleting the file in case we fail.)
|
||||||
*
|
*
|
||||||
* Note: The call to heap_create() changes relname for
|
* Note: The call to heap_create() changes relname for temp tables; it
|
||||||
* temp tables; it becomes the true physical relname.
|
* becomes the true physical relname. The call to
|
||||||
* The call to heap_storage_create() does all the "real"
|
* heap_storage_create() does all the "real" work of creating the disk
|
||||||
* work of creating the disk file for the relation.
|
* file for the relation.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
new_rel_desc = heap_create(relname, tupdesc, istemp, false,
|
new_rel_desc = heap_create(relname, tupdesc, istemp, false,
|
||||||
allow_system_table_mods);
|
allow_system_table_mods);
|
||||||
@@ -838,13 +816,12 @@ heap_create_with_catalog(char *relname,
|
|||||||
/* Assign an OID for the relation's tuple type */
|
/* Assign an OID for the relation's tuple type */
|
||||||
new_type_oid = newoid();
|
new_type_oid = newoid();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now create an entry in pg_class for the relation.
|
* now create an entry in pg_class for the relation.
|
||||||
*
|
*
|
||||||
* NOTE: we could get a unique-index failure here, in case someone else
|
* NOTE: we could get a unique-index failure here, in case someone else
|
||||||
* is creating the same relation name in parallel but hadn't committed
|
* is creating the same relation name in parallel but hadn't committed
|
||||||
* yet when we checked for a duplicate name above.
|
* yet when we checked for a duplicate name above.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock);
|
pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
@@ -856,20 +833,18 @@ heap_create_with_catalog(char *relname,
|
|||||||
relkind,
|
relkind,
|
||||||
temp_relname);
|
temp_relname);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* since defining a relation also defines a complex type,
|
* since defining a relation also defines a complex type, we add a new
|
||||||
* we add a new system type corresponding to the new relation.
|
* system type corresponding to the new relation.
|
||||||
*
|
*
|
||||||
* NOTE: we could get a unique-index failure here, in case the same name
|
* NOTE: we could get a unique-index failure here, in case the same name
|
||||||
* has already been used for a type.
|
* has already been used for a type.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
AddNewRelationType(relname, new_rel_oid, new_type_oid);
|
AddNewRelationType(relname, new_rel_oid, new_type_oid);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now add tuples to pg_attribute for the attributes in
|
* now add tuples to pg_attribute for the attributes in our new
|
||||||
* our new relation.
|
* relation.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
AddNewAttributeTuples(new_rel_oid, tupdesc);
|
AddNewAttributeTuples(new_rel_oid, tupdesc);
|
||||||
|
|
||||||
@@ -887,12 +862,11 @@ heap_create_with_catalog(char *relname,
|
|||||||
if (relkind != RELKIND_VIEW)
|
if (relkind != RELKIND_VIEW)
|
||||||
heap_storage_create(new_rel_desc);
|
heap_storage_create(new_rel_desc);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* ok, the relation has been cataloged, so close our relations
|
* ok, the relation has been cataloged, so close our relations and
|
||||||
* and return the oid of the newly created relation.
|
* return the oid of the newly created relation.
|
||||||
*
|
*
|
||||||
* SOMEDAY: fill the STATISTIC relation properly.
|
* SOMEDAY: fill the STATISTIC relation properly.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_close(new_rel_desc, NoLock); /* do not unlock till end of xact */
|
heap_close(new_rel_desc, NoLock); /* do not unlock till end of xact */
|
||||||
heap_close(pg_class_desc, RowExclusiveLock);
|
heap_close(pg_class_desc, RowExclusiveLock);
|
||||||
@@ -950,16 +924,13 @@ RelationRemoveInheritance(Relation relation)
|
|||||||
ScanKeyData entry;
|
ScanKeyData entry;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open pg_inherits
|
* open pg_inherits
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
catalogRelation = heap_openr(InheritsRelationName, RowExclusiveLock);
|
catalogRelation = heap_openr(InheritsRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* form a scan key for the subclasses of this class
|
* form a scan key for the subclasses of this class and begin scanning
|
||||||
* and begin scanning
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_inherits_inhparent,
|
ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_inherits_inhparent,
|
||||||
F_OIDEQ,
|
F_OIDEQ,
|
||||||
@@ -971,9 +942,8 @@ RelationRemoveInheritance(Relation relation)
|
|||||||
1,
|
1,
|
||||||
&entry);
|
&entry);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if any subclasses exist, then we disallow the deletion.
|
* if any subclasses exist, then we disallow the deletion.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tuple = heap_getnext(scan, 0);
|
tuple = heap_getnext(scan, 0);
|
||||||
if (HeapTupleIsValid(tuple))
|
if (HeapTupleIsValid(tuple))
|
||||||
@@ -992,10 +962,9 @@ RelationRemoveInheritance(Relation relation)
|
|||||||
}
|
}
|
||||||
heap_endscan(scan);
|
heap_endscan(scan);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* If we get here, it means the relation has no subclasses
|
* If we get here, it means the relation has no subclasses so we can
|
||||||
* so we can trash it. First we remove dead INHERITS tuples.
|
* trash it. First we remove dead INHERITS tuples.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
entry.sk_attno = Anum_pg_inherits_inhrelid;
|
entry.sk_attno = Anum_pg_inherits_inhrelid;
|
||||||
|
|
||||||
@@ -1014,9 +983,8 @@ RelationRemoveInheritance(Relation relation)
|
|||||||
heap_endscan(scan);
|
heap_endscan(scan);
|
||||||
heap_close(catalogRelation, RowExclusiveLock);
|
heap_close(catalogRelation, RowExclusiveLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now remove dead IPL tuples
|
* now remove dead IPL tuples
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
catalogRelation = heap_openr(InheritancePrecidenceListRelationName,
|
catalogRelation = heap_openr(InheritancePrecidenceListRelationName,
|
||||||
RowExclusiveLock);
|
RowExclusiveLock);
|
||||||
@@ -1083,9 +1051,8 @@ DeleteRelationTuple(Relation rel)
|
|||||||
Relation pg_class_desc;
|
Relation pg_class_desc;
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open pg_class
|
* open pg_class
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock);
|
pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
@@ -1096,9 +1063,8 @@ DeleteRelationTuple(Relation rel)
|
|||||||
elog(ERROR, "Relation \"%s\" does not exist",
|
elog(ERROR, "Relation \"%s\" does not exist",
|
||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* delete the relation tuple from pg_class, and finish up.
|
* delete the relation tuple from pg_class, and finish up.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
simple_heap_delete(pg_class_desc, &tup->t_self);
|
simple_heap_delete(pg_class_desc, &tup->t_self);
|
||||||
heap_freetuple(tup);
|
heap_freetuple(tup);
|
||||||
@@ -1212,13 +1178,12 @@ heap_truncate(char *relname)
|
|||||||
rel = heap_openr(relname, AccessExclusiveLock);
|
rel = heap_openr(relname, AccessExclusiveLock);
|
||||||
rid = RelationGetRelid(rel);
|
rid = RelationGetRelid(rel);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* TRUNCATE TABLE within a transaction block is dangerous, because
|
* TRUNCATE TABLE within a transaction block is dangerous, because if
|
||||||
* if the transaction is later rolled back we have no way to
|
* the transaction is later rolled back we have no way to undo
|
||||||
* undo truncation of the relation's physical file. Disallow it
|
* truncation of the relation's physical file. Disallow it except for
|
||||||
* except for a rel created in the current xact (which would be deleted
|
* a rel created in the current xact (which would be deleted on abort,
|
||||||
* on abort, anyway).
|
* anyway).
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (IsTransactionBlock() && !rel->rd_myxactonly)
|
if (IsTransactionBlock() && !rel->rd_myxactonly)
|
||||||
elog(ERROR, "TRUNCATE TABLE cannot run inside a BEGIN/END block");
|
elog(ERROR, "TRUNCATE TABLE cannot run inside a BEGIN/END block");
|
||||||
@@ -1256,9 +1221,8 @@ DeleteAttributeTuples(Relation rel)
|
|||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
int2 attnum;
|
int2 attnum;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open pg_attribute
|
* open pg_attribute
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_attribute_desc = heap_openr(AttributeRelationName, RowExclusiveLock);
|
pg_attribute_desc = heap_openr(AttributeRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
@@ -1305,16 +1269,14 @@ DeleteTypeTuple(Relation rel)
|
|||||||
HeapTuple atttup;
|
HeapTuple atttup;
|
||||||
Oid typoid;
|
Oid typoid;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open pg_type
|
* open pg_type
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
|
pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create a scan key to locate the type tuple corresponding
|
* create a scan key to locate the type tuple corresponding to this
|
||||||
* to this relation.
|
* relation.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ScanKeyEntryInitialize(&key, 0,
|
ScanKeyEntryInitialize(&key, 0,
|
||||||
Anum_pg_type_typrelid,
|
Anum_pg_type_typrelid,
|
||||||
@@ -1327,10 +1289,9 @@ DeleteTypeTuple(Relation rel)
|
|||||||
1,
|
1,
|
||||||
&key);
|
&key);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* use heap_getnext() to fetch the pg_type tuple. If this
|
* use heap_getnext() to fetch the pg_type tuple. If this tuple is
|
||||||
* tuple is not valid then something's wrong.
|
* not valid then something's wrong.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tup = heap_getnext(pg_type_scan, 0);
|
tup = heap_getnext(pg_type_scan, 0);
|
||||||
|
|
||||||
@@ -1342,12 +1303,10 @@ DeleteTypeTuple(Relation rel)
|
|||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now scan pg_attribute. if any other relations have
|
* now scan pg_attribute. if any other relations have attributes of
|
||||||
* attributes of the type of the relation we are deleteing
|
* the type of the relation we are deleteing then we have to disallow
|
||||||
* then we have to disallow the deletion. should talk to
|
* the deletion. should talk to stonebraker about this. -cim 6/19/90
|
||||||
* stonebraker about this. -cim 6/19/90
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
typoid = tup->t_data->t_oid;
|
typoid = tup->t_data->t_oid;
|
||||||
|
|
||||||
@@ -1365,11 +1324,9 @@ DeleteTypeTuple(Relation rel)
|
|||||||
1,
|
1,
|
||||||
&attkey);
|
&attkey);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* try and get a pg_attribute tuple. if we succeed it means
|
* try and get a pg_attribute tuple. if we succeed it means we can't
|
||||||
* we can't delete the relation because something depends on
|
* delete the relation because something depends on the schema.
|
||||||
* the schema.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
atttup = heap_getnext(pg_attribute_scan, 0);
|
atttup = heap_getnext(pg_attribute_scan, 0);
|
||||||
|
|
||||||
@@ -1388,10 +1345,9 @@ DeleteTypeTuple(Relation rel)
|
|||||||
heap_endscan(pg_attribute_scan);
|
heap_endscan(pg_attribute_scan);
|
||||||
heap_close(pg_attribute_desc, RowExclusiveLock);
|
heap_close(pg_attribute_desc, RowExclusiveLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Ok, it's safe so we delete the relation tuple
|
* Ok, it's safe so we delete the relation tuple from pg_type and
|
||||||
* from pg_type and finish up.
|
* finish up.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
simple_heap_delete(pg_type_desc, &tup->t_self);
|
simple_heap_delete(pg_type_desc, &tup->t_self);
|
||||||
|
|
||||||
@@ -1414,17 +1370,15 @@ heap_drop_with_catalog(const char *relname,
|
|||||||
bool istemp = is_temp_rel_name(relname);
|
bool istemp = is_temp_rel_name(relname);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Open and lock the relation.
|
* Open and lock the relation.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
rel = heap_openr(relname, AccessExclusiveLock);
|
rel = heap_openr(relname, AccessExclusiveLock);
|
||||||
rid = RelationGetRelid(rel);
|
rid = RelationGetRelid(rel);
|
||||||
has_toasttable = rel->rd_rel->reltoastrelid != InvalidOid;
|
has_toasttable = rel->rd_rel->reltoastrelid != InvalidOid;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* prevent deletion of system relations
|
* prevent deletion of system relations
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
/* allow temp of pg_class? Guess so. */
|
/* allow temp of pg_class? Guess so. */
|
||||||
if (!istemp && !allow_system_table_mods &&
|
if (!istemp && !allow_system_table_mods &&
|
||||||
@@ -1432,19 +1386,17 @@ heap_drop_with_catalog(const char *relname,
|
|||||||
elog(ERROR, "System relation \"%s\" may not be dropped",
|
elog(ERROR, "System relation \"%s\" may not be dropped",
|
||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Release all buffers that belong to this relation, after writing
|
* Release all buffers that belong to this relation, after writing any
|
||||||
* any that are dirty
|
* that are dirty
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
i = FlushRelationBuffers(rel, (BlockNumber) 0);
|
i = FlushRelationBuffers(rel, (BlockNumber) 0);
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
elog(ERROR, "heap_drop_with_catalog: FlushRelationBuffers returned %d",
|
elog(ERROR, "heap_drop_with_catalog: FlushRelationBuffers returned %d",
|
||||||
i);
|
i);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* remove rules if necessary
|
* remove rules if necessary
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (rel->rd_rules != NULL)
|
if (rel->rd_rules != NULL)
|
||||||
RelationRemoveRules(rid);
|
RelationRemoveRules(rid);
|
||||||
@@ -1452,27 +1404,23 @@ heap_drop_with_catalog(const char *relname,
|
|||||||
/* triggers */
|
/* triggers */
|
||||||
RelationRemoveTriggers(rel);
|
RelationRemoveTriggers(rel);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* remove inheritance information
|
* remove inheritance information
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
RelationRemoveInheritance(rel);
|
RelationRemoveInheritance(rel);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* remove indexes if necessary
|
* remove indexes if necessary
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
RelationRemoveIndexes(rel);
|
RelationRemoveIndexes(rel);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* delete attribute tuples
|
* delete attribute tuples
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
DeleteAttributeTuples(rel);
|
DeleteAttributeTuples(rel);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* delete comments, statistics, and constraints
|
* delete comments, statistics, and constraints
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
DeleteComments(RelationGetRelid(rel));
|
DeleteComments(RelationGetRelid(rel));
|
||||||
|
|
||||||
@@ -1480,21 +1428,18 @@ heap_drop_with_catalog(const char *relname,
|
|||||||
|
|
||||||
RemoveConstraints(rel);
|
RemoveConstraints(rel);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* delete type tuple
|
* delete type tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
DeleteTypeTuple(rel);
|
DeleteTypeTuple(rel);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* delete relation tuple
|
* delete relation tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
DeleteRelationTuple(rel);
|
DeleteRelationTuple(rel);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* unlink the relation's physical file and finish up.
|
* unlink the relation's physical file and finish up.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (rel->rd_rel->relkind != RELKIND_VIEW)
|
if (rel->rd_rel->relkind != RELKIND_VIEW)
|
||||||
smgrunlink(DEFAULT_SMGR, rel);
|
smgrunlink(DEFAULT_SMGR, rel);
|
||||||
@@ -1506,9 +1451,8 @@ heap_drop_with_catalog(const char *relname,
|
|||||||
*/
|
*/
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* flush the relation from the relcache
|
* flush the relation from the relcache
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
RelationForgetRelation(rid);
|
RelationForgetRelation(rid);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.143 2001/03/22 03:59:19 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.144 2001/03/22 06:16:10 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@@ -235,9 +235,8 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||||||
heapTupDesc = RelationGetDescr(heapRelation);
|
heapTupDesc = RelationGetDescr(heapRelation);
|
||||||
natts = RelationGetForm(heapRelation)->relnatts;
|
natts = RelationGetForm(heapRelation)->relnatts;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* allocate the new tuple descriptor
|
* allocate the new tuple descriptor
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
indexTupDesc = CreateTemplateTupleDesc(numatts);
|
indexTupDesc = CreateTemplateTupleDesc(numatts);
|
||||||
@@ -255,21 +254,20 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||||||
Form_pg_attribute from;
|
Form_pg_attribute from;
|
||||||
Form_pg_attribute to;
|
Form_pg_attribute to;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the attribute number and make sure it's valid;
|
* get the attribute number and make sure it's valid; determine
|
||||||
* determine which attribute descriptor to copy
|
* which attribute descriptor to copy
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
atnum = attNums[i];
|
atnum = attNums[i];
|
||||||
|
|
||||||
if (!AttrNumberIsForUserDefinedAttr(atnum))
|
if (!AttrNumberIsForUserDefinedAttr(atnum))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* here we are indexing on a system attribute (-1...-n)
|
/*
|
||||||
* so we convert atnum into a usable index 0...n-1 so we can
|
* here we are indexing on a system attribute (-1...-n) so we
|
||||||
* use it to dereference the array sysatts[] which stores
|
* convert atnum into a usable index 0...n-1 so we can use it
|
||||||
* tuple descriptor information for system attributes.
|
* to dereference the array sysatts[] which stores tuple
|
||||||
* ----------------
|
* descriptor information for system attributes.
|
||||||
*/
|
*/
|
||||||
if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0)
|
if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0)
|
||||||
elog(ERROR, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
|
elog(ERROR, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
|
||||||
@@ -279,9 +277,9 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* here we are indexing on a normal attribute (1...n)
|
* here we are indexing on a normal attribute (1...n)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (atnum > natts)
|
if (atnum > natts)
|
||||||
elog(ERROR, "Cannot create index: attribute %d does not exist",
|
elog(ERROR, "Cannot create index: attribute %d does not exist",
|
||||||
@@ -291,10 +289,9 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||||||
from = heapTupDesc->attrs[atind];
|
from = heapTupDesc->attrs[atind];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now that we've determined the "from", let's copy
|
* now that we've determined the "from", let's copy the tuple desc
|
||||||
* the tuple desc data...
|
* data...
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
indexTupDesc->attrs[i] = to =
|
indexTupDesc->attrs[i] = to =
|
||||||
(Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
|
(Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
|
||||||
@@ -346,26 +343,23 @@ AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
|
|||||||
ScanKeyData key;
|
ScanKeyData key;
|
||||||
Form_pg_am aform;
|
Form_pg_am aform;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* form a scan key for the pg_am relation
|
* form a scan key for the pg_am relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
|
ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
|
||||||
F_OIDEQ,
|
F_OIDEQ,
|
||||||
ObjectIdGetDatum(accessMethodObjectId));
|
ObjectIdGetDatum(accessMethodObjectId));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* fetch the desired access method tuple
|
* fetch the desired access method tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_am_desc = heap_openr(AccessMethodRelationName, AccessShareLock);
|
pg_am_desc = heap_openr(AccessMethodRelationName, AccessShareLock);
|
||||||
pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
|
pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
|
||||||
|
|
||||||
pg_am_tuple = heap_getnext(pg_am_scan, 0);
|
pg_am_tuple = heap_getnext(pg_am_scan, 0);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* return NULL if not found
|
* return NULL if not found
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!HeapTupleIsValid(pg_am_tuple))
|
if (!HeapTupleIsValid(pg_am_tuple))
|
||||||
{
|
{
|
||||||
@@ -374,9 +368,8 @@ AccessMethodObjectIdGetForm(Oid accessMethodObjectId,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if found AM tuple, then copy it into resultCxt and return the copy
|
* if found AM tuple, then copy it into resultCxt and return the copy
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
aform = (Form_pg_am) MemoryContextAlloc(resultCxt, sizeof *aform);
|
aform = (Form_pg_am) MemoryContextAlloc(resultCxt, sizeof *aform);
|
||||||
memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
|
memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
|
||||||
@@ -397,9 +390,8 @@ ConstructIndexReldesc(Relation indexRelation, Oid amoid)
|
|||||||
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
|
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
|
||||||
CacheMemoryContext);
|
CacheMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* XXX missing the initialization of some other fields
|
* XXX missing the initialization of some other fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
indexRelation->rd_rel->relowner = GetUserId();
|
indexRelation->rd_rel->relowner = GetUserId();
|
||||||
@@ -428,11 +420,10 @@ UpdateRelationRelation(Relation indexRelation, char *temp_relname)
|
|||||||
CLASS_TUPLE_SIZE,
|
CLASS_TUPLE_SIZE,
|
||||||
(char *) indexRelation->rd_rel);
|
(char *) indexRelation->rd_rel);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* the new tuple must have the same oid as the relcache entry for the
|
* the new tuple must have the same oid as the relcache entry for the
|
||||||
* index. sure would be embarrassing to do this sort of thing in
|
* index. sure would be embarrassing to do this sort of thing in
|
||||||
* polite company.
|
* polite company.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tuple->t_data->t_oid = RelationGetRelid(indexRelation);
|
tuple->t_data->t_oid = RelationGetRelid(indexRelation);
|
||||||
heap_insert(pg_class, tuple);
|
heap_insert(pg_class, tuple);
|
||||||
@@ -500,23 +491,21 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
|
|||||||
TupleDesc indexTupDesc;
|
TupleDesc indexTupDesc;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open the attribute relation
|
* open the attribute relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
|
pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize *null, *replace and *value
|
* initialize *null, *replace and *value
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
MemSet(nullv, ' ', Natts_pg_attribute);
|
MemSet(nullv, ' ', Natts_pg_attribute);
|
||||||
MemSet(replace, ' ', Natts_pg_attribute);
|
MemSet(replace, ' ', Natts_pg_attribute);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------
|
||||||
* create the first attribute tuple.
|
* create the first attribute tuple.
|
||||||
* XXX For now, only change the ATTNUM attribute value
|
* XXX For now, only change the ATTNUM attribute value
|
||||||
* ----------------
|
* ----------
|
||||||
*/
|
*/
|
||||||
replace[Anum_pg_attribute_attnum - 1] = 'r';
|
replace[Anum_pg_attribute_attnum - 1] = 'r';
|
||||||
replace[Anum_pg_attribute_attcacheoff - 1] = 'r';
|
replace[Anum_pg_attribute_attcacheoff - 1] = 'r';
|
||||||
@@ -535,9 +524,8 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
|
|||||||
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
|
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* insert the first attribute tuple.
|
* insert the first attribute tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
cur_tuple = heap_modifytuple(init_tuple,
|
cur_tuple = heap_modifytuple(init_tuple,
|
||||||
pg_attribute,
|
pg_attribute,
|
||||||
@@ -550,18 +538,17 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
|
|||||||
if (hasind)
|
if (hasind)
|
||||||
CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, cur_tuple);
|
CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, cur_tuple);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now we use the information in the index cur_tuple
|
* now we use the information in the index cur_tuple descriptor to
|
||||||
* descriptor to form the remaining attribute tuples.
|
* form the remaining attribute tuples.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
indexTupDesc = RelationGetDescr(indexRelation);
|
indexTupDesc = RelationGetDescr(indexRelation);
|
||||||
|
|
||||||
for (i = 1; i < numatts; i += 1)
|
for (i = 1; i < numatts; i += 1)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* process the remaining attributes...
|
* process the remaining attributes...
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
memmove(GETSTRUCT(cur_tuple),
|
memmove(GETSTRUCT(cur_tuple),
|
||||||
(char *) indexTupDesc->attrs[i],
|
(char *) indexTupDesc->attrs[i],
|
||||||
@@ -580,10 +567,9 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
|
|||||||
if (hasind)
|
if (hasind)
|
||||||
CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
|
CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* ModifyHeapTuple returns a new copy of a cur_tuple
|
* ModifyHeapTuple returns a new copy of a cur_tuple so we free
|
||||||
* so we free the original and use the copy..
|
* the original and use the copy..
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
cur_tuple = new_tuple;
|
cur_tuple = new_tuple;
|
||||||
}
|
}
|
||||||
@@ -617,10 +603,9 @@ UpdateIndexRelation(Oid indexoid,
|
|||||||
int i;
|
int i;
|
||||||
Relation idescs[Num_pg_index_indices];
|
Relation idescs[Num_pg_index_indices];
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* allocate a Form_pg_index big enough to hold the
|
* allocate a Form_pg_index big enough to hold the index-predicate (if
|
||||||
* index-predicate (if any) in string form
|
* any) in string form
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (indexInfo->ii_Predicate != NULL)
|
if (indexInfo->ii_Predicate != NULL)
|
||||||
{
|
{
|
||||||
@@ -638,9 +623,8 @@ UpdateIndexRelation(Oid indexoid,
|
|||||||
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));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* store information into the index tuple form
|
* store information into the index tuple form
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
indexForm->indexrelid = indexoid;
|
indexForm->indexrelid = indexoid;
|
||||||
indexForm->indrelid = heapoid;
|
indexForm->indrelid = heapoid;
|
||||||
@@ -652,11 +636,10 @@ UpdateIndexRelation(Oid indexoid,
|
|||||||
indexForm->indisprimary = primary;
|
indexForm->indisprimary = primary;
|
||||||
memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
|
memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy index key and op class information
|
* copy index key and op class information
|
||||||
*
|
*
|
||||||
* We zeroed the extra slots (if any) above --- that's essential.
|
* We zeroed the extra slots (if any) above --- that's essential.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
|
for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
|
||||||
indexForm->indkey[i] = indexInfo->ii_KeyAttrNumbers[i];
|
indexForm->indkey[i] = indexInfo->ii_KeyAttrNumbers[i];
|
||||||
@@ -664,29 +647,25 @@ UpdateIndexRelation(Oid indexoid,
|
|||||||
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
|
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
|
||||||
indexForm->indclass[i] = classOids[i];
|
indexForm->indclass[i] = classOids[i];
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open the system catalog index relation
|
* open the system catalog index relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
|
pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* form a tuple to insert into pg_index
|
* form a tuple to insert into pg_index
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tuple = heap_addheader(Natts_pg_index,
|
tuple = heap_addheader(Natts_pg_index,
|
||||||
itupLen,
|
itupLen,
|
||||||
(char *) indexForm);
|
(char *) indexForm);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* insert the tuple into the pg_index
|
* insert the tuple into the pg_index
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_insert(pg_index, tuple);
|
heap_insert(pg_index, tuple);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* add index tuples for it
|
* add index tuples for it
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!IsIgnoringSystemIndexes())
|
if (!IsIgnoringSystemIndexes())
|
||||||
{
|
{
|
||||||
@@ -695,9 +674,8 @@ UpdateIndexRelation(Oid indexoid,
|
|||||||
CatalogCloseIndices(Num_pg_index_indices, idescs);
|
CatalogCloseIndices(Num_pg_index_indices, idescs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* close the relation and free the tuple
|
* close the relation and free the tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_close(pg_index, RowExclusiveLock);
|
heap_close(pg_index, RowExclusiveLock);
|
||||||
pfree(predText);
|
pfree(predText);
|
||||||
@@ -802,27 +780,24 @@ InitIndexStrategy(int numatts,
|
|||||||
Oid attrelid;
|
Oid attrelid;
|
||||||
Size strsize;
|
Size strsize;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from the index relation descriptor
|
* get information from the index relation descriptor
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
attrelid = indexRelation->rd_att->attrs[0]->attrelid;
|
attrelid = indexRelation->rd_att->attrs[0]->attrelid;
|
||||||
amstrategies = indexRelation->rd_am->amstrategies;
|
amstrategies = indexRelation->rd_am->amstrategies;
|
||||||
amsupport = indexRelation->rd_am->amsupport;
|
amsupport = indexRelation->rd_am->amsupport;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the size of the strategy
|
* get the size of the strategy
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
|
strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* allocate the new index strategy structure
|
* allocate the new index strategy structure
|
||||||
*
|
*
|
||||||
* the index strategy has to be allocated in the same
|
* the index strategy has to be allocated in the same context as the
|
||||||
* context as the relation descriptor cache or else
|
* relation descriptor cache or else it will be lost at the end of the
|
||||||
* it will be lost at the end of the transaction.
|
* transaction.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!CacheMemoryContext)
|
if (!CacheMemoryContext)
|
||||||
CreateCacheMemoryContext();
|
CreateCacheMemoryContext();
|
||||||
@@ -839,11 +814,10 @@ InitIndexStrategy(int numatts,
|
|||||||
else
|
else
|
||||||
support = (RegProcedure *) NULL;
|
support = (RegProcedure *) NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* fill in the index strategy structure with information
|
* fill in the index strategy structure with information from the
|
||||||
* from the catalogs. First we must advance the command counter
|
* catalogs. First we must advance the command counter so that we
|
||||||
* so that we will see the newly-entered index catalog tuples.
|
* will see the newly-entered index catalog tuples.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
|
||||||
@@ -852,9 +826,8 @@ InitIndexStrategy(int numatts,
|
|||||||
attrelid, accessMethodObjectId,
|
attrelid, accessMethodObjectId,
|
||||||
amstrategies, amsupport, numatts);
|
amstrategies, amsupport, numatts);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* store the strategy information in the index reldesc
|
* store the strategy information in the index reldesc
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
RelationSetIndexSupport(indexRelation, strategy, support);
|
RelationSetIndexSupport(indexRelation, strategy, support);
|
||||||
}
|
}
|
||||||
@@ -884,17 +857,15 @@ index_create(char *heapRelationName,
|
|||||||
|
|
||||||
SetReindexProcessing(false);
|
SetReindexProcessing(false);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* check parameters
|
* check parameters
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (indexInfo->ii_NumIndexAttrs < 1 ||
|
if (indexInfo->ii_NumIndexAttrs < 1 ||
|
||||||
indexInfo->ii_NumKeyAttrs < 1)
|
indexInfo->ii_NumKeyAttrs < 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
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
|
heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
|
||||||
|
|
||||||
@@ -903,9 +874,8 @@ index_create(char *heapRelationName,
|
|||||||
*/
|
*/
|
||||||
heapRelation = heap_open(heapoid, ShareLock);
|
heapRelation = heap_open(heapoid, ShareLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* construct new tuple descriptor
|
* construct new tuple descriptor
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (OidIsValid(indexInfo->ii_FuncOid))
|
if (OidIsValid(indexInfo->ii_FuncOid))
|
||||||
indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid);
|
indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid);
|
||||||
@@ -923,9 +893,8 @@ index_create(char *heapRelationName,
|
|||||||
* change this */
|
* change this */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create the index relation
|
* create the index relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
indexRelation = heap_create(indexRelationName, indexTupDesc,
|
indexRelation = heap_create(indexRelationName, indexTupDesc,
|
||||||
istemp, false, allow_system_table_mods);
|
istemp, false, allow_system_table_mods);
|
||||||
@@ -937,11 +906,10 @@ index_create(char *heapRelationName,
|
|||||||
*/
|
*/
|
||||||
LockRelation(indexRelation, AccessExclusiveLock);
|
LockRelation(indexRelation, AccessExclusiveLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* construct the index relation descriptor
|
* construct the index relation descriptor
|
||||||
*
|
*
|
||||||
* XXX should have a proper way to create cataloged relations
|
* XXX should have a proper way to create cataloged relations
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ConstructIndexReldesc(indexRelation, accessMethodObjectId);
|
ConstructIndexReldesc(indexRelation, accessMethodObjectId);
|
||||||
|
|
||||||
@@ -957,18 +925,16 @@ index_create(char *heapRelationName,
|
|||||||
*/
|
*/
|
||||||
heap_storage_create(indexRelation);
|
heap_storage_create(indexRelation);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now update the object id's of all the attribute
|
* now update the object id's of all the attribute tuple forms in the
|
||||||
* tuple forms in the index relation's tuple descriptor
|
* index relation's tuple descriptor
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
InitializeAttributeOids(indexRelation,
|
InitializeAttributeOids(indexRelation,
|
||||||
indexInfo->ii_NumIndexAttrs,
|
indexInfo->ii_NumIndexAttrs,
|
||||||
indexoid);
|
indexoid);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* append ATTRIBUTE tuples for the index
|
* append ATTRIBUTE tuples for the index
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
|
AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
|
||||||
|
|
||||||
@@ -983,9 +949,8 @@ index_create(char *heapRelationName,
|
|||||||
UpdateIndexRelation(indexoid, heapoid, indexInfo,
|
UpdateIndexRelation(indexoid, heapoid, indexInfo,
|
||||||
classObjectId, islossy, primary);
|
classObjectId, islossy, primary);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize the index strategy
|
* initialize the index strategy
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
|
InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
|
||||||
indexRelation,
|
indexRelation,
|
||||||
@@ -1033,15 +998,15 @@ index_drop(Oid indexId)
|
|||||||
|
|
||||||
Assert(OidIsValid(indexId));
|
Assert(OidIsValid(indexId));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* To drop an index safely, we must grab exclusive lock on its parent
|
* To drop an index safely, we must grab exclusive lock on its parent
|
||||||
* table; otherwise there could be other backends using the index!
|
* table; otherwise there could be other backends using the index!
|
||||||
* Exclusive lock on the index alone is insufficient because the index
|
* Exclusive lock on the index alone is insufficient because the index
|
||||||
* access routines are a little slipshod about obtaining adequate locking
|
* access routines are a little slipshod about obtaining adequate
|
||||||
* (see ExecOpenIndices()). We do grab exclusive lock on the index too,
|
* locking (see ExecOpenIndices()). We do grab exclusive lock on the
|
||||||
* just to be safe. Both locks must be held till end of transaction,
|
* index too, just to be safe. Both locks must be held till end of
|
||||||
* else other backends will still see this index in pg_index.
|
* transaction, else other backends will still see this index in
|
||||||
* ----------------
|
* pg_index.
|
||||||
*/
|
*/
|
||||||
heapId = IndexGetRelation(indexId);
|
heapId = IndexGetRelation(indexId);
|
||||||
userHeapRelation = heap_open(heapId, AccessExclusiveLock);
|
userHeapRelation = heap_open(heapId, AccessExclusiveLock);
|
||||||
@@ -1049,22 +1014,19 @@ index_drop(Oid indexId)
|
|||||||
userIndexRelation = index_open(indexId);
|
userIndexRelation = index_open(indexId);
|
||||||
LockRelation(userIndexRelation, AccessExclusiveLock);
|
LockRelation(userIndexRelation, AccessExclusiveLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Note: unlike heap_drop_with_catalog, we do not need to prevent
|
* Note: unlike heap_drop_with_catalog, we do not need to prevent
|
||||||
* deletion of system indexes here; that's checked for upstream.
|
* deletion of system indexes here; that's checked for upstream. If we
|
||||||
* If we did check it here, deletion of TOAST tables would fail...
|
* did check it here, deletion of TOAST tables would fail...
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* fix DESCRIPTION relation
|
* fix DESCRIPTION relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
DeleteComments(indexId);
|
DeleteComments(indexId);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* fix RELATION relation
|
* fix RELATION relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
|
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
@@ -1091,9 +1053,8 @@ index_drop(Oid indexId)
|
|||||||
|
|
||||||
heap_close(relationRelation, RowExclusiveLock);
|
heap_close(relationRelation, RowExclusiveLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* fix ATTRIBUTE relation
|
* fix ATTRIBUTE relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock);
|
attributeRelation = heap_openr(AttributeRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
@@ -1110,9 +1071,8 @@ index_drop(Oid indexId)
|
|||||||
}
|
}
|
||||||
heap_close(attributeRelation, RowExclusiveLock);
|
heap_close(attributeRelation, RowExclusiveLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* fix INDEX relation
|
* fix INDEX relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
|
indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
@@ -1171,9 +1131,8 @@ BuildIndexInfo(HeapTuple indexTuple)
|
|||||||
int i;
|
int i;
|
||||||
int numKeys;
|
int numKeys;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* count the number of keys, and copy them into the IndexInfo
|
* count the number of keys, and copy them into the IndexInfo
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
numKeys = 0;
|
numKeys = 0;
|
||||||
for (i = 0; i < INDEX_MAX_KEYS &&
|
for (i = 0; i < INDEX_MAX_KEYS &&
|
||||||
@@ -1184,13 +1143,12 @@ BuildIndexInfo(HeapTuple indexTuple)
|
|||||||
}
|
}
|
||||||
ii->ii_NumKeyAttrs = numKeys;
|
ii->ii_NumKeyAttrs = numKeys;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Handle functional index.
|
* Handle functional index.
|
||||||
*
|
*
|
||||||
* If we have a functional index then the number of
|
* If we have a functional index then the number of attributes defined in
|
||||||
* attributes defined in the index must be 1 (the function's
|
* the index must be 1 (the function's single return value).
|
||||||
* single return value). Otherwise it's same as number of keys.
|
* Otherwise it's same as number of keys.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ii->ii_FuncOid = indexStruct->indproc;
|
ii->ii_FuncOid = indexStruct->indproc;
|
||||||
|
|
||||||
@@ -1203,9 +1161,8 @@ BuildIndexInfo(HeapTuple indexTuple)
|
|||||||
else
|
else
|
||||||
ii->ii_NumIndexAttrs = numKeys;
|
ii->ii_NumIndexAttrs = numKeys;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* If partial index, convert predicate into expression nodetree
|
* If partial index, convert predicate into expression nodetree
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (VARSIZE(&indexStruct->indpred) != 0)
|
if (VARSIZE(&indexStruct->indpred) != 0)
|
||||||
{
|
{
|
||||||
@@ -1257,9 +1214,9 @@ FormIndexDatum(IndexInfo *indexInfo,
|
|||||||
|
|
||||||
if (OidIsValid(indexInfo->ii_FuncOid))
|
if (OidIsValid(indexInfo->ii_FuncOid))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* Functional index --- compute the single index attribute
|
* Functional index --- compute the single index attribute
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
FunctionCallInfoData fcinfo;
|
FunctionCallInfoData fcinfo;
|
||||||
bool anynull = false;
|
bool anynull = false;
|
||||||
@@ -1292,10 +1249,10 @@ FormIndexDatum(IndexInfo *indexInfo,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* Plain index --- for each attribute we need from the heap tuple,
|
* Plain index --- for each attribute we need from the heap tuple,
|
||||||
* get the attribute and stick it into the datum and nullv arrays.
|
* get the attribute and stick it into the datum and nullv arrays.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
|
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
|
||||||
{
|
{
|
||||||
@@ -1465,9 +1422,8 @@ setRelhasindex(Oid relid, bool hasindex)
|
|||||||
relid);
|
relid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Update hasindex in pg_class.
|
* Update hasindex in pg_class.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (pg_class_scan)
|
if (pg_class_scan)
|
||||||
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
|
||||||
@@ -1601,22 +1557,20 @@ UpdateStats(Oid relid, long reltuples)
|
|||||||
HeapScanDesc pg_class_scan = NULL;
|
HeapScanDesc pg_class_scan = NULL;
|
||||||
bool in_place_upd;
|
bool in_place_upd;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* This routine handles updates for both the heap and index relation
|
* This routine handles updates for both the heap and index relation
|
||||||
* statistics. In order to guarantee that we're able to *see* the index
|
* statistics. In order to guarantee that we're able to *see* the
|
||||||
* relation tuple, we bump the command counter id here. The index
|
* index relation tuple, we bump the command counter id here. The
|
||||||
* relation tuple was created in the current transaction.
|
* index relation tuple was created in the current transaction.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* CommandCounterIncrement() flushes invalid cache entries, including
|
* CommandCounterIncrement() flushes invalid cache entries, including
|
||||||
* those for the heap and index relations for which we're updating
|
* those for the heap and index relations for which we're updating
|
||||||
* statistics. Now that the cache is flushed, it's safe to open the
|
* statistics. Now that the cache is flushed, it's safe to open the
|
||||||
* relation again. We need the relation open in order to figure out
|
* relation again. We need the relation open in order to figure out
|
||||||
* how many blocks it contains.
|
* how many blocks it contains.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1630,9 +1584,8 @@ UpdateStats(Oid relid, long reltuples)
|
|||||||
/* Grab lock to be held till end of xact (probably redundant...) */
|
/* Grab lock to be held till end of xact (probably redundant...) */
|
||||||
LockRelation(whichRel, ShareLock);
|
LockRelation(whichRel, ShareLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Find the RELATION relation tuple for the given relation.
|
* Find the RELATION relation tuple for the given relation.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
|
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
@@ -1670,16 +1623,15 @@ UpdateStats(Oid relid, long reltuples)
|
|||||||
relid);
|
relid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Figure values to insert.
|
* Figure values to insert.
|
||||||
*
|
*
|
||||||
* If we found zero tuples in the scan, do NOT believe it; instead put
|
* If we found zero tuples in the scan, do NOT believe it; instead put a
|
||||||
* a bogus estimate into the statistics fields. Otherwise, the common
|
* bogus estimate into the statistics fields. Otherwise, the common
|
||||||
* pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table
|
* pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table
|
||||||
* with zero size statistics until a VACUUM is done. The optimizer will
|
* with zero size statistics until a VACUUM is done. The optimizer
|
||||||
* generate very bad plans if the stats claim the table is empty when
|
* will generate very bad plans if the stats claim the table is empty
|
||||||
* it is actually sizable. See also CREATE TABLE in heap.c.
|
* when it is actually sizable. See also CREATE TABLE in heap.c.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
relpages = RelationGetNumberOfBlocks(whichRel);
|
relpages = RelationGetNumberOfBlocks(whichRel);
|
||||||
|
|
||||||
@@ -1708,9 +1660,8 @@ UpdateStats(Oid relid, long reltuples)
|
|||||||
whichRel->rd_rel->relpages = relpages;
|
whichRel->rd_rel->relpages = relpages;
|
||||||
whichRel->rd_rel->reltuples = reltuples;
|
whichRel->rd_rel->reltuples = reltuples;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Update statistics in pg_class.
|
* Update statistics in pg_class.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (in_place_upd)
|
if (in_place_upd)
|
||||||
{
|
{
|
||||||
@@ -1798,9 +1749,8 @@ DefaultBuild(Relation heapRelation,
|
|||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
InsertIndexResult insertResult;
|
InsertIndexResult insertResult;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* more & better checking is needed
|
* more & better checking is needed
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(OidIsValid(indexRelation->rd_rel->relam)); /* XXX */
|
Assert(OidIsValid(indexRelation->rd_rel->relam)); /* XXX */
|
||||||
|
|
||||||
@@ -1833,9 +1783,8 @@ DefaultBuild(Relation heapRelation,
|
|||||||
econtext = MakeExprContext(NULL, TransactionCommandContext);
|
econtext = MakeExprContext(NULL, TransactionCommandContext);
|
||||||
#endif /* OMIT_PARTIAL_INDEX */
|
#endif /* OMIT_PARTIAL_INDEX */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Ok, begin our scan of the base relation.
|
* Ok, begin our scan of the base relation.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
scan = heap_beginscan(heapRelation, /* relation */
|
scan = heap_beginscan(heapRelation, /* relation */
|
||||||
0, /* start at end */
|
0, /* start at end */
|
||||||
@@ -1845,12 +1794,11 @@ DefaultBuild(Relation heapRelation,
|
|||||||
|
|
||||||
reltuples = indtuples = 0;
|
reltuples = indtuples = 0;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* for each tuple in the base relation, we create an index
|
* for each tuple in the base relation, we create an index tuple and
|
||||||
* tuple and add it to the index relation. We keep a running
|
* add it to the index relation. We keep a running count of the
|
||||||
* count of the number of tuples so that we can update pg_class
|
* number of tuples so that we can update pg_class with correct
|
||||||
* with correct statistics when we're done building the index.
|
* statistics when we're done building the index.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
|
while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
|
||||||
{
|
{
|
||||||
@@ -1888,10 +1836,9 @@ DefaultBuild(Relation heapRelation,
|
|||||||
|
|
||||||
indtuples++;
|
indtuples++;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* FormIndexDatum fills in its datum and null parameters
|
* FormIndexDatum fills in its datum and null parameters with
|
||||||
* with attribute information taken from the given heap tuple.
|
* attribute information taken from the given heap tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
FormIndexDatum(indexInfo,
|
FormIndexDatum(indexInfo,
|
||||||
heapTuple,
|
heapTuple,
|
||||||
@@ -1956,18 +1903,16 @@ index_build(Relation heapRelation,
|
|||||||
{
|
{
|
||||||
RegProcedure procedure;
|
RegProcedure procedure;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(RelationIsValid(indexRelation));
|
Assert(RelationIsValid(indexRelation));
|
||||||
Assert(PointerIsValid(indexRelation->rd_am));
|
Assert(PointerIsValid(indexRelation->rd_am));
|
||||||
|
|
||||||
procedure = indexRelation->rd_am->ambuild;
|
procedure = indexRelation->rd_am->ambuild;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* use the access method build procedure if supplied, else default.
|
* use the access method build procedure if supplied, else default.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (RegProcedureIsValid(procedure))
|
if (RegProcedureIsValid(procedure))
|
||||||
OidFunctionCall5(procedure,
|
OidFunctionCall5(procedure,
|
||||||
@@ -2042,11 +1987,10 @@ reindex_index(Oid indexId, bool force, bool inplace)
|
|||||||
accessMethodId;
|
accessMethodId;
|
||||||
bool old;
|
bool old;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* REINDEX within a transaction block is dangerous, because
|
* REINDEX within a transaction block is dangerous, because if the
|
||||||
* if the transaction is later rolled back we have no way to
|
* transaction is later rolled back we have no way to undo truncation
|
||||||
* undo truncation of the index's physical file. Disallow it.
|
* of the index's physical file. Disallow it.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (IsTransactionBlock())
|
if (IsTransactionBlock())
|
||||||
elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
|
elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.56 2001/03/22 03:59:20 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.57 2001/03/22 06:16:10 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.
|
||||||
@@ -102,17 +102,15 @@ OperatorGetWithOpenRelation(Relation pg_operator_desc,
|
|||||||
opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs;
|
opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs;
|
||||||
opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs;
|
opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* form scan key
|
* form scan key
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
opKey[0].sk_argument = PointerGetDatum(operatorName);
|
opKey[0].sk_argument = PointerGetDatum(operatorName);
|
||||||
opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
|
opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
|
||||||
opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
|
opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* begin the scan
|
* begin the scan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_operator_scan = heap_beginscan(pg_operator_desc,
|
pg_operator_scan = heap_beginscan(pg_operator_desc,
|
||||||
0,
|
0,
|
||||||
@@ -120,10 +118,9 @@ OperatorGetWithOpenRelation(Relation pg_operator_desc,
|
|||||||
3,
|
3,
|
||||||
opKey);
|
opKey);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* fetch the operator tuple, if it exists, and determine
|
* fetch the operator tuple, if it exists, and determine the proper
|
||||||
* the proper return oid value.
|
* return oid value.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tup = heap_getnext(pg_operator_scan, 0);
|
tup = heap_getnext(pg_operator_scan, 0);
|
||||||
|
|
||||||
@@ -140,9 +137,8 @@ OperatorGetWithOpenRelation(Relation pg_operator_desc,
|
|||||||
*defined = false;
|
*defined = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* close the scan and return the oid.
|
* close the scan and return the oid.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_endscan(pg_operator_scan);
|
heap_endscan(pg_operator_scan);
|
||||||
|
|
||||||
@@ -170,11 +166,10 @@ OperatorGet(char *operatorName,
|
|||||||
bool leftDefined = false;
|
bool leftDefined = false;
|
||||||
bool rightDefined = false;
|
bool rightDefined = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* look up the operator data types.
|
* look up the operator data types.
|
||||||
*
|
*
|
||||||
* Note: types must be defined before operators
|
* Note: types must be defined before operators
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (leftTypeName)
|
if (leftTypeName)
|
||||||
{
|
{
|
||||||
@@ -198,16 +193,14 @@ OperatorGet(char *operatorName,
|
|||||||
(OidIsValid(rightObjectId) && rightDefined)))
|
(OidIsValid(rightObjectId) && rightDefined)))
|
||||||
elog(ERROR, "OperatorGet: must have at least one argument type");
|
elog(ERROR, "OperatorGet: must have at least one argument type");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open the pg_operator relation
|
* open the pg_operator relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
|
pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the oid for the operator with the appropriate name
|
* get the oid for the operator with the appropriate name and
|
||||||
* and left/right types.
|
* left/right types.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
|
operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
|
||||||
operatorName,
|
operatorName,
|
||||||
@@ -215,9 +208,8 @@ OperatorGet(char *operatorName,
|
|||||||
rightObjectId,
|
rightObjectId,
|
||||||
defined);
|
defined);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* close the relation and return the operator oid.
|
* close the relation and return the operator oid.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_close(pg_operator_desc, AccessShareLock);
|
heap_close(pg_operator_desc, AccessShareLock);
|
||||||
|
|
||||||
@@ -243,9 +235,8 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
|
|||||||
NameData oname;
|
NameData oname;
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize our *nulls and *values arrays
|
* initialize our *nulls and *values arrays
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < Natts_pg_operator; ++i)
|
for (i = 0; i < Natts_pg_operator; ++i)
|
||||||
{
|
{
|
||||||
@@ -253,10 +244,9 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
|
|||||||
values[i] = (Datum) NULL; /* redundant, but safe */
|
values[i] = (Datum) NULL; /* redundant, but safe */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* 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;
|
||||||
namestrcpy(&oname, operatorName);
|
namestrcpy(&oname, operatorName);
|
||||||
@@ -277,9 +267,8 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
|
|||||||
values[i++] = ObjectIdGetDatum(InvalidOid);
|
values[i++] = ObjectIdGetDatum(InvalidOid);
|
||||||
values[i++] = ObjectIdGetDatum(InvalidOid);
|
values[i++] = ObjectIdGetDatum(InvalidOid);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create a new operator tuple
|
* create a new operator tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tupDesc = pg_operator_desc->rd_att;
|
tupDesc = pg_operator_desc->rd_att;
|
||||||
|
|
||||||
@@ -287,10 +276,8 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
|
|||||||
values,
|
values,
|
||||||
nulls);
|
nulls);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* insert our "shell" operator tuple and
|
* insert our "shell" operator tuple and close the relation
|
||||||
* close the relation
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_insert(pg_operator_desc, tup);
|
heap_insert(pg_operator_desc, tup);
|
||||||
operatorObjectId = tup->t_data->t_oid;
|
operatorObjectId = tup->t_data->t_oid;
|
||||||
@@ -304,9 +291,8 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
|
|||||||
CatalogCloseIndices(Num_pg_operator_indices, idescs);
|
CatalogCloseIndices(Num_pg_operator_indices, idescs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* free the tuple and return the operator oid
|
* free the tuple and return the operator oid
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_freetuple(tup);
|
heap_freetuple(tup);
|
||||||
|
|
||||||
@@ -335,9 +321,8 @@ OperatorShellMake(char *operatorName,
|
|||||||
bool leftDefined = false;
|
bool leftDefined = false;
|
||||||
bool rightDefined = false;
|
bool rightDefined = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the left and right type oid's for this operator
|
* get the left and right type oid's for this operator
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (leftTypeName)
|
if (leftTypeName)
|
||||||
leftObjectId = TypeGet(leftTypeName, &leftDefined);
|
leftObjectId = TypeGet(leftTypeName, &leftDefined);
|
||||||
@@ -349,24 +334,22 @@ OperatorShellMake(char *operatorName,
|
|||||||
(OidIsValid(rightObjectId) && rightDefined)))
|
(OidIsValid(rightObjectId) && rightDefined)))
|
||||||
elog(ERROR, "OperatorShellMake: no valid argument types??");
|
elog(ERROR, "OperatorShellMake: no valid argument types??");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open pg_operator
|
* open pg_operator
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
|
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* add a "shell" operator tuple to the operator relation
|
* add a "shell" operator tuple to the operator relation and recover
|
||||||
* and recover the shell tuple's oid.
|
* the shell tuple's oid.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
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.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_close(pg_operator_desc, RowExclusiveLock);
|
heap_close(pg_operator_desc, RowExclusiveLock);
|
||||||
|
|
||||||
@@ -516,11 +499,10 @@ OperatorDef(char *operatorName,
|
|||||||
* filling in a previously-created shell.
|
* filling in a previously-created shell.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* look up the operator data types.
|
* look up the operator data types.
|
||||||
*
|
*
|
||||||
* Note: types must be defined before operators
|
* Note: types must be defined before operators
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (leftTypeName)
|
if (leftTypeName)
|
||||||
{
|
{
|
||||||
@@ -551,12 +533,10 @@ OperatorDef(char *operatorName,
|
|||||||
nulls[i] = ' ';
|
nulls[i] = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Look up registered procedures -- find the return type
|
* Look up registered procedures -- find the return type of
|
||||||
* of procedureName to place in "result" field.
|
* procedureName to place in "result" field. Do this before shells are
|
||||||
* Do this before shells are created so we don't
|
* created so we don't have to worry about deleting them later.
|
||||||
* have to worry about deleting them later.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||||
if (!leftTypeName)
|
if (!leftTypeName)
|
||||||
@@ -589,9 +569,8 @@ OperatorDef(char *operatorName,
|
|||||||
|
|
||||||
ReleaseSysCache(tup);
|
ReleaseSysCache(tup);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* find restriction
|
* find restriction
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (restrictionName)
|
if (restrictionName)
|
||||||
{ /* optional */
|
{ /* optional */
|
||||||
@@ -617,9 +596,8 @@ OperatorDef(char *operatorName,
|
|||||||
else
|
else
|
||||||
values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
|
values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* find join - only valid for binary operators
|
* find join - only valid for binary operators
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (joinName)
|
if (joinName)
|
||||||
{ /* optional */
|
{ /* optional */
|
||||||
@@ -645,9 +623,8 @@ OperatorDef(char *operatorName,
|
|||||||
else
|
else
|
||||||
values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
|
values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* set up values in the operator tuple
|
* set up values in the operator tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
i = 0;
|
i = 0;
|
||||||
namestrcpy(&oname, operatorName);
|
namestrcpy(&oname, operatorName);
|
||||||
@@ -1077,11 +1054,10 @@ OperatorCreate(char *operatorName,
|
|||||||
elog(ERROR, "OperatorCreate: only binary operators can have sort links");
|
elog(ERROR, "OperatorCreate: only binary operators can have sort links");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Use OperatorDef() to define the specified operator and
|
* Use OperatorDef() to define the specified operator and also create
|
||||||
* also create shells for the operator's associated operators
|
* shells for the operator's associated operators if they don't
|
||||||
* if they don't already exist.
|
* already exist.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
OperatorDef(operatorName,
|
OperatorDef(operatorName,
|
||||||
leftTypeName,
|
leftTypeName,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.54 2001/03/22 03:59:20 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.55 2001/03/22 06:16:10 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -73,9 +73,8 @@ ProcedureCreate(char *procedureName,
|
|||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
Oid retval;
|
Oid retval;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(PointerIsValid(prosrc));
|
Assert(PointerIsValid(prosrc));
|
||||||
Assert(PointerIsValid(probin));
|
Assert(PointerIsValid(probin));
|
||||||
@@ -142,16 +141,16 @@ ProcedureCreate(char *procedureName,
|
|||||||
if (strcmp(procedureName, GENERICSETNAME) == 0)
|
if (strcmp(procedureName, GENERICSETNAME) == 0)
|
||||||
{
|
{
|
||||||
#ifdef SETS_FIXED
|
#ifdef SETS_FIXED
|
||||||
/* ----------
|
|
||||||
* The code below doesn't work any more because the
|
/*
|
||||||
* PROSRC system cache and the pg_proc_prosrc_index
|
* The code below doesn't work any more because the PROSRC
|
||||||
* have been removed. Instead a sequential heap scan
|
* system cache and the pg_proc_prosrc_index have been
|
||||||
* or something better must get implemented. The reason
|
* removed. Instead a sequential heap scan or something better
|
||||||
* for removing is that nbtree index crashes if sources
|
* must get implemented. The reason for removing is that
|
||||||
* exceed 2K --- what's likely for procedural languages.
|
* nbtree index crashes if sources exceed 2K --- what's likely
|
||||||
|
* for procedural languages.
|
||||||
*
|
*
|
||||||
* 1999/09/30 Jan
|
* 1999/09/30 Jan
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
text *prosrctext;
|
text *prosrctext;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.60 2001/03/22 03:59:20 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.61 2001/03/22 06:16:11 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -48,9 +48,8 @@ TypeGetWithOpenRelation(Relation pg_type_desc,
|
|||||||
Oid typoid;
|
Oid typoid;
|
||||||
ScanKeyData typeKey[1];
|
ScanKeyData typeKey[1];
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize the scan key and begin a scan of pg_type
|
* initialize the scan key and begin a scan of pg_type
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ScanKeyEntryInitialize(typeKey,
|
ScanKeyEntryInitialize(typeKey,
|
||||||
0,
|
0,
|
||||||
@@ -64,16 +63,14 @@ TypeGetWithOpenRelation(Relation pg_type_desc,
|
|||||||
1,
|
1,
|
||||||
typeKey);
|
typeKey);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the type tuple, if it exists.
|
* get the type tuple, if it exists.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tup = heap_getnext(scan, 0);
|
tup = heap_getnext(scan, 0);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if no type tuple exists for the given type name, then
|
* if no type tuple exists for the given type name, then end the scan
|
||||||
* end the scan and return appropriate information.
|
* and return appropriate information.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!HeapTupleIsValid(tup))
|
if (!HeapTupleIsValid(tup))
|
||||||
{
|
{
|
||||||
@@ -82,11 +79,10 @@ TypeGetWithOpenRelation(Relation pg_type_desc,
|
|||||||
return InvalidOid;
|
return InvalidOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* here, the type tuple does exist so we pull information from
|
* here, the type tuple does exist so we pull information from the
|
||||||
* the typisdefined field of the tuple and return the tuple's
|
* typisdefined field of the tuple and return the tuple's oid, which
|
||||||
* oid, which is the oid of the type.
|
* is the oid of the type.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
*defined = (bool) ((Form_pg_type) GETSTRUCT(tup))->typisdefined;
|
*defined = (bool) ((Form_pg_type) GETSTRUCT(tup))->typisdefined;
|
||||||
typoid = tup->t_data->t_oid;
|
typoid = tup->t_data->t_oid;
|
||||||
@@ -116,23 +112,20 @@ TypeGet(char *typeName, /* name of type to be fetched */
|
|||||||
Relation pg_type_desc;
|
Relation pg_type_desc;
|
||||||
Oid typeoid;
|
Oid typeoid;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open the pg_type relation
|
* open the pg_type relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_type_desc = heap_openr(TypeRelationName, AccessShareLock);
|
pg_type_desc = heap_openr(TypeRelationName, AccessShareLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* scan the type relation for the information we want
|
* scan the type relation for the information we want
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
typeoid = TypeGetWithOpenRelation(pg_type_desc,
|
typeoid = TypeGetWithOpenRelation(pg_type_desc,
|
||||||
typeName,
|
typeName,
|
||||||
defined);
|
defined);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* close the type relation and return the type oid.
|
* close the type relation and return the type oid.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_close(pg_type_desc, AccessShareLock);
|
heap_close(pg_type_desc, AccessShareLock);
|
||||||
|
|
||||||
@@ -155,9 +148,8 @@ TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
|
|||||||
NameData name;
|
NameData name;
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize our *nulls and *values arrays
|
* initialize our *nulls and *values arrays
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < Natts_pg_type; ++i)
|
for (i = 0; i < Natts_pg_type; ++i)
|
||||||
{
|
{
|
||||||
@@ -165,9 +157,8 @@ TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
|
|||||||
values[i] = (Datum) NULL; /* redundant, but safe */
|
values[i] = (Datum) NULL; /* redundant, but safe */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize *values with the type name and dummy values
|
* initialize *values with the type name and dummy values
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
i = 0;
|
i = 0;
|
||||||
namestrcpy(&name, typeName);
|
namestrcpy(&name, typeName);
|
||||||
@@ -190,17 +181,15 @@ TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
|
|||||||
values[i++] = DirectFunctionCall1(textin,
|
values[i++] = DirectFunctionCall1(textin,
|
||||||
CStringGetDatum(typeName)); /* 17 */
|
CStringGetDatum(typeName)); /* 17 */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create a new type tuple with FormHeapTuple
|
* create a new type tuple with FormHeapTuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tupDesc = pg_type_desc->rd_att;
|
tupDesc = pg_type_desc->rd_att;
|
||||||
|
|
||||||
tup = heap_formtuple(tupDesc, values, nulls);
|
tup = heap_formtuple(tupDesc, values, nulls);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* insert the tuple in the relation and get the tuple's oid.
|
* insert the tuple in the relation and get the tuple's oid.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_insert(pg_type_desc, tup);
|
heap_insert(pg_type_desc, tup);
|
||||||
typoid = tup->t_data->t_oid;
|
typoid = tup->t_data->t_oid;
|
||||||
@@ -213,9 +202,9 @@ TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
|
|||||||
CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
|
CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
|
||||||
CatalogCloseIndices(Num_pg_type_indices, idescs);
|
CatalogCloseIndices(Num_pg_type_indices, idescs);
|
||||||
}
|
}
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* free the tuple and return the type-oid
|
* free the tuple and return the type-oid
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_freetuple(tup);
|
heap_freetuple(tup);
|
||||||
|
|
||||||
@@ -243,21 +232,18 @@ TypeShellMake(char *typeName)
|
|||||||
|
|
||||||
Assert(PointerIsValid(typeName));
|
Assert(PointerIsValid(typeName));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open pg_type
|
* open pg_type
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
|
pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* insert the shell tuple
|
* insert the shell tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
|
typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* close pg_type and return the tuple's oid.
|
* close pg_type and return the tuple's oid.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_close(pg_type_desc, RowExclusiveLock);
|
heap_close(pg_type_desc, RowExclusiveLock);
|
||||||
|
|
||||||
@@ -311,20 +297,18 @@ TypeCreate(char *typeName,
|
|||||||
Oid argList[FUNC_MAX_ARGS];
|
Oid argList[FUNC_MAX_ARGS];
|
||||||
ScanKeyData typeKey[1];
|
ScanKeyData typeKey[1];
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* check that the type is not already defined. It might exist as
|
* check that the type is not already defined. It might exist as a
|
||||||
* a shell type, however (but only if assignedTypeOid is not given).
|
* shell type, however (but only if assignedTypeOid is not given).
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
typeObjectId = TypeGet(typeName, &defined);
|
typeObjectId = TypeGet(typeName, &defined);
|
||||||
if (OidIsValid(typeObjectId) &&
|
if (OidIsValid(typeObjectId) &&
|
||||||
(defined || assignedTypeOid != InvalidOid))
|
(defined || assignedTypeOid != InvalidOid))
|
||||||
elog(ERROR, "TypeCreate: type %s already defined", typeName);
|
elog(ERROR, "TypeCreate: type %s already defined", typeName);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if this type has an associated elementType, then we check that
|
* if this type has an associated elementType, then we check that it
|
||||||
* it is defined.
|
* is defined.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (elementTypeName)
|
if (elementTypeName)
|
||||||
{
|
{
|
||||||
@@ -333,16 +317,14 @@ TypeCreate(char *typeName,
|
|||||||
elog(ERROR, "TypeCreate: type %s is not defined", elementTypeName);
|
elog(ERROR, "TypeCreate: type %s is not defined", elementTypeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* XXX comment me
|
* XXX comment me
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (externalSize == 0)
|
if (externalSize == 0)
|
||||||
externalSize = -1; /* variable length */
|
externalSize = -1; /* variable length */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize arrays needed by FormHeapTuple
|
* initialize arrays needed by FormHeapTuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < Natts_pg_type; ++i)
|
for (i = 0; i < Natts_pg_type; ++i)
|
||||||
{
|
{
|
||||||
@@ -362,9 +344,8 @@ TypeCreate(char *typeName,
|
|||||||
if (internalSize == 0)
|
if (internalSize == 0)
|
||||||
internalSize = -1;
|
internalSize = -1;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize the *values information
|
* initialize the *values information
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
i = 0;
|
i = 0;
|
||||||
namestrcpy(&name, typeName);
|
namestrcpy(&name, typeName);
|
||||||
@@ -441,28 +422,24 @@ TypeCreate(char *typeName,
|
|||||||
values[i++] = ObjectIdGetDatum(procOid); /* 11 - 14 */
|
values[i++] = ObjectIdGetDatum(procOid); /* 11 - 14 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* set default alignment
|
* set default alignment
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
values[i++] = CharGetDatum(alignment); /* 15 */
|
values[i++] = CharGetDatum(alignment); /* 15 */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* set default storage for TOAST
|
* set default storage for TOAST
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
values[i++] = CharGetDatum(storage); /* 16 */
|
values[i++] = CharGetDatum(storage); /* 16 */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize the default value for this type.
|
* initialize the default value for this type.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
values[i] = DirectFunctionCall1(textin, /* 17 */
|
values[i] = DirectFunctionCall1(textin, /* 17 */
|
||||||
CStringGetDatum(defaultTypeValue ? defaultTypeValue : "-"));
|
CStringGetDatum(defaultTypeValue ? defaultTypeValue : "-"));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open pg_type and begin a scan for the type name.
|
* open pg_type and begin a scan for the type name.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
|
pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
@@ -478,11 +455,9 @@ TypeCreate(char *typeName,
|
|||||||
1,
|
1,
|
||||||
typeKey);
|
typeKey);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* define the type either by adding a tuple to the type
|
* define the type either by adding a tuple to the type relation, or
|
||||||
* relation, or by updating the fields of the "shell" tuple
|
* by updating the fields of the "shell" tuple already there.
|
||||||
* already there.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tup = heap_getnext(pg_type_scan, 0);
|
tup = heap_getnext(pg_type_scan, 0);
|
||||||
if (HeapTupleIsValid(tup))
|
if (HeapTupleIsValid(tup))
|
||||||
@@ -517,9 +492,8 @@ TypeCreate(char *typeName,
|
|||||||
typeObjectId = tup->t_data->t_oid;
|
typeObjectId = tup->t_data->t_oid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* finish up
|
* finish up
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_endscan(pg_type_scan);
|
heap_endscan(pg_type_scan);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/recipe.c,v 1.12 2001/01/24 19:42:53 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/recipe.c,v 1.13 2001/03/22 06:16:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -203,10 +203,10 @@ beginRecipe(RecipeStmt *stmt)
|
|||||||
* skip the rule rewrite and time qual stuff
|
* skip the rule rewrite and time qual stuff
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ----------------------------------------------------------
|
/*
|
||||||
* 1) plan the main query, everything from an eye node back to
|
* 1) plan the main query, everything from an eye node back to a
|
||||||
a Tee
|
* Tee
|
||||||
* ---------------------------------------------------------- */
|
*/
|
||||||
parsetree = qList->qtrees[0];
|
parsetree = qList->qtrees[0];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -218,11 +218,11 @@ beginRecipe(RecipeStmt *stmt)
|
|||||||
|
|
||||||
plan = planner(parsetree);
|
plan = planner(parsetree);
|
||||||
|
|
||||||
/* ----------------------------------------------------------
|
/*
|
||||||
* 2) plan the tee queries, (subgraphs rooted from a Tee)
|
* 2) plan the tee queries, (subgraphs rooted from a Tee) by the
|
||||||
by the time the eye is processed, all tees that contribute
|
* time the eye is processed, all tees that contribute to that eye
|
||||||
to that eye will have been included in the teeInfo list
|
* will have been included in the teeInfo list
|
||||||
* ---------------------------------------------------------- */
|
*/
|
||||||
if (teeInfo)
|
if (teeInfo)
|
||||||
{
|
{
|
||||||
int t;
|
int t;
|
||||||
@@ -258,10 +258,10 @@ beginRecipe(RecipeStmt *stmt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------
|
/*
|
||||||
* 3) replace the tee table scans in the main plan with
|
* 3) replace the tee table scans in the main plan with actual
|
||||||
actual tee plannodes
|
* tee plannodes
|
||||||
* ---------------------------------------------------------- */
|
*/
|
||||||
|
|
||||||
plan = replaceTeeScans(plan, parsetree, teeInfo);
|
plan = replaceTeeScans(plan, parsetree, teeInfo);
|
||||||
|
|
||||||
@@ -274,9 +274,9 @@ beginRecipe(RecipeStmt *stmt)
|
|||||||
queryDesc = CreateQueryDesc(parsetree,
|
queryDesc = CreateQueryDesc(parsetree,
|
||||||
plan,
|
plan,
|
||||||
whereToSendOutput);
|
whereToSendOutput);
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* call ExecStart to prepare the plan for execution
|
* call ExecStart to prepare the plan for execution
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
attinfo = ExecutorStart(queryDesc, NULL);
|
attinfo = ExecutorStart(queryDesc, NULL);
|
||||||
|
|
||||||
@@ -323,15 +323,14 @@ tg_rewriteQuery(TgRecipe * r,
|
|||||||
orig = q->qtrees[0];
|
orig = q->qtrees[0];
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
/*
|
||||||
step 1:
|
* step 1:
|
||||||
|
*
|
||||||
form a combined range table from all the range tables in the original
|
* form a combined range table from all the range tables in the original
|
||||||
query as well as the input nodes
|
* query as well as the input nodes
|
||||||
|
*
|
||||||
form a combined qualification from the qual in the original plus
|
* form a combined qualification from the qual in the original plus the
|
||||||
the quals of the input nodes
|
* quals of the input nodes
|
||||||
-------------------------------------------------------------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* start with the original range table */
|
/* start with the original range table */
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.15 2001/03/22 03:59:20 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.16 2001/03/22 06:16:11 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -582,9 +582,8 @@ update_attstats(Oid relid, int natts, VacAttrStats *vacattrstats)
|
|||||||
for (i = 0; i < Natts_pg_statistic; ++i)
|
for (i = 0; i < Natts_pg_statistic; ++i)
|
||||||
nulls[i] = ' ';
|
nulls[i] = ' ';
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize values[]
|
* initialize values[]
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
i = 0;
|
i = 0;
|
||||||
values[i++] = ObjectIdGetDatum(relid); /* starelid */
|
values[i++] = ObjectIdGetDatum(relid); /* starelid */
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.123 2001/03/22 03:59:21 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.124 2001/03/22 06:16:11 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The PerformAddAttribute() code, like most of the relation
|
* The PerformAddAttribute() code, like most of the relation
|
||||||
@@ -69,28 +69,24 @@ PortalCleanup(Portal portal)
|
|||||||
{
|
{
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
AssertArg(PortalIsValid(portal));
|
AssertArg(PortalIsValid(portal));
|
||||||
AssertArg(portal->cleanup == PortalCleanup);
|
AssertArg(portal->cleanup == PortalCleanup);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* set proper portal-executor context before calling ExecMain.
|
* set proper portal-executor context before calling ExecMain.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* tell the executor to shutdown the query
|
* tell the executor to shutdown the query
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
|
ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* switch back to previous context
|
* switch back to previous context
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(oldcontext);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
}
|
}
|
||||||
@@ -111,9 +107,8 @@ PerformPortalFetch(char *name,
|
|||||||
EState *estate;
|
EState *estate;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
{
|
{
|
||||||
@@ -121,9 +116,8 @@ PerformPortalFetch(char *name,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the portal from the portal name
|
* get the portal from the portal name
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
portal = GetPortalByName(name);
|
portal = GetPortalByName(name);
|
||||||
if (!PortalIsValid(portal))
|
if (!PortalIsValid(portal))
|
||||||
@@ -133,18 +127,16 @@ PerformPortalFetch(char *name,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* switch into the portal context
|
* switch into the portal context
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* tell the destination to prepare to receive some tuples.
|
* tell the destination to prepare to receive some tuples.
|
||||||
*
|
*
|
||||||
* If we've been asked for a MOVE, make a temporary QueryDesc
|
* If we've been asked for a MOVE, make a temporary QueryDesc with the
|
||||||
* with the appropriate dummy destination.
|
* appropriate dummy destination.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
queryDesc = PortalGetQueryDesc(portal);
|
queryDesc = PortalGetQueryDesc(portal);
|
||||||
estate = PortalGetState(portal);
|
estate = PortalGetState(portal);
|
||||||
@@ -168,15 +160,14 @@ PerformPortalFetch(char *name,
|
|||||||
tag,
|
tag,
|
||||||
dest);
|
dest);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Determine which direction to go in, and check to see if we're already
|
* Determine which direction to go in, and check to see if we're
|
||||||
* at the end of the available tuples in that direction. If so, do
|
* already at the end of the available tuples in that direction. If
|
||||||
* nothing. (This check exists because not all plan node types are
|
* so, do nothing. (This check exists because not all plan node types
|
||||||
* robust about being called again if they've already returned NULL
|
* are robust about being called again if they've already returned
|
||||||
* once.) If it's OK to do the fetch, call the executor. Then,
|
* NULL once.) If it's OK to do the fetch, call the executor. Then,
|
||||||
* update the atStart/atEnd state depending on the number of tuples
|
* update the atStart/atEnd state depending on the number of tuples
|
||||||
* that were retrieved.
|
* that were retrieved.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (forward)
|
if (forward)
|
||||||
{
|
{
|
||||||
@@ -201,19 +192,17 @@ PerformPortalFetch(char *name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Clean up and switch back to old context.
|
* Clean up and switch back to old context.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (dest == None) /* MOVE */
|
if (dest == None) /* MOVE */
|
||||||
pfree(queryDesc);
|
pfree(queryDesc);
|
||||||
|
|
||||||
MemoryContextSwitchTo(oldcontext);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Note: the "end-of-command" tag is returned by higher-level
|
* Note: the "end-of-command" tag is returned by higher-level utility
|
||||||
* utility code
|
* code
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,9 +215,8 @@ PerformPortalClose(char *name, CommandDest dest)
|
|||||||
{
|
{
|
||||||
Portal portal;
|
Portal portal;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
{
|
{
|
||||||
@@ -236,9 +224,8 @@ PerformPortalClose(char *name, CommandDest dest)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the portal from the portal name
|
* get the portal from the portal name
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
portal = GetPortalByName(name);
|
portal = GetPortalByName(name);
|
||||||
if (!PortalIsValid(portal))
|
if (!PortalIsValid(portal))
|
||||||
@@ -248,9 +235,8 @@ PerformPortalClose(char *name, CommandDest dest)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Note: PortalCleanup is called as a side-effect
|
* Note: PortalCleanup is called as a side-effect
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
PortalDrop(&portal);
|
PortalDrop(&portal);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.135 2001/03/22 03:59:21 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.136 2001/03/22 06:16:11 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -888,16 +888,14 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
|
|||||||
{
|
{
|
||||||
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
|
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Check the constraints of the tuple
|
* Check the constraints of the tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (rel->rd_att->constr)
|
if (rel->rd_att->constr)
|
||||||
ExecConstraints("CopyFrom", resultRelInfo, slot, estate);
|
ExecConstraints("CopyFrom", resultRelInfo, slot, estate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* OK, store the tuple and create index entries for it
|
* OK, store the tuple and create index entries for it
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heap_insert(rel, tuple);
|
heap_insert(rel, tuple);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.73 2001/03/22 03:59:22 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.74 2001/03/22 06:16:11 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -68,10 +68,9 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
|||||||
stmt->relname, NAMEDATALEN);
|
stmt->relname, NAMEDATALEN);
|
||||||
StrNCpy(relname, stmt->relname, NAMEDATALEN);
|
StrNCpy(relname, stmt->relname, NAMEDATALEN);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Look up inheritance ancestors and generate relation schema,
|
* Look up inheritance ancestors and generate relation schema,
|
||||||
* including inherited attributes.
|
* including inherited attributes.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
schema = MergeAttributes(schema, stmt->inhRelnames, stmt->istemp,
|
schema = MergeAttributes(schema, stmt->inhRelnames, stmt->istemp,
|
||||||
&inheritOids, &old_constraints);
|
&inheritOids, &old_constraints);
|
||||||
@@ -80,14 +79,12 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
|||||||
if (numberOfAttributes <= 0)
|
if (numberOfAttributes <= 0)
|
||||||
elog(ERROR, "DefineRelation: please inherit from a relation or define an attribute");
|
elog(ERROR, "DefineRelation: please inherit from a relation or define an attribute");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create a relation descriptor from the relation schema
|
* create a relation descriptor from the relation schema and create
|
||||||
* and create the relation. Note that in this stage only
|
* the relation. Note that in this stage only inherited (pre-cooked)
|
||||||
* inherited (pre-cooked) defaults and constraints will be
|
* defaults and constraints will be included into the new relation.
|
||||||
* included into the new relation. (BuildDescForRelation
|
* (BuildDescForRelation takes care of the inherited defaults, but we
|
||||||
* takes care of the inherited defaults, but we have to copy
|
* have to copy inherited constraints here.)
|
||||||
* inherited constraints here.)
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
descriptor = BuildDescForRelation(schema, relname);
|
descriptor = BuildDescForRelation(schema, relname);
|
||||||
|
|
||||||
@@ -559,18 +556,16 @@ StoreCatalogInheritance(Oid relationId, List *supers)
|
|||||||
List *entry;
|
List *entry;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
AssertArg(OidIsValid(relationId));
|
AssertArg(OidIsValid(relationId));
|
||||||
|
|
||||||
if (supers == NIL)
|
if (supers == NIL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Catalog INHERITS information using direct ancestors only.
|
* Catalog INHERITS information using direct ancestors only.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
relation = heap_openr(InheritsRelationName, RowExclusiveLock);
|
relation = heap_openr(InheritsRelationName, RowExclusiveLock);
|
||||||
desc = RelationGetDescr(relation);
|
desc = RelationGetDescr(relation);
|
||||||
@@ -620,9 +615,8 @@ StoreCatalogInheritance(Oid relationId, List *supers)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* 1. append after each relationId, its superclasses, recursively.
|
* 1. append after each relationId, its superclasses, recursively.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
foreach(entry, supers)
|
foreach(entry, supers)
|
||||||
{
|
{
|
||||||
@@ -656,9 +650,8 @@ StoreCatalogInheritance(Oid relationId, List *supers)
|
|||||||
lnext(current) = next;
|
lnext(current) = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* 2. remove all but last of duplicates.
|
* 2. remove all but last of duplicates.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
foreach(entry, supers)
|
foreach(entry, supers)
|
||||||
{
|
{
|
||||||
@@ -690,9 +683,8 @@ again:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Catalog IPL information using expanded list.
|
* Catalog IPL information using expanded list.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
relation = heap_openr(InheritancePrecidenceListRelationName, RowExclusiveLock);
|
relation = heap_openr(InheritancePrecidenceListRelationName, RowExclusiveLock);
|
||||||
desc = RelationGetDescr(relation);
|
desc = RelationGetDescr(relation);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.53 2001/03/22 03:59:22 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.54 2001/03/22 06:16:11 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
|
||||||
@@ -442,9 +442,8 @@ DefineOperator(char *oprName,
|
|||||||
if (functionName == NULL)
|
if (functionName == NULL)
|
||||||
elog(ERROR, "Define: \"procedure\" unspecified");
|
elog(ERROR, "Define: \"procedure\" unspecified");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now have OperatorCreate do all the work..
|
* now have OperatorCreate do all the work..
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
OperatorCreate(oprName, /* operator name */
|
OperatorCreate(oprName, /* operator name */
|
||||||
typeName1, /* first type name */
|
typeName1, /* first type name */
|
||||||
@@ -640,9 +639,8 @@ DefineType(char *typeName, List *parameters)
|
|||||||
if (internalLength != -1 && storage != 'p')
|
if (internalLength != -1 && storage != 'p')
|
||||||
elog(ERROR, "Define: fixed size types must have storage PLAIN");
|
elog(ERROR, "Define: fixed size types must have storage PLAIN");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now have TypeCreate do all the real work.
|
* now have TypeCreate do all the real work.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
TypeCreate(typeName, /* type name */
|
TypeCreate(typeName, /* type name */
|
||||||
InvalidOid, /* preassigned type oid (not done here) */
|
InvalidOid, /* preassigned type oid (not done here) */
|
||||||
@@ -661,10 +659,9 @@ DefineType(char *typeName, List *parameters)
|
|||||||
alignment, /* required alignment */
|
alignment, /* required alignment */
|
||||||
storage); /* TOAST strategy */
|
storage); /* TOAST strategy */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* When we create a base type (as opposed to a complex type)
|
* When we create a base type (as opposed to a complex type) we need
|
||||||
* we need to have an array entry for it in pg_type as well.
|
* to have an array entry for it in pg_type as well.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
shadow_type = makeArrayTypeName(typeName);
|
shadow_type = makeArrayTypeName(typeName);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.46 2001/03/22 03:59:23 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.47 2001/03/22 06:16:11 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -405,16 +405,15 @@ FuncIndexArgs(IndexInfo *indexInfo,
|
|||||||
nargs++;
|
nargs++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Lookup the function procedure to get its OID and result type.
|
* Lookup the function procedure to get its OID and result type.
|
||||||
*
|
*
|
||||||
* We rely on parse_func.c to find the correct function in the
|
* We rely on parse_func.c to find the correct function in the possible
|
||||||
* possible presence of binary-compatible types. However, parse_func
|
* presence of binary-compatible types. However, parse_func may do
|
||||||
* may do too much: it will accept a function that requires run-time
|
* too much: it will accept a function that requires run-time coercion
|
||||||
* coercion of input types, and the executor is not currently set up
|
* of input types, and the executor is not currently set up to support
|
||||||
* to support that. So, check to make sure that the selected function
|
* that. So, check to make sure that the selected function has
|
||||||
* has exact-match or binary-compatible input types.
|
* exact-match or binary-compatible input types.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!func_get_detail(funcIndex->name, nargs, argTypes,
|
if (!func_get_detail(funcIndex->name, nargs, argTypes,
|
||||||
&funcid, &rettype, &retset, &true_typeids))
|
&funcid, &rettype, &retset, &true_typeids))
|
||||||
@@ -637,11 +636,10 @@ ReindexIndex(const char *name, bool force /* currently unused */ )
|
|||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
bool overwrite = false;
|
bool overwrite = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* REINDEX within a transaction block is dangerous, because
|
* REINDEX within a transaction block is dangerous, because if the
|
||||||
* if the transaction is later rolled back we have no way to
|
* transaction is later rolled back we have no way to undo truncation
|
||||||
* undo truncation of the index's physical file. Disallow it.
|
* of the index's physical file. Disallow it.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (IsTransactionBlock())
|
if (IsTransactionBlock())
|
||||||
elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
|
elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
|
||||||
@@ -681,11 +679,10 @@ ReindexTable(const char *name, bool force)
|
|||||||
{
|
{
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* REINDEX within a transaction block is dangerous, because
|
* REINDEX within a transaction block is dangerous, because if the
|
||||||
* if the transaction is later rolled back we have no way to
|
* transaction is later rolled back we have no way to undo truncation
|
||||||
* undo truncation of the index's physical file. Disallow it.
|
* of the index's physical file. Disallow it.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (IsTransactionBlock())
|
if (IsTransactionBlock())
|
||||||
elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
|
elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
|
||||||
|
|||||||
@@ -59,9 +59,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
|
|||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Check permission
|
* Check permission
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!superuser())
|
if (!superuser())
|
||||||
{
|
{
|
||||||
@@ -69,10 +68,9 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
|
|||||||
"permitted to create procedural languages");
|
"permitted to create procedural languages");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Translate the language name and check that
|
* Translate the language name and check that this language doesn't
|
||||||
* this language doesn't already exist
|
* already exist
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case_translate_language_name(stmt->plname, languageName);
|
case_translate_language_name(stmt->plname, languageName);
|
||||||
|
|
||||||
@@ -81,10 +79,9 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
|
|||||||
0, 0, 0))
|
0, 0, 0))
|
||||||
elog(ERROR, "Language %s already exists", languageName);
|
elog(ERROR, "Language %s already exists", languageName);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Lookup the PL handler function and check that it is
|
* Lookup the PL handler function and check that it is of return type
|
||||||
* of return type Opaque
|
* Opaque
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
memset(typev, 0, sizeof(typev));
|
memset(typev, 0, sizeof(typev));
|
||||||
procTup = SearchSysCache(PROCNAME,
|
procTup = SearchSysCache(PROCNAME,
|
||||||
@@ -99,9 +96,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
|
|||||||
elog(ERROR, "PL handler function %s() isn't of return type Opaque",
|
elog(ERROR, "PL handler function %s() isn't of return type Opaque",
|
||||||
stmt->plhandler);
|
stmt->plhandler);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Insert the new language into pg_language
|
* Insert the new language into pg_language
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < Natts_pg_language; i++)
|
for (i = 0; i < Natts_pg_language; i++)
|
||||||
{
|
{
|
||||||
@@ -150,9 +146,8 @@ DropProceduralLanguage(DropPLangStmt *stmt)
|
|||||||
HeapTuple langTup;
|
HeapTuple langTup;
|
||||||
Relation rel;
|
Relation rel;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Check permission
|
* Check permission
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!superuser())
|
if (!superuser())
|
||||||
{
|
{
|
||||||
@@ -160,10 +155,9 @@ DropProceduralLanguage(DropPLangStmt *stmt)
|
|||||||
"permitted to drop procedural languages");
|
"permitted to drop procedural languages");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Translate the language name, check that
|
* Translate the language name, check that this language exist and is
|
||||||
* this language exist and is a PL
|
* a PL
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case_translate_language_name(stmt->plname, languageName);
|
case_translate_language_name(stmt->plname, languageName);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.89 2001/03/22 03:59:23 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.90 2001/03/22 06:16:11 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -72,10 +72,9 @@ CreateTrigger(CreateTrigStmt *stmt)
|
|||||||
if (!pg_ownercheck(GetUserId(), stmt->relname, RELNAME))
|
if (!pg_ownercheck(GetUserId(), stmt->relname, RELNAME))
|
||||||
elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
|
elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If trigger is a constraint, user trigger name as constraint
|
* If trigger is a constraint, user trigger name as constraint name
|
||||||
* name and build a unique trigger name instead.
|
* and build a unique trigger name instead.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (stmt->isconstraint)
|
if (stmt->isconstraint)
|
||||||
{
|
{
|
||||||
@@ -413,15 +412,14 @@ RelationRemoveTriggers(Relation rel)
|
|||||||
|
|
||||||
heap_endscan(tgscan);
|
heap_endscan(tgscan);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If we deleted any triggers, must update pg_class entry and
|
* If we deleted any triggers, must update pg_class entry and advance
|
||||||
* advance command counter to make the updated entry visible.
|
* command counter to make the updated entry visible. This is fairly
|
||||||
* This is fairly annoying, since we'e just going to drop the
|
* annoying, since we'e just going to drop the durn thing later, but
|
||||||
* durn thing later, but it's necessary to have a consistent
|
* it's necessary to have a consistent state in case we do
|
||||||
* state in case we do CommandCounterIncrement() below ---
|
* CommandCounterIncrement() below --- if RelationBuildTriggers()
|
||||||
* if RelationBuildTriggers() runs, it will complain otherwise.
|
* runs, it will complain otherwise. Perhaps RelationBuildTriggers()
|
||||||
* Perhaps RelationBuildTriggers() shouldn't be so picky...
|
* shouldn't be so picky...
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
@@ -446,9 +444,8 @@ RelationRemoveTriggers(Relation rel)
|
|||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Also drop all constraint triggers referencing this relation
|
* Also drop all constraint triggers referencing this relation
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgconstrrelid,
|
ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgconstrrelid,
|
||||||
F_OIDEQ, RelationGetRelid(rel));
|
F_OIDEQ, RelationGetRelid(rel));
|
||||||
@@ -473,12 +470,11 @@ RelationRemoveTriggers(Relation rel)
|
|||||||
|
|
||||||
DropTrigger(&stmt);
|
DropTrigger(&stmt);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Need to do a command counter increment here to show up
|
* Need to do a command counter increment here to show up new
|
||||||
* new pg_class.reltriggers in the next loop iteration
|
* pg_class.reltriggers in the next loop iteration (in case there
|
||||||
* (in case there are multiple referential integrity action
|
* are multiple referential integrity action triggers for the same
|
||||||
* triggers for the same FK table defined on the PK table).
|
* FK table defined on the PK table).
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
|
||||||
@@ -1182,18 +1178,15 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
|
|||||||
List *sl;
|
List *sl;
|
||||||
DeferredTriggerStatus trigstate;
|
DeferredTriggerStatus trigstate;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Not deferrable triggers (i.e. normal AFTER ROW triggers
|
* Not deferrable triggers (i.e. normal AFTER ROW triggers and
|
||||||
* and constraints declared NOT DEFERRABLE, the state is
|
* constraints declared NOT DEFERRABLE, the state is allways false.
|
||||||
* allways false.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if ((itemstate & TRIGGER_DEFERRED_DEFERRABLE) == 0)
|
if ((itemstate & TRIGGER_DEFERRED_DEFERRABLE) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Lookup if we know an individual state for this trigger
|
* Lookup if we know an individual state for this trigger
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
foreach(sl, deftrig_trigstates)
|
foreach(sl, deftrig_trigstates)
|
||||||
{
|
{
|
||||||
@@ -1202,19 +1195,16 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
|
|||||||
return trigstate->dts_tgisdeferred;
|
return trigstate->dts_tgisdeferred;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* No individual state known - so if the user issued a
|
* No individual state known - so if the user issued a SET CONSTRAINT
|
||||||
* SET CONSTRAINT ALL ..., we return that instead of the
|
* ALL ..., we return that instead of the triggers default state.
|
||||||
* triggers default state.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (deftrig_all_isset)
|
if (deftrig_all_isset)
|
||||||
return deftrig_all_isdeferred;
|
return deftrig_all_isdeferred;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* No ALL state known either, remember the default state
|
* No ALL state known either, remember the default state as the
|
||||||
* as the current and return that.
|
* current and return that.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||||
|
|
||||||
@@ -1319,9 +1309,8 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
|
|||||||
Buffer oldbuffer;
|
Buffer oldbuffer;
|
||||||
Buffer newbuffer;
|
Buffer newbuffer;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Open the heap and fetch the required OLD and NEW tuples.
|
* Open the heap and fetch the required OLD and NEW tuples.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
rel = heap_open(event->dte_relid, NoLock);
|
rel = heap_open(event->dte_relid, NoLock);
|
||||||
|
|
||||||
@@ -1341,9 +1330,8 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
|
|||||||
elog(ERROR, "deferredTriggerExecute: failed to fetch new tuple");
|
elog(ERROR, "deferredTriggerExecute: failed to fetch new tuple");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Setup the trigger information
|
* Setup the trigger information
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
LocTriggerData.type = T_TriggerData;
|
LocTriggerData.type = T_TriggerData;
|
||||||
LocTriggerData.tg_event = (event->dte_event & TRIGGER_EVENT_OPMASK) |
|
LocTriggerData.tg_event = (event->dte_event & TRIGGER_EVENT_OPMASK) |
|
||||||
@@ -1374,10 +1362,9 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Call the trigger and throw away an eventually returned
|
* Call the trigger and throw away an eventually returned updated
|
||||||
* updated tuple.
|
* tuple.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
rettuple = ExecCallTriggerFunc(LocTriggerData.tg_trigger,
|
rettuple = ExecCallTriggerFunc(LocTriggerData.tg_trigger,
|
||||||
&LocTriggerData,
|
&LocTriggerData,
|
||||||
@@ -1385,16 +1372,14 @@ deferredTriggerExecute(DeferredTriggerEvent event, int itemno,
|
|||||||
if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple)
|
if (rettuple != NULL && rettuple != &oldtuple && rettuple != &newtuple)
|
||||||
heap_freetuple(rettuple);
|
heap_freetuple(rettuple);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Might have been a referential integrity constraint trigger.
|
* Might have been a referential integrity constraint trigger. Reset
|
||||||
* Reset the snapshot overriding flag.
|
* the snapshot overriding flag.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ReferentialIntegritySnapshotOverride = false;
|
ReferentialIntegritySnapshotOverride = false;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Release buffers and close the relation
|
* Release buffers and close the relation
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (ItemPointerIsValid(&(event->dte_oldctid)))
|
if (ItemPointerIsValid(&(event->dte_oldctid)))
|
||||||
ReleaseBuffer(oldbuffer);
|
ReleaseBuffer(oldbuffer);
|
||||||
@@ -1420,14 +1405,13 @@ deferredTriggerInvokeEvents(bool immediate_only)
|
|||||||
int i;
|
int i;
|
||||||
MemoryContext per_tuple_context;
|
MemoryContext per_tuple_context;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* For now we process all events - to speedup transaction blocks
|
* For now we process all events - to speedup transaction blocks we
|
||||||
* we need to remember the actual end of the queue at EndQuery
|
* need to remember the actual end of the queue at EndQuery and
|
||||||
* and process only events that are newer. On state changes we
|
* process only events that are newer. On state changes we simply
|
||||||
* simply reset the position to the beginning of the queue and
|
* reset the position to the beginning of the queue and process all
|
||||||
* process all events once with the new states when the
|
* events once with the new states when the SET CONSTRAINTS ...
|
||||||
* SET CONSTRAINTS ... command finishes and calls EndQuery.
|
* command finishes and calls EndQuery.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Make a per-tuple memory context for trigger function calls */
|
/* Make a per-tuple memory context for trigger function calls */
|
||||||
@@ -1440,9 +1424,9 @@ deferredTriggerInvokeEvents(bool immediate_only)
|
|||||||
|
|
||||||
for (event = deftrig_events; event != NULL; event = event->dte_next)
|
for (event = deftrig_events; event != NULL; event = event->dte_next)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Check if event is completely done.
|
* Check if event is completely done.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (event->dte_event & (TRIGGER_DEFERRED_DONE |
|
if (event->dte_event & (TRIGGER_DEFERRED_DONE |
|
||||||
TRIGGER_DEFERRED_CANCELED))
|
TRIGGER_DEFERRED_CANCELED))
|
||||||
@@ -1450,9 +1434,8 @@ deferredTriggerInvokeEvents(bool immediate_only)
|
|||||||
|
|
||||||
MemoryContextReset(per_tuple_context);
|
MemoryContextReset(per_tuple_context);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Check each trigger item in the event.
|
* Check each trigger item in the event.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
still_deferred_ones = false;
|
still_deferred_ones = false;
|
||||||
for (i = 0; i < event->dte_n_items; i++)
|
for (i = 0; i < event->dte_n_items; i++)
|
||||||
@@ -1460,10 +1443,9 @@ deferredTriggerInvokeEvents(bool immediate_only)
|
|||||||
if (event->dte_item[i].dti_state & TRIGGER_DEFERRED_DONE)
|
if (event->dte_item[i].dti_state & TRIGGER_DEFERRED_DONE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* This trigger item hasn't been called yet. Check if
|
* This trigger item hasn't been called yet. Check if we
|
||||||
* we should call it now.
|
* should call it now.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (immediate_only && deferredTriggerCheckState(
|
if (immediate_only && deferredTriggerCheckState(
|
||||||
event->dte_item[i].dti_tgoid,
|
event->dte_item[i].dti_tgoid,
|
||||||
@@ -1473,18 +1455,15 @@ deferredTriggerInvokeEvents(bool immediate_only)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* So let's fire it...
|
* So let's fire it...
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
deferredTriggerExecute(event, i, per_tuple_context);
|
deferredTriggerExecute(event, i, per_tuple_context);
|
||||||
event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
|
event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Remember in the event itself if all trigger items are
|
* Remember in the event itself if all trigger items are done.
|
||||||
* done.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (!still_deferred_ones)
|
if (!still_deferred_ones)
|
||||||
event->dte_event |= TRIGGER_DEFERRED_DONE;
|
event->dte_event |= TRIGGER_DEFERRED_DONE;
|
||||||
@@ -1532,10 +1511,9 @@ DeferredTriggerBeginXact(void)
|
|||||||
elog(ERROR,
|
elog(ERROR,
|
||||||
"DeferredTriggerBeginXact() called while inside transaction");
|
"DeferredTriggerBeginXact() called while inside transaction");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Create the per transaction memory context and copy all states
|
* Create the per transaction memory context and copy all states from
|
||||||
* from the per session context to here.
|
* the per session context to here.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
deftrig_cxt = AllocSetContextCreate(TopTransactionContext,
|
deftrig_cxt = AllocSetContextCreate(TopTransactionContext,
|
||||||
"DeferredTriggerXact",
|
"DeferredTriggerXact",
|
||||||
@@ -1578,9 +1556,9 @@ DeferredTriggerBeginXact(void)
|
|||||||
void
|
void
|
||||||
DeferredTriggerEndQuery(void)
|
DeferredTriggerEndQuery(void)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Ignore call if we aren't in a transaction.
|
* Ignore call if we aren't in a transaction.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (deftrig_cxt == NULL)
|
if (deftrig_cxt == NULL)
|
||||||
return;
|
return;
|
||||||
@@ -1599,9 +1577,9 @@ DeferredTriggerEndQuery(void)
|
|||||||
void
|
void
|
||||||
DeferredTriggerEndXact(void)
|
DeferredTriggerEndXact(void)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Ignore call if we aren't in a transaction.
|
* Ignore call if we aren't in a transaction.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (deftrig_cxt == NULL)
|
if (deftrig_cxt == NULL)
|
||||||
return;
|
return;
|
||||||
@@ -1624,9 +1602,9 @@ DeferredTriggerEndXact(void)
|
|||||||
void
|
void
|
||||||
DeferredTriggerAbortXact(void)
|
DeferredTriggerAbortXact(void)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Ignore call if we aren't in a transaction.
|
* Ignore call if we aren't in a transaction.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (deftrig_cxt == NULL)
|
if (deftrig_cxt == NULL)
|
||||||
return;
|
return;
|
||||||
@@ -1655,20 +1633,19 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
DeferredTriggerStatus state;
|
DeferredTriggerStatus state;
|
||||||
bool hasindex;
|
bool hasindex;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle SET CONSTRAINTS ALL ...
|
* Handle SET CONSTRAINTS ALL ...
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (stmt->constraints == NIL)
|
if (stmt->constraints == NIL)
|
||||||
{
|
{
|
||||||
if (!IsTransactionBlock())
|
if (!IsTransactionBlock())
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* ... outside of a transaction block
|
* ... outside of a transaction block
|
||||||
*
|
*
|
||||||
* Drop all information about individual trigger states per
|
* Drop all information about individual trigger states per
|
||||||
* session.
|
* session.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
l = deftrig_dfl_trigstates;
|
l = deftrig_dfl_trigstates;
|
||||||
while (l != NIL)
|
while (l != NIL)
|
||||||
@@ -1681,9 +1658,8 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
}
|
}
|
||||||
deftrig_dfl_trigstates = NIL;
|
deftrig_dfl_trigstates = NIL;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Set the session ALL state to known.
|
* Set the session ALL state to known.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
deftrig_dfl_all_isset = true;
|
deftrig_dfl_all_isset = true;
|
||||||
deftrig_dfl_all_isdeferred = stmt->deferred;
|
deftrig_dfl_all_isdeferred = stmt->deferred;
|
||||||
@@ -1692,12 +1668,12 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* ... inside of a transaction block
|
* ... inside of a transaction block
|
||||||
*
|
*
|
||||||
* Drop all information about individual trigger states per
|
* Drop all information about individual trigger states per
|
||||||
* transaction.
|
* transaction.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
l = deftrig_trigstates;
|
l = deftrig_trigstates;
|
||||||
while (l != NIL)
|
while (l != NIL)
|
||||||
@@ -1710,9 +1686,8 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
}
|
}
|
||||||
deftrig_trigstates = NIL;
|
deftrig_trigstates = NIL;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Set the per transaction ALL state to known.
|
* Set the per transaction ALL state to known.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
deftrig_all_isset = true;
|
deftrig_all_isset = true;
|
||||||
deftrig_all_isdeferred = stmt->deferred;
|
deftrig_all_isdeferred = stmt->deferred;
|
||||||
@@ -1743,16 +1718,14 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
Form_pg_trigger pg_trigger;
|
Form_pg_trigger pg_trigger;
|
||||||
Oid constr_oid;
|
Oid constr_oid;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Check that only named constraints are set explicitly
|
* Check that only named constraints are set explicitly
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (strcmp((char *) lfirst(l), "") == 0)
|
if (strcmp((char *) lfirst(l), "") == 0)
|
||||||
elog(ERROR, "unnamed constraints cannot be set explicitly");
|
elog(ERROR, "unnamed constraints cannot be set explicitly");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Setup to scan pg_trigger by tgconstrname ...
|
* Setup to scan pg_trigger by tgconstrname ...
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ScanKeyEntryInitialize(&skey,
|
ScanKeyEntryInitialize(&skey,
|
||||||
(bits16) 0x0,
|
(bits16) 0x0,
|
||||||
@@ -1765,9 +1738,8 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
else
|
else
|
||||||
tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey);
|
tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* ... and search for the constraint trigger row
|
* ... and search for the constraint trigger row
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
found = false;
|
found = false;
|
||||||
for (;;)
|
for (;;)
|
||||||
@@ -1792,11 +1764,10 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If we found some, check that they fit the deferrability
|
* If we found some, check that they fit the deferrability but
|
||||||
* but skip ON <event> RESTRICT ones, since they are silently
|
* skip ON <event> RESTRICT ones, since they are silently
|
||||||
* never deferrable.
|
* never deferrable.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
|
pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
|
||||||
if (stmt->deferred && !pg_trigger->tgdeferrable &&
|
if (stmt->deferred && !pg_trigger->tgdeferrable &&
|
||||||
@@ -1813,9 +1784,8 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Not found ?
|
* Not found ?
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (!found)
|
if (!found)
|
||||||
elog(ERROR, "Constraint '%s' does not exist", (char *) lfirst(l));
|
elog(ERROR, "Constraint '%s' does not exist", (char *) lfirst(l));
|
||||||
@@ -1831,10 +1801,10 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
|
|
||||||
if (!IsTransactionBlock())
|
if (!IsTransactionBlock())
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* Outside of a transaction block set the trigger
|
/*
|
||||||
* states of individual triggers on session level.
|
* Outside of a transaction block set the trigger states of
|
||||||
* ----------
|
* individual triggers on session level.
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
|
oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
|
||||||
|
|
||||||
@@ -1869,10 +1839,10 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* Inside of a transaction block set the trigger
|
/*
|
||||||
* states of individual triggers on transaction level.
|
* Inside of a transaction block set the trigger states of
|
||||||
* ----------
|
* individual triggers on transaction level.
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||||
|
|
||||||
@@ -1938,9 +1908,8 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||||||
elog(ERROR,
|
elog(ERROR,
|
||||||
"DeferredTriggerSaveEvent() called outside of transaction");
|
"DeferredTriggerSaveEvent() called outside of transaction");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the CTID's of OLD and NEW
|
* Get the CTID's of OLD and NEW
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (oldtup != NULL)
|
if (oldtup != NULL)
|
||||||
ItemPointerCopy(&(oldtup->t_self), &(oldctid));
|
ItemPointerCopy(&(oldtup->t_self), &(oldctid));
|
||||||
@@ -1951,9 +1920,8 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||||||
else
|
else
|
||||||
ItemPointerSetInvalid(&(newctid));
|
ItemPointerSetInvalid(&(newctid));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Create a new event
|
* Create a new event
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||||
|
|
||||||
@@ -1991,11 +1959,11 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TRIGGER_EVENT_UPDATE:
|
case TRIGGER_EVENT_UPDATE:
|
||||||
/* ----------
|
|
||||||
* On UPDATE check if the tuple updated has been inserted
|
/*
|
||||||
* or a foreign referenced key value that's changing now
|
* On UPDATE check if the tuple updated has been inserted or a
|
||||||
* has been updated once before in this transaction.
|
* foreign referenced key value that's changing now has been
|
||||||
* ----------
|
* updated once before in this transaction.
|
||||||
*/
|
*/
|
||||||
if (oldtup->t_data->t_xmin != GetCurrentTransactionId())
|
if (oldtup->t_data->t_xmin != GetCurrentTransactionId())
|
||||||
prev_event = NULL;
|
prev_event = NULL;
|
||||||
@@ -2003,18 +1971,16 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||||||
prev_event =
|
prev_event =
|
||||||
deferredTriggerGetPreviousEvent(rel->rd_id, &oldctid);
|
deferredTriggerGetPreviousEvent(rel->rd_id, &oldctid);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Now check if one of the referenced keys is changed.
|
* Now check if one of the referenced keys is changed.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < ntriggers; i++)
|
for (i = 0; i < ntriggers; i++)
|
||||||
{
|
{
|
||||||
bool is_ri_trigger;
|
bool is_ri_trigger;
|
||||||
bool key_unchanged;
|
bool key_unchanged;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* We are interested in RI_FKEY triggers only.
|
* We are interested in RI_FKEY triggers only.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
switch (triggers[i]->tgfoid)
|
switch (triggers[i]->tgfoid)
|
||||||
{
|
{
|
||||||
@@ -2044,11 +2010,11 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||||||
|
|
||||||
if (key_unchanged)
|
if (key_unchanged)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* The key hasn't changed, so no need later to invoke
|
* The key hasn't changed, so no need later to invoke
|
||||||
* the trigger at all. But remember other states from
|
* the trigger at all. But remember other states from
|
||||||
* the possible earlier event.
|
* the possible earlier event.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
new_event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
|
new_event->dte_item[i].dti_state |= TRIGGER_DEFERRED_DONE;
|
||||||
|
|
||||||
@@ -2057,10 +2023,11 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||||||
if (prev_event->dte_event &
|
if (prev_event->dte_event &
|
||||||
TRIGGER_DEFERRED_ROW_INSERTED)
|
TRIGGER_DEFERRED_ROW_INSERTED)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* This is a row inserted during our transaction.
|
/*
|
||||||
* So any key value is considered changed.
|
* This is a row inserted during our
|
||||||
* ----------
|
* transaction. So any key value is considered
|
||||||
|
* changed.
|
||||||
*/
|
*/
|
||||||
new_event->dte_event |=
|
new_event->dte_event |=
|
||||||
TRIGGER_DEFERRED_ROW_INSERTED;
|
TRIGGER_DEFERRED_ROW_INSERTED;
|
||||||
@@ -2071,11 +2038,11 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* This is a row, previously updated. So
|
/*
|
||||||
* if this key has been changed before, we
|
* This is a row, previously updated. So if
|
||||||
* still remember that it happened.
|
* this key has been changed before, we still
|
||||||
* ----------
|
* remember that it happened.
|
||||||
*/
|
*/
|
||||||
if (prev_event->dte_item[i].dti_state &
|
if (prev_event->dte_item[i].dti_state &
|
||||||
TRIGGER_DEFERRED_KEY_CHANGED)
|
TRIGGER_DEFERRED_KEY_CHANGED)
|
||||||
@@ -2090,10 +2057,10 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Bomb out if this key has been changed before.
|
* Bomb out if this key has been changed before.
|
||||||
* Otherwise remember that we do so.
|
* Otherwise remember that we do so.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (prev_event)
|
if (prev_event)
|
||||||
{
|
{
|
||||||
@@ -2112,10 +2079,9 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||||||
NameGetDatum(&(rel->rd_rel->relname)))));
|
NameGetDatum(&(rel->rd_rel->relname)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* This is the first change to this key, so let
|
* This is the first change to this key, so let it
|
||||||
* it happen.
|
* happen.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
new_event->dte_item[i].dti_state |=
|
new_event->dte_item[i].dti_state |=
|
||||||
TRIGGER_DEFERRED_KEY_CHANGED;
|
TRIGGER_DEFERRED_KEY_CHANGED;
|
||||||
@@ -2126,18 +2092,17 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TRIGGER_EVENT_DELETE:
|
case TRIGGER_EVENT_DELETE:
|
||||||
/* ----------
|
|
||||||
* On DELETE check if the tuple deleted has been inserted
|
/*
|
||||||
* or a possibly referenced key value has changed in this
|
* On DELETE check if the tuple deleted has been inserted or a
|
||||||
|
* possibly referenced key value has changed in this
|
||||||
* transaction.
|
* transaction.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (oldtup->t_data->t_xmin != GetCurrentTransactionId())
|
if (oldtup->t_data->t_xmin != GetCurrentTransactionId())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Look at the previous event to the same tuple.
|
* Look at the previous event to the same tuple.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
prev_event = deferredTriggerGetPreviousEvent(rel->rd_id, &oldctid);
|
prev_event = deferredTriggerGetPreviousEvent(rel->rd_id, &oldctid);
|
||||||
if (prev_event->dte_event & TRIGGER_DEFERRED_KEY_CHANGED)
|
if (prev_event->dte_event & TRIGGER_DEFERRED_KEY_CHANGED)
|
||||||
@@ -2149,9 +2114,8 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Anything's fine up to here. Add the new event to the queue.
|
* Anything's fine up to here. Add the new event to the queue.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||||
deferredTriggerAddEvent(new_event);
|
deferredTriggerAddEvent(new_event);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.74 2001/03/22 03:59:24 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.75 2001/03/22 06:16:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -538,14 +538,14 @@ DropUser(DropUserStmt *stmt)
|
|||||||
|
|
||||||
usesysid = DatumGetInt32(heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &null));
|
usesysid = DatumGetInt32(heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &null));
|
||||||
|
|
||||||
/*-------------------
|
/*
|
||||||
* Check if user still owns a database. If so, error out.
|
* Check if user still owns a database. If so, error out.
|
||||||
*
|
*
|
||||||
* (It used to be that this function would drop the database automatically.
|
* (It used to be that this function would drop the database
|
||||||
* This is not only very dangerous for people that don't read the manual,
|
* automatically. This is not only very dangerous for people that
|
||||||
* it doesn't seem to be the behaviour one would expect either.)
|
* don't read the manual, it doesn't seem to be the behaviour one
|
||||||
* -- petere 2000/01/14)
|
* would expect either.) -- petere 2000/01/14)
|
||||||
*-------------------*/
|
*/
|
||||||
pg_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
|
pg_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
|
||||||
pg_dsc = RelationGetDescr(pg_rel);
|
pg_dsc = RelationGetDescr(pg_rel);
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
* ExecInitTee
|
* ExecInitTee
|
||||||
* ExecEndTee
|
* ExecEndTee
|
||||||
*
|
*
|
||||||
* $Id: nodeTee.c,v 1.9 2001/01/24 19:42:55 momjian Exp $
|
* $Id: nodeTee.c,v 1.10 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -60,9 +60,8 @@ ExecInitTee(Tee * node, EState *currentEstate, Plan *parent)
|
|||||||
if (node->plan.state)
|
if (node->plan.state)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign the node's execution state
|
* assign the node's execution state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -93,9 +92,8 @@ ExecInitTee(Tee * node, EState *currentEstate, Plan *parent)
|
|||||||
node->plan.state = estate;
|
node->plan.state = estate;
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create teeState structure
|
* create teeState structure
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
teeState = makeNode(TeeState);
|
teeState = makeNode(TeeState);
|
||||||
teeState->tee_leftPlace = 0;
|
teeState->tee_leftPlace = 0;
|
||||||
@@ -120,9 +118,9 @@ ExecInitTee(Tee * node, EState *currentEstate, Plan *parent)
|
|||||||
ExecAssignExprContext(estate, &(teeState->cstate));
|
ExecAssignExprContext(estate, &(teeState->cstate));
|
||||||
|
|
||||||
#define TEE_NSLOTS 2
|
#define TEE_NSLOTS 2
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* initialize tuple slots
|
* initialize tuple slots
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &(teeState->cstate));
|
ExecInitResultTupleSlot(estate, &(teeState->cstate));
|
||||||
|
|
||||||
@@ -130,15 +128,15 @@ ExecInitTee(Tee * node, EState *currentEstate, Plan *parent)
|
|||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan((Plan *) node);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* the tuple type info is from the outer plan of this node
|
* the tuple type info is from the outer plan of this node the result
|
||||||
* the result type is also the same as the outerplan
|
* type is also the same as the outerplan
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &(teeState->cstate));
|
ExecAssignResultTypeFromOuterPlan((Plan *) node, &(teeState->cstate));
|
||||||
ExecAssignProjectionInfo((Plan *) node, &teeState->cstate);
|
ExecAssignProjectionInfo((Plan *) node, &teeState->cstate);
|
||||||
|
|
||||||
/* ---------------------------------------
|
/*
|
||||||
initialize temporary relation to buffer tuples
|
* initialize temporary relation to buffer tuples
|
||||||
*/
|
*/
|
||||||
tupType = ExecGetResultType(&(teeState->cstate));
|
tupType = ExecGetResultType(&(teeState->cstate));
|
||||||
len = ExecTargetListLength(((Plan *) node)->targetlist);
|
len = ExecTargetListLength(((Plan *) node)->targetlist);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: execAmi.c,v 1.57 2001/03/22 03:59:25 momjian Exp $
|
* $Id: execAmi.c,v 1.58 2001/03/22 06:16:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -78,23 +78,20 @@ ExecOpenScanR(Oid relOid,
|
|||||||
Relation relation;
|
Relation relation;
|
||||||
Pointer scanDesc;
|
Pointer scanDesc;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* note: scanDesc returned by ExecBeginScan can be either
|
* note: scanDesc returned by ExecBeginScan can be either a
|
||||||
* a HeapScanDesc or an IndexScanDesc so for now we
|
* HeapScanDesc or an IndexScanDesc so for now we make it a Pointer.
|
||||||
* make it a Pointer. There should be a better scan
|
* There should be a better scan abstraction someday -cim 9/9/89
|
||||||
* abstraction someday -cim 9/9/89
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Open the relation with the correct call depending
|
* Open the relation with the correct call depending on whether this
|
||||||
* on whether this is a heap relation or an index relation.
|
* is a heap relation or an index relation.
|
||||||
*
|
*
|
||||||
* For a table, acquire AccessShareLock for the duration of the query
|
* For a table, acquire AccessShareLock for the duration of the query
|
||||||
* execution. For indexes, acquire no lock here; the index machinery
|
* execution. For indexes, acquire no lock here; the index machinery
|
||||||
* does its own locks and unlocks. (We rely on having some kind of
|
* does its own locks and unlocks. (We rely on having some kind of
|
||||||
* lock on the parent table to ensure the index won't go away!)
|
* lock on the parent table to ensure the index won't go away!)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (isindex)
|
if (isindex)
|
||||||
relation = index_open(relOid);
|
relation = index_open(relOid);
|
||||||
@@ -136,13 +133,12 @@ ExecBeginScan(Relation relation,
|
|||||||
{
|
{
|
||||||
Pointer scanDesc;
|
Pointer scanDesc;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open the appropriate type of scan.
|
* open the appropriate type of scan.
|
||||||
*
|
*
|
||||||
* Note: ambeginscan()'s second arg is a boolean indicating
|
* Note: ambeginscan()'s second arg is a boolean indicating that the scan
|
||||||
* that the scan should be done in reverse.. That is,
|
* should be done in reverse.. That is, if you pass it true, then the
|
||||||
* if you pass it true, then the scan is backward.
|
* scan is backward.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (isindex)
|
if (isindex)
|
||||||
{
|
{
|
||||||
@@ -180,9 +176,8 @@ ExecCloseR(Plan *node)
|
|||||||
Relation relation;
|
Relation relation;
|
||||||
HeapScanDesc scanDesc;
|
HeapScanDesc scanDesc;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get state for node and shut down the heap scan, if any
|
* get state for node and shut down the heap scan, if any
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
{
|
{
|
||||||
@@ -209,10 +204,9 @@ ExecCloseR(Plan *node)
|
|||||||
if (scanDesc != NULL)
|
if (scanDesc != NULL)
|
||||||
heap_endscan(scanDesc);
|
heap_endscan(scanDesc);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if this is an index scan then we have to take care
|
* if this is an index scan then we have to take care of the index
|
||||||
* of the index relations as well.
|
* relations as well.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (IsA(node, IndexScan))
|
if (IsA(node, IndexScan))
|
||||||
{
|
{
|
||||||
@@ -229,10 +223,10 @@ ExecCloseR(Plan *node)
|
|||||||
|
|
||||||
for (i = 0; i < numIndices; i++)
|
for (i = 0; i < numIndices; i++)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* shut down each of the index scans and
|
/*
|
||||||
* close each of the index relations
|
* shut down each of the index scans and close each of the
|
||||||
* ----------------
|
* index relations
|
||||||
*/
|
*/
|
||||||
if (indexScanDescs[i] != NULL)
|
if (indexScanDescs[i] != NULL)
|
||||||
index_endscan(indexScanDescs[i]);
|
index_endscan(indexScanDescs[i]);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.26 2001/03/22 03:59:26 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.27 2001/03/22 06:16:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -90,12 +90,10 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType)
|
|||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
oldContext = MemoryContextSwitchTo(junkContext);
|
oldContext = MemoryContextSwitchTo(junkContext);
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* First find the "clean" target list, i.e. all the entries
|
* First find the "clean" target list, i.e. all the entries in the
|
||||||
* in the original target list which have a false 'resjunk'
|
* original target list which have a false 'resjunk' NOTE: make copy
|
||||||
* NOTE: make copy of the Resdom nodes, because we have
|
* of the Resdom nodes, because we have to change the 'resno's...
|
||||||
* to change the 'resno's...
|
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
cleanTargetList = NIL;
|
cleanTargetList = NIL;
|
||||||
cleanResno = 1;
|
cleanResno = 1;
|
||||||
@@ -167,25 +165,23 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* Now calculate the tuple type for the cleaned tuple (we were already
|
* Now calculate the tuple type for the cleaned tuple (we were already
|
||||||
* given the type for the original targetlist).
|
* given the type for the original targetlist).
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
cleanTupType = ExecTypeFromTL(cleanTargetList);
|
cleanTupType = ExecTypeFromTL(cleanTargetList);
|
||||||
|
|
||||||
len = ExecTargetListLength(targetList);
|
len = ExecTargetListLength(targetList);
|
||||||
cleanLength = ExecTargetListLength(cleanTargetList);
|
cleanLength = ExecTargetListLength(cleanTargetList);
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* Now calculate the "map" between the original tuple's attributes
|
* Now calculate the "map" between the original tuple's attributes and
|
||||||
* and the "clean" tuple's attributes.
|
* the "clean" tuple's attributes.
|
||||||
*
|
*
|
||||||
* The "map" is an array of "cleanLength" attribute numbers, i.e.
|
* The "map" is an array of "cleanLength" attribute numbers, i.e. one
|
||||||
* one entry for every attribute of the "clean" tuple.
|
* entry for every attribute of the "clean" tuple. The value of this
|
||||||
* The value of this entry is the attribute number of the corresponding
|
* entry is the attribute number of the corresponding attribute of the
|
||||||
* attribute of the "original" tuple.
|
* "original" tuple.
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
if (cleanLength > 0)
|
if (cleanLength > 0)
|
||||||
{
|
{
|
||||||
@@ -236,9 +232,8 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType)
|
|||||||
else
|
else
|
||||||
cleanMap = NULL;
|
cleanMap = NULL;
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* Finally create and initialize the JunkFilter struct.
|
* Finally create and initialize the JunkFilter struct.
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
junkfilter = makeNode(JunkFilter);
|
junkfilter = makeNode(JunkFilter);
|
||||||
|
|
||||||
@@ -298,10 +293,9 @@ ExecGetJunkAttribute(JunkFilter *junkfilter,
|
|||||||
TupleDesc tupType;
|
TupleDesc tupType;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* first look in the junkfilter's target list for
|
* first look in the junkfilter's target list for an attribute with
|
||||||
* an attribute with the given name
|
* the given name
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
resno = InvalidAttrNumber;
|
resno = InvalidAttrNumber;
|
||||||
targetList = junkfilter->jf_targetList;
|
targetList = junkfilter->jf_targetList;
|
||||||
@@ -327,9 +321,8 @@ ExecGetJunkAttribute(JunkFilter *junkfilter,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* Now extract the attribute value from the tuple.
|
* Now extract the attribute value from the tuple.
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
tuple = slot->val;
|
tuple = slot->val;
|
||||||
tupType = junkfilter->jf_tupType;
|
tupType = junkfilter->jf_tupType;
|
||||||
@@ -361,9 +354,8 @@ ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
|
|||||||
Datum values_array[64];
|
Datum values_array[64];
|
||||||
char nulls_array[64];
|
char nulls_array[64];
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get info from the slot and the junk filter
|
* get info from the slot and the junk filter
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tuple = slot->val;
|
tuple = slot->val;
|
||||||
|
|
||||||
@@ -372,21 +364,19 @@ ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
|
|||||||
cleanLength = junkfilter->jf_cleanLength;
|
cleanLength = junkfilter->jf_cleanLength;
|
||||||
cleanMap = junkfilter->jf_cleanMap;
|
cleanMap = junkfilter->jf_cleanMap;
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* Handle the trivial case first.
|
* Handle the trivial case first.
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
if (cleanLength == 0)
|
if (cleanLength == 0)
|
||||||
return (HeapTuple) NULL;
|
return (HeapTuple) NULL;
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* Create the arrays that will hold the attribute values
|
* Create the arrays that will hold the attribute values and the null
|
||||||
* and the null information for the new "clean" tuple.
|
* information for the new "clean" tuple.
|
||||||
*
|
*
|
||||||
* Note: we use memory on the stack to optimize things when
|
* Note: we use memory on the stack to optimize things when we are
|
||||||
* we are dealing with a small number of tuples.
|
* dealing with a small number of tuples. for large tuples we just use
|
||||||
* for large tuples we just use palloc.
|
* palloc.
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
if (cleanLength > 64)
|
if (cleanLength > 64)
|
||||||
{
|
{
|
||||||
@@ -399,9 +389,8 @@ ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
|
|||||||
nulls = nulls_array;
|
nulls = nulls_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* Exctract one by one all the values of the "clean" tuple.
|
* Exctract one by one all the values of the "clean" tuple.
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < cleanLength; i++)
|
for (i = 0; i < cleanLength; i++)
|
||||||
{
|
{
|
||||||
@@ -413,18 +402,16 @@ ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
|
|||||||
nulls[i] = ' ';
|
nulls[i] = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* Now form the new tuple.
|
* Now form the new tuple.
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
cleanTuple = heap_formtuple(cleanTupType,
|
cleanTuple = heap_formtuple(cleanTupType,
|
||||||
values,
|
values,
|
||||||
nulls);
|
nulls);
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* We are done. Free any space allocated for 'values' and 'nulls'
|
* We are done. Free any space allocated for 'values' and 'nulls' and
|
||||||
* and return the new tuple.
|
* return the new tuple.
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
if (cleanLength > 64)
|
if (cleanLength > 64)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.25 2001/01/29 00:39:18 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.26 2001/03/22 06:16:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -117,10 +117,8 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
|
|||||||
bool result;
|
bool result;
|
||||||
List *subp;
|
List *subp;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* do nothing when we get to the end
|
* do nothing when we get to the end of a leaf on tree.
|
||||||
* of a leaf on tree.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -134,9 +132,9 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
|
|||||||
|
|
||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* control nodes
|
* control nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_Result:
|
case T_Result:
|
||||||
result = ExecInitResult((Result *) node, estate, parent);
|
result = ExecInitResult((Result *) node, estate, parent);
|
||||||
@@ -146,9 +144,8 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
|
|||||||
result = ExecInitAppend((Append *) node, estate, parent);
|
result = ExecInitAppend((Append *) node, estate, parent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* scan nodes
|
* scan nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_SeqScan:
|
case T_SeqScan:
|
||||||
result = ExecInitSeqScan((SeqScan *) node, estate, parent);
|
result = ExecInitSeqScan((SeqScan *) node, estate, parent);
|
||||||
@@ -167,9 +164,8 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
|
|||||||
parent);
|
parent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* join nodes
|
* join nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_NestLoop:
|
case T_NestLoop:
|
||||||
result = ExecInitNestLoop((NestLoop *) node, estate, parent);
|
result = ExecInitNestLoop((NestLoop *) node, estate, parent);
|
||||||
@@ -187,9 +183,8 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
|
|||||||
result = ExecInitHashJoin((HashJoin *) node, estate, parent);
|
result = ExecInitHashJoin((HashJoin *) node, estate, parent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* materialization nodes
|
* materialization nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_Material:
|
case T_Material:
|
||||||
result = ExecInitMaterial((Material *) node, estate, parent);
|
result = ExecInitMaterial((Material *) node, estate, parent);
|
||||||
@@ -253,9 +248,8 @@ ExecProcNode(Plan *node, Plan *parent)
|
|||||||
|
|
||||||
CHECK_FOR_INTERRUPTS();
|
CHECK_FOR_INTERRUPTS();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* deal with NULL nodes..
|
* deal with NULL nodes..
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -265,9 +259,9 @@ ExecProcNode(Plan *node, Plan *parent)
|
|||||||
|
|
||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* control nodes
|
* control nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_Result:
|
case T_Result:
|
||||||
result = ExecResult((Result *) node);
|
result = ExecResult((Result *) node);
|
||||||
@@ -277,9 +271,8 @@ ExecProcNode(Plan *node, Plan *parent)
|
|||||||
result = ExecProcAppend((Append *) node);
|
result = ExecProcAppend((Append *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* scan nodes
|
* scan nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_SeqScan:
|
case T_SeqScan:
|
||||||
result = ExecSeqScan((SeqScan *) node);
|
result = ExecSeqScan((SeqScan *) node);
|
||||||
@@ -297,9 +290,8 @@ ExecProcNode(Plan *node, Plan *parent)
|
|||||||
result = ExecSubqueryScan((SubqueryScan *) node);
|
result = ExecSubqueryScan((SubqueryScan *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* join nodes
|
* join nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_NestLoop:
|
case T_NestLoop:
|
||||||
result = ExecNestLoop((NestLoop *) node);
|
result = ExecNestLoop((NestLoop *) node);
|
||||||
@@ -317,9 +309,8 @@ ExecProcNode(Plan *node, Plan *parent)
|
|||||||
result = ExecHashJoin((HashJoin *) node);
|
result = ExecHashJoin((HashJoin *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* materialization nodes
|
* materialization nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_Material:
|
case T_Material:
|
||||||
result = ExecMaterial((Material *) node);
|
result = ExecMaterial((Material *) node);
|
||||||
@@ -366,9 +357,9 @@ ExecCountSlotsNode(Plan *node)
|
|||||||
|
|
||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* control nodes
|
* control nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_Result:
|
case T_Result:
|
||||||
return ExecCountSlotsResult((Result *) node);
|
return ExecCountSlotsResult((Result *) node);
|
||||||
@@ -376,9 +367,8 @@ ExecCountSlotsNode(Plan *node)
|
|||||||
case T_Append:
|
case T_Append:
|
||||||
return ExecCountSlotsAppend((Append *) node);
|
return ExecCountSlotsAppend((Append *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* scan nodes
|
* scan nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_SeqScan:
|
case T_SeqScan:
|
||||||
return ExecCountSlotsSeqScan((SeqScan *) node);
|
return ExecCountSlotsSeqScan((SeqScan *) node);
|
||||||
@@ -392,9 +382,8 @@ ExecCountSlotsNode(Plan *node)
|
|||||||
case T_SubqueryScan:
|
case T_SubqueryScan:
|
||||||
return ExecCountSlotsSubqueryScan((SubqueryScan *) node);
|
return ExecCountSlotsSubqueryScan((SubqueryScan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* join nodes
|
* join nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_NestLoop:
|
case T_NestLoop:
|
||||||
return ExecCountSlotsNestLoop((NestLoop *) node);
|
return ExecCountSlotsNestLoop((NestLoop *) node);
|
||||||
@@ -408,9 +397,8 @@ ExecCountSlotsNode(Plan *node)
|
|||||||
case T_HashJoin:
|
case T_HashJoin:
|
||||||
return ExecCountSlotsHashJoin((HashJoin *) node);
|
return ExecCountSlotsHashJoin((HashJoin *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* materialization nodes
|
* materialization nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_Material:
|
case T_Material:
|
||||||
return ExecCountSlotsMaterial((Material *) node);
|
return ExecCountSlotsMaterial((Material *) node);
|
||||||
@@ -457,10 +445,8 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||||||
{
|
{
|
||||||
List *subp;
|
List *subp;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* do nothing when we get to the end
|
* do nothing when we get to the end of a leaf on tree.
|
||||||
* of a leaf on tree.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return;
|
return;
|
||||||
@@ -477,9 +463,9 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||||||
|
|
||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* control nodes
|
* control nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_Result:
|
case T_Result:
|
||||||
ExecEndResult((Result *) node);
|
ExecEndResult((Result *) node);
|
||||||
@@ -489,9 +475,8 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||||||
ExecEndAppend((Append *) node);
|
ExecEndAppend((Append *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* scan nodes
|
* scan nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_SeqScan:
|
case T_SeqScan:
|
||||||
ExecEndSeqScan((SeqScan *) node);
|
ExecEndSeqScan((SeqScan *) node);
|
||||||
@@ -509,9 +494,8 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||||||
ExecEndSubqueryScan((SubqueryScan *) node);
|
ExecEndSubqueryScan((SubqueryScan *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* join nodes
|
* join nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_NestLoop:
|
case T_NestLoop:
|
||||||
ExecEndNestLoop((NestLoop *) node);
|
ExecEndNestLoop((NestLoop *) node);
|
||||||
@@ -529,9 +513,8 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||||||
ExecEndHashJoin((HashJoin *) node);
|
ExecEndHashJoin((HashJoin *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* materialization nodes
|
* materialization nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case T_Material:
|
case T_Material:
|
||||||
ExecEndMaterial((Material *) node);
|
ExecEndMaterial((Material *) node);
|
||||||
@@ -726,9 +709,9 @@ ExecGetTupType(Plan *node)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* should never get here
|
* should never get here
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
elog(ERROR, "ExecGetTupType: node type %d unsupported",
|
elog(ERROR, "ExecGetTupType: node type %d unsupported",
|
||||||
(int) nodeTag(node));
|
(int) nodeTag(node));
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.16 2001/03/22 03:59:26 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.17 2001/03/22 06:16:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -55,20 +55,18 @@ ExecScan(Scan *node,
|
|||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
TupleTableSlot *resultSlot;
|
TupleTableSlot *resultSlot;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Fetch data from node
|
* Fetch data from node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
estate = node->plan.state;
|
estate = node->plan.state;
|
||||||
scanstate = node->scanstate;
|
scanstate = node->scanstate;
|
||||||
econtext = scanstate->cstate.cs_ExprContext;
|
econtext = scanstate->cstate.cs_ExprContext;
|
||||||
qual = node->plan.qual;
|
qual = node->plan.qual;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Check to see if we're still projecting out tuples from a previous
|
* Check to see if we're still projecting out tuples from a previous
|
||||||
* scan tuple (because there is a function-returning-set in the
|
* scan tuple (because there is a function-returning-set in the
|
||||||
* projection expressions). If so, try to project another one.
|
* projection expressions). If so, try to project another one.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (scanstate->cstate.cs_TupFromTlist)
|
if (scanstate->cstate.cs_TupFromTlist)
|
||||||
{
|
{
|
||||||
@@ -79,11 +77,10 @@ ExecScan(Scan *node,
|
|||||||
scanstate->cstate.cs_TupFromTlist = false;
|
scanstate->cstate.cs_TupFromTlist = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Reset per-tuple memory context to free any expression evaluation
|
* Reset per-tuple memory context to free any expression evaluation
|
||||||
* storage allocated in the previous tuple cycle. Note this can't
|
* storage allocated in the previous tuple cycle. Note this can't
|
||||||
* happen until we're done projecting out tuples from a scan tuple.
|
* happen until we're done projecting out tuples from a scan tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
@@ -97,12 +94,11 @@ ExecScan(Scan *node,
|
|||||||
|
|
||||||
slot = (*accessMtd) (node);
|
slot = (*accessMtd) (node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if the slot returned by the accessMtd contains
|
* if the slot returned by the accessMtd contains NULL, then it
|
||||||
* NULL, then it means there is nothing more to scan
|
* means there is nothing more to scan so we just return an empty
|
||||||
* so we just return an empty slot, being careful to use
|
* slot, being careful to use the projection result slot so it has
|
||||||
* the projection result slot so it has correct tupleDesc.
|
* correct tupleDesc.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
{
|
{
|
||||||
@@ -112,29 +108,27 @@ ExecScan(Scan *node,
|
|||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* place the current tuple into the expr context
|
* place the current tuple into the expr context
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
econtext->ecxt_scantuple = slot;
|
econtext->ecxt_scantuple = slot;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* check that the current tuple satisfies the qual-clause
|
* check that the current tuple satisfies the qual-clause
|
||||||
*
|
*
|
||||||
* check for non-nil qual here to avoid a function call to
|
* check for non-nil qual here to avoid a function call to ExecQual()
|
||||||
* ExecQual() when the qual is nil ... saves only a few cycles,
|
* when the qual is nil ... saves only a few cycles, but they add
|
||||||
* but they add up ...
|
* up ...
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!qual || ExecQual(qual, econtext, false))
|
if (!qual || ExecQual(qual, econtext, false))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* Found a satisfactory scan tuple.
|
* Found a satisfactory scan tuple.
|
||||||
*
|
*
|
||||||
* Form a projection tuple, store it in the result tuple
|
* Form a projection tuple, store it in the result tuple slot and
|
||||||
* slot and return it --- unless we find we can project no
|
* return it --- unless we find we can project no tuples from
|
||||||
* tuples from this scan tuple, in which case continue scan.
|
* this scan tuple, in which case continue scan.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
resultSlot = ExecProject(scanstate->cstate.cs_ProjInfo, &isDone);
|
resultSlot = ExecProject(scanstate->cstate.cs_ProjInfo, &isDone);
|
||||||
if (isDone != ExprEndResult)
|
if (isDone != ExprEndResult)
|
||||||
@@ -144,9 +138,8 @@ ExecScan(Scan *node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Tuple fails qual, so free per-tuple memory and try again.
|
* Tuple fails qual, so free per-tuple memory and try again.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.47 2001/03/22 03:59:26 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.48 2001/03/22 06:16:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -134,29 +134,26 @@ ExecCreateTupleTable(int initialSize) /* initial number of slots in
|
|||||||
TupleTable newtable; /* newly allocated table */
|
TupleTable newtable; /* newly allocated table */
|
||||||
TupleTableSlot *array; /* newly allocated slot array */
|
TupleTableSlot *array; /* newly allocated slot array */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(initialSize >= 1);
|
Assert(initialSize >= 1);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Now allocate our new table along with space for the pointers
|
* Now allocate our new table along with space for the pointers to the
|
||||||
* to the tuples.
|
* tuples.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
newtable = (TupleTable) palloc(sizeof(TupleTableData));
|
newtable = (TupleTable) palloc(sizeof(TupleTableData));
|
||||||
array = (TupleTableSlot *) palloc(initialSize * sizeof(TupleTableSlot));
|
array = (TupleTableSlot *) palloc(initialSize * sizeof(TupleTableSlot));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clean out the slots we just allocated
|
* clean out the slots we just allocated
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
MemSet(array, 0, initialSize * sizeof(TupleTableSlot));
|
MemSet(array, 0, initialSize * sizeof(TupleTableSlot));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize the new table and return it to the caller.
|
* initialize the new table and return it to the caller.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newtable->size = initialSize;
|
newtable->size = initialSize;
|
||||||
newtable->next = 0;
|
newtable->next = 0;
|
||||||
@@ -182,25 +179,22 @@ ExecDropTupleTable(TupleTable table, /* tuple table */
|
|||||||
TupleTableSlot *array; /* start of table array */
|
TupleTableSlot *array; /* start of table array */
|
||||||
int i; /* counter */
|
int i; /* counter */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(table != NULL);
|
Assert(table != NULL);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from the table
|
* get information from the table
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
array = table->array;
|
array = table->array;
|
||||||
next = table->next;
|
next = table->next;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* first free all the valid pointers in the tuple array
|
* first free all the valid pointers in the tuple array and drop
|
||||||
* and drop refcounts of any referenced buffers,
|
* refcounts of any referenced buffers, if that's what the caller
|
||||||
* if that's what the caller wants. (There is probably
|
* wants. (There is probably no good reason for the caller ever not
|
||||||
* no good reason for the caller ever not to want it!)
|
* to want it!)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (shouldFree)
|
if (shouldFree)
|
||||||
{
|
{
|
||||||
@@ -213,9 +207,8 @@ ExecDropTupleTable(TupleTable table, /* tuple table */
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* finally free the tuple array and the table itself.
|
* finally free the tuple array and the table itself.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pfree(array);
|
pfree(array);
|
||||||
pfree(table);
|
pfree(table);
|
||||||
@@ -242,36 +235,32 @@ ExecAllocTableSlot(TupleTable table)
|
|||||||
int slotnum; /* new slot number */
|
int slotnum; /* new slot number */
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(table != NULL);
|
Assert(table != NULL);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if our table is full we have to allocate a larger
|
* if our table is full we have to allocate a larger size table.
|
||||||
* size table. Since ExecAllocTableSlot() is only called
|
* Since ExecAllocTableSlot() is only called before the table is ever
|
||||||
* before the table is ever used to store tuples, we don't
|
* used to store tuples, we don't have to worry about the contents of
|
||||||
* have to worry about the contents of the old table.
|
* the old table. If this changes, then we will have to preserve the
|
||||||
* If this changes, then we will have to preserve the contents.
|
* contents. -cim 6/23/90
|
||||||
* -cim 6/23/90
|
|
||||||
*
|
*
|
||||||
* Unfortunately, we *cannot* do this. All of the nodes in
|
* Unfortunately, we *cannot* do this. All of the nodes in the plan that
|
||||||
* the plan that have already initialized their slots will have
|
* have already initialized their slots will have pointers into
|
||||||
* pointers into _freed_ memory. This leads to bad ends. We
|
* _freed_ memory. This leads to bad ends. We now count the number
|
||||||
* now count the number of slots we will need and create all the
|
* of slots we will need and create all the slots we will need ahead
|
||||||
* slots we will need ahead of time. The if below should never
|
* of time. The if below should never happen now. Fail if it does.
|
||||||
* happen now. Fail if it does. -mer 4 Aug 1992
|
* -mer 4 Aug 1992
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (table->next >= table->size)
|
if (table->next >= table->size)
|
||||||
elog(ERROR, "Plan requires more slots than are available"
|
elog(ERROR, "Plan requires more slots than are available"
|
||||||
"\n\tsend mail to your local executor guru to fix this");
|
"\n\tsend mail to your local executor guru to fix this");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* at this point, space in the table is guaranteed so we
|
* at this point, space in the table is guaranteed so we reserve the
|
||||||
* reserve the next slot, initialize and return it.
|
* next slot, initialize and return it.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
slotnum = table->next;
|
slotnum = table->next;
|
||||||
table->next++;
|
table->next++;
|
||||||
@@ -358,9 +347,9 @@ ExecStoreTuple(HeapTuple tuple,
|
|||||||
Buffer buffer,
|
Buffer buffer,
|
||||||
bool shouldFree)
|
bool shouldFree)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(slot != NULL);
|
Assert(slot != NULL);
|
||||||
/* passing shouldFree=true for a tuple on a disk page is not sane */
|
/* passing shouldFree=true for a tuple on a disk page is not sane */
|
||||||
@@ -369,10 +358,9 @@ ExecStoreTuple(HeapTuple tuple,
|
|||||||
/* clear out any old contents of the slot */
|
/* clear out any old contents of the slot */
|
||||||
ExecClearTuple(slot);
|
ExecClearTuple(slot);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* store the new tuple into the specified slot and
|
* store the new tuple into the specified slot and return the slot
|
||||||
* return the slot into which we stored the tuple.
|
* into which we stored the tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
slot->val = tuple;
|
slot->val = tuple;
|
||||||
slot->ttc_buffer = buffer;
|
slot->ttc_buffer = buffer;
|
||||||
@@ -401,21 +389,18 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
|
|||||||
{
|
{
|
||||||
HeapTuple oldtuple; /* prior contents of slot */
|
HeapTuple oldtuple; /* prior contents of slot */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(slot != NULL);
|
Assert(slot != NULL);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from the tuple table
|
* get information from the tuple table
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
oldtuple = slot->val;
|
oldtuple = slot->val;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* free the old contents of the specified slot if necessary.
|
* free the old contents of the specified slot if necessary.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (slot->ttc_shouldFree && oldtuple != NULL)
|
if (slot->ttc_shouldFree && oldtuple != NULL)
|
||||||
heap_freetuple(oldtuple);
|
heap_freetuple(oldtuple);
|
||||||
@@ -424,9 +409,8 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
|
|||||||
|
|
||||||
slot->ttc_shouldFree = true;/* probably useless code... */
|
slot->ttc_shouldFree = true;/* probably useless code... */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Drop the pin on the referenced buffer, if there is one.
|
* Drop the pin on the referenced buffer, if there is one.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (BufferIsValid(slot->ttc_buffer))
|
if (BufferIsValid(slot->ttc_buffer))
|
||||||
ReleaseBuffer(slot->ttc_buffer);
|
ReleaseBuffer(slot->ttc_buffer);
|
||||||
@@ -582,24 +566,21 @@ ExecTypeFromTL(List *targetList)
|
|||||||
Oid restype;
|
Oid restype;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* examine targetlist - if empty then return NULL
|
* examine targetlist - if empty then return NULL
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
len = ExecTargetListLength(targetList);
|
len = ExecTargetListLength(targetList);
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* allocate a new typeInfo
|
* allocate a new typeInfo
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
typeInfo = CreateTemplateTupleDesc(len);
|
typeInfo = CreateTemplateTupleDesc(len);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* scan list, generate type info for each entry
|
* scan list, generate type info for each entry
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
foreach(tlitem, targetList)
|
foreach(tlitem, targetList)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.74 2001/03/22 03:59:26 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.75 2001/03/22 06:16:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -336,18 +336,16 @@ ExecFreeProjectionInfo(CommonState *commonstate)
|
|||||||
{
|
{
|
||||||
ProjectionInfo *projInfo;
|
ProjectionInfo *projInfo;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get projection info. if NULL then this node has
|
* get projection info. if NULL then this node has none so we just
|
||||||
* none so we just return.
|
* return.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
projInfo = commonstate->cs_ProjInfo;
|
projInfo = commonstate->cs_ProjInfo;
|
||||||
if (projInfo == NULL)
|
if (projInfo == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clean up memory used.
|
* clean up memory used.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (projInfo->pi_tupValue != NULL)
|
if (projInfo->pi_tupValue != NULL)
|
||||||
pfree(projInfo->pi_tupValue);
|
pfree(projInfo->pi_tupValue);
|
||||||
@@ -365,18 +363,16 @@ ExecFreeExprContext(CommonState *commonstate)
|
|||||||
{
|
{
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get expression context. if NULL then this node has
|
* get expression context. if NULL then this node has none so we just
|
||||||
* none so we just return.
|
* return.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
econtext = commonstate->cs_ExprContext;
|
econtext = commonstate->cs_ExprContext;
|
||||||
if (econtext == NULL)
|
if (econtext == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clean up memory used.
|
* clean up memory used.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
|
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
|
||||||
pfree(econtext);
|
pfree(econtext);
|
||||||
@@ -476,18 +472,16 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
|
|||||||
IsSystemRelationName(RelationGetRelationName(resultRelation)))
|
IsSystemRelationName(RelationGetRelationName(resultRelation)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Get cached list of index OIDs
|
* Get cached list of index OIDs
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
indexoidlist = RelationGetIndexList(resultRelation);
|
indexoidlist = RelationGetIndexList(resultRelation);
|
||||||
len = length(indexoidlist);
|
len = length(indexoidlist);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* allocate space for result arrays
|
* allocate space for result arrays
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
|
relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
|
||||||
indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));
|
indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));
|
||||||
@@ -496,9 +490,8 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
|
|||||||
resultRelInfo->ri_IndexRelationDescs = relationDescs;
|
resultRelInfo->ri_IndexRelationDescs = relationDescs;
|
||||||
resultRelInfo->ri_IndexRelationInfo = indexInfoArray;
|
resultRelInfo->ri_IndexRelationInfo = indexInfoArray;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* For each index, open the index relation and save pg_index info.
|
* For each index, open the index relation and save pg_index info.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
i = 0;
|
i = 0;
|
||||||
foreach(indexoidscan, indexoidlist)
|
foreach(indexoidscan, indexoidlist)
|
||||||
@@ -508,24 +501,23 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
|
|||||||
HeapTuple indexTuple;
|
HeapTuple indexTuple;
|
||||||
IndexInfo *ii;
|
IndexInfo *ii;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Open (and lock, if necessary) the index relation
|
* Open (and lock, if necessary) the index relation
|
||||||
*
|
*
|
||||||
* Hack for not btree and hash indices: they use relation level
|
* Hack for not btree and hash indices: they use relation level
|
||||||
* exclusive locking on update (i.e. - they are not ready for MVCC)
|
* exclusive locking on update (i.e. - they are not ready for
|
||||||
* and so we have to exclusively lock indices here to prevent
|
* MVCC) and so we have to exclusively lock indices here to
|
||||||
* deadlocks if we will scan them - index_beginscan places
|
* prevent deadlocks if we will scan them - index_beginscan places
|
||||||
* AccessShareLock, indices update methods don't use locks at all.
|
* AccessShareLock, indices update methods don't use locks at all.
|
||||||
* We release this lock in ExecCloseIndices. Note, that hashes use
|
* We release this lock in ExecCloseIndices. Note, that hashes use
|
||||||
* page level locking - i.e. are not deadlock-free - let's them be
|
* page level locking - i.e. are not deadlock-free - let's them be
|
||||||
* on their way -:)) vadim 03-12-1998
|
* on their way -:)) vadim 03-12-1998
|
||||||
*
|
*
|
||||||
* If there are multiple not-btree-or-hash indices, all backends must
|
* If there are multiple not-btree-or-hash indices, all backends must
|
||||||
* lock the indices in the same order or we will get deadlocks here
|
* lock the indices in the same order or we will get deadlocks
|
||||||
* during concurrent updates. This is now guaranteed by
|
* here during concurrent updates. This is now guaranteed by
|
||||||
* RelationGetIndexList(), which promises to return the index list
|
* RelationGetIndexList(), which promises to return the index list
|
||||||
* in OID order. tgl 06-19-2000
|
* in OID order. tgl 06-19-2000
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
indexDesc = index_open(indexOid);
|
indexDesc = index_open(indexOid);
|
||||||
|
|
||||||
@@ -533,9 +525,8 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
|
|||||||
indexDesc->rd_rel->relam != HASH_AM_OID)
|
indexDesc->rd_rel->relam != HASH_AM_OID)
|
||||||
LockRelation(indexDesc, AccessExclusiveLock);
|
LockRelation(indexDesc, AccessExclusiveLock);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Get the pg_index tuple for the index
|
* Get the pg_index tuple for the index
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
indexTuple = SearchSysCache(INDEXRELID,
|
indexTuple = SearchSysCache(INDEXRELID,
|
||||||
ObjectIdGetDatum(indexOid),
|
ObjectIdGetDatum(indexOid),
|
||||||
@@ -543,9 +534,8 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
|
|||||||
if (!HeapTupleIsValid(indexTuple))
|
if (!HeapTupleIsValid(indexTuple))
|
||||||
elog(ERROR, "ExecOpenIndices: index %u not found", indexOid);
|
elog(ERROR, "ExecOpenIndices: index %u not found", indexOid);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* extract the index key information from the tuple
|
* extract the index key information from the tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ii = BuildIndexInfo(indexTuple);
|
ii = BuildIndexInfo(indexTuple);
|
||||||
|
|
||||||
@@ -647,9 +637,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
|
|||||||
/* Arrange for econtext's scan tuple to be the tuple under test */
|
/* Arrange for econtext's scan tuple to be the tuple under test */
|
||||||
econtext->ecxt_scantuple = slot;
|
econtext->ecxt_scantuple = slot;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* for each index, form and insert the index tuple
|
* for each index, form and insert the index tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < numIndices; i++)
|
for (i = 0; i < numIndices; i++)
|
||||||
{
|
{
|
||||||
@@ -669,10 +658,9 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* FormIndexDatum fills in its datum and null parameters
|
* FormIndexDatum fills in its datum and null parameters with
|
||||||
* with attribute information taken from the given heap tuple.
|
* attribute information taken from the given heap tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
FormIndexDatum(indexInfo,
|
FormIndexDatum(indexInfo,
|
||||||
heapTuple,
|
heapTuple,
|
||||||
@@ -687,9 +675,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
|
|||||||
&(heapTuple->t_self), /* tid of heap tuple */
|
&(heapTuple->t_self), /* tid of heap tuple */
|
||||||
heapRelation);
|
heapRelation);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* keep track of index inserts for debugging
|
* keep track of index inserts for debugging
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
IncrIndexInserted();
|
IncrIndexInserted();
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.44 2001/03/22 03:59:26 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.45 2001/03/22 06:16:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -162,9 +162,8 @@ init_sql_fcache(FmgrInfo *finfo)
|
|||||||
Datum tmp;
|
Datum tmp;
|
||||||
bool isNull;
|
bool isNull;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the procedure tuple corresponding to the given function Oid
|
* get the procedure tuple corresponding to the given function Oid
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
procedureTuple = SearchSysCache(PROCOID,
|
procedureTuple = SearchSysCache(PROCOID,
|
||||||
ObjectIdGetDatum(foid),
|
ObjectIdGetDatum(foid),
|
||||||
@@ -175,9 +174,8 @@ init_sql_fcache(FmgrInfo *finfo)
|
|||||||
|
|
||||||
procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
|
procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the return type from the procedure tuple
|
* get the return type from the procedure tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
typeTuple = SearchSysCache(TYPEOID,
|
typeTuple = SearchSysCache(TYPEOID,
|
||||||
ObjectIdGetDatum(procedureStruct->prorettype),
|
ObjectIdGetDatum(procedureStruct->prorettype),
|
||||||
@@ -191,9 +189,8 @@ init_sql_fcache(FmgrInfo *finfo)
|
|||||||
fcache = (SQLFunctionCachePtr) palloc(sizeof(SQLFunctionCache));
|
fcache = (SQLFunctionCachePtr) palloc(sizeof(SQLFunctionCache));
|
||||||
MemSet(fcache, 0, sizeof(SQLFunctionCache));
|
MemSet(fcache, 0, sizeof(SQLFunctionCache));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the type length and by-value flag from the type tuple
|
* get the type length and by-value flag from the type tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
fcache->typlen = typeStruct->typlen;
|
fcache->typlen = typeStruct->typlen;
|
||||||
if (typeStruct->typrelid == InvalidOid)
|
if (typeStruct->typrelid == InvalidOid)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.76 2001/03/22 03:59:27 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.77 2001/03/22 06:16:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -202,13 +202,12 @@ initialize_aggregate(AggStatePerAgg peraggstate)
|
|||||||
peraggstate->transValue = peraggstate->initValue;
|
peraggstate->transValue = peraggstate->initValue;
|
||||||
peraggstate->transValueIsNull = peraggstate->initValueIsNull;
|
peraggstate->transValueIsNull = peraggstate->initValueIsNull;
|
||||||
|
|
||||||
/* ------------------------------------------
|
/*
|
||||||
* If the initial value for the transition state doesn't exist in the
|
* If the initial value for the transition state doesn't exist in the
|
||||||
* pg_aggregate table then we will let the first non-NULL value returned
|
* pg_aggregate table then we will let the first non-NULL value
|
||||||
* from the outer procNode become the initial value. (This is useful for
|
* returned from the outer procNode become the initial value. (This is
|
||||||
* aggregates like max() and min().) The noTransValue flag signals that
|
* useful for aggregates like max() and min().) The noTransValue flag
|
||||||
* we still need to do this.
|
* signals that we still need to do this.
|
||||||
* ------------------------------------------
|
|
||||||
*/
|
*/
|
||||||
peraggstate->noTransValue = peraggstate->initValueIsNull;
|
peraggstate->noTransValue = peraggstate->initValueIsNull;
|
||||||
}
|
}
|
||||||
@@ -477,9 +476,8 @@ ExecAgg(Agg *node)
|
|||||||
int aggno;
|
int aggno;
|
||||||
bool isNull;
|
bool isNull;
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* get state info from node
|
* get state info from node
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
aggstate = node->aggstate;
|
aggstate = node->aggstate;
|
||||||
estate = node->plan.state;
|
estate = node->plan.state;
|
||||||
@@ -516,9 +514,8 @@ ExecAgg(Agg *node)
|
|||||||
|
|
||||||
inputTuple = NULL; /* no saved input tuple yet */
|
inputTuple = NULL; /* no saved input tuple yet */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* for each tuple from the outer plan, update all the aggregates
|
* for each tuple from the outer plan, update all the aggregates
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@@ -829,9 +826,8 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||||||
outerPlan = outerPlan(node);
|
outerPlan = outerPlan(node);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize source tuple type.
|
* initialize source tuple type.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignScanTypeFromOuterPlan((Plan *) node, &aggstate->csstate);
|
ExecAssignScanTypeFromOuterPlan((Plan *) node, &aggstate->csstate);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.39 2001/01/24 19:42:54 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.40 2001/03/22 06:16:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -81,9 +81,8 @@ exec_append_initialize_next(Append *node)
|
|||||||
int whichplan;
|
int whichplan;
|
||||||
int nplans;
|
int nplans;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from the append node
|
* get information from the append node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
estate = node->plan.state;
|
estate = node->plan.state;
|
||||||
appendstate = node->appendstate;
|
appendstate = node->appendstate;
|
||||||
@@ -92,35 +91,34 @@ exec_append_initialize_next(Append *node)
|
|||||||
|
|
||||||
if (whichplan < 0)
|
if (whichplan < 0)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* if scanning in reverse, we start at
|
/*
|
||||||
* the last scan in the list and then
|
* if scanning in reverse, we start at the last scan in the list
|
||||||
* proceed back to the first.. in any case
|
* and then proceed back to the first.. in any case we inform
|
||||||
* we inform ExecProcAppend that we are
|
* ExecProcAppend that we are at the end of the line by returning
|
||||||
* at the end of the line by returning FALSE
|
* FALSE
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
appendstate->as_whichplan = 0;
|
appendstate->as_whichplan = 0;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
else if (whichplan >= nplans)
|
else if (whichplan >= nplans)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* as above, end the scan if we go beyond
|
/*
|
||||||
* the last scan in our list..
|
* as above, end the scan if we go beyond the last scan in our
|
||||||
* ----------------
|
* list..
|
||||||
*/
|
*/
|
||||||
appendstate->as_whichplan = nplans - 1;
|
appendstate->as_whichplan = nplans - 1;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* initialize the scan
|
* initialize the scan
|
||||||
*
|
*
|
||||||
* If we are controlling the target relation, select the proper
|
* If we are controlling the target relation, select the proper
|
||||||
* active ResultRelInfo and junk filter for this target.
|
* active ResultRelInfo and junk filter for this target.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (node->isTarget)
|
if (node->isTarget)
|
||||||
{
|
{
|
||||||
@@ -162,10 +160,8 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
|
|||||||
|
|
||||||
CXT1_printf("ExecInitAppend: context is %d\n", CurrentMemoryContext);
|
CXT1_printf("ExecInitAppend: context is %d\n", CurrentMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign execution state to node and get information
|
* assign execution state to node and get information for append state
|
||||||
* for append state
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->plan.state = estate;
|
node->plan.state = estate;
|
||||||
|
|
||||||
@@ -175,9 +171,8 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
|
|||||||
initialized = (bool *) palloc(nplans * sizeof(bool));
|
initialized = (bool *) palloc(nplans * sizeof(bool));
|
||||||
MemSet(initialized, 0, nplans * sizeof(bool));
|
MemSet(initialized, 0, nplans * sizeof(bool));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create new AppendState for our append node
|
* create new AppendState for our append node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
appendstate = makeNode(AppendState);
|
appendstate = makeNode(AppendState);
|
||||||
appendstate->as_whichplan = 0;
|
appendstate->as_whichplan = 0;
|
||||||
@@ -186,26 +181,24 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
|
|||||||
|
|
||||||
node->appendstate = appendstate;
|
node->appendstate = appendstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* Append plans don't have expression contexts because they
|
* Append plans don't have expression contexts because they never call
|
||||||
* never call ExecQual or ExecProject.
|
* ExecQual or ExecProject.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define APPEND_NSLOTS 1
|
#define APPEND_NSLOTS 1
|
||||||
/* ----------------
|
|
||||||
* append nodes still have Result slots, which hold pointers
|
/*
|
||||||
* to tuples, so we have to initialize them.
|
* append nodes still have Result slots, which hold pointers to
|
||||||
* ----------------
|
* tuples, so we have to initialize them.
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &appendstate->cstate);
|
ExecInitResultTupleSlot(estate, &appendstate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* call ExecInitNode on each of the plans in our list
|
* call ExecInitNode on each of the plans in our list and save the
|
||||||
* and save the results into the array "initialized"
|
* results into the array "initialized"
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < nplans; i++)
|
for (i = 0; i < nplans; i++)
|
||||||
{
|
{
|
||||||
@@ -216,16 +209,14 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
|
|||||||
initialized[i] = ExecInitNode(initNode, estate, (Plan *) node);
|
initialized[i] = ExecInitNode(initNode, estate, (Plan *) node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize tuple type
|
* initialize tuple type
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &appendstate->cstate);
|
ExecAssignResultTypeFromTL((Plan *) node, &appendstate->cstate);
|
||||||
appendstate->cstate.cs_ProjInfo = NULL;
|
appendstate->cstate.cs_ProjInfo = NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* return the result from the first subplan's initialization
|
* return the result from the first subplan's initialization
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
appendstate->as_whichplan = 0;
|
appendstate->as_whichplan = 0;
|
||||||
exec_append_initialize_next(node);
|
exec_append_initialize_next(node);
|
||||||
@@ -264,9 +255,8 @@ ExecProcAppend(Append *node)
|
|||||||
TupleTableSlot *result_slot;
|
TupleTableSlot *result_slot;
|
||||||
ScanDirection direction;
|
ScanDirection direction;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from the node
|
* get information from the node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
appendstate = node->appendstate;
|
appendstate = node->appendstate;
|
||||||
estate = node->plan.state;
|
estate = node->plan.state;
|
||||||
@@ -275,49 +265,46 @@ ExecProcAppend(Append *node)
|
|||||||
whichplan = appendstate->as_whichplan;
|
whichplan = appendstate->as_whichplan;
|
||||||
result_slot = appendstate->cstate.cs_ResultTupleSlot;
|
result_slot = appendstate->cstate.cs_ResultTupleSlot;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* figure out which subplan we are currently processing
|
* figure out which subplan we are currently processing
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
subnode = (Plan *) nth(whichplan, appendplans);
|
subnode = (Plan *) nth(whichplan, appendplans);
|
||||||
|
|
||||||
if (subnode == NULL)
|
if (subnode == NULL)
|
||||||
elog(DEBUG, "ExecProcAppend: subnode is NULL");
|
elog(DEBUG, "ExecProcAppend: subnode is NULL");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get a tuple from the subplan
|
* get a tuple from the subplan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
result = ExecProcNode(subnode, (Plan *) node);
|
result = ExecProcNode(subnode, (Plan *) node);
|
||||||
|
|
||||||
if (!TupIsNull(result))
|
if (!TupIsNull(result))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* if the subplan gave us something then place a copy of
|
/*
|
||||||
* whatever we get into our result slot and return it.
|
* if the subplan gave us something then place a copy of whatever
|
||||||
|
* we get into our result slot and return it.
|
||||||
*
|
*
|
||||||
* Note we rely on the subplan to retain ownership of the
|
* Note we rely on the subplan to retain ownership of the tuple for
|
||||||
* tuple for as long as we need it --- we don't copy it.
|
* as long as we need it --- we don't copy it.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
return ExecStoreTuple(result->val, result_slot, InvalidBuffer, false);
|
return ExecStoreTuple(result->val, result_slot, InvalidBuffer, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* .. go on to the "next" subplan in the appropriate
|
/*
|
||||||
* direction and try processing again (recursively)
|
* .. go on to the "next" subplan in the appropriate direction and
|
||||||
* ----------------
|
* try processing again (recursively)
|
||||||
*/
|
*/
|
||||||
if (ScanDirectionIsForward(direction))
|
if (ScanDirectionIsForward(direction))
|
||||||
appendstate->as_whichplan++;
|
appendstate->as_whichplan++;
|
||||||
else
|
else
|
||||||
appendstate->as_whichplan--;
|
appendstate->as_whichplan--;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* return something from next node or an empty slot
|
* return something from next node or an empty slot if all of our
|
||||||
* if all of our subplans have been exhausted.
|
* subplans have been exhausted.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (exec_append_initialize_next(node))
|
if (exec_append_initialize_next(node))
|
||||||
{
|
{
|
||||||
@@ -347,9 +334,8 @@ ExecEndAppend(Append *node)
|
|||||||
bool *initialized;
|
bool *initialized;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from the node
|
* get information from the node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
appendstate = node->appendstate;
|
appendstate = node->appendstate;
|
||||||
estate = node->plan.state;
|
estate = node->plan.state;
|
||||||
@@ -357,9 +343,8 @@ ExecEndAppend(Append *node)
|
|||||||
nplans = appendstate->as_nplans;
|
nplans = appendstate->as_nplans;
|
||||||
initialized = appendstate->as_initialized;
|
initialized = appendstate->as_initialized;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* shut down each of the subscans
|
* shut down each of the subscans
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < nplans; i++)
|
for (i = 0; i < nplans; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
* locate group boundaries.
|
* locate group boundaries.
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.42 2001/03/22 03:59:27 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.43 2001/03/22 06:16:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -76,9 +76,8 @@ ExecGroupEveryTuple(Group *node)
|
|||||||
ProjectionInfo *projInfo;
|
ProjectionInfo *projInfo;
|
||||||
TupleTableSlot *resultSlot;
|
TupleTableSlot *resultSlot;
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* get state info from node
|
* get state info from node
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
grpstate = node->grpstate;
|
grpstate = node->grpstate;
|
||||||
if (grpstate->grp_done)
|
if (grpstate->grp_done)
|
||||||
@@ -156,10 +155,9 @@ ExecGroupEveryTuple(Group *node)
|
|||||||
InvalidBuffer, false);
|
InvalidBuffer, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* form a projection tuple, store it in the result tuple
|
* form a projection tuple, store it in the result tuple slot and
|
||||||
* slot and return it.
|
* return it.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
projInfo = grpstate->csstate.cstate.cs_ProjInfo;
|
projInfo = grpstate->csstate.cstate.cs_ProjInfo;
|
||||||
|
|
||||||
@@ -187,9 +185,8 @@ ExecGroupOneTuple(Group *node)
|
|||||||
ProjectionInfo *projInfo;
|
ProjectionInfo *projInfo;
|
||||||
TupleTableSlot *resultSlot;
|
TupleTableSlot *resultSlot;
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* get state info from node
|
* get state info from node
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
grpstate = node->grpstate;
|
grpstate = node->grpstate;
|
||||||
if (grpstate->grp_done)
|
if (grpstate->grp_done)
|
||||||
@@ -243,10 +240,9 @@ ExecGroupOneTuple(Group *node)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* form a projection tuple, store it in the result tuple
|
* form a projection tuple, store it in the result tuple slot and
|
||||||
* slot and return it.
|
* return it.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
projInfo = grpstate->csstate.cstate.cs_ProjInfo;
|
projInfo = grpstate->csstate.cstate.cs_ProjInfo;
|
||||||
|
|
||||||
@@ -316,9 +312,8 @@ ExecInitGroup(Group *node, EState *estate, Plan *parent)
|
|||||||
outerPlan = outerPlan(node);
|
outerPlan = outerPlan(node);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize tuple type.
|
* initialize tuple type.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignScanTypeFromOuterPlan((Plan *) node, &grpstate->csstate);
|
ExecAssignScanTypeFromOuterPlan((Plan *) node, &grpstate->csstate);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* $Id: nodeHash.c,v 1.55 2001/03/22 03:59:27 momjian Exp $
|
* $Id: nodeHash.c,v 1.56 2001/03/22 06:16:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -55,9 +55,8 @@ ExecHash(Hash *node)
|
|||||||
int nbatch;
|
int nbatch;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get state info from node
|
* get state info from node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hashstate = node->hashstate;
|
hashstate = node->hashstate;
|
||||||
@@ -72,25 +71,23 @@ ExecHash(Hash *node)
|
|||||||
|
|
||||||
if (nbatch > 0)
|
if (nbatch > 0)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* Open temp files for inner batches, if needed.
|
/*
|
||||||
* Note that file buffers are palloc'd in regular executor context.
|
* Open temp files for inner batches, if needed. Note that file
|
||||||
* ----------------
|
* buffers are palloc'd in regular executor context.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < nbatch; i++)
|
for (i = 0; i < nbatch; i++)
|
||||||
hashtable->innerBatchFile[i] = BufFileCreateTemp();
|
hashtable->innerBatchFile[i] = BufFileCreateTemp();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* set expression context
|
* set expression context
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
hashkey = node->hashkey;
|
hashkey = node->hashkey;
|
||||||
econtext = hashstate->cstate.cs_ExprContext;
|
econtext = hashstate->cstate.cs_ExprContext;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get all inner tuples and insert into the hash table (or temp files)
|
* get all inner tuples and insert into the hash table (or temp files)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@@ -102,10 +99,9 @@ ExecHash(Hash *node)
|
|||||||
ExecClearTuple(slot);
|
ExecClearTuple(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* Return the slot so that we have the tuple descriptor
|
* Return the slot so that we have the tuple descriptor when we need
|
||||||
* when we need to save/restore them. -Jeff 11 July 1991
|
* to save/restore them. -Jeff 11 July 1991
|
||||||
* ---------------------
|
|
||||||
*/
|
*/
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
@@ -125,45 +121,39 @@ ExecInitHash(Hash *node, EState *estate, Plan *parent)
|
|||||||
SO1_printf("ExecInitHash: %s\n",
|
SO1_printf("ExecInitHash: %s\n",
|
||||||
"initializing hash node");
|
"initializing hash node");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign the node's execution state
|
* assign the node's execution state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->plan.state = estate;
|
node->plan.state = estate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create state structure
|
* create state structure
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
hashstate = makeNode(HashState);
|
hashstate = makeNode(HashState);
|
||||||
node->hashstate = hashstate;
|
node->hashstate = hashstate;
|
||||||
hashstate->hashtable = NULL;
|
hashstate->hashtable = NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* + create expression context for node
|
* create expression context for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &hashstate->cstate);
|
ExecAssignExprContext(estate, &hashstate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize our result slot
|
* initialize our result slot
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &hashstate->cstate);
|
ExecInitResultTupleSlot(estate, &hashstate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initializes child nodes
|
* initializes child nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan(node);
|
outerPlan = outerPlan(node);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize tuple type. no need to initialize projection
|
* initialize tuple type. no need to initialize projection info
|
||||||
* info because this node doesn't do projections
|
* because this node doesn't do projections
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &hashstate->cstate);
|
ExecAssignResultTypeFromOuterPlan((Plan *) node, &hashstate->cstate);
|
||||||
hashstate->cstate.cs_ProjInfo = NULL;
|
hashstate->cstate.cs_ProjInfo = NULL;
|
||||||
@@ -192,23 +182,20 @@ ExecEndHash(Hash *node)
|
|||||||
HashState *hashstate;
|
HashState *hashstate;
|
||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get info from the hash state
|
* get info from the hash state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
hashstate = node->hashstate;
|
hashstate = node->hashstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* free projection info. no need to free result type info
|
* free projection info. no need to free result type info because
|
||||||
* because that came from the outer plan...
|
* that came from the outer plan...
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&hashstate->cstate);
|
ExecFreeProjectionInfo(&hashstate->cstate);
|
||||||
ExecFreeExprContext(&hashstate->cstate);
|
ExecFreeExprContext(&hashstate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* shut down the subplan
|
* shut down the subplan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan(node);
|
outerPlan = outerPlan(node);
|
||||||
ExecEndNode(outerPlan, (Plan *) node);
|
ExecEndNode(outerPlan, (Plan *) node);
|
||||||
@@ -239,13 +226,13 @@ ExecHashTableCreate(Hash *node)
|
|||||||
int i;
|
int i;
|
||||||
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
|
||||||
* (it's the "outer" subtree of this node, but the inner relation of
|
* the "outer" subtree of this node, but the inner relation of the
|
||||||
* the hashjoin).
|
* hashjoin).
|
||||||
* Caution: this is only the planner's estimates, and so
|
*
|
||||||
* can't be trusted too far. Apply a healthy fudge factor.
|
* Caution: this is only the planner's estimates, and so can't be trusted
|
||||||
* ----------------
|
* too far. Apply a healthy fudge factor.
|
||||||
*/
|
*/
|
||||||
outerNode = outerPlan(node);
|
outerNode = outerPlan(node);
|
||||||
ntuples = outerNode->plan_rows;
|
ntuples = outerNode->plan_rows;
|
||||||
@@ -331,11 +318,11 @@ ExecHashTableCreate(Hash *node)
|
|||||||
nbatch, totalbuckets, nbuckets);
|
nbatch, totalbuckets, nbuckets);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Initialize the hash table control block.
|
* Initialize the hash table control block.
|
||||||
|
*
|
||||||
* The hashtable control block is just palloc'd from the executor's
|
* The hashtable control block is just palloc'd from the executor's
|
||||||
* per-query memory context.
|
* per-query memory context.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
hashtable = (HashJoinTable) palloc(sizeof(HashTableData));
|
hashtable = (HashJoinTable) palloc(sizeof(HashTableData));
|
||||||
hashtable->nbuckets = nbuckets;
|
hashtable->nbuckets = nbuckets;
|
||||||
@@ -348,18 +335,16 @@ ExecHashTableCreate(Hash *node)
|
|||||||
hashtable->innerBatchSize = NULL;
|
hashtable->innerBatchSize = NULL;
|
||||||
hashtable->outerBatchSize = NULL;
|
hashtable->outerBatchSize = NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Get info about the datatype of the hash key.
|
* Get info about the datatype of the hash key.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
get_typlenbyval(exprType(node->hashkey),
|
get_typlenbyval(exprType(node->hashkey),
|
||||||
&hashtable->typLen,
|
&hashtable->typLen,
|
||||||
&hashtable->typByVal);
|
&hashtable->typByVal);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Create temporary memory contexts in which to keep the hashtable
|
* Create temporary memory contexts in which to keep the hashtable
|
||||||
* working storage. See notes in executor/hashjoin.h.
|
* working storage. See notes in executor/hashjoin.h.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
hashtable->hashCxt = AllocSetContextCreate(CurrentMemoryContext,
|
hashtable->hashCxt = AllocSetContextCreate(CurrentMemoryContext,
|
||||||
"HashTableContext",
|
"HashTableContext",
|
||||||
@@ -379,9 +364,9 @@ ExecHashTableCreate(Hash *node)
|
|||||||
|
|
||||||
if (nbatch > 0)
|
if (nbatch > 0)
|
||||||
{
|
{
|
||||||
/* ---------------
|
|
||||||
|
/*
|
||||||
* allocate and initialize the file arrays in hashCxt
|
* allocate and initialize the file arrays in hashCxt
|
||||||
* ---------------
|
|
||||||
*/
|
*/
|
||||||
hashtable->innerBatchFile = (BufFile **)
|
hashtable->innerBatchFile = (BufFile **)
|
||||||
palloc(nbatch * sizeof(BufFile *));
|
palloc(nbatch * sizeof(BufFile *));
|
||||||
@@ -464,15 +449,14 @@ ExecHashTableInsert(HashJoinTable hashtable,
|
|||||||
TupleTableSlot *slot = econtext->ecxt_innertuple;
|
TupleTableSlot *slot = econtext->ecxt_innertuple;
|
||||||
HeapTuple heapTuple = slot->val;
|
HeapTuple heapTuple = slot->val;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* decide whether to put the tuple in the hash table or a tmp file
|
* decide whether to put the tuple in the hash table or a tmp file
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (bucketno < hashtable->nbuckets)
|
if (bucketno < hashtable->nbuckets)
|
||||||
{
|
{
|
||||||
/* ---------------
|
|
||||||
|
/*
|
||||||
* put the tuple in hash table
|
* put the tuple in hash table
|
||||||
* ---------------
|
|
||||||
*/
|
*/
|
||||||
HashJoinTuple hashTuple;
|
HashJoinTuple hashTuple;
|
||||||
int hashTupleSize;
|
int hashTupleSize;
|
||||||
@@ -496,9 +480,9 @@ ExecHashTableInsert(HashJoinTable hashtable,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* -----------------
|
|
||||||
|
/*
|
||||||
* 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);
|
||||||
@@ -524,20 +508,18 @@ ExecHashGetBucket(HashJoinTable hashtable,
|
|||||||
Datum keyval;
|
Datum keyval;
|
||||||
bool isNull;
|
bool isNull;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Get the join attribute value of the tuple
|
* Get the join attribute value of the tuple
|
||||||
*
|
*
|
||||||
* We reset the eval context each time to avoid any possibility
|
* We reset the eval context each time to avoid any possibility of memory
|
||||||
* of memory leaks in the hash function.
|
* leaks in the hash function.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
keyval = ExecEvalExprSwitchContext(hashkey, econtext, &isNull, NULL);
|
keyval = ExecEvalExprSwitchContext(hashkey, econtext, &isNull, NULL);
|
||||||
|
|
||||||
/* ------------------
|
/*
|
||||||
* compute the hash function
|
* compute the hash function
|
||||||
* ------------------
|
|
||||||
*/
|
*/
|
||||||
if (isNull)
|
if (isNull)
|
||||||
bucketno = 0;
|
bucketno = 0;
|
||||||
@@ -606,9 +588,8 @@ ExecScanHashBucket(HashJoinState *hjstate,
|
|||||||
hashTuple = hashTuple->next;
|
hashTuple = hashTuple->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* no match
|
* no match
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.37 2001/03/22 03:59:27 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.38 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -64,9 +64,8 @@ ExecHashJoin(HashJoin *node)
|
|||||||
int i;
|
int i;
|
||||||
bool hashPhaseDone;
|
bool hashPhaseDone;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from HashJoin node
|
* get information from HashJoin node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
hjstate = node->hashjoinstate;
|
hjstate = node->hashjoinstate;
|
||||||
hjclauses = node->hashclauses;
|
hjclauses = node->hashclauses;
|
||||||
@@ -79,18 +78,16 @@ ExecHashJoin(HashJoin *node)
|
|||||||
hashPhaseDone = hjstate->hj_hashdone;
|
hashPhaseDone = hjstate->hj_hashdone;
|
||||||
dir = estate->es_direction;
|
dir = estate->es_direction;
|
||||||
|
|
||||||
/* -----------------
|
/*
|
||||||
* get information from HashJoin state
|
* get information from HashJoin state
|
||||||
* -----------------
|
|
||||||
*/
|
*/
|
||||||
hashtable = hjstate->hj_HashTable;
|
hashtable = hjstate->hj_HashTable;
|
||||||
econtext = hjstate->jstate.cs_ExprContext;
|
econtext = hjstate->jstate.cs_ExprContext;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Check to see if we're still projecting out tuples from a previous
|
* Check to see if we're still projecting out tuples from a previous
|
||||||
* join tuple (because there is a function-returning-set in the
|
* join tuple (because there is a function-returning-set in the
|
||||||
* projection expressions). If so, try to project another one.
|
* projection expressions). If so, try to project another one.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (hjstate->jstate.cs_TupFromTlist)
|
if (hjstate->jstate.cs_TupFromTlist)
|
||||||
{
|
{
|
||||||
@@ -103,42 +100,39 @@ ExecHashJoin(HashJoin *node)
|
|||||||
hjstate->jstate.cs_TupFromTlist = false;
|
hjstate->jstate.cs_TupFromTlist = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Reset per-tuple memory context to free any expression evaluation
|
* Reset per-tuple memory context to free any expression evaluation
|
||||||
* storage allocated in the previous tuple cycle. Note this can't
|
* storage allocated in the previous tuple cycle. Note this can't
|
||||||
* happen until we're done projecting out tuples from a join tuple.
|
* happen until we're done projecting out tuples from a join tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if this is the first call, build the hash table for inner relation
|
* if this is the first call, build the hash table for inner relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!hashPhaseDone)
|
if (!hashPhaseDone)
|
||||||
{ /* if the hash phase not completed */
|
{ /* if the hash phase not completed */
|
||||||
if (hashtable == NULL)
|
if (hashtable == NULL)
|
||||||
{ /* if the hash table has not been created */
|
{ /* if the hash table has not been created */
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* create the hash table
|
* create the hash table
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
hashtable = ExecHashTableCreate(hashNode);
|
hashtable = ExecHashTableCreate(hashNode);
|
||||||
hjstate->hj_HashTable = hashtable;
|
hjstate->hj_HashTable = hashtable;
|
||||||
hjstate->hj_InnerHashKey = hashNode->hashkey;
|
hjstate->hj_InnerHashKey = hashNode->hashkey;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* execute the Hash node, to build the hash table
|
* execute the Hash node, to build the hash table
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
hashNode->hashstate->hashtable = hashtable;
|
hashNode->hashstate->hashtable = hashtable;
|
||||||
innerTupleSlot = ExecProcNode((Plan *) hashNode, (Plan *) node);
|
innerTupleSlot = ExecProcNode((Plan *) hashNode, (Plan *) node);
|
||||||
}
|
}
|
||||||
hjstate->hj_hashdone = true;
|
hjstate->hj_hashdone = true;
|
||||||
/* ----------------
|
|
||||||
* Open temp files for outer batches, if needed.
|
/*
|
||||||
* Note that file buffers are palloc'd in regular executor context.
|
* Open temp files for outer batches, if needed. Note that file
|
||||||
* ----------------
|
* buffers are palloc'd in regular executor context.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < hashtable->nbatch; i++)
|
for (i = 0; i < hashtable->nbatch; i++)
|
||||||
hashtable->outerBatchFile[i] = BufFileCreateTemp();
|
hashtable->outerBatchFile[i] = BufFileCreateTemp();
|
||||||
@@ -146,9 +140,8 @@ ExecHashJoin(HashJoin *node)
|
|||||||
else if (hashtable == NULL)
|
else if (hashtable == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Now get an outer tuple and probe into the hash table for matches
|
* Now get an outer tuple and probe into the hash table for matches
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = hjstate->jstate.cs_OuterTupleSlot;
|
outerTupleSlot = hjstate->jstate.cs_OuterTupleSlot;
|
||||||
outerVar = (Node *) get_leftop(clause);
|
outerVar = (Node *) get_leftop(clause);
|
||||||
@@ -188,11 +181,10 @@ ExecHashJoin(HashJoin *node)
|
|||||||
outerVar);
|
outerVar);
|
||||||
hjstate->hj_CurTuple = NULL;
|
hjstate->hj_CurTuple = NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Now we've got an outer tuple and the corresponding hash bucket,
|
* Now we've got an outer tuple and the corresponding hash
|
||||||
* but this tuple may not belong to the current batch.
|
* bucket, but this tuple may not belong to the current batch.
|
||||||
* This need only be checked in the first pass.
|
* This need only be checked in the first pass.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (hashtable->curbatch == 0)
|
if (hashtable->curbatch == 0)
|
||||||
{
|
{
|
||||||
@@ -240,14 +232,13 @@ ExecHashJoin(HashJoin *node)
|
|||||||
/* reset temp memory each time to avoid leaks from qual expr */
|
/* reset temp memory each time to avoid leaks from qual expr */
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if we pass the qual, then save state for next call and
|
* if we pass the qual, then save state for next call and have
|
||||||
* have ExecProject form the projection, store it
|
* ExecProject form the projection, store it in the tuple
|
||||||
* in the tuple table, and return the slot.
|
* table, and return the slot.
|
||||||
*
|
*
|
||||||
* Only the joinquals determine MatchedOuter status,
|
* Only the joinquals determine MatchedOuter status, but all
|
||||||
* but all quals must pass to actually return the tuple.
|
* quals must pass to actually return the tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (ExecQual(joinqual, econtext, false))
|
if (ExecQual(joinqual, econtext, false))
|
||||||
{
|
{
|
||||||
@@ -269,11 +260,10 @@ ExecHashJoin(HashJoin *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Now the current outer tuple has run out of matches,
|
* Now the current outer tuple has run out of matches, so check
|
||||||
* so check whether to emit a dummy outer-join tuple.
|
* whether to emit a dummy outer-join tuple. If not, loop around
|
||||||
* If not, loop around to get a new outer tuple.
|
* to get a new outer tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
hjstate->hj_NeedNewOuter = true;
|
hjstate->hj_NeedNewOuter = true;
|
||||||
|
|
||||||
@@ -291,11 +281,11 @@ ExecHashJoin(HashJoin *node)
|
|||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* qualification was satisfied so we project and
|
/*
|
||||||
* return the slot containing the result tuple
|
* qualification was satisfied so we project and return
|
||||||
* using ExecProject().
|
* the slot containing the result tuple using
|
||||||
* ----------------
|
* ExecProject().
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
|
|
||||||
@@ -325,30 +315,26 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
|||||||
Plan *outerNode;
|
Plan *outerNode;
|
||||||
Hash *hashNode;
|
Hash *hashNode;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign the node's execution state
|
* assign the node's execution state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->join.plan.state = estate;
|
node->join.plan.state = estate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create state structure
|
* create state structure
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
hjstate = makeNode(HashJoinState);
|
hjstate = makeNode(HashJoinState);
|
||||||
node->hashjoinstate = hjstate;
|
node->hashjoinstate = hjstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* + create expression context for node
|
* create expression context for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &hjstate->jstate);
|
ExecAssignExprContext(estate, &hjstate->jstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initializes child nodes
|
* initializes child nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerNode = outerPlan((Plan *) node);
|
outerNode = outerPlan((Plan *) node);
|
||||||
hashNode = (Hash *) innerPlan((Plan *) node);
|
hashNode = (Hash *) innerPlan((Plan *) node);
|
||||||
@@ -357,9 +343,9 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
|||||||
ExecInitNode((Plan *) hashNode, estate, (Plan *) node);
|
ExecInitNode((Plan *) hashNode, estate, (Plan *) node);
|
||||||
|
|
||||||
#define HASHJOIN_NSLOTS 3
|
#define HASHJOIN_NSLOTS 3
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &hjstate->jstate);
|
ExecInitResultTupleSlot(estate, &hjstate->jstate);
|
||||||
hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate);
|
hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate);
|
||||||
@@ -378,14 +364,12 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
|||||||
(int) node->join.jointype);
|
(int) node->join.jointype);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now for some voodoo. our temporary tuple slot
|
* now for some voodoo. our temporary tuple slot is actually the
|
||||||
* is actually the result tuple slot of the Hash node
|
* result tuple slot of the Hash node (which is our inner plan). we
|
||||||
* (which is our inner plan). we do this because Hash
|
* do this because Hash nodes don't return tuples via ExecProcNode()
|
||||||
* nodes don't return tuples via ExecProcNode() -- instead
|
* -- instead the hash join node uses ExecScanHashBucket() to get at
|
||||||
* the hash join node uses ExecScanHashBucket() to get
|
* the contents of the hash table. -cim 6/9/91
|
||||||
* at the contents of the hash table. -cim 6/9/91
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
HashState *hashstate = hashNode->hashstate;
|
HashState *hashstate = hashNode->hashstate;
|
||||||
@@ -394,9 +378,8 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
|||||||
hjstate->hj_HashTupleSlot = slot;
|
hjstate->hj_HashTupleSlot = slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize tuple type and projection info
|
* initialize tuple type and projection info
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &hjstate->jstate);
|
ExecAssignResultTypeFromTL((Plan *) node, &hjstate->jstate);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &hjstate->jstate);
|
ExecAssignProjectionInfo((Plan *) node, &hjstate->jstate);
|
||||||
@@ -405,9 +388,8 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
|||||||
ExecGetTupType(outerNode),
|
ExecGetTupType(outerNode),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize hash-specific info
|
* initialize hash-specific info
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hjstate->hj_hashdone = false;
|
hjstate->hj_hashdone = false;
|
||||||
@@ -444,15 +426,13 @@ ExecEndHashJoin(HashJoin *node)
|
|||||||
{
|
{
|
||||||
HashJoinState *hjstate;
|
HashJoinState *hjstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get info from the HashJoin state
|
* get info from the HashJoin state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
hjstate = node->hashjoinstate;
|
hjstate = node->hashjoinstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* free hash table in case we end plan before all tuples are retrieved
|
* free hash table in case we end plan before all tuples are retrieved
|
||||||
* ---------------
|
|
||||||
*/
|
*/
|
||||||
if (hjstate->hj_HashTable)
|
if (hjstate->hj_HashTable)
|
||||||
{
|
{
|
||||||
@@ -460,28 +440,24 @@ ExecEndHashJoin(HashJoin *node)
|
|||||||
hjstate->hj_HashTable = NULL;
|
hjstate->hj_HashTable = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* Free the projection info and the scan attribute info
|
||||||
*
|
*
|
||||||
* Note: we don't ExecFreeResultType(hjstate)
|
* Note: we don't ExecFreeResultType(hjstate) because the rule manager
|
||||||
* because the rule manager depends on the tupType
|
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||||
* returned by ExecMain(). So for now, this
|
* freed at end-transaction time. -cim 6/2/91
|
||||||
* is freed at end-transaction time. -cim 6/2/91
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&hjstate->jstate);
|
ExecFreeProjectionInfo(&hjstate->jstate);
|
||||||
ExecFreeExprContext(&hjstate->jstate);
|
ExecFreeExprContext(&hjstate->jstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clean up subtrees
|
* clean up subtrees
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
||||||
ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
|
ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(hjstate->jstate.cs_ResultTupleSlot);
|
ExecClearTuple(hjstate->jstate.cs_ResultTupleSlot);
|
||||||
ExecClearTuple(hjstate->hj_OuterTupleSlot);
|
ExecClearTuple(hjstate->hj_OuterTupleSlot);
|
||||||
@@ -598,10 +574,9 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
|
|||||||
hashtable->outerBatchFile[newbatch - 2] = NULL;
|
hashtable->outerBatchFile[newbatch - 2] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------
|
/*
|
||||||
* We can skip over any batches that are empty on either side.
|
* We can skip over any batches that are empty on either side. Release
|
||||||
* Release associated temp files right away.
|
* associated temp files right away.
|
||||||
* --------------
|
|
||||||
*/
|
*/
|
||||||
while (newbatch <= nbatch &&
|
while (newbatch <= nbatch &&
|
||||||
(innerBatchSize[newbatch - 1] == 0L ||
|
(innerBatchSize[newbatch - 1] == 0L ||
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.58 2001/03/22 03:59:28 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.59 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -84,9 +84,8 @@ IndexNext(IndexScan *node)
|
|||||||
bool bBackward;
|
bool bBackward;
|
||||||
int indexNumber;
|
int indexNumber;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* extract necessary information from index scan node
|
* extract necessary information from index scan node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
estate = node->scan.plan.state;
|
estate = node->scan.plan.state;
|
||||||
direction = estate->es_direction;
|
direction = estate->es_direction;
|
||||||
@@ -145,11 +144,10 @@ IndexNext(IndexScan *node)
|
|||||||
|
|
||||||
tuple = &(indexstate->iss_htup);
|
tuple = &(indexstate->iss_htup);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* ok, now that we have what we need, fetch an index tuple.
|
* ok, now that we have what we need, fetch an index tuple. if
|
||||||
* if scanning this index succeeded then return the
|
* scanning this index succeeded then return the appropriate heap
|
||||||
* appropriate heap tuple.. else return NULL.
|
* tuple.. else return NULL.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
bBackward = ScanDirectionIsBackward(direction);
|
bBackward = ScanDirectionIsBackward(direction);
|
||||||
if (bBackward)
|
if (bBackward)
|
||||||
@@ -238,10 +236,10 @@ IndexNext(IndexScan *node)
|
|||||||
indexstate->iss_IndexPtr++;
|
indexstate->iss_IndexPtr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* ----------------
|
|
||||||
* if we get here it means the index scan failed so we
|
/*
|
||||||
* are at the end of the scan..
|
* if we get here it means the index scan failed so we are at the end
|
||||||
* ----------------
|
* of the scan..
|
||||||
*/
|
*/
|
||||||
return ExecClearTuple(slot);
|
return ExecClearTuple(slot);
|
||||||
}
|
}
|
||||||
@@ -272,17 +270,15 @@ ExecIndexScan(IndexScan *node)
|
|||||||
{
|
{
|
||||||
IndexScanState *indexstate = node->indxstate;
|
IndexScanState *indexstate = node->indxstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* If we have runtime keys and they've not already been set up,
|
* If we have runtime keys and they've not already been set up, do it
|
||||||
* do it now.
|
* now.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (indexstate->iss_RuntimeKeyInfo && !indexstate->iss_RuntimeKeysReady)
|
if (indexstate->iss_RuntimeKeyInfo && !indexstate->iss_RuntimeKeysReady)
|
||||||
ExecReScan((Plan *) node, NULL, NULL);
|
ExecReScan((Plan *) node, NULL, NULL);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* use IndexNext as access method
|
* use IndexNext as access method
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
return ExecScan(&node->scan, (ExecScanAccessMtd) IndexNext);
|
return ExecScan(&node->scan, (ExecScanAccessMtd) IndexNext);
|
||||||
}
|
}
|
||||||
@@ -448,37 +444,32 @@ ExecEndIndexScan(IndexScan *node)
|
|||||||
indxqual = node->indxqual;
|
indxqual = node->indxqual;
|
||||||
runtimeKeyInfo = indexstate->iss_RuntimeKeyInfo;
|
runtimeKeyInfo = indexstate->iss_RuntimeKeyInfo;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* extract information from the node
|
* extract information from the node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
numIndices = indexstate->iss_NumIndices;
|
numIndices = indexstate->iss_NumIndices;
|
||||||
scanKeys = indexstate->iss_ScanKeys;
|
scanKeys = indexstate->iss_ScanKeys;
|
||||||
numScanKeys = indexstate->iss_NumScanKeys;
|
numScanKeys = indexstate->iss_NumScanKeys;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* Free the projection info and the scan attribute info
|
||||||
*
|
*
|
||||||
* Note: we don't ExecFreeResultType(scanstate)
|
* Note: we don't ExecFreeResultType(scanstate) because the rule manager
|
||||||
* because the rule manager depends on the tupType
|
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||||
* returned by ExecMain(). So for now, this
|
* freed at end-transaction time. -cim 6/2/91
|
||||||
* is freed at end-transaction time. -cim 6/2/91
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&scanstate->cstate);
|
ExecFreeProjectionInfo(&scanstate->cstate);
|
||||||
ExecFreeExprContext(&scanstate->cstate);
|
ExecFreeExprContext(&scanstate->cstate);
|
||||||
if (indexstate->iss_RuntimeContext)
|
if (indexstate->iss_RuntimeContext)
|
||||||
FreeExprContext(indexstate->iss_RuntimeContext);
|
FreeExprContext(indexstate->iss_RuntimeContext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* close the heap and index relations
|
* close the heap and index relations
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecCloseR((Plan *) node);
|
ExecCloseR((Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* free the scan keys used in scanning the indices
|
* free the scan keys used in scanning the indices
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < numIndices; i++)
|
for (i = 0; i < numIndices; i++)
|
||||||
{
|
{
|
||||||
@@ -498,9 +489,8 @@ ExecEndIndexScan(IndexScan *node)
|
|||||||
pfree(runtimeKeyInfo);
|
pfree(runtimeKeyInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clear out tuple table slots
|
* clear out tuple table slots
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
|
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
|
||||||
ExecClearTuple(scanstate->css_ScanTupleSlot);
|
ExecClearTuple(scanstate->css_ScanTupleSlot);
|
||||||
@@ -605,49 +595,44 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
HeapScanDesc currentScanDesc;
|
HeapScanDesc currentScanDesc;
|
||||||
ScanDirection direction;
|
ScanDirection direction;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign execution state to node
|
* assign execution state to node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->scan.plan.state = estate;
|
node->scan.plan.state = estate;
|
||||||
|
|
||||||
/* --------------------------------
|
/*
|
||||||
* Part 1) initialize scan state
|
* Part 1) initialize scan state
|
||||||
*
|
*
|
||||||
* create new CommonScanState for node
|
* create new CommonScanState for node
|
||||||
* --------------------------------
|
|
||||||
*/
|
*/
|
||||||
scanstate = makeNode(CommonScanState);
|
scanstate = makeNode(CommonScanState);
|
||||||
node->scan.scanstate = scanstate;
|
node->scan.scanstate = scanstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* + create expression context for node
|
* create expression context for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &scanstate->cstate);
|
ExecAssignExprContext(estate, &scanstate->cstate);
|
||||||
|
|
||||||
#define INDEXSCAN_NSLOTS 3
|
#define INDEXSCAN_NSLOTS 3
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &scanstate->cstate);
|
ExecInitResultTupleSlot(estate, &scanstate->cstate);
|
||||||
ExecInitScanTupleSlot(estate, scanstate);
|
ExecInitScanTupleSlot(estate, scanstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize projection info. result type comes from scan desc
|
* initialize projection info. result type comes from scan desc
|
||||||
* below..
|
* below..
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
|
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
|
||||||
|
|
||||||
/* --------------------------------
|
/*
|
||||||
* Part 2) initialize index scan state
|
* Part 2) initialize index scan state
|
||||||
*
|
*
|
||||||
* create new IndexScanState for node
|
* create new IndexScanState for node
|
||||||
* --------------------------------
|
|
||||||
*/
|
*/
|
||||||
indexstate = makeNode(IndexScanState);
|
indexstate = makeNode(IndexScanState);
|
||||||
indexstate->iss_NumIndices = 0;
|
indexstate->iss_NumIndices = 0;
|
||||||
@@ -662,9 +647,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
|
|
||||||
node->indxstate = indexstate;
|
node->indxstate = indexstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the index node information
|
* get the index node information
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
indxid = node->indxid;
|
indxid = node->indxid;
|
||||||
numIndices = length(indxid);
|
numIndices = length(indxid);
|
||||||
@@ -672,27 +656,24 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
|
|
||||||
CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
|
CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* scanKeys is used to keep track of the ScanKey's. This is needed
|
* scanKeys is used to keep track of the ScanKey's. This is needed
|
||||||
* because a single scan may use several indices and each index has
|
* because a single scan may use several indices and each index has
|
||||||
* its own ScanKey.
|
* its own ScanKey.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
numScanKeys = (int *) palloc(numIndices * sizeof(int));
|
numScanKeys = (int *) palloc(numIndices * sizeof(int));
|
||||||
scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
|
scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
|
||||||
relationDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
|
relationDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
|
||||||
scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
|
scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize space for runtime key info (may not be needed)
|
* initialize space for runtime key info (may not be needed)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
have_runtime_keys = false;
|
have_runtime_keys = false;
|
||||||
runtimeKeyInfo = (int **) palloc(numIndices * sizeof(int *));
|
runtimeKeyInfo = (int **) palloc(numIndices * sizeof(int *));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* build the index scan keys from the index qualification
|
* build the index scan keys from the index qualification
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
indxqual = node->indxqual;
|
indxqual = node->indxqual;
|
||||||
for (i = 0; i < numIndices; i++)
|
for (i = 0; i < numIndices; i++)
|
||||||
@@ -713,10 +694,9 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
|
|
||||||
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, convert each qual's
|
||||||
* convert each qual's opclause into a single scan key
|
* opclause into a single scan key
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (j = 0; j < n_keys; j++)
|
for (j = 0; j < n_keys; j++)
|
||||||
{
|
{
|
||||||
@@ -731,9 +711,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
Oid opid; /* operator id used in scan */
|
Oid opid; /* operator id used in scan */
|
||||||
Datum scanvalue = 0; /* value used in scan (if const) */
|
Datum scanvalue = 0; /* value used in scan (if const) */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* extract clause information from the qualification
|
* extract clause information from the qualification
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
clause = nth(j, qual);
|
clause = nth(j, qual);
|
||||||
|
|
||||||
@@ -743,26 +722,25 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
|
|
||||||
opid = op->opid;
|
opid = op->opid;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Here we figure out the contents of the index qual.
|
* Here we figure out the contents of the index qual. The
|
||||||
* The usual case is (var op const) or (const op var)
|
* usual case is (var op const) or (const op var) which means
|
||||||
* which means we form a scan key for the attribute
|
* we form a scan key for the attribute listed in the var node
|
||||||
* listed in the var node and use the value of the const.
|
* and use the value of the const.
|
||||||
*
|
*
|
||||||
* If we don't have a const node, then it means that
|
* If we don't have a const node, then it means that one of the
|
||||||
* one of the var nodes refers to the "scan" tuple and
|
* var nodes refers to the "scan" tuple and is used to
|
||||||
* is used to determine which attribute to scan, and the
|
* determine which attribute to scan, and the other expression
|
||||||
* other expression is used to calculate the value used in
|
* is used to calculate the value used in scanning the index.
|
||||||
* scanning the index.
|
|
||||||
*
|
*
|
||||||
* This means our index scan's scan key is a function of
|
* This means our index scan's scan key is a function of
|
||||||
* information obtained during the execution of the plan
|
* information obtained during the execution of the plan in
|
||||||
* in which case we need to recalculate the index scan key
|
* which case we need to recalculate the index scan key at run
|
||||||
* at run time.
|
* time.
|
||||||
*
|
*
|
||||||
* Hence, we set have_runtime_keys to true and then set
|
* Hence, we set have_runtime_keys to true and then set the
|
||||||
* the appropriate flag in run_keys to LEFT_OP or RIGHT_OP.
|
* appropriate flag in run_keys to LEFT_OP or RIGHT_OP. The
|
||||||
* The corresponding scan keys are recomputed at run time.
|
* corresponding scan keys are recomputed at run time.
|
||||||
*
|
*
|
||||||
* XXX Although this code *thinks* it can handle an indexqual
|
* XXX Although this code *thinks* it can handle an indexqual
|
||||||
* with the indexkey on either side, in fact it cannot.
|
* with the indexkey on either side, in fact it cannot.
|
||||||
@@ -770,21 +748,20 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
* the left (the planner/optimizer makes sure it never passes
|
* the left (the planner/optimizer makes sure it never passes
|
||||||
* anything else). The reason: the scankey machinery has no
|
* anything else). The reason: the scankey machinery has no
|
||||||
* provision for distinguishing which side of the operator is
|
* provision for distinguishing which side of the operator is
|
||||||
* the indexed attribute and which is the compared-to constant.
|
* the indexed attribute and which is the compared-to
|
||||||
* It just assumes that the attribute is on the left :-(
|
* constant. It just assumes that the attribute is on the left
|
||||||
|
* :-(
|
||||||
*
|
*
|
||||||
* I am leaving this code able to support both ways, even though
|
* I am leaving this code able to support both ways, even though
|
||||||
* half of it is dead code, on the off chance that someone will
|
* half of it is dead code, on the off chance that someone
|
||||||
* fix the scankey machinery someday --- tgl 8/11/99.
|
* will fix the scankey machinery someday --- tgl 8/11/99.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
scanvar = NO_OP;
|
scanvar = NO_OP;
|
||||||
run_keys[j] = NO_OP;
|
run_keys[j] = NO_OP;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* determine information in leftop
|
* determine information in leftop
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
leftop = (Node *) get_leftop(clause);
|
leftop = (Node *) get_leftop(clause);
|
||||||
|
|
||||||
@@ -795,21 +772,21 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
|
|
||||||
if (IsA(leftop, Var) &&var_is_rel((Var *) leftop))
|
if (IsA(leftop, Var) &&var_is_rel((Var *) leftop))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* if the leftop is a "rel-var", then it means
|
/*
|
||||||
* that it is a var node which tells us which
|
* if the leftop is a "rel-var", then it means that it is
|
||||||
* attribute to use for our scan key.
|
* a var node which tells us which attribute to use for
|
||||||
* ----------------
|
* our scan key.
|
||||||
*/
|
*/
|
||||||
varattno = ((Var *) leftop)->varattno;
|
varattno = ((Var *) leftop)->varattno;
|
||||||
scanvar = LEFT_OP;
|
scanvar = LEFT_OP;
|
||||||
}
|
}
|
||||||
else if (IsA(leftop, Const))
|
else if (IsA(leftop, Const))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* if the leftop is a const node then it means
|
/*
|
||||||
* it identifies the value to place in our scan key.
|
* if the leftop is a const node then it means it
|
||||||
* ----------------
|
* identifies the value to place in our scan key.
|
||||||
*/
|
*/
|
||||||
scanvalue = ((Const *) leftop)->constvalue;
|
scanvalue = ((Const *) leftop)->constvalue;
|
||||||
if (((Const *) leftop)->constisnull)
|
if (((Const *) leftop)->constisnull)
|
||||||
@@ -819,10 +796,9 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
{
|
{
|
||||||
bool isnull;
|
bool isnull;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if the leftop is a Param node then it means
|
* if the leftop is a Param node then it means it
|
||||||
* it identifies the value to place in our scan key.
|
* identifies the value to place in our scan key.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Life was so easy before ... subselects */
|
/* Life was so easy before ... subselects */
|
||||||
@@ -844,19 +820,18 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* otherwise, the leftop contains an expression evaluable
|
* otherwise, the leftop contains an expression evaluable
|
||||||
* at runtime to figure out the value to place in our
|
* at runtime to figure out the value to place in our scan
|
||||||
* scan key.
|
* key.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
have_runtime_keys = true;
|
have_runtime_keys = true;
|
||||||
run_keys[j] = LEFT_OP;
|
run_keys[j] = LEFT_OP;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now determine information in rightop
|
* now determine information in rightop
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
rightop = (Node *) get_rightop(clause);
|
rightop = (Node *) get_rightop(clause);
|
||||||
|
|
||||||
@@ -867,30 +842,29 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
|
|
||||||
if (IsA(rightop, Var) &&var_is_rel((Var *) rightop))
|
if (IsA(rightop, Var) &&var_is_rel((Var *) rightop))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* here we make sure only one op identifies the
|
* here we make sure only one op identifies the
|
||||||
* scan-attribute...
|
* scan-attribute...
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (scanvar == LEFT_OP)
|
if (scanvar == LEFT_OP)
|
||||||
elog(ERROR, "ExecInitIndexScan: %s",
|
elog(ERROR, "ExecInitIndexScan: %s",
|
||||||
"both left and right op's are rel-vars");
|
"both left and right op's are rel-vars");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if the rightop is a "rel-var", then it means
|
* if the rightop is a "rel-var", then it means that it is
|
||||||
* that it is a var node which tells us which
|
* a var node which tells us which attribute to use for
|
||||||
* attribute to use for our scan key.
|
* our scan key.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
varattno = ((Var *) rightop)->varattno;
|
varattno = ((Var *) rightop)->varattno;
|
||||||
scanvar = RIGHT_OP;
|
scanvar = RIGHT_OP;
|
||||||
}
|
}
|
||||||
else if (IsA(rightop, Const))
|
else if (IsA(rightop, Const))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* if the rightop is a const node then it means
|
/*
|
||||||
* it identifies the value to place in our scan key.
|
* if the rightop is a const node then it means it
|
||||||
* ----------------
|
* identifies the value to place in our scan key.
|
||||||
*/
|
*/
|
||||||
scanvalue = ((Const *) rightop)->constvalue;
|
scanvalue = ((Const *) rightop)->constvalue;
|
||||||
if (((Const *) rightop)->constisnull)
|
if (((Const *) rightop)->constisnull)
|
||||||
@@ -900,10 +874,9 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
{
|
{
|
||||||
bool isnull;
|
bool isnull;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if the rightop is a Param node then it means
|
* if the rightop is a Param node then it means it
|
||||||
* it identifies the value to place in our scan key.
|
* identifies the value to place in our scan key.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Life was so easy before ... subselects */
|
/* Life was so easy before ... subselects */
|
||||||
@@ -925,28 +898,26 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* otherwise, the rightop contains an expression evaluable
|
* otherwise, the rightop contains an expression evaluable
|
||||||
* at runtime to figure out the value to place in our
|
* at runtime to figure out the value to place in our scan
|
||||||
* scan key.
|
* key.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
have_runtime_keys = true;
|
have_runtime_keys = true;
|
||||||
run_keys[j] = RIGHT_OP;
|
run_keys[j] = RIGHT_OP;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now check that at least one op tells us the scan
|
* now check that at least one op tells us the scan
|
||||||
* attribute...
|
* attribute...
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (scanvar == NO_OP)
|
if (scanvar == NO_OP)
|
||||||
elog(ERROR, "ExecInitIndexScan: %s",
|
elog(ERROR, "ExecInitIndexScan: %s",
|
||||||
"neither leftop nor rightop refer to scan relation");
|
"neither leftop nor rightop refer to scan relation");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize the scan key's fields appropriately
|
* initialize the scan key's fields appropriately
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ScanKeyEntryInitialize(&scan_keys[j],
|
ScanKeyEntryInitialize(&scan_keys[j],
|
||||||
flags,
|
flags,
|
||||||
@@ -956,9 +927,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
scanvalue); /* constant */
|
scanvalue); /* constant */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* store the key information into our arrays.
|
* store the key information into our arrays.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
numScanKeys[i] = n_keys;
|
numScanKeys[i] = n_keys;
|
||||||
scanKeys[i] = scan_keys;
|
scanKeys[i] = scan_keys;
|
||||||
@@ -972,20 +942,17 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
indexstate->iss_ScanKeys = scanKeys;
|
indexstate->iss_ScanKeys = scanKeys;
|
||||||
indexstate->iss_NumScanKeys = numScanKeys;
|
indexstate->iss_NumScanKeys = numScanKeys;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* If all of our keys have the form (op var const) , then we have no
|
* If all of our keys have the form (op var const) , then we have no
|
||||||
* runtime keys so we store NULL in the runtime key info.
|
* runtime keys so we store NULL in the runtime key info. Otherwise
|
||||||
* Otherwise runtime key info contains an array of pointers
|
* runtime key info contains an array of pointers (one for each index)
|
||||||
* (one for each index) to arrays of flags (one for each key)
|
* to arrays of flags (one for each key) which indicate that the qual
|
||||||
* which indicate that the qual needs to be evaluated at runtime.
|
* needs to be evaluated at runtime. -cim 10/24/89
|
||||||
* -cim 10/24/89
|
|
||||||
*
|
*
|
||||||
* If we do have runtime keys, we need an ExprContext to evaluate them;
|
* If we do have runtime keys, we need an ExprContext to evaluate them;
|
||||||
* the node's standard context won't do because we want to reset that
|
* the node's standard context won't do because we want to reset that
|
||||||
* context for every tuple. So, build another context just like the
|
* context for every tuple. So, build another context just like the
|
||||||
* other one...
|
* other one... -tgl 7/11/00
|
||||||
* -tgl 7/11/00
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (have_runtime_keys)
|
if (have_runtime_keys)
|
||||||
{
|
{
|
||||||
@@ -1009,18 +976,15 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
pfree(runtimeKeyInfo);
|
pfree(runtimeKeyInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the range table and direction information
|
* get the range table and direction information from the execution
|
||||||
* from the execution state (these are needed to
|
* state (these are needed to open the relations).
|
||||||
* open the relations).
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
rangeTable = estate->es_range_table;
|
rangeTable = estate->es_range_table;
|
||||||
direction = estate->es_direction;
|
direction = estate->es_direction;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open the base relation
|
* open the base relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
relid = node->scan.scanrelid;
|
relid = node->scan.scanrelid;
|
||||||
rtentry = rt_fetch(relid, rangeTable);
|
rtentry = rt_fetch(relid, rangeTable);
|
||||||
@@ -1040,17 +1004,15 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
scanstate->css_currentRelation = currentRelation;
|
scanstate->css_currentRelation = currentRelation;
|
||||||
scanstate->css_currentScanDesc = currentScanDesc;
|
scanstate->css_currentScanDesc = currentScanDesc;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the scan type from the relation descriptor.
|
* get the scan type from the relation descriptor.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
|
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
|
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open the index relations and initialize
|
* open the index relations and initialize relation and scan
|
||||||
* relation and scan descriptors.
|
* descriptors.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < numIndices; i++)
|
for (i = 0; i < numIndices; i++)
|
||||||
{
|
{
|
||||||
@@ -1073,9 +1035,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
indexstate->iss_RelationDescs = relationDescs;
|
indexstate->iss_RelationDescs = relationDescs;
|
||||||
indexstate->iss_ScanDescs = scanDescs;
|
indexstate->iss_ScanDescs = scanDescs;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* all done.
|
* all done.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.4 2001/03/22 03:59:28 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.5 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -44,46 +44,43 @@ ExecLimit(Limit *node)
|
|||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
long netlimit;
|
long netlimit;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from the node
|
* get information from the node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
limitstate = node->limitstate;
|
limitstate = node->limitstate;
|
||||||
direction = node->plan.state->es_direction;
|
direction = node->plan.state->es_direction;
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan((Plan *) node);
|
||||||
resultTupleSlot = limitstate->cstate.cs_ResultTupleSlot;
|
resultTupleSlot = limitstate->cstate.cs_ResultTupleSlot;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* If first call for this scan, compute limit/offset.
|
* If first call for this scan, compute limit/offset. (We can't do
|
||||||
* (We can't do this any earlier, because parameters from upper nodes
|
* this any earlier, because parameters from upper nodes may not be
|
||||||
* may not be set until now.)
|
* set until now.)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!limitstate->parmsSet)
|
if (!limitstate->parmsSet)
|
||||||
recompute_limits(node);
|
recompute_limits(node);
|
||||||
netlimit = limitstate->offset + limitstate->count;
|
netlimit = limitstate->offset + limitstate->count;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now loop, returning only desired tuples.
|
* now loop, returning only desired tuples.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/*----------------
|
|
||||||
|
/*
|
||||||
* If we have reached the subplan EOF or the limit, just quit.
|
* If we have reached the subplan EOF or the limit, just quit.
|
||||||
*
|
*
|
||||||
* NOTE: when scanning forwards, we must fetch one tuple beyond the
|
* NOTE: when scanning forwards, we must fetch one tuple beyond the
|
||||||
* COUNT limit before we can return NULL, else the subplan won't be
|
* COUNT limit before we can return NULL, else the subplan won't
|
||||||
* properly positioned to start going backwards. Hence test here
|
* be properly positioned to start going backwards. Hence test
|
||||||
* is for position > netlimit not position >= netlimit.
|
* here is for position > netlimit not position >= netlimit.
|
||||||
*
|
*
|
||||||
* Similarly, when scanning backwards, we must re-fetch the last
|
* Similarly, when scanning backwards, we must re-fetch the last
|
||||||
* tuple in the offset region before we can return NULL. Otherwise
|
* tuple in the offset region before we can return NULL.
|
||||||
* we won't be correctly aligned to start going forward again. So,
|
* Otherwise we won't be correctly aligned to start going forward
|
||||||
* although you might think we can quit when position = offset + 1,
|
* again. So, although you might think we can quit when position
|
||||||
* we have to fetch a subplan tuple first, and then exit when
|
* = offset + 1, we have to fetch a subplan tuple first, and then
|
||||||
* position = offset.
|
* exit when position = offset.
|
||||||
*----------------
|
|
||||||
*/
|
*/
|
||||||
if (ScanDirectionIsForward(direction))
|
if (ScanDirectionIsForward(direction))
|
||||||
{
|
{
|
||||||
@@ -97,9 +94,9 @@ ExecLimit(Limit *node)
|
|||||||
if (limitstate->position <= limitstate->offset)
|
if (limitstate->position <= limitstate->offset)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* fetch a tuple from the outer subplan
|
* fetch a tuple from the outer subplan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
slot = ExecProcNode(outerPlan, (Plan *) node);
|
slot = ExecProcNode(outerPlan, (Plan *) node);
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
@@ -136,10 +133,9 @@ ExecLimit(Limit *node)
|
|||||||
}
|
}
|
||||||
limitstate->atEnd = false;
|
limitstate->atEnd = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Now, is this a tuple we want? If not, loop around to fetch
|
* Now, is this a tuple we want? If not, loop around to fetch
|
||||||
* another tuple from the subplan.
|
* another tuple from the subplan.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (limitstate->position > limitstate->offset &&
|
if (limitstate->position > limitstate->offset &&
|
||||||
(limitstate->noCount || limitstate->position <= netlimit))
|
(limitstate->noCount || limitstate->position <= netlimit))
|
||||||
@@ -224,47 +220,42 @@ ExecInitLimit(Limit *node, EState *estate, Plan *parent)
|
|||||||
LimitState *limitstate;
|
LimitState *limitstate;
|
||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign execution state to node
|
* assign execution state to node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->plan.state = estate;
|
node->plan.state = estate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create new LimitState for node
|
* create new LimitState for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
limitstate = makeNode(LimitState);
|
limitstate = makeNode(LimitState);
|
||||||
node->limitstate = limitstate;
|
node->limitstate = limitstate;
|
||||||
limitstate->parmsSet = false;
|
limitstate->parmsSet = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* Limit nodes never call ExecQual or ExecProject, but they need
|
* Limit nodes never call ExecQual or ExecProject, but they need an
|
||||||
* an exprcontext anyway to evaluate the limit/offset parameters in.
|
* exprcontext anyway to evaluate the limit/offset parameters in.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &limitstate->cstate);
|
ExecAssignExprContext(estate, &limitstate->cstate);
|
||||||
|
|
||||||
#define LIMIT_NSLOTS 1
|
#define LIMIT_NSLOTS 1
|
||||||
/* ------------
|
|
||||||
|
/*
|
||||||
* Tuple table initialization
|
* Tuple table initialization
|
||||||
* ------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &limitstate->cstate);
|
ExecInitResultTupleSlot(estate, &limitstate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* then initialize outer plan
|
* then initialize outer plan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan((Plan *) node);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* limit nodes do no projections, so initialize
|
* limit nodes do no projections, so initialize projection info for
|
||||||
* projection info for this node appropriately
|
* this node appropriately
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &limitstate->cstate);
|
ExecAssignResultTypeFromOuterPlan((Plan *) node, &limitstate->cstate);
|
||||||
limitstate->cstate.cs_ProjInfo = NULL;
|
limitstate->cstate.cs_ProjInfo = NULL;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.34 2001/03/22 03:59:28 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.35 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -53,46 +53,41 @@ ExecMaterial(Material *node)
|
|||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
bool should_free;
|
bool should_free;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get state info from node
|
* get state info from node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
matstate = node->matstate;
|
matstate = node->matstate;
|
||||||
estate = node->plan.state;
|
estate = node->plan.state;
|
||||||
dir = estate->es_direction;
|
dir = estate->es_direction;
|
||||||
tuplestorestate = (Tuplestorestate *) matstate->tuplestorestate;
|
tuplestorestate = (Tuplestorestate *) matstate->tuplestorestate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* If first time through, read all tuples from outer plan and
|
* If first time through, read all tuples from outer plan and pass
|
||||||
* pass them to tuplestore.c.
|
* them to tuplestore.c. Subsequent calls just fetch tuples from
|
||||||
* Subsequent calls just fetch tuples from tuplestore.
|
* tuplestore.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (tuplestorestate == NULL)
|
if (tuplestorestate == NULL)
|
||||||
{
|
{
|
||||||
Plan *outerNode;
|
Plan *outerNode;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Want to scan subplan in the forward direction while creating
|
* Want to scan subplan in the forward direction while creating
|
||||||
* the stored data. (Does setting my direction actually affect
|
* the stored data. (Does setting my direction actually affect
|
||||||
* the subplan? I bet this is useless code...)
|
* the subplan? I bet this is useless code...)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
estate->es_direction = ForwardScanDirection;
|
estate->es_direction = ForwardScanDirection;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Initialize tuplestore module.
|
* Initialize tuplestore module.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */
|
tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */
|
||||||
SortMem);
|
SortMem);
|
||||||
|
|
||||||
matstate->tuplestorestate = (void *) tuplestorestate;
|
matstate->tuplestorestate = (void *) tuplestorestate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Scan the subplan and feed all the tuples to tuplestore.
|
* Scan the subplan and feed all the tuples to tuplestore.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerNode = outerPlan((Plan *) node);
|
outerNode = outerPlan((Plan *) node);
|
||||||
|
|
||||||
@@ -107,23 +102,20 @@ ExecMaterial(Material *node)
|
|||||||
ExecClearTuple(slot);
|
ExecClearTuple(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Complete the store.
|
* Complete the store.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tuplestore_donestoring(tuplestorestate);
|
tuplestore_donestoring(tuplestorestate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* restore to user specified direction
|
* restore to user specified direction
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
estate->es_direction = dir;
|
estate->es_direction = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Get the first or next tuple from tuplestore.
|
* Get the first or next tuple from tuplestore. Returns NULL if no
|
||||||
* Returns NULL if no more tuples.
|
* more tuples.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
slot = (TupleTableSlot *) matstate->csstate.cstate.cs_ResultTupleSlot;
|
slot = (TupleTableSlot *) matstate->csstate.cstate.cs_ResultTupleSlot;
|
||||||
heapTuple = tuplestore_getheaptuple(tuplestorestate,
|
heapTuple = tuplestore_getheaptuple(tuplestorestate,
|
||||||
@@ -143,50 +135,44 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
|
|||||||
MaterialState *matstate;
|
MaterialState *matstate;
|
||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign the node's execution state
|
* assign the node's execution state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->plan.state = estate;
|
node->plan.state = estate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create state structure
|
* create state structure
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
matstate = makeNode(MaterialState);
|
matstate = makeNode(MaterialState);
|
||||||
matstate->tuplestorestate = NULL;
|
matstate->tuplestorestate = NULL;
|
||||||
node->matstate = matstate;
|
node->matstate = matstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* Materialization nodes don't need ExprContexts because
|
* Materialization nodes don't need ExprContexts because they never call
|
||||||
* they never call ExecQual or ExecProject.
|
* ExecQual or ExecProject.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MATERIAL_NSLOTS 1
|
#define MATERIAL_NSLOTS 1
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
*
|
*
|
||||||
* material nodes only return tuples from their materialized
|
* material nodes only return tuples from their materialized relation.
|
||||||
* relation.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &matstate->csstate.cstate);
|
ExecInitResultTupleSlot(estate, &matstate->csstate.cstate);
|
||||||
ExecInitScanTupleSlot(estate, &matstate->csstate);
|
ExecInitScanTupleSlot(estate, &matstate->csstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initializes child nodes
|
* initializes child nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan((Plan *) node);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize tuple type. no need to initialize projection
|
* initialize tuple type. no need to initialize projection info
|
||||||
* info because this node doesn't do projections.
|
* because this node doesn't do projections.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &matstate->csstate.cstate);
|
ExecAssignResultTypeFromOuterPlan((Plan *) node, &matstate->csstate.cstate);
|
||||||
ExecAssignScanTypeFromOuterPlan((Plan *) node, &matstate->csstate);
|
ExecAssignScanTypeFromOuterPlan((Plan *) node, &matstate->csstate);
|
||||||
@@ -213,28 +199,24 @@ ExecEndMaterial(Material *node)
|
|||||||
MaterialState *matstate;
|
MaterialState *matstate;
|
||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get info from the material state
|
* get info from the material state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
matstate = node->matstate;
|
matstate = node->matstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* shut down the subplan
|
* shut down the subplan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan((Plan *) node);
|
||||||
ExecEndNode(outerPlan, (Plan *) node);
|
ExecEndNode(outerPlan, (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(matstate->csstate.css_ScanTupleSlot);
|
ExecClearTuple(matstate->csstate.css_ScanTupleSlot);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Release tuplestore resources
|
* Release tuplestore resources
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (matstate->tuplestorestate != NULL)
|
if (matstate->tuplestorestate != NULL)
|
||||||
tuplestore_end((Tuplestorestate *) matstate->tuplestorestate);
|
tuplestore_end((Tuplestorestate *) matstate->tuplestorestate);
|
||||||
@@ -252,9 +234,8 @@ ExecMaterialMarkPos(Material *node)
|
|||||||
{
|
{
|
||||||
MaterialState *matstate = node->matstate;
|
MaterialState *matstate = node->matstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if we haven't materialized yet, just return.
|
* if we haven't materialized yet, just return.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!matstate->tuplestorestate)
|
if (!matstate->tuplestorestate)
|
||||||
return;
|
return;
|
||||||
@@ -273,16 +254,14 @@ ExecMaterialRestrPos(Material *node)
|
|||||||
{
|
{
|
||||||
MaterialState *matstate = node->matstate;
|
MaterialState *matstate = node->matstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if we haven't materialized yet, just return.
|
* if we haven't materialized yet, just return.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!matstate->tuplestorestate)
|
if (!matstate->tuplestorestate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* restore the scan to the previously marked position
|
* restore the scan to the previously marked position
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tuplestore_restorepos((Tuplestorestate *) matstate->tuplestorestate);
|
tuplestore_restorepos((Tuplestorestate *) matstate->tuplestorestate);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.43 2001/03/22 03:59:29 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.44 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -114,38 +114,36 @@ MJFormSkipQual(List *qualList, char *replaceopname)
|
|||||||
Oid oprleft,
|
Oid oprleft,
|
||||||
oprright;
|
oprright;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* qualList is a list: ((op .. ..) ...)
|
* qualList is a list: ((op .. ..) ...)
|
||||||
* first we make a copy of it. copyObject() makes a deep copy
|
*
|
||||||
* so let's use it instead of the old fashoned lispCopy()...
|
* first we make a copy of it. copyObject() makes a deep copy so let's
|
||||||
* ----------------
|
* use it instead of the old fashoned lispCopy()...
|
||||||
*/
|
*/
|
||||||
qualCopy = (List *) copyObject((Node *) qualList);
|
qualCopy = (List *) copyObject((Node *) qualList);
|
||||||
|
|
||||||
foreach(qualcdr, qualCopy)
|
foreach(qualcdr, qualCopy)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* first get the current (op .. ..) list
|
* first get the current (op .. ..) list
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
qual = lfirst(qualcdr);
|
qual = lfirst(qualcdr);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now get at the op
|
* now get at the op
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
op = (Oper *) qual->oper;
|
op = (Oper *) qual->oper;
|
||||||
if (!IsA(op, Oper))
|
if (!IsA(op, Oper))
|
||||||
elog(ERROR, "MJFormSkipQual: op not an Oper!");
|
elog(ERROR, "MJFormSkipQual: op not an Oper!");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Get the declared left and right operand types of the operator.
|
* Get the declared left and right operand types of the operator.
|
||||||
* Note we do *not* use the actual operand types, since those might
|
* Note we do *not* use the actual operand types, since those
|
||||||
* be different in scenarios with binary-compatible data types.
|
* might be different in scenarios with binary-compatible data
|
||||||
* There should be "<" and ">" operators matching a mergejoinable
|
* types. There should be "<" and ">" operators matching a
|
||||||
* "=" operator's declared operand types, but we might not find them
|
* mergejoinable "=" operator's declared operand types, but we
|
||||||
* if we search with the actual operand types.
|
* might not find them if we search with the actual operand types.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
optup = SearchSysCache(OPEROID,
|
optup = SearchSysCache(OPEROID,
|
||||||
ObjectIdGetDatum(op->opno),
|
ObjectIdGetDatum(op->opno),
|
||||||
@@ -157,10 +155,9 @@ MJFormSkipQual(List *qualList, char *replaceopname)
|
|||||||
oprright = opform->oprright;
|
oprright = opform->oprright;
|
||||||
ReleaseSysCache(optup);
|
ReleaseSysCache(optup);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Now look up the matching "<" or ">" operator. If there isn't one,
|
* Now look up the matching "<" or ">" operator. If there isn't
|
||||||
* whoever marked the "=" operator mergejoinable was a loser.
|
* one, whoever marked the "=" operator mergejoinable was a loser.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
optup = SearchSysCache(OPERNAME,
|
optup = SearchSysCache(OPERNAME,
|
||||||
PointerGetDatum(replaceopname),
|
PointerGetDatum(replaceopname),
|
||||||
@@ -173,9 +170,8 @@ MJFormSkipQual(List *qualList, char *replaceopname)
|
|||||||
op->opno, replaceopname);
|
op->opno, replaceopname);
|
||||||
opform = (Form_pg_operator) GETSTRUCT(optup);
|
opform = (Form_pg_operator) GETSTRUCT(optup);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* And replace the data in the copied operator node.
|
* And replace the data in the copied operator node.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
op->opno = optup->t_data->t_oid;
|
op->opno = optup->t_data->t_oid;
|
||||||
op->opid = opform->oprcode;
|
op->opid = opform->oprcode;
|
||||||
@@ -216,12 +212,10 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
|
|||||||
*/
|
*/
|
||||||
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
|
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* for each pair of clauses, test them until
|
* for each pair of clauses, test them until our compare conditions
|
||||||
* our compare conditions are satisfied.
|
* are satisfied. if we reach the end of the list, none of our key
|
||||||
* if we reach the end of the list, none of our key greater-than
|
* greater-than conditions were satisfied so we return false.
|
||||||
* conditions were satisfied so we return false.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
result = false; /* assume 'false' result */
|
result = false; /* assume 'false' result */
|
||||||
|
|
||||||
@@ -231,12 +225,11 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
|
|||||||
Datum const_value;
|
Datum const_value;
|
||||||
bool isNull;
|
bool isNull;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* first test if our compare clause is satisfied.
|
* first test if our compare clause is satisfied. if so then
|
||||||
* if so then return true.
|
* return true.
|
||||||
*
|
*
|
||||||
* A NULL result is considered false.
|
* A NULL result is considered false.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
const_value = ExecEvalExpr((Node *) lfirst(clause), econtext,
|
const_value = ExecEvalExpr((Node *) lfirst(clause), econtext,
|
||||||
&isNull, NULL);
|
&isNull, NULL);
|
||||||
@@ -247,11 +240,10 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* ok, the compare clause failed so we test if the keys
|
* ok, the compare clause failed so we test if the keys are
|
||||||
* are equal... if key1 != key2, we return false.
|
* equal... if key1 != key2, we return false. otherwise key1 =
|
||||||
* otherwise key1 = key2 so we move on to the next pair of keys.
|
* key2 so we move on to the next pair of keys.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
const_value = ExecEvalExpr((Node *) lfirst(eqclause),
|
const_value = ExecEvalExpr((Node *) lfirst(eqclause),
|
||||||
econtext,
|
econtext,
|
||||||
@@ -404,9 +396,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
bool doFillOuter;
|
bool doFillOuter;
|
||||||
bool doFillInner;
|
bool doFillInner;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from node
|
* get information from node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
mergestate = node->mergestate;
|
mergestate = node->mergestate;
|
||||||
estate = node->join.plan.state;
|
estate = node->join.plan.state;
|
||||||
@@ -455,11 +446,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
innerSkipQual = mergestate->mj_OuterSkipQual;
|
innerSkipQual = mergestate->mj_OuterSkipQual;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Check to see if we're still projecting out tuples from a previous
|
* Check to see if we're still projecting out tuples from a previous
|
||||||
* join tuple (because there is a function-returning-set in the
|
* join tuple (because there is a function-returning-set in the
|
||||||
* projection expressions). If so, try to project another one.
|
* projection expressions). If so, try to project another one.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (mergestate->jstate.cs_TupFromTlist)
|
if (mergestate->jstate.cs_TupFromTlist)
|
||||||
{
|
{
|
||||||
@@ -473,25 +463,23 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
mergestate->jstate.cs_TupFromTlist = false;
|
mergestate->jstate.cs_TupFromTlist = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Reset per-tuple memory context to free any expression evaluation
|
* Reset per-tuple memory context to free any expression evaluation
|
||||||
* storage allocated in the previous tuple cycle. Note this can't
|
* storage allocated in the previous tuple cycle. Note this can't
|
||||||
* happen until we're done projecting out tuples from a join tuple.
|
* happen until we're done projecting out tuples from a join tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* ok, everything is setup.. let's go to work
|
* ok, everything is setup.. let's go to work
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* get the current state of the join and do things accordingly.
|
* get the current state of the join and do things accordingly.
|
||||||
* Note: The join states are highlighted with 32-* comments for
|
* Note: The join states are highlighted with 32-* comments for
|
||||||
* improved readability.
|
* improved readability.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
MJ_dump(mergestate);
|
MJ_dump(mergestate);
|
||||||
|
|
||||||
@@ -553,10 +541,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* OK, we have the initial tuples. Begin by skipping
|
* OK, we have the initial tuples. Begin by skipping
|
||||||
* unmatched inner tuples.
|
* unmatched inner tuples.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
|
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
|
||||||
break;
|
break;
|
||||||
@@ -644,10 +631,11 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
if (qualResult)
|
if (qualResult)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* qualification succeeded. now form the desired
|
* qualification succeeded. now form the desired
|
||||||
* projection tuple and return the slot containing it.
|
* projection tuple and return the slot containing
|
||||||
* ----------------
|
* it.
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
@@ -697,10 +685,11 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* qualification succeeded. now form the desired
|
* qualification succeeded. now form the desired
|
||||||
* projection tuple and return the slot containing it.
|
* projection tuple and return the slot containing
|
||||||
* ----------------
|
* it.
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
@@ -719,9 +708,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now we get the next inner tuple, if any
|
* now we get the next inner tuple, if any
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
||||||
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
||||||
@@ -775,10 +763,11 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* qualification succeeded. now form the desired
|
* qualification succeeded. now form the desired
|
||||||
* projection tuple and return the slot containing it.
|
* projection tuple and return the slot containing
|
||||||
* ----------------
|
* it.
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
@@ -797,19 +786,17 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now we get the next outer tuple, if any
|
* now we get the next outer tuple, if any
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
||||||
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
||||||
MJ_DEBUG_PROC_NODE(outerTupleSlot);
|
MJ_DEBUG_PROC_NODE(outerTupleSlot);
|
||||||
mergestate->mj_MatchedOuter = false;
|
mergestate->mj_MatchedOuter = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if the outer tuple is null then we are done with the
|
* if the outer tuple is null then we are done with the
|
||||||
* join, unless we have inner tuples we need to null-fill.
|
* join, unless we have inner tuples we need to null-fill.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (TupIsNull(outerTupleSlot))
|
if (TupIsNull(outerTupleSlot))
|
||||||
{
|
{
|
||||||
@@ -869,9 +856,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
case EXEC_MJ_TESTOUTER:
|
case EXEC_MJ_TESTOUTER:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_TESTOUTER\n");
|
MJ_printf("ExecMergeJoin: EXEC_MJ_TESTOUTER\n");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* here we compare the outer tuple with the marked inner tuple
|
* here we compare the outer tuple with the marked inner
|
||||||
* ----------------
|
* tuple
|
||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
@@ -967,11 +954,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
case EXEC_MJ_SKIPOUTER_BEGIN:
|
case EXEC_MJ_SKIPOUTER_BEGIN:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_BEGIN\n");
|
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_BEGIN\n");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* before we advance, make sure the current tuples
|
* before we advance, make sure the current tuples do not
|
||||||
* do not satisfy the mergeclauses. If they do, then
|
* satisfy the mergeclauses. If they do, then we update
|
||||||
* we update the marked tuple and go join them.
|
* the marked tuple and go join them.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
@@ -999,9 +985,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
case EXEC_MJ_SKIPOUTER_TEST:
|
case EXEC_MJ_SKIPOUTER_TEST:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_TEST\n");
|
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_TEST\n");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* ok, now test the skip qualification
|
* ok, now test the skip qualification
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
@@ -1014,10 +999,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);
|
MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* compareResult is true as long as we should
|
* compareResult is true as long as we should continue
|
||||||
* continue skipping outer tuples.
|
* skipping outer tuples.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (compareResult)
|
if (compareResult)
|
||||||
{
|
{
|
||||||
@@ -1025,12 +1009,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now check the inner skip qual to see if we
|
* now check the inner skip qual to see if we should now
|
||||||
* should now skip inner tuples... if we fail the
|
* skip inner tuples... if we fail the inner skip qual,
|
||||||
* inner skip qual, then we know we have a new pair
|
* then we know we have a new pair of matching tuples.
|
||||||
* of matching tuples.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
compareResult = MergeCompare(mergeclauses,
|
compareResult = MergeCompare(mergeclauses,
|
||||||
innerSkipQual,
|
innerSkipQual,
|
||||||
@@ -1044,10 +1026,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
|
mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*------------------------------------------------
|
/*
|
||||||
* Before advancing, we check to see if we must emit an
|
* Before advancing, we check to see if we must emit an
|
||||||
* outer-join fill tuple for this outer tuple.
|
* outer-join fill tuple for this outer tuple.
|
||||||
*------------------------------------------------
|
|
||||||
*/
|
*/
|
||||||
case EXEC_MJ_SKIPOUTER_ADVANCE:
|
case EXEC_MJ_SKIPOUTER_ADVANCE:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_ADVANCE\n");
|
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_ADVANCE\n");
|
||||||
@@ -1071,10 +1052,11 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* qualification succeeded. now form the desired
|
* qualification succeeded. now form the desired
|
||||||
* projection tuple and return the slot containing it.
|
* projection tuple and return the slot containing
|
||||||
* ----------------
|
* it.
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
@@ -1093,19 +1075,17 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now we get the next outer tuple, if any
|
* now we get the next outer tuple, if any
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
||||||
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
||||||
MJ_DEBUG_PROC_NODE(outerTupleSlot);
|
MJ_DEBUG_PROC_NODE(outerTupleSlot);
|
||||||
mergestate->mj_MatchedOuter = false;
|
mergestate->mj_MatchedOuter = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if the outer tuple is null then we are done with the
|
* if the outer tuple is null then we are done with the
|
||||||
* join, unless we have inner tuples we need to null-fill.
|
* join, unless we have inner tuples we need to null-fill.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (TupIsNull(outerTupleSlot))
|
if (TupIsNull(outerTupleSlot))
|
||||||
{
|
{
|
||||||
@@ -1125,9 +1105,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* otherwise test the new tuple against the skip qual.
|
* otherwise test the new tuple against the skip qual.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
|
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
|
||||||
break;
|
break;
|
||||||
@@ -1155,11 +1134,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
case EXEC_MJ_SKIPINNER_BEGIN:
|
case EXEC_MJ_SKIPINNER_BEGIN:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_BEGIN\n");
|
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_BEGIN\n");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* before we advance, make sure the current tuples
|
* before we advance, make sure the current tuples do not
|
||||||
* do not satisfy the mergeclauses. If they do, then
|
* satisfy the mergeclauses. If they do, then we update
|
||||||
* we update the marked tuple and go join them.
|
* the marked tuple and go join them.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
@@ -1187,9 +1165,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
case EXEC_MJ_SKIPINNER_TEST:
|
case EXEC_MJ_SKIPINNER_TEST:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_TEST\n");
|
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_TEST\n");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* ok, now test the skip qualification
|
* ok, now test the skip qualification
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
@@ -1202,10 +1179,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);
|
MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* compareResult is true as long as we should
|
* compareResult is true as long as we should continue
|
||||||
* continue skipping inner tuples.
|
* skipping inner tuples.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (compareResult)
|
if (compareResult)
|
||||||
{
|
{
|
||||||
@@ -1213,12 +1189,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now check the outer skip qual to see if we
|
* now check the outer skip qual to see if we should now
|
||||||
* should now skip outer tuples... if we fail the
|
* skip outer tuples... if we fail the outer skip qual,
|
||||||
* outer skip qual, then we know we have a new pair
|
* then we know we have a new pair of matching tuples.
|
||||||
* of matching tuples.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
compareResult = MergeCompare(mergeclauses,
|
compareResult = MergeCompare(mergeclauses,
|
||||||
outerSkipQual,
|
outerSkipQual,
|
||||||
@@ -1232,10 +1206,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
|
mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*------------------------------------------------
|
/*
|
||||||
* Before advancing, we check to see if we must emit an
|
* Before advancing, we check to see if we must emit an
|
||||||
* outer-join fill tuple for this inner tuple.
|
* outer-join fill tuple for this inner tuple.
|
||||||
*------------------------------------------------
|
|
||||||
*/
|
*/
|
||||||
case EXEC_MJ_SKIPINNER_ADVANCE:
|
case EXEC_MJ_SKIPINNER_ADVANCE:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_ADVANCE\n");
|
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_ADVANCE\n");
|
||||||
@@ -1259,10 +1232,11 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* qualification succeeded. now form the desired
|
* qualification succeeded. now form the desired
|
||||||
* projection tuple and return the slot containing it.
|
* projection tuple and return the slot containing
|
||||||
* ----------------
|
* it.
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
@@ -1281,19 +1255,17 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now we get the next inner tuple, if any
|
* now we get the next inner tuple, if any
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
||||||
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
||||||
MJ_DEBUG_PROC_NODE(innerTupleSlot);
|
MJ_DEBUG_PROC_NODE(innerTupleSlot);
|
||||||
mergestate->mj_MatchedInner = false;
|
mergestate->mj_MatchedInner = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if the inner tuple is null then we are done with the
|
* if the inner tuple is null then we are done with the
|
||||||
* join, unless we have outer tuples we need to null-fill.
|
* join, unless we have outer tuples we need to null-fill.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (TupIsNull(innerTupleSlot))
|
if (TupIsNull(innerTupleSlot))
|
||||||
{
|
{
|
||||||
@@ -1313,9 +1285,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* otherwise test the new tuple against the skip qual.
|
* otherwise test the new tuple against the skip qual.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
|
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
|
||||||
break;
|
break;
|
||||||
@@ -1349,10 +1320,11 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* qualification succeeded. now form the desired
|
* qualification succeeded. now form the desired
|
||||||
* projection tuple and return the slot containing it.
|
* projection tuple and return the slot containing
|
||||||
* ----------------
|
* it.
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
@@ -1371,9 +1343,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now we get the next inner tuple, if any
|
* now we get the next inner tuple, if any
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
||||||
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
||||||
@@ -1418,10 +1389,11 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* qualification succeeded. now form the desired
|
* qualification succeeded. now form the desired
|
||||||
* projection tuple and return the slot containing it.
|
* projection tuple and return the slot containing
|
||||||
* ----------------
|
* it.
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
@@ -1440,9 +1412,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now we get the next outer tuple, if any
|
* now we get the next outer tuple, if any
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
||||||
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
||||||
@@ -1487,39 +1458,35 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||||||
MJ1_printf("ExecInitMergeJoin: %s\n",
|
MJ1_printf("ExecInitMergeJoin: %s\n",
|
||||||
"initializing node");
|
"initializing node");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign the node's execution state and
|
* assign the node's execution state and get the range table and
|
||||||
* get the range table and direction from it
|
* direction from it
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->join.plan.state = estate;
|
node->join.plan.state = estate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create new merge state for node
|
* create new merge state for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
mergestate = makeNode(MergeJoinState);
|
mergestate = makeNode(MergeJoinState);
|
||||||
node->mergestate = mergestate;
|
node->mergestate = mergestate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* + create expression context for node
|
* create expression context for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &mergestate->jstate);
|
ExecAssignExprContext(estate, &mergestate->jstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize subplans
|
* initialize subplans
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
|
ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
|
||||||
ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
|
ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
|
||||||
|
|
||||||
#define MERGEJOIN_NSLOTS 4
|
#define MERGEJOIN_NSLOTS 4
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &mergestate->jstate);
|
ExecInitResultTupleSlot(estate, &mergestate->jstate);
|
||||||
|
|
||||||
@@ -1569,16 +1536,14 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||||||
(int) node->join.jointype);
|
(int) node->join.jointype);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize tuple type and projection info
|
* initialize tuple type and projection info
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &mergestate->jstate);
|
ExecAssignResultTypeFromTL((Plan *) node, &mergestate->jstate);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &mergestate->jstate);
|
ExecAssignProjectionInfo((Plan *) node, &mergestate->jstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* form merge skip qualifications
|
* form merge skip qualifications
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
joinclauses = node->mergeclauses;
|
joinclauses = node->mergeclauses;
|
||||||
mergestate->mj_OuterSkipQual = MJFormSkipQual(joinclauses, "<");
|
mergestate->mj_OuterSkipQual = MJFormSkipQual(joinclauses, "<");
|
||||||
@@ -1590,9 +1555,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||||||
MJ_nodeDisplay(mergestate->mj_InnerSkipQual);
|
MJ_nodeDisplay(mergestate->mj_InnerSkipQual);
|
||||||
MJ_printf("\n");
|
MJ_printf("\n");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize join state
|
* initialize join state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
|
mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
|
||||||
mergestate->jstate.cs_TupFromTlist = false;
|
mergestate->jstate.cs_TupFromTlist = false;
|
||||||
@@ -1601,9 +1565,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||||||
mergestate->mj_OuterTupleSlot = NULL;
|
mergestate->mj_OuterTupleSlot = NULL;
|
||||||
mergestate->mj_InnerTupleSlot = NULL;
|
mergestate->mj_InnerTupleSlot = NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialization successful
|
* initialization successful
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
MJ1_printf("ExecInitMergeJoin: %s\n",
|
MJ1_printf("ExecInitMergeJoin: %s\n",
|
||||||
"node initialized");
|
"node initialized");
|
||||||
@@ -1634,34 +1597,29 @@ ExecEndMergeJoin(MergeJoin *node)
|
|||||||
MJ1_printf("ExecEndMergeJoin: %s\n",
|
MJ1_printf("ExecEndMergeJoin: %s\n",
|
||||||
"ending node processing");
|
"ending node processing");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get state information from the node
|
* get state information from the node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
mergestate = node->mergestate;
|
mergestate = node->mergestate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* Free the projection info and the scan attribute info
|
||||||
*
|
*
|
||||||
* Note: we don't ExecFreeResultType(mergestate)
|
* Note: we don't ExecFreeResultType(mergestate) because the rule manager
|
||||||
* because the rule manager depends on the tupType
|
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||||
* returned by ExecMain(). So for now, this
|
* freed at end-transaction time. -cim 6/2/91
|
||||||
* is freed at end-transaction time. -cim 6/2/91
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&mergestate->jstate);
|
ExecFreeProjectionInfo(&mergestate->jstate);
|
||||||
ExecFreeExprContext(&mergestate->jstate);
|
ExecFreeExprContext(&mergestate->jstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* shut down the subplans
|
* shut down the subplans
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecEndNode((Plan *) innerPlan((Plan *) node), (Plan *) node);
|
ExecEndNode((Plan *) innerPlan((Plan *) node), (Plan *) node);
|
||||||
ExecEndNode((Plan *) outerPlan((Plan *) node), (Plan *) node);
|
ExecEndNode((Plan *) outerPlan((Plan *) node), (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(mergestate->jstate.cs_ResultTupleSlot);
|
ExecClearTuple(mergestate->jstate.cs_ResultTupleSlot);
|
||||||
ExecClearTuple(mergestate->mj_MarkedTupleSlot);
|
ExecClearTuple(mergestate->mj_MarkedTupleSlot);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.23 2001/03/22 03:59:29 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.24 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -68,9 +68,8 @@ ExecNestLoop(NestLoop *node)
|
|||||||
List *otherqual;
|
List *otherqual;
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from the node
|
* get information from the node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ENL1_printf("getting info from node");
|
ENL1_printf("getting info from node");
|
||||||
|
|
||||||
@@ -81,18 +80,16 @@ ExecNestLoop(NestLoop *node)
|
|||||||
innerPlan = innerPlan((Plan *) node);
|
innerPlan = innerPlan((Plan *) node);
|
||||||
econtext = nlstate->jstate.cs_ExprContext;
|
econtext = nlstate->jstate.cs_ExprContext;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the current outer tuple
|
* get the current outer tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot;
|
outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Check to see if we're still projecting out tuples from a previous
|
* Check to see if we're still projecting out tuples from a previous
|
||||||
* join tuple (because there is a function-returning-set in the
|
* join tuple (because there is a function-returning-set in the
|
||||||
* projection expressions). If so, try to project another one.
|
* projection expressions). If so, try to project another one.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (nlstate->jstate.cs_TupFromTlist)
|
if (nlstate->jstate.cs_TupFromTlist)
|
||||||
{
|
{
|
||||||
@@ -106,37 +103,34 @@ ExecNestLoop(NestLoop *node)
|
|||||||
nlstate->jstate.cs_TupFromTlist = false;
|
nlstate->jstate.cs_TupFromTlist = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Reset per-tuple memory context to free any expression evaluation
|
* Reset per-tuple memory context to free any expression evaluation
|
||||||
* storage allocated in the previous tuple cycle. Note this can't
|
* storage allocated in the previous tuple cycle. Note this can't
|
||||||
* happen until we're done projecting out tuples from a join tuple.
|
* happen until we're done projecting out tuples from a join tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Ok, everything is setup for the join so now loop until
|
* Ok, everything is setup for the join so now loop until we return a
|
||||||
* we return a qualifying join tuple.
|
* qualifying join tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ENL1_printf("entering main loop");
|
ENL1_printf("entering main loop");
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* If we don't have an outer tuple, get the next one and
|
/*
|
||||||
* reset the inner scan.
|
* If we don't have an outer tuple, get the next one and reset the
|
||||||
* ----------------
|
* inner scan.
|
||||||
*/
|
*/
|
||||||
if (nlstate->nl_NeedNewOuter)
|
if (nlstate->nl_NeedNewOuter)
|
||||||
{
|
{
|
||||||
ENL1_printf("getting new outer tuple");
|
ENL1_printf("getting new outer tuple");
|
||||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if there are no more outer tuples, then the join
|
* if there are no more outer tuples, then the join is
|
||||||
* is complete..
|
* complete..
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (TupIsNull(outerTupleSlot))
|
if (TupIsNull(outerTupleSlot))
|
||||||
{
|
{
|
||||||
@@ -150,9 +144,8 @@ ExecNestLoop(NestLoop *node)
|
|||||||
nlstate->nl_NeedNewOuter = false;
|
nlstate->nl_NeedNewOuter = false;
|
||||||
nlstate->nl_MatchedOuter = false;
|
nlstate->nl_MatchedOuter = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now rescan the inner plan
|
* now rescan the inner plan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ENL1_printf("rescanning inner plan");
|
ENL1_printf("rescanning inner plan");
|
||||||
|
|
||||||
@@ -164,9 +157,8 @@ ExecNestLoop(NestLoop *node)
|
|||||||
ExecReScan(innerPlan, econtext, (Plan *) node);
|
ExecReScan(innerPlan, econtext, (Plan *) node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* we have an outerTuple, try to get the next inner tuple.
|
* we have an outerTuple, try to get the next inner tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ENL1_printf("getting new inner tuple");
|
ENL1_printf("getting new inner tuple");
|
||||||
|
|
||||||
@@ -195,11 +187,11 @@ ExecNestLoop(NestLoop *node)
|
|||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* qualification was satisfied so we project and
|
* qualification was satisfied so we project and
|
||||||
* return the slot containing the result tuple
|
* return the slot containing the result tuple using
|
||||||
* using ExecProject().
|
* ExecProject().
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
@@ -223,14 +215,13 @@ ExecNestLoop(NestLoop *node)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* at this point we have a new pair of inner and outer
|
* at this point we have a new pair of inner and outer tuples so
|
||||||
* tuples so we test the inner and outer tuples to see
|
* we test the inner and outer tuples to see if they satisfy the
|
||||||
* if they satisfy the node's qualification.
|
* node's qualification.
|
||||||
*
|
*
|
||||||
* Only the joinquals determine MatchedOuter status,
|
* Only the joinquals determine MatchedOuter status, but all quals
|
||||||
* but all quals must pass to actually return the tuple.
|
* must pass to actually return the tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ENL1_printf("testing qualification");
|
ENL1_printf("testing qualification");
|
||||||
|
|
||||||
@@ -240,11 +231,11 @@ ExecNestLoop(NestLoop *node)
|
|||||||
|
|
||||||
if (otherqual == NIL || ExecQual(otherqual, econtext, false))
|
if (otherqual == NIL || ExecQual(otherqual, econtext, false))
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* qualification was satisfied so we project and
|
/*
|
||||||
* return the slot containing the result tuple
|
* qualification was satisfied so we project and return
|
||||||
* using ExecProject().
|
* the slot containing the result tuple using
|
||||||
* ----------------
|
* ExecProject().
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
@@ -262,9 +253,8 @@ ExecNestLoop(NestLoop *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Tuple fails qual, so free per-tuple memory and try again.
|
* Tuple fails qual, so free per-tuple memory and try again.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
@@ -288,38 +278,34 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
|
|||||||
NL1_printf("ExecInitNestLoop: %s\n",
|
NL1_printf("ExecInitNestLoop: %s\n",
|
||||||
"initializing node");
|
"initializing node");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign execution state to node
|
* assign execution state to node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->join.plan.state = estate;
|
node->join.plan.state = estate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create new nest loop state
|
* create new nest loop state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
nlstate = makeNode(NestLoopState);
|
nlstate = makeNode(NestLoopState);
|
||||||
node->nlstate = nlstate;
|
node->nlstate = nlstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* + create expression context for node
|
* create expression context for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &nlstate->jstate);
|
ExecAssignExprContext(estate, &nlstate->jstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now initialize children
|
* now initialize children
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
|
ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
|
||||||
ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
|
ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
|
||||||
|
|
||||||
#define NESTLOOP_NSLOTS 2
|
#define NESTLOOP_NSLOTS 2
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &nlstate->jstate);
|
ExecInitResultTupleSlot(estate, &nlstate->jstate);
|
||||||
|
|
||||||
@@ -337,16 +323,14 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
|
|||||||
(int) node->join.jointype);
|
(int) node->join.jointype);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize tuple type and projection info
|
* initialize tuple type and projection info
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &nlstate->jstate);
|
ExecAssignResultTypeFromTL((Plan *) node, &nlstate->jstate);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &nlstate->jstate);
|
ExecAssignProjectionInfo((Plan *) node, &nlstate->jstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* finally, wipe the current outer tuple clean.
|
* finally, wipe the current outer tuple clean.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
nlstate->jstate.cs_OuterTupleSlot = NULL;
|
nlstate->jstate.cs_OuterTupleSlot = NULL;
|
||||||
nlstate->jstate.cs_TupFromTlist = false;
|
nlstate->jstate.cs_TupFromTlist = false;
|
||||||
@@ -380,34 +364,29 @@ ExecEndNestLoop(NestLoop *node)
|
|||||||
NL1_printf("ExecEndNestLoop: %s\n",
|
NL1_printf("ExecEndNestLoop: %s\n",
|
||||||
"ending node processing");
|
"ending node processing");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get info from the node
|
* get info from the node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
nlstate = node->nlstate;
|
nlstate = node->nlstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Free the projection info
|
* Free the projection info
|
||||||
*
|
*
|
||||||
* Note: we don't ExecFreeResultType(nlstate)
|
* Note: we don't ExecFreeResultType(nlstate) because the rule manager
|
||||||
* because the rule manager depends on the tupType
|
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||||
* returned by ExecMain(). So for now, this
|
* freed at end-transaction time. -cim 6/2/91
|
||||||
* is freed at end-transaction time. -cim 6/2/91
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&nlstate->jstate);
|
ExecFreeProjectionInfo(&nlstate->jstate);
|
||||||
ExecFreeExprContext(&nlstate->jstate);
|
ExecFreeExprContext(&nlstate->jstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* close down subplans
|
* close down subplans
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
||||||
ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
|
ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(nlstate->jstate.cs_ResultTupleSlot);
|
ExecClearTuple(nlstate->jstate.cs_ResultTupleSlot);
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.18 2001/03/22 03:59:29 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.19 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -69,16 +69,14 @@ ExecResult(Result *node)
|
|||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize the result node's state
|
* initialize the result node's state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
resstate = node->resstate;
|
resstate = node->resstate;
|
||||||
econtext = resstate->cstate.cs_ExprContext;
|
econtext = resstate->cstate.cs_ExprContext;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* check constant qualifications like (2 > 1), if not already done
|
* check constant qualifications like (2 > 1), if not already done
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (resstate->rs_checkqual)
|
if (resstate->rs_checkqual)
|
||||||
{
|
{
|
||||||
@@ -94,11 +92,10 @@ ExecResult(Result *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Check to see if we're still projecting out tuples from a previous
|
* Check to see if we're still projecting out tuples from a previous
|
||||||
* scan tuple (because there is a function-returning-set in the
|
* scan tuple (because there is a function-returning-set in the
|
||||||
* projection expressions). If so, try to project another one.
|
* projection expressions). If so, try to project another one.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (resstate->cstate.cs_TupFromTlist)
|
if (resstate->cstate.cs_TupFromTlist)
|
||||||
{
|
{
|
||||||
@@ -109,20 +106,18 @@ ExecResult(Result *node)
|
|||||||
resstate->cstate.cs_TupFromTlist = false;
|
resstate->cstate.cs_TupFromTlist = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Reset per-tuple memory context to free any expression evaluation
|
* Reset per-tuple memory context to free any expression evaluation
|
||||||
* storage allocated in the previous tuple cycle. Note this can't
|
* storage allocated in the previous tuple cycle. Note this can't
|
||||||
* happen until we're done projecting out tuples from a scan tuple.
|
* happen until we're done projecting out tuples from a scan tuple.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if rs_done is true then it means that we were asked to return
|
* if rs_done is true then it means that we were asked to return a
|
||||||
* a constant tuple and we already did the last time ExecResult()
|
* constant tuple and we already did the last time ExecResult() was
|
||||||
* was called, OR that we failed the constant qual check.
|
* called, OR that we failed the constant qual check. Either way, now
|
||||||
* Either way, now we are through.
|
* we are through.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
while (!resstate->rs_done)
|
while (!resstate->rs_done)
|
||||||
{
|
{
|
||||||
@@ -130,9 +125,10 @@ ExecResult(Result *node)
|
|||||||
|
|
||||||
if (outerPlan != NULL)
|
if (outerPlan != NULL)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* retrieve tuples from the outer plan until there are no more.
|
/*
|
||||||
* ----------------
|
* retrieve tuples from the outer plan until there are no
|
||||||
|
* more.
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
||||||
|
|
||||||
@@ -141,28 +137,27 @@ ExecResult(Result *node)
|
|||||||
|
|
||||||
resstate->cstate.cs_OuterTupleSlot = outerTupleSlot;
|
resstate->cstate.cs_OuterTupleSlot = outerTupleSlot;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* XXX gross hack. use outer tuple as scan tuple for projection
|
* XXX gross hack. use outer tuple as scan tuple for
|
||||||
* ----------------
|
* projection
|
||||||
*/
|
*/
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
econtext->ecxt_scantuple = outerTupleSlot;
|
econtext->ecxt_scantuple = outerTupleSlot;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* if we don't have an outer plan, then we are just generating
|
* if we don't have an outer plan, then we are just generating
|
||||||
* the results from a constant target list. Do it only once.
|
* the results from a constant target list. Do it only once.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
resstate->rs_done = true;
|
resstate->rs_done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* form the result tuple using ExecProject(), and return it
|
* form the result tuple using ExecProject(), and return it ---
|
||||||
* --- unless the projection produces an empty set, in which case
|
* unless the projection produces an empty set, in which case we
|
||||||
* we must loop back to see if there are more outerPlan tuples.
|
* must loop back to see if there are more outerPlan tuples.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
resultSlot = ExecProject(resstate->cstate.cs_ProjInfo, &isDone);
|
resultSlot = ExecProject(resstate->cstate.cs_ProjInfo, &isDone);
|
||||||
|
|
||||||
@@ -189,39 +184,35 @@ ExecInitResult(Result *node, EState *estate, Plan *parent)
|
|||||||
{
|
{
|
||||||
ResultState *resstate;
|
ResultState *resstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign execution state to node
|
* assign execution state to node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->plan.state = estate;
|
node->plan.state = estate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create new ResultState for node
|
* create new ResultState for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
resstate = makeNode(ResultState);
|
resstate = makeNode(ResultState);
|
||||||
resstate->rs_done = false;
|
resstate->rs_done = false;
|
||||||
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
|
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
|
||||||
node->resstate = resstate;
|
node->resstate = resstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* + create expression context for node
|
* create expression context for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &resstate->cstate);
|
ExecAssignExprContext(estate, &resstate->cstate);
|
||||||
|
|
||||||
#define RESULT_NSLOTS 1
|
#define RESULT_NSLOTS 1
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &resstate->cstate);
|
ExecInitResultTupleSlot(estate, &resstate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* then initialize children
|
* then initialize children
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitNode(outerPlan(node), estate, (Plan *) node);
|
ExecInitNode(outerPlan(node), estate, (Plan *) node);
|
||||||
|
|
||||||
@@ -230,9 +221,8 @@ ExecInitResult(Result *node, EState *estate, Plan *parent)
|
|||||||
*/
|
*/
|
||||||
Assert(innerPlan(node) == NULL);
|
Assert(innerPlan(node) == NULL);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize tuple type and projection info
|
* initialize tuple type and projection info
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &resstate->cstate);
|
ExecAssignResultTypeFromTL((Plan *) node, &resstate->cstate);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &resstate->cstate);
|
ExecAssignProjectionInfo((Plan *) node, &resstate->cstate);
|
||||||
@@ -259,27 +249,23 @@ ExecEndResult(Result *node)
|
|||||||
|
|
||||||
resstate = node->resstate;
|
resstate = node->resstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Free the projection info
|
* Free the projection info
|
||||||
*
|
*
|
||||||
* Note: we don't ExecFreeResultType(resstate)
|
* Note: we don't ExecFreeResultType(resstate) because the rule manager
|
||||||
* because the rule manager depends on the tupType
|
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||||
* returned by ExecMain(). So for now, this
|
* freed at end-transaction time. -cim 6/2/91
|
||||||
* is freed at end-transaction time. -cim 6/2/91
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&resstate->cstate);
|
ExecFreeProjectionInfo(&resstate->cstate);
|
||||||
ExecFreeExprContext(&resstate->cstate);
|
ExecFreeExprContext(&resstate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* shut down subplans
|
* shut down subplans
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecEndNode(outerPlan(node), (Plan *) node);
|
ExecEndNode(outerPlan(node), (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
|
ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
|
||||||
pfree(resstate);
|
pfree(resstate);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.28 2001/03/22 03:59:29 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.29 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -54,9 +54,8 @@ SeqNext(SeqScan *node)
|
|||||||
ScanDirection direction;
|
ScanDirection direction;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from the estate and scan state
|
* get information from the estate and scan state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
estate = node->plan.state;
|
estate = node->plan.state;
|
||||||
scanstate = node->scanstate;
|
scanstate = node->scanstate;
|
||||||
@@ -91,21 +90,19 @@ SeqNext(SeqScan *node)
|
|||||||
return (slot);
|
return (slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the next tuple from the access methods
|
* get the next tuple from the access methods
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tuple = heap_getnext(scandesc, ScanDirectionIsBackward(direction));
|
tuple = heap_getnext(scandesc, ScanDirectionIsBackward(direction));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* save the tuple and the buffer returned to us by the access methods
|
* save the tuple and the buffer returned to us by the access methods
|
||||||
* in our scan tuple slot and return the slot. Note: we pass 'false'
|
* in our scan tuple slot and return the slot. Note: we pass 'false'
|
||||||
* because tuples returned by heap_getnext() are pointers onto
|
* because tuples returned by heap_getnext() are pointers onto disk
|
||||||
* disk pages and were not created with palloc() and so should not
|
* pages and were not created with palloc() and so should not be
|
||||||
* be pfree()'d. Note also that ExecStoreTuple will increment the
|
* pfree()'d. Note also that ExecStoreTuple will increment the
|
||||||
* refcount of the buffer; the refcount will not be dropped until
|
* refcount of the buffer; the refcount will not be dropped until the
|
||||||
* the tuple table slot is cleared.
|
* tuple table slot is cleared.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
slot = ExecStoreTuple(tuple,/* tuple to store */
|
slot = ExecStoreTuple(tuple,/* tuple to store */
|
||||||
@@ -130,9 +127,9 @@ SeqNext(SeqScan *node)
|
|||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecSeqScan(SeqScan *node)
|
ExecSeqScan(SeqScan *node)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* use SeqNext as access method
|
* use SeqNext as access method
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
return ExecScan(node, (ExecScanAccessMtd) SeqNext);
|
return ExecScan(node, (ExecScanAccessMtd) SeqNext);
|
||||||
}
|
}
|
||||||
@@ -156,11 +153,9 @@ InitScanRelation(SeqScan *node, EState *estate,
|
|||||||
Relation currentRelation;
|
Relation currentRelation;
|
||||||
HeapScanDesc currentScanDesc;
|
HeapScanDesc currentScanDesc;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the relation object id from the relid'th entry
|
* get the relation object id from the relid'th entry in the range
|
||||||
* in the range table, open that relation and initialize
|
* table, open that relation and initialize the scan state...
|
||||||
* the scan state...
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
relid = node->scanrelid;
|
relid = node->scanrelid;
|
||||||
rangeTable = estate->es_range_table;
|
rangeTable = estate->es_range_table;
|
||||||
@@ -197,55 +192,49 @@ ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
|
|||||||
Oid reloid;
|
Oid reloid;
|
||||||
HeapScanDesc scandesc;
|
HeapScanDesc scandesc;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Once upon a time it was possible to have an outerPlan of a SeqScan,
|
* Once upon a time it was possible to have an outerPlan of a SeqScan,
|
||||||
* but not any more.
|
* but not any more.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(outerPlan((Plan *) node) == NULL);
|
Assert(outerPlan((Plan *) node) == NULL);
|
||||||
Assert(innerPlan((Plan *) node) == NULL);
|
Assert(innerPlan((Plan *) node) == NULL);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign the node's execution state
|
* assign the node's execution state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->plan.state = estate;
|
node->plan.state = estate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create new CommonScanState for node
|
* create new CommonScanState for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
scanstate = makeNode(CommonScanState);
|
scanstate = makeNode(CommonScanState);
|
||||||
node->scanstate = scanstate;
|
node->scanstate = scanstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* + create expression context for node
|
* create expression context for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &scanstate->cstate);
|
ExecAssignExprContext(estate, &scanstate->cstate);
|
||||||
|
|
||||||
#define SEQSCAN_NSLOTS 3
|
#define SEQSCAN_NSLOTS 3
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &scanstate->cstate);
|
ExecInitResultTupleSlot(estate, &scanstate->cstate);
|
||||||
ExecInitScanTupleSlot(estate, scanstate);
|
ExecInitScanTupleSlot(estate, scanstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize scan relation
|
* initialize scan relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
reloid = InitScanRelation(node, estate, scanstate);
|
reloid = InitScanRelation(node, estate, scanstate);
|
||||||
|
|
||||||
scandesc = scanstate->css_currentScanDesc;
|
scandesc = scanstate->css_currentScanDesc;
|
||||||
scanstate->cstate.cs_TupFromTlist = false;
|
scanstate->cstate.cs_TupFromTlist = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize tuple type
|
* initialize tuple type
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
|
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
|
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
|
||||||
@@ -272,33 +261,28 @@ ExecEndSeqScan(SeqScan *node)
|
|||||||
{
|
{
|
||||||
CommonScanState *scanstate;
|
CommonScanState *scanstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from node
|
* get information from node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
scanstate = node->scanstate;
|
scanstate = node->scanstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* Free the projection info and the scan attribute info
|
||||||
*
|
*
|
||||||
* Note: we don't ExecFreeResultType(scanstate)
|
* Note: we don't ExecFreeResultType(scanstate) because the rule manager
|
||||||
* because the rule manager depends on the tupType
|
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||||
* returned by ExecMain(). So for now, this
|
* freed at end-transaction time. -cim 6/2/91
|
||||||
* is freed at end-transaction time. -cim 6/2/91
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&scanstate->cstate);
|
ExecFreeProjectionInfo(&scanstate->cstate);
|
||||||
ExecFreeExprContext(&scanstate->cstate);
|
ExecFreeExprContext(&scanstate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* close scan relation
|
* close scan relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecCloseR((Plan *) node);
|
ExecCloseR((Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
|
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
|
||||||
ExecClearTuple(scanstate->css_ScanTupleSlot);
|
ExecClearTuple(scanstate->css_ScanTupleSlot);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.3 2001/03/22 03:59:29 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.4 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -51,19 +51,17 @@ ExecSetOp(SetOp *node)
|
|||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from the node
|
* get information from the node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
setopstate = node->setopstate;
|
setopstate = node->setopstate;
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan((Plan *) node);
|
||||||
resultTupleSlot = setopstate->cstate.cs_ResultTupleSlot;
|
resultTupleSlot = setopstate->cstate.cs_ResultTupleSlot;
|
||||||
tupDesc = ExecGetResultType(&setopstate->cstate);
|
tupDesc = ExecGetResultType(&setopstate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* If the previously-returned tuple needs to be returned more than
|
* If the previously-returned tuple needs to be returned more than
|
||||||
* once, keep returning it.
|
* once, keep returning it.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (setopstate->numOutput > 0)
|
if (setopstate->numOutput > 0)
|
||||||
{
|
{
|
||||||
@@ -74,23 +72,21 @@ ExecSetOp(SetOp *node)
|
|||||||
/* Flag that we have no current tuple */
|
/* Flag that we have no current tuple */
|
||||||
ExecClearTuple(resultTupleSlot);
|
ExecClearTuple(resultTupleSlot);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Absorb groups of duplicate tuples, counting them, and
|
* Absorb groups of duplicate tuples, counting them, and saving the
|
||||||
* saving the first of each group as a possible return value.
|
* first of each group as a possible return value. At the end of each
|
||||||
* At the end of each group, decide whether to return anything.
|
* group, decide whether to return anything.
|
||||||
*
|
*
|
||||||
* We assume that the tuples arrive in sorted order
|
* We assume that the tuples arrive in sorted order so we can detect
|
||||||
* so we can detect duplicates easily.
|
* duplicates easily.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
TupleTableSlot *inputTupleSlot;
|
TupleTableSlot *inputTupleSlot;
|
||||||
bool endOfGroup;
|
bool endOfGroup;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* fetch a tuple from the outer subplan, unless we already did.
|
* fetch a tuple from the outer subplan, unless we already did.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (setopstate->cstate.cs_OuterTupleSlot == NULL &&
|
if (setopstate->cstate.cs_OuterTupleSlot == NULL &&
|
||||||
!setopstate->subplan_done)
|
!setopstate->subplan_done)
|
||||||
@@ -235,15 +231,13 @@ ExecInitSetOp(SetOp *node, EState *estate, Plan *parent)
|
|||||||
SetOpState *setopstate;
|
SetOpState *setopstate;
|
||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign execution state to node
|
* assign execution state to node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->plan.state = estate;
|
node->plan.state = estate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create new SetOpState for node
|
* create new SetOpState for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
setopstate = makeNode(SetOpState);
|
setopstate = makeNode(SetOpState);
|
||||||
node->setopstate = setopstate;
|
node->setopstate = setopstate;
|
||||||
@@ -251,13 +245,12 @@ ExecInitSetOp(SetOp *node, EState *estate, Plan *parent)
|
|||||||
setopstate->subplan_done = false;
|
setopstate->subplan_done = false;
|
||||||
setopstate->numOutput = 0;
|
setopstate->numOutput = 0;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* SetOp nodes have no ExprContext initialization because
|
* SetOp nodes have no ExprContext initialization because they never call
|
||||||
* they never call ExecQual or ExecProject. But they do need a
|
* ExecQual or ExecProject. But they do need a per-tuple memory
|
||||||
* per-tuple memory context anyway for calling execTuplesMatch.
|
* context anyway for calling execTuplesMatch.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
setopstate->tempContext =
|
setopstate->tempContext =
|
||||||
AllocSetContextCreate(CurrentMemoryContext,
|
AllocSetContextCreate(CurrentMemoryContext,
|
||||||
@@ -267,23 +260,21 @@ ExecInitSetOp(SetOp *node, EState *estate, Plan *parent)
|
|||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
#define SETOP_NSLOTS 1
|
#define SETOP_NSLOTS 1
|
||||||
/* ------------
|
|
||||||
|
/*
|
||||||
* Tuple table initialization
|
* Tuple table initialization
|
||||||
* ------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &setopstate->cstate);
|
ExecInitResultTupleSlot(estate, &setopstate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* then initialize outer plan
|
* then initialize outer plan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan((Plan *) node);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* setop nodes do no projections, so initialize
|
* setop nodes do no projections, so initialize projection info for
|
||||||
* projection info for this node appropriately
|
* this node appropriately
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &setopstate->cstate);
|
ExecAssignResultTypeFromOuterPlan((Plan *) node, &setopstate->cstate);
|
||||||
setopstate->cstate.cs_ProjInfo = NULL;
|
setopstate->cstate.cs_ProjInfo = NULL;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.31 2001/01/29 00:39:19 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.32 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -39,25 +39,22 @@ FormSortKeys(Sort *sortnode)
|
|||||||
Index reskey;
|
Index reskey;
|
||||||
Oid reskeyop;
|
Oid reskeyop;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from the node
|
* get information from the node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
targetList = sortnode->plan.targetlist;
|
targetList = sortnode->plan.targetlist;
|
||||||
keycount = sortnode->keycount;
|
keycount = sortnode->keycount;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* first allocate space for scan keys
|
* first allocate space for scan keys
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (keycount <= 0)
|
if (keycount <= 0)
|
||||||
elog(ERROR, "FormSortKeys: keycount <= 0");
|
elog(ERROR, "FormSortKeys: keycount <= 0");
|
||||||
sortkeys = (ScanKey) palloc(keycount * sizeof(ScanKeyData));
|
sortkeys = (ScanKey) palloc(keycount * sizeof(ScanKeyData));
|
||||||
MemSet((char *) sortkeys, 0, keycount * sizeof(ScanKeyData));
|
MemSet((char *) sortkeys, 0, keycount * sizeof(ScanKeyData));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* form each scan key from the resdom info in the target list
|
* form each scan key from the resdom info in the target list
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
foreach(tl, targetList)
|
foreach(tl, targetList)
|
||||||
{
|
{
|
||||||
@@ -106,9 +103,8 @@ ExecSort(Sort *node)
|
|||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
bool should_free;
|
bool should_free;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get state info from node
|
* get state info from node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
SO1_printf("ExecSort: %s\n",
|
SO1_printf("ExecSort: %s\n",
|
||||||
"entering routine");
|
"entering routine");
|
||||||
@@ -118,11 +114,10 @@ ExecSort(Sort *node)
|
|||||||
dir = estate->es_direction;
|
dir = estate->es_direction;
|
||||||
tuplesortstate = (Tuplesortstate *) sortstate->tuplesortstate;
|
tuplesortstate = (Tuplesortstate *) sortstate->tuplesortstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* If first time through, read all tuples from outer plan and
|
* If first time through, read all tuples from outer plan and pass
|
||||||
* pass them to tuplesort.c.
|
* them to tuplesort.c. Subsequent calls just fetch tuples from
|
||||||
* Subsequent calls just fetch tuples from tuplesort.
|
* tuplesort.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!sortstate->sort_Done)
|
if (!sortstate->sort_Done)
|
||||||
@@ -134,17 +129,16 @@ ExecSort(Sort *node)
|
|||||||
|
|
||||||
SO1_printf("ExecSort: %s\n",
|
SO1_printf("ExecSort: %s\n",
|
||||||
"sorting subplan");
|
"sorting subplan");
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* Want to scan subplan in the forward direction while creating
|
* Want to scan subplan in the forward direction while creating
|
||||||
* the sorted data. (Does setting my direction actually affect
|
* the sorted data. (Does setting my direction actually affect
|
||||||
* the subplan? I bet this is useless code...)
|
* the subplan? I bet this is useless code...)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
estate->es_direction = ForwardScanDirection;
|
estate->es_direction = ForwardScanDirection;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Initialize tuplesort module.
|
* Initialize tuplesort module.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
SO1_printf("ExecSort: %s\n",
|
SO1_printf("ExecSort: %s\n",
|
||||||
"calling tuplesort_begin");
|
"calling tuplesort_begin");
|
||||||
@@ -159,9 +153,8 @@ ExecSort(Sort *node)
|
|||||||
|
|
||||||
sortstate->tuplesortstate = (void *) tuplesortstate;
|
sortstate->tuplesortstate = (void *) tuplesortstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Scan the subplan and feed all the tuples to tuplesort.
|
* Scan the subplan and feed all the tuples to tuplesort.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
@@ -174,27 +167,23 @@ ExecSort(Sort *node)
|
|||||||
tuplesort_puttuple(tuplesortstate, (void *) slot->val);
|
tuplesort_puttuple(tuplesortstate, (void *) slot->val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Complete the sort.
|
* Complete the sort.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tuplesort_performsort(tuplesortstate);
|
tuplesort_performsort(tuplesortstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* restore to user specified direction
|
* restore to user specified direction
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
estate->es_direction = dir;
|
estate->es_direction = dir;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* make sure the tuple descriptor is up to date (is this needed?)
|
* make sure the tuple descriptor is up to date (is this needed?)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultType(&sortstate->csstate.cstate, tupDesc, false);
|
ExecAssignResultType(&sortstate->csstate.cstate, tupDesc, false);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* finally set the sorted flag to true
|
* finally set the sorted flag to true
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
sortstate->sort_Done = true;
|
sortstate->sort_Done = true;
|
||||||
SO1_printf(stderr, "ExecSort: sorting done.\n");
|
SO1_printf(stderr, "ExecSort: sorting done.\n");
|
||||||
@@ -203,10 +192,9 @@ ExecSort(Sort *node)
|
|||||||
SO1_printf("ExecSort: %s\n",
|
SO1_printf("ExecSort: %s\n",
|
||||||
"retrieving tuple from tuplesort");
|
"retrieving tuple from tuplesort");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Get the first or next tuple from tuplesort.
|
* Get the first or next tuple from tuplesort. Returns NULL if no more
|
||||||
* Returns NULL if no more tuples.
|
* tuples.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
heapTuple = tuplesort_getheaptuple(tuplesortstate,
|
heapTuple = tuplesort_getheaptuple(tuplesortstate,
|
||||||
ScanDirectionIsForward(dir),
|
ScanDirectionIsForward(dir),
|
||||||
@@ -232,15 +220,13 @@ ExecInitSort(Sort *node, EState *estate, Plan *parent)
|
|||||||
SO1_printf("ExecInitSort: %s\n",
|
SO1_printf("ExecInitSort: %s\n",
|
||||||
"initializing sort node");
|
"initializing sort node");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign the node's execution state
|
* assign the node's execution state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->plan.state = estate;
|
node->plan.state = estate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create state structure
|
* create state structure
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
sortstate = makeNode(SortState);
|
sortstate = makeNode(SortState);
|
||||||
sortstate->sort_Done = false;
|
sortstate->sort_Done = false;
|
||||||
@@ -249,42 +235,37 @@ ExecInitSort(Sort *node, EState *estate, Plan *parent)
|
|||||||
|
|
||||||
node->sortstate = sortstate;
|
node->sortstate = sortstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* Sort nodes don't initialize their ExprContexts because
|
* Sort nodes don't initialize their ExprContexts because they never call
|
||||||
* they never call ExecQual or ExecProject.
|
* ExecQual or ExecProject.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SORT_NSLOTS 1
|
#define SORT_NSLOTS 1
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
*
|
*
|
||||||
* sort nodes only return scan tuples from their sorted
|
* sort nodes only return scan tuples from their sorted relation.
|
||||||
* relation.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &sortstate->csstate.cstate);
|
ExecInitResultTupleSlot(estate, &sortstate->csstate.cstate);
|
||||||
ExecInitScanTupleSlot(estate, &sortstate->csstate);
|
ExecInitScanTupleSlot(estate, &sortstate->csstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initializes child nodes
|
* initializes child nodes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan((Plan *) node);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize sortstate information
|
* initialize sortstate information
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
sortstate->sort_Keys = FormSortKeys(node);
|
sortstate->sort_Keys = FormSortKeys(node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize tuple type. no need to initialize projection
|
* initialize tuple type. no need to initialize projection info
|
||||||
* info because this node doesn't do projections.
|
* because this node doesn't do projections.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &sortstate->csstate.cstate);
|
ExecAssignResultTypeFromOuterPlan((Plan *) node, &sortstate->csstate.cstate);
|
||||||
ExecAssignScanTypeFromOuterPlan((Plan *) node, &sortstate->csstate);
|
ExecAssignScanTypeFromOuterPlan((Plan *) node, &sortstate->csstate);
|
||||||
@@ -314,31 +295,27 @@ ExecEndSort(Sort *node)
|
|||||||
SortState *sortstate;
|
SortState *sortstate;
|
||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get info from the sort state
|
* get info from the sort state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
SO1_printf("ExecEndSort: %s\n",
|
SO1_printf("ExecEndSort: %s\n",
|
||||||
"shutting down sort node");
|
"shutting down sort node");
|
||||||
|
|
||||||
sortstate = node->sortstate;
|
sortstate = node->sortstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* shut down the subplan
|
* shut down the subplan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan((Plan *) node);
|
||||||
ExecEndNode(outerPlan, (Plan *) node);
|
ExecEndNode(outerPlan, (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(sortstate->csstate.css_ScanTupleSlot);
|
ExecClearTuple(sortstate->csstate.css_ScanTupleSlot);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Release tuplesort resources
|
* Release tuplesort resources
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (sortstate->tuplesortstate != NULL)
|
if (sortstate->tuplesortstate != NULL)
|
||||||
tuplesort_end((Tuplesortstate *) sortstate->tuplesortstate);
|
tuplesort_end((Tuplesortstate *) sortstate->tuplesortstate);
|
||||||
@@ -365,9 +342,8 @@ ExecSortMarkPos(Sort *node)
|
|||||||
{
|
{
|
||||||
SortState *sortstate = node->sortstate;
|
SortState *sortstate = node->sortstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if we haven't sorted yet, just return
|
* if we haven't sorted yet, just return
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!sortstate->sort_Done)
|
if (!sortstate->sort_Done)
|
||||||
return;
|
return;
|
||||||
@@ -386,16 +362,14 @@ ExecSortRestrPos(Sort *node)
|
|||||||
{
|
{
|
||||||
SortState *sortstate = node->sortstate;
|
SortState *sortstate = node->sortstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if we haven't sorted yet, just return.
|
* if we haven't sorted yet, just return.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!sortstate->sort_Done)
|
if (!sortstate->sort_Done)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* restore the scan to the previously marked position
|
* restore the scan to the previously marked position
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tuplesort_restorepos((Tuplesortstate *) sortstate->tuplesortstate);
|
tuplesort_restorepos((Tuplesortstate *) sortstate->tuplesortstate);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.5 2001/03/22 03:59:29 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.6 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -55,9 +55,8 @@ SubqueryNext(SubqueryScan *node)
|
|||||||
ScanDirection direction;
|
ScanDirection direction;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from the estate and scan state
|
* get information from the estate and scan state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
estate = node->scan.plan.state;
|
estate = node->scan.plan.state;
|
||||||
subquerystate = (SubqueryScanState *) node->scan.scanstate;
|
subquerystate = (SubqueryScanState *) node->scan.scanstate;
|
||||||
@@ -85,9 +84,8 @@ SubqueryNext(SubqueryScan *node)
|
|||||||
return (slot);
|
return (slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the next tuple from the sub-query
|
* get the next tuple from the sub-query
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
subquerystate->sss_SubEState->es_direction = direction;
|
subquerystate->sss_SubEState->es_direction = direction;
|
||||||
|
|
||||||
@@ -111,9 +109,9 @@ SubqueryNext(SubqueryScan *node)
|
|||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecSubqueryScan(SubqueryScan *node)
|
ExecSubqueryScan(SubqueryScan *node)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* use SubqueryNext as access method
|
* use SubqueryNext as access method
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
return ExecScan(&node->scan, (ExecScanAccessMtd) SubqueryNext);
|
return ExecScan(&node->scan, (ExecScanAccessMtd) SubqueryNext);
|
||||||
}
|
}
|
||||||
@@ -129,46 +127,41 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
|
|||||||
RangeTblEntry *rte;
|
RangeTblEntry *rte;
|
||||||
EState *sp_estate;
|
EState *sp_estate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* SubqueryScan should not have any "normal" children.
|
* SubqueryScan should not have any "normal" children.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Assert(outerPlan((Plan *) node) == NULL);
|
Assert(outerPlan((Plan *) node) == NULL);
|
||||||
Assert(innerPlan((Plan *) node) == NULL);
|
Assert(innerPlan((Plan *) node) == NULL);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign the node's execution state
|
* assign the node's execution state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->scan.plan.state = estate;
|
node->scan.plan.state = estate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create new SubqueryScanState for node
|
* create new SubqueryScanState for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
subquerystate = makeNode(SubqueryScanState);
|
subquerystate = makeNode(SubqueryScanState);
|
||||||
node->scan.scanstate = (CommonScanState *) subquerystate;
|
node->scan.scanstate = (CommonScanState *) subquerystate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* + create expression context for node
|
* create expression context for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &subquerystate->csstate.cstate);
|
ExecAssignExprContext(estate, &subquerystate->csstate.cstate);
|
||||||
|
|
||||||
#define SUBQUERYSCAN_NSLOTS 2
|
#define SUBQUERYSCAN_NSLOTS 2
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &subquerystate->csstate.cstate);
|
ExecInitResultTupleSlot(estate, &subquerystate->csstate.cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize subquery
|
* initialize subquery
|
||||||
*
|
*
|
||||||
* This should agree with ExecInitSubPlan
|
* This should agree with ExecInitSubPlan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
|
rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
|
||||||
Assert(rte->subquery != NULL);
|
Assert(rte->subquery != NULL);
|
||||||
@@ -189,9 +182,8 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
|
|||||||
subquerystate->csstate.css_ScanTupleSlot = NULL;
|
subquerystate->csstate.css_ScanTupleSlot = NULL;
|
||||||
subquerystate->csstate.cstate.cs_TupFromTlist = false;
|
subquerystate->csstate.cstate.cs_TupFromTlist = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize tuple type
|
* initialize tuple type
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &subquerystate->csstate.cstate);
|
ExecAssignResultTypeFromTL((Plan *) node, &subquerystate->csstate.cstate);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &subquerystate->csstate.cstate);
|
ExecAssignProjectionInfo((Plan *) node, &subquerystate->csstate.cstate);
|
||||||
@@ -222,27 +214,23 @@ ExecEndSubqueryScan(SubqueryScan *node)
|
|||||||
{
|
{
|
||||||
SubqueryScanState *subquerystate;
|
SubqueryScanState *subquerystate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from node
|
* get information from node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
subquerystate = (SubqueryScanState *) node->scan.scanstate;
|
subquerystate = (SubqueryScanState *) node->scan.scanstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* Free the projection info and the scan attribute info
|
||||||
*
|
*
|
||||||
* Note: we don't ExecFreeResultType(subquerystate)
|
* Note: we don't ExecFreeResultType(subquerystate) because the rule
|
||||||
* because the rule manager depends on the tupType
|
* manager depends on the tupType returned by ExecMain(). So for now,
|
||||||
* returned by ExecMain(). So for now, this
|
* this is freed at end-transaction time. -cim 6/2/91
|
||||||
* is freed at end-transaction time. -cim 6/2/91
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&subquerystate->csstate.cstate);
|
ExecFreeProjectionInfo(&subquerystate->csstate.cstate);
|
||||||
ExecFreeExprContext(&subquerystate->csstate.cstate);
|
ExecFreeExprContext(&subquerystate->csstate.cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* close down subquery
|
* close down subquery
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecEndNode(node->subplan, node->subplan);
|
ExecEndNode(node->subplan, node->subplan);
|
||||||
|
|
||||||
@@ -250,9 +238,8 @@ ExecEndSubqueryScan(SubqueryScan *node)
|
|||||||
|
|
||||||
subquerystate->csstate.css_ScanTupleSlot = NULL;
|
subquerystate->csstate.css_ScanTupleSlot = NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(subquerystate->csstate.cstate.cs_ResultTupleSlot);
|
ExecClearTuple(subquerystate->csstate.cstate.cs_ResultTupleSlot);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.15 2001/03/22 03:59:29 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.16 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -83,9 +83,8 @@ TidNext(TidScan *node)
|
|||||||
ItemPointer *tidList,
|
ItemPointer *tidList,
|
||||||
itemptr;
|
itemptr;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* extract necessary information from tid scan node
|
* extract necessary information from tid scan node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
estate = node->scan.plan.state;
|
estate = node->scan.plan.state;
|
||||||
direction = estate->es_direction;
|
direction = estate->es_direction;
|
||||||
@@ -120,11 +119,10 @@ TidNext(TidScan *node)
|
|||||||
|
|
||||||
tuple = &(tidstate->tss_htup);
|
tuple = &(tidstate->tss_htup);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* ok, now that we have what we need, fetch an tid tuple.
|
* ok, now that we have what we need, fetch an tid tuple. if scanning
|
||||||
* if scanning this tid succeeded then return the
|
* this tid succeeded then return the appropriate heap tuple.. else
|
||||||
* appropriate heap tuple.. else return NULL.
|
* return NULL.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
bBackward = ScanDirectionIsBackward(direction);
|
bBackward = ScanDirectionIsBackward(direction);
|
||||||
if (bBackward)
|
if (bBackward)
|
||||||
@@ -161,13 +159,12 @@ TidNext(TidScan *node)
|
|||||||
bool prev_matches = false;
|
bool prev_matches = false;
|
||||||
int prev_tid;
|
int prev_tid;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* store the scanned tuple in the scan tuple slot of
|
* store the scanned tuple in the scan tuple slot of the scan
|
||||||
* the scan state. Eventually we will only do this and not
|
* state. Eventually we will only do this and not return a
|
||||||
* return a tuple. Note: we pass 'false' because tuples
|
* tuple. Note: we pass 'false' because tuples returned by
|
||||||
* returned by amgetnext are pointers onto disk pages and
|
* amgetnext are pointers onto disk pages and were not created
|
||||||
* were not created with palloc() and so should not be pfree()'d.
|
* with palloc() and so should not be pfree()'d.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecStoreTuple(tuple, /* tuple to store */
|
ExecStoreTuple(tuple, /* tuple to store */
|
||||||
slot,/* slot to store in */
|
slot,/* slot to store in */
|
||||||
@@ -211,10 +208,10 @@ TidNext(TidScan *node)
|
|||||||
if (slot_is_valid)
|
if (slot_is_valid)
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
/* ----------------
|
|
||||||
* if we get here it means the tid scan failed so we
|
/*
|
||||||
* are at the end of the scan..
|
* if we get here it means the tid scan failed so we are at the end of
|
||||||
* ----------------
|
* the scan..
|
||||||
*/
|
*/
|
||||||
return ExecClearTuple(slot);
|
return ExecClearTuple(slot);
|
||||||
}
|
}
|
||||||
@@ -241,9 +238,9 @@ TidNext(TidScan *node)
|
|||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecTidScan(TidScan *node)
|
ExecTidScan(TidScan *node)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* use TidNext as access method
|
* use TidNext as access method
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
return ExecScan(&node->scan, (ExecScanAccessMtd) TidNext);
|
return ExecScan(&node->scan, (ExecScanAccessMtd) TidNext);
|
||||||
}
|
}
|
||||||
@@ -281,9 +278,8 @@ ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||||||
node->scan.scanstate->cstate.cs_ExprContext,
|
node->scan.scanstate->cstate.cs_ExprContext,
|
||||||
tidList);
|
tidList);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* perhaps return something meaningful
|
* perhaps return something meaningful
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -306,32 +302,27 @@ ExecEndTidScan(TidScan *node)
|
|||||||
if (tidstate && tidstate->tss_TidList)
|
if (tidstate && tidstate->tss_TidList)
|
||||||
pfree(tidstate->tss_TidList);
|
pfree(tidstate->tss_TidList);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* extract information from the node
|
* extract information from the node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* Free the projection info and the scan attribute info
|
||||||
*
|
*
|
||||||
* Note: we don't ExecFreeResultType(scanstate)
|
* Note: we don't ExecFreeResultType(scanstate) because the rule manager
|
||||||
* because the rule manager depends on the tupType
|
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||||
* returned by ExecMain(). So for now, this
|
* freed at end-transaction time. -cim 6/2/91
|
||||||
* is freed at end-transaction time. -cim 6/2/91
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&scanstate->cstate);
|
ExecFreeProjectionInfo(&scanstate->cstate);
|
||||||
ExecFreeExprContext(&scanstate->cstate);
|
ExecFreeExprContext(&scanstate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* close the heap and tid relations
|
* close the heap and tid relations
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecCloseR((Plan *) node);
|
ExecCloseR((Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* clear out tuple table slots
|
* clear out tuple table slots
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
|
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
|
||||||
ExecClearTuple(scanstate->css_ScanTupleSlot);
|
ExecClearTuple(scanstate->css_ScanTupleSlot);
|
||||||
@@ -400,56 +391,50 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
|||||||
Relation currentRelation;
|
Relation currentRelation;
|
||||||
List *execParam = NIL;
|
List *execParam = NIL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign execution state to node
|
* assign execution state to node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->scan.plan.state = estate;
|
node->scan.plan.state = estate;
|
||||||
|
|
||||||
/* --------------------------------
|
/*
|
||||||
* Part 1) initialize scan state
|
* Part 1) initialize scan state
|
||||||
*
|
*
|
||||||
* create new CommonScanState for node
|
* create new CommonScanState for node
|
||||||
* --------------------------------
|
|
||||||
*/
|
*/
|
||||||
scanstate = makeNode(CommonScanState);
|
scanstate = makeNode(CommonScanState);
|
||||||
node->scan.scanstate = scanstate;
|
node->scan.scanstate = scanstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* + create expression context for node
|
* create expression context for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &scanstate->cstate);
|
ExecAssignExprContext(estate, &scanstate->cstate);
|
||||||
|
|
||||||
#define TIDSCAN_NSLOTS 3
|
#define TIDSCAN_NSLOTS 3
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &scanstate->cstate);
|
ExecInitResultTupleSlot(estate, &scanstate->cstate);
|
||||||
ExecInitScanTupleSlot(estate, scanstate);
|
ExecInitScanTupleSlot(estate, scanstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize projection info. result type comes from scan desc
|
* initialize projection info. result type comes from scan desc
|
||||||
* below..
|
* below..
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
|
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
|
||||||
|
|
||||||
/* --------------------------------
|
/*
|
||||||
* Part 2) initialize tid scan state
|
* Part 2) initialize tid scan state
|
||||||
*
|
*
|
||||||
* create new TidScanState for node
|
* create new TidScanState for node
|
||||||
* --------------------------------
|
|
||||||
*/
|
*/
|
||||||
tidstate = makeNode(TidScanState);
|
tidstate = makeNode(TidScanState);
|
||||||
node->tidstate = tidstate;
|
node->tidstate = tidstate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the tid node information
|
* get the tid node information
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
tidList = (ItemPointer *) palloc(length(node->tideval) * sizeof(ItemPointer));
|
tidList = (ItemPointer *) palloc(length(node->tideval) * sizeof(ItemPointer));
|
||||||
numTids = 0;
|
numTids = 0;
|
||||||
@@ -463,17 +448,14 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
|||||||
tidstate->tss_TidPtr = tidPtr;
|
tidstate->tss_TidPtr = tidPtr;
|
||||||
tidstate->tss_TidList = tidList;
|
tidstate->tss_TidList = tidList;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the range table and direction information
|
* get the range table and direction information from the execution
|
||||||
* from the execution state (these are needed to
|
* state (these are needed to open the relations).
|
||||||
* open the relations).
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
rangeTable = estate->es_range_table;
|
rangeTable = estate->es_range_table;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* open the base relation
|
* open the base relation
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
relid = node->scan.scanrelid;
|
relid = node->scan.scanrelid;
|
||||||
rtentry = rt_fetch(relid, rangeTable);
|
rtentry = rt_fetch(relid, rangeTable);
|
||||||
@@ -483,9 +465,8 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
|||||||
scanstate->css_currentRelation = currentRelation;
|
scanstate->css_currentRelation = currentRelation;
|
||||||
scanstate->css_currentScanDesc = 0;
|
scanstate->css_currentScanDesc = 0;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get the scan type from the relation descriptor.
|
* get the scan type from the relation descriptor.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
|
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
|
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
|
||||||
@@ -496,9 +477,8 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
|||||||
*/
|
*/
|
||||||
((Plan *) node)->chgParam = execParam;
|
((Plan *) node)->chgParam = execParam;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* all done.
|
* all done.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.31 2001/01/24 19:42:55 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.32 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -47,43 +47,38 @@ ExecUnique(Unique *node)
|
|||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get information from the node
|
* get information from the node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
uniquestate = node->uniquestate;
|
uniquestate = node->uniquestate;
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan((Plan *) node);
|
||||||
resultTupleSlot = uniquestate->cstate.cs_ResultTupleSlot;
|
resultTupleSlot = uniquestate->cstate.cs_ResultTupleSlot;
|
||||||
tupDesc = ExecGetResultType(&uniquestate->cstate);
|
tupDesc = ExecGetResultType(&uniquestate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* now loop, returning only non-duplicate tuples.
|
* now loop, returning only non-duplicate tuples. We assume that the
|
||||||
* We assume that the tuples arrive in sorted order
|
* tuples arrive in sorted order so we can detect duplicates easily.
|
||||||
* so we can detect duplicates easily.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* fetch a tuple from the outer subplan
|
* fetch a tuple from the outer subplan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
slot = ExecProcNode(outerPlan, (Plan *) node);
|
slot = ExecProcNode(outerPlan, (Plan *) node);
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Always return the first tuple from the subplan.
|
* Always return the first tuple from the subplan.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (uniquestate->priorTuple == NULL)
|
if (uniquestate->priorTuple == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Else test if the new tuple and the previously returned
|
* Else test if the new tuple and the previously returned tuple
|
||||||
* tuple match. If so then we loop back and fetch
|
* match. If so then we loop back and fetch another new tuple
|
||||||
* another new tuple from the subplan.
|
* from the subplan.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!execTuplesMatch(slot->val, uniquestate->priorTuple,
|
if (!execTuplesMatch(slot->val, uniquestate->priorTuple,
|
||||||
tupDesc,
|
tupDesc,
|
||||||
@@ -93,18 +88,17 @@ ExecUnique(Unique *node)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* We have a new tuple different from the previous saved tuple (if any).
|
* We have a new tuple different from the previous saved tuple (if
|
||||||
* Save it and return it. We must copy it because the source subplan
|
* any). Save it and return it. We must copy it because the source
|
||||||
* won't guarantee that this source tuple is still accessible after
|
* subplan won't guarantee that this source tuple is still accessible
|
||||||
* fetching the next source tuple.
|
* after fetching the next source tuple.
|
||||||
*
|
*
|
||||||
* Note that we manage the copy ourselves. We can't rely on the result
|
* Note that we manage the copy ourselves. We can't rely on the result
|
||||||
* tuple slot to maintain the tuple reference because our caller may
|
* tuple slot to maintain the tuple reference because our caller may
|
||||||
* replace the slot contents with a different tuple (see junk filter
|
* replace the slot contents with a different tuple (see junk filter
|
||||||
* handling in execMain.c). We assume that the caller will no longer
|
* handling in execMain.c). We assume that the caller will no longer
|
||||||
* be interested in the current tuple after he next calls us.
|
* be interested in the current tuple after he next calls us.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (uniquestate->priorTuple != NULL)
|
if (uniquestate->priorTuple != NULL)
|
||||||
heap_freetuple(uniquestate->priorTuple);
|
heap_freetuple(uniquestate->priorTuple);
|
||||||
@@ -131,27 +125,24 @@ ExecInitUnique(Unique *node, EState *estate, Plan *parent)
|
|||||||
UniqueState *uniquestate;
|
UniqueState *uniquestate;
|
||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* assign execution state to node
|
* assign execution state to node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
node->plan.state = estate;
|
node->plan.state = estate;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create new UniqueState for node
|
* create new UniqueState for node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
uniquestate = makeNode(UniqueState);
|
uniquestate = makeNode(UniqueState);
|
||||||
node->uniquestate = uniquestate;
|
node->uniquestate = uniquestate;
|
||||||
uniquestate->priorTuple = NULL;
|
uniquestate->priorTuple = NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* Unique nodes have no ExprContext initialization because
|
* Unique nodes have no ExprContext initialization because they never
|
||||||
* they never call ExecQual or ExecProject. But they do need a
|
* call ExecQual or ExecProject. But they do need a per-tuple memory
|
||||||
* per-tuple memory context anyway for calling execTuplesMatch.
|
* context anyway for calling execTuplesMatch.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
uniquestate->tempContext =
|
uniquestate->tempContext =
|
||||||
AllocSetContextCreate(CurrentMemoryContext,
|
AllocSetContextCreate(CurrentMemoryContext,
|
||||||
@@ -161,23 +152,21 @@ ExecInitUnique(Unique *node, EState *estate, Plan *parent)
|
|||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
#define UNIQUE_NSLOTS 1
|
#define UNIQUE_NSLOTS 1
|
||||||
/* ------------
|
|
||||||
|
/*
|
||||||
* Tuple table initialization
|
* Tuple table initialization
|
||||||
* ------------
|
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &uniquestate->cstate);
|
ExecInitResultTupleSlot(estate, &uniquestate->cstate);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* then initialize outer plan
|
* then initialize outer plan
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan((Plan *) node);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* unique nodes do no projections, so initialize
|
* unique nodes do no projections, so initialize projection info for
|
||||||
* projection info for this node appropriately
|
* this node appropriately
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &uniquestate->cstate);
|
ExecAssignResultTypeFromOuterPlan((Plan *) node, &uniquestate->cstate);
|
||||||
uniquestate->cstate.cs_ProjInfo = NULL;
|
uniquestate->cstate.cs_ProjInfo = NULL;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: stringinfo.c,v 1.27 2001/01/24 19:42:55 momjian Exp $
|
* $Id: stringinfo.c,v 1.28 2001/03/22 06:16:13 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -106,11 +106,11 @@ appendStringInfo(StringInfo str, const char *fmt,...)
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/*----------
|
|
||||||
* Try to format the given string into the available space;
|
/*
|
||||||
* but if there's hardly any space, don't bother trying,
|
* Try to format the given string into the available space; but if
|
||||||
* just fall through to enlarge the buffer first.
|
* there's hardly any space, don't bother trying, just fall
|
||||||
*----------
|
* through to enlarge the buffer first.
|
||||||
*/
|
*/
|
||||||
avail = str->maxlen - str->len - 1;
|
avail = str->maxlen - str->len - 1;
|
||||||
if (avail > 16)
|
if (avail > 16)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.139 2001/03/22 03:59:31 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.140 2001/03/22 06:16:14 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -114,9 +114,8 @@ _copyPlan(Plan *from)
|
|||||||
{
|
{
|
||||||
Plan *newnode = makeNode(Plan);
|
Plan *newnode = makeNode(Plan);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy the node superclass fields
|
* copy the node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields(from, newnode);
|
CopyPlanFields(from, newnode);
|
||||||
|
|
||||||
@@ -133,15 +132,13 @@ _copyResult(Result *from)
|
|||||||
{
|
{
|
||||||
Result *newnode = makeNode(Result);
|
Result *newnode = makeNode(Result);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, resconstantqual);
|
Node_Copy(from, newnode, resconstantqual);
|
||||||
|
|
||||||
@@ -165,15 +162,13 @@ _copyAppend(Append *from)
|
|||||||
{
|
{
|
||||||
Append *newnode = makeNode(Append);
|
Append *newnode = makeNode(Append);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, appendplans);
|
Node_Copy(from, newnode, appendplans);
|
||||||
newnode->isTarget = from->isTarget;
|
newnode->isTarget = from->isTarget;
|
||||||
@@ -205,9 +200,8 @@ _copyScan(Scan *from)
|
|||||||
{
|
{
|
||||||
Scan *newnode = makeNode(Scan);
|
Scan *newnode = makeNode(Scan);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
CopyScanFields((Scan *) from, (Scan *) newnode);
|
CopyScanFields((Scan *) from, (Scan *) newnode);
|
||||||
@@ -224,9 +218,8 @@ _copySeqScan(SeqScan *from)
|
|||||||
{
|
{
|
||||||
SeqScan *newnode = makeNode(SeqScan);
|
SeqScan *newnode = makeNode(SeqScan);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
CopyScanFields((Scan *) from, (Scan *) newnode);
|
CopyScanFields((Scan *) from, (Scan *) newnode);
|
||||||
@@ -243,16 +236,14 @@ _copyIndexScan(IndexScan *from)
|
|||||||
{
|
{
|
||||||
IndexScan *newnode = makeNode(IndexScan);
|
IndexScan *newnode = makeNode(IndexScan);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
CopyScanFields((Scan *) from, (Scan *) newnode);
|
CopyScanFields((Scan *) from, (Scan *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->indxid = listCopy(from->indxid);
|
newnode->indxid = listCopy(from->indxid);
|
||||||
Node_Copy(from, newnode, indxqual);
|
Node_Copy(from, newnode, indxqual);
|
||||||
@@ -282,15 +273,14 @@ _copyTidScan(TidScan *from)
|
|||||||
{
|
{
|
||||||
TidScan *newnode = makeNode(TidScan);
|
TidScan *newnode = makeNode(TidScan);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
CopyScanFields((Scan *) from, (Scan *) newnode);
|
CopyScanFields((Scan *) from, (Scan *) newnode);
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->needRescan = from->needRescan;
|
newnode->needRescan = from->needRescan;
|
||||||
Node_Copy(from, newnode, tideval);
|
Node_Copy(from, newnode, tideval);
|
||||||
@@ -307,16 +297,14 @@ _copySubqueryScan(SubqueryScan *from)
|
|||||||
{
|
{
|
||||||
SubqueryScan *newnode = makeNode(SubqueryScan);
|
SubqueryScan *newnode = makeNode(SubqueryScan);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
CopyScanFields((Scan *) from, (Scan *) newnode);
|
CopyScanFields((Scan *) from, (Scan *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, subplan);
|
Node_Copy(from, newnode, subplan);
|
||||||
|
|
||||||
@@ -352,9 +340,8 @@ _copyJoin(Join *from)
|
|||||||
{
|
{
|
||||||
Join *newnode = makeNode(Join);
|
Join *newnode = makeNode(Join);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
CopyJoinFields(from, newnode);
|
CopyJoinFields(from, newnode);
|
||||||
@@ -372,9 +359,8 @@ _copyNestLoop(NestLoop *from)
|
|||||||
{
|
{
|
||||||
NestLoop *newnode = makeNode(NestLoop);
|
NestLoop *newnode = makeNode(NestLoop);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
CopyJoinFields((Join *) from, (Join *) newnode);
|
CopyJoinFields((Join *) from, (Join *) newnode);
|
||||||
@@ -392,16 +378,14 @@ _copyMergeJoin(MergeJoin *from)
|
|||||||
{
|
{
|
||||||
MergeJoin *newnode = makeNode(MergeJoin);
|
MergeJoin *newnode = makeNode(MergeJoin);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
CopyJoinFields((Join *) from, (Join *) newnode);
|
CopyJoinFields((Join *) from, (Join *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, mergeclauses);
|
Node_Copy(from, newnode, mergeclauses);
|
||||||
|
|
||||||
@@ -424,16 +408,14 @@ _copyHashJoin(HashJoin *from)
|
|||||||
{
|
{
|
||||||
HashJoin *newnode = makeNode(HashJoin);
|
HashJoin *newnode = makeNode(HashJoin);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
CopyJoinFields((Join *) from, (Join *) newnode);
|
CopyJoinFields((Join *) from, (Join *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, hashclauses);
|
Node_Copy(from, newnode, hashclauses);
|
||||||
newnode->hashjoinop = from->hashjoinop;
|
newnode->hashjoinop = from->hashjoinop;
|
||||||
@@ -458,9 +440,8 @@ _copyMaterial(Material *from)
|
|||||||
{
|
{
|
||||||
Material *newnode = makeNode(Material);
|
Material *newnode = makeNode(Material);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
|
|
||||||
@@ -477,9 +458,8 @@ _copySort(Sort *from)
|
|||||||
{
|
{
|
||||||
Sort *newnode = makeNode(Sort);
|
Sort *newnode = makeNode(Sort);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
|
|
||||||
@@ -546,15 +526,13 @@ _copyUnique(Unique *from)
|
|||||||
{
|
{
|
||||||
Unique *newnode = makeNode(Unique);
|
Unique *newnode = makeNode(Unique);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->numCols = from->numCols;
|
newnode->numCols = from->numCols;
|
||||||
newnode->uniqColIdx = palloc(from->numCols * sizeof(AttrNumber));
|
newnode->uniqColIdx = palloc(from->numCols * sizeof(AttrNumber));
|
||||||
@@ -572,15 +550,13 @@ _copySetOp(SetOp *from)
|
|||||||
{
|
{
|
||||||
SetOp *newnode = makeNode(SetOp);
|
SetOp *newnode = makeNode(SetOp);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->cmd = from->cmd;
|
newnode->cmd = from->cmd;
|
||||||
newnode->numCols = from->numCols;
|
newnode->numCols = from->numCols;
|
||||||
@@ -600,15 +576,13 @@ _copyLimit(Limit *from)
|
|||||||
{
|
{
|
||||||
Limit *newnode = makeNode(Limit);
|
Limit *newnode = makeNode(Limit);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, limitOffset);
|
Node_Copy(from, newnode, limitOffset);
|
||||||
Node_Copy(from, newnode, limitCount);
|
Node_Copy(from, newnode, limitCount);
|
||||||
@@ -625,15 +599,13 @@ _copyHash(Hash *from)
|
|||||||
{
|
{
|
||||||
Hash *newnode = makeNode(Hash);
|
Hash *newnode = makeNode(Hash);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, hashkey);
|
Node_Copy(from, newnode, hashkey);
|
||||||
|
|
||||||
@@ -691,9 +663,8 @@ _copyFjoin(Fjoin *from)
|
|||||||
{
|
{
|
||||||
Fjoin *newnode = makeNode(Fjoin);
|
Fjoin *newnode = makeNode(Fjoin);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
newnode->fj_initialized = from->fj_initialized;
|
newnode->fj_initialized = from->fj_initialized;
|
||||||
@@ -726,9 +697,8 @@ _copyExpr(Expr *from)
|
|||||||
{
|
{
|
||||||
Expr *newnode = makeNode(Expr);
|
Expr *newnode = makeNode(Expr);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->typeOid = from->typeOid;
|
newnode->typeOid = from->typeOid;
|
||||||
newnode->opType = from->opType;
|
newnode->opType = from->opType;
|
||||||
@@ -748,9 +718,8 @@ _copyVar(Var *from)
|
|||||||
{
|
{
|
||||||
Var *newnode = makeNode(Var);
|
Var *newnode = makeNode(Var);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->varno = from->varno;
|
newnode->varno = from->varno;
|
||||||
newnode->varattno = from->varattno;
|
newnode->varattno = from->varattno;
|
||||||
@@ -785,9 +754,8 @@ _copyOper(Oper *from)
|
|||||||
{
|
{
|
||||||
Oper *newnode = makeNode(Oper);
|
Oper *newnode = makeNode(Oper);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->opno = from->opno;
|
newnode->opno = from->opno;
|
||||||
newnode->opid = from->opid;
|
newnode->opid = from->opid;
|
||||||
@@ -807,27 +775,27 @@ _copyConst(Const *from)
|
|||||||
{
|
{
|
||||||
Const *newnode = makeNode(Const);
|
Const *newnode = makeNode(Const);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->consttype = from->consttype;
|
newnode->consttype = from->consttype;
|
||||||
newnode->constlen = from->constlen;
|
newnode->constlen = from->constlen;
|
||||||
|
|
||||||
if (from->constbyval || from->constisnull)
|
if (from->constbyval || from->constisnull)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* passed by value so just copy the datum.
|
/*
|
||||||
* Also, don't try to copy struct when value is null!
|
* passed by value so just copy the datum. Also, don't try to copy
|
||||||
* ----------------
|
* struct when value is null!
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
newnode->constvalue = from->constvalue;
|
newnode->constvalue = from->constvalue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* not passed by value. datum contains a pointer.
|
* not passed by value. datum contains a pointer.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
int length = from->constlen;
|
int length = from->constlen;
|
||||||
|
|
||||||
@@ -856,9 +824,8 @@ _copyParam(Param *from)
|
|||||||
{
|
{
|
||||||
Param *newnode = makeNode(Param);
|
Param *newnode = makeNode(Param);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->paramkind = from->paramkind;
|
newnode->paramkind = from->paramkind;
|
||||||
newnode->paramid = from->paramid;
|
newnode->paramid = from->paramid;
|
||||||
@@ -879,9 +846,8 @@ _copyFunc(Func *from)
|
|||||||
{
|
{
|
||||||
Func *newnode = makeNode(Func);
|
Func *newnode = makeNode(Func);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->funcid = from->funcid;
|
newnode->funcid = from->funcid;
|
||||||
newnode->functype = from->functype;
|
newnode->functype = from->functype;
|
||||||
@@ -900,9 +866,8 @@ _copyAggref(Aggref *from)
|
|||||||
{
|
{
|
||||||
Aggref *newnode = makeNode(Aggref);
|
Aggref *newnode = makeNode(Aggref);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->aggname = pstrdup(from->aggname);
|
newnode->aggname = pstrdup(from->aggname);
|
||||||
newnode->basetype = from->basetype;
|
newnode->basetype = from->basetype;
|
||||||
@@ -924,9 +889,8 @@ _copySubLink(SubLink *from)
|
|||||||
{
|
{
|
||||||
SubLink *newnode = makeNode(SubLink);
|
SubLink *newnode = makeNode(SubLink);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->subLinkType = from->subLinkType;
|
newnode->subLinkType = from->subLinkType;
|
||||||
newnode->useor = from->useor;
|
newnode->useor = from->useor;
|
||||||
@@ -946,9 +910,8 @@ _copyFieldSelect(FieldSelect *from)
|
|||||||
{
|
{
|
||||||
FieldSelect *newnode = makeNode(FieldSelect);
|
FieldSelect *newnode = makeNode(FieldSelect);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, arg);
|
Node_Copy(from, newnode, arg);
|
||||||
newnode->fieldnum = from->fieldnum;
|
newnode->fieldnum = from->fieldnum;
|
||||||
@@ -967,9 +930,8 @@ _copyRelabelType(RelabelType *from)
|
|||||||
{
|
{
|
||||||
RelabelType *newnode = makeNode(RelabelType);
|
RelabelType *newnode = makeNode(RelabelType);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, arg);
|
Node_Copy(from, newnode, arg);
|
||||||
newnode->resulttype = from->resulttype;
|
newnode->resulttype = from->resulttype;
|
||||||
@@ -1026,9 +988,8 @@ _copyCaseExpr(CaseExpr *from)
|
|||||||
{
|
{
|
||||||
CaseExpr *newnode = makeNode(CaseExpr);
|
CaseExpr *newnode = makeNode(CaseExpr);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->casetype = from->casetype;
|
newnode->casetype = from->casetype;
|
||||||
|
|
||||||
@@ -1048,9 +1009,8 @@ _copyCaseWhen(CaseWhen *from)
|
|||||||
{
|
{
|
||||||
CaseWhen *newnode = makeNode(CaseWhen);
|
CaseWhen *newnode = makeNode(CaseWhen);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, expr);
|
Node_Copy(from, newnode, expr);
|
||||||
Node_Copy(from, newnode, result);
|
Node_Copy(from, newnode, result);
|
||||||
@@ -1063,9 +1023,8 @@ _copyArrayRef(ArrayRef *from)
|
|||||||
{
|
{
|
||||||
ArrayRef *newnode = makeNode(ArrayRef);
|
ArrayRef *newnode = makeNode(ArrayRef);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->refattrlength = from->refattrlength;
|
newnode->refattrlength = from->refattrlength;
|
||||||
newnode->refelemlength = from->refelemlength;
|
newnode->refelemlength = from->refelemlength;
|
||||||
@@ -1229,15 +1188,13 @@ _copyIndexPath(IndexPath *from)
|
|||||||
{
|
{
|
||||||
IndexPath *newnode = makeNode(IndexPath);
|
IndexPath *newnode = makeNode(IndexPath);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy the node superclass fields
|
* copy the node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPathFields((Path *) from, (Path *) newnode);
|
CopyPathFields((Path *) from, (Path *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->indexid = listCopy(from->indexid);
|
newnode->indexid = listCopy(from->indexid);
|
||||||
Node_Copy(from, newnode, indexqual);
|
Node_Copy(from, newnode, indexqual);
|
||||||
@@ -1258,15 +1215,13 @@ _copyTidPath(TidPath *from)
|
|||||||
{
|
{
|
||||||
TidPath *newnode = makeNode(TidPath);
|
TidPath *newnode = makeNode(TidPath);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy the node superclass fields
|
* copy the node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPathFields((Path *) from, (Path *) newnode);
|
CopyPathFields((Path *) from, (Path *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, tideval);
|
Node_Copy(from, newnode, tideval);
|
||||||
newnode->unjoined_relids = listCopy(from->unjoined_relids);
|
newnode->unjoined_relids = listCopy(from->unjoined_relids);
|
||||||
@@ -1283,15 +1238,13 @@ _copyAppendPath(AppendPath *from)
|
|||||||
{
|
{
|
||||||
AppendPath *newnode = makeNode(AppendPath);
|
AppendPath *newnode = makeNode(AppendPath);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy the node superclass fields
|
* copy the node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPathFields((Path *) from, (Path *) newnode);
|
CopyPathFields((Path *) from, (Path *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, subpaths);
|
Node_Copy(from, newnode, subpaths);
|
||||||
|
|
||||||
@@ -1323,9 +1276,8 @@ _copyNestPath(NestPath *from)
|
|||||||
{
|
{
|
||||||
NestPath *newnode = makeNode(NestPath);
|
NestPath *newnode = makeNode(NestPath);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy the node superclass fields
|
* copy the node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPathFields((Path *) from, (Path *) newnode);
|
CopyPathFields((Path *) from, (Path *) newnode);
|
||||||
CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
|
CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
|
||||||
@@ -1342,16 +1294,14 @@ _copyMergePath(MergePath *from)
|
|||||||
{
|
{
|
||||||
MergePath *newnode = makeNode(MergePath);
|
MergePath *newnode = makeNode(MergePath);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy the node superclass fields
|
* copy the node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPathFields((Path *) from, (Path *) newnode);
|
CopyPathFields((Path *) from, (Path *) newnode);
|
||||||
CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
|
CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy the remainder of the node
|
* copy the remainder of the node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, path_mergeclauses);
|
Node_Copy(from, newnode, path_mergeclauses);
|
||||||
Node_Copy(from, newnode, outersortkeys);
|
Node_Copy(from, newnode, outersortkeys);
|
||||||
@@ -1369,16 +1319,14 @@ _copyHashPath(HashPath *from)
|
|||||||
{
|
{
|
||||||
HashPath *newnode = makeNode(HashPath);
|
HashPath *newnode = makeNode(HashPath);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy the node superclass fields
|
* copy the node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyPathFields((Path *) from, (Path *) newnode);
|
CopyPathFields((Path *) from, (Path *) newnode);
|
||||||
CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
|
CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, path_hashclauses);
|
Node_Copy(from, newnode, path_hashclauses);
|
||||||
|
|
||||||
@@ -1394,9 +1342,8 @@ _copyPathKeyItem(PathKeyItem *from)
|
|||||||
{
|
{
|
||||||
PathKeyItem *newnode = makeNode(PathKeyItem);
|
PathKeyItem *newnode = makeNode(PathKeyItem);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, key);
|
Node_Copy(from, newnode, key);
|
||||||
newnode->sortop = from->sortop;
|
newnode->sortop = from->sortop;
|
||||||
@@ -1413,9 +1360,8 @@ _copyRestrictInfo(RestrictInfo *from)
|
|||||||
{
|
{
|
||||||
RestrictInfo *newnode = makeNode(RestrictInfo);
|
RestrictInfo *newnode = makeNode(RestrictInfo);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, clause);
|
Node_Copy(from, newnode, clause);
|
||||||
newnode->eval_cost = from->eval_cost;
|
newnode->eval_cost = from->eval_cost;
|
||||||
@@ -1447,9 +1393,8 @@ _copyJoinInfo(JoinInfo *from)
|
|||||||
{
|
{
|
||||||
JoinInfo *newnode = makeNode(JoinInfo);
|
JoinInfo *newnode = makeNode(JoinInfo);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
newnode->unjoined_relids = listCopy(from->unjoined_relids);
|
newnode->unjoined_relids = listCopy(from->unjoined_relids);
|
||||||
Node_Copy(from, newnode, jinfo_restrictinfo);
|
Node_Copy(from, newnode, jinfo_restrictinfo);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/_deadcode/Attic/predmig.c,v 1.9 2001/03/22 03:59:35 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/_deadcode/Attic/predmig.c,v 1.10 2001/03/22 06:16:14 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/_deadcode/Attic/xfunc.c,v 1.15 2001/01/24 19:42:58 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/_deadcode/Attic/xfunc.c,v 1.16 2001/03/22 06:16:14 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -1447,15 +1447,13 @@ xfunc_copyrel(RelOptInfo from, RelOptInfo *to)
|
|||||||
if (newnode == NULL)
|
if (newnode == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy node superclass fields
|
* copy node superclass fields
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
CopyNodeFields((Node) from, (Node) newnode, alloc);
|
CopyNodeFields((Node) from, (Node) newnode, alloc);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Node_Copy(from, newnode, alloc, relids);
|
Node_Copy(from, newnode, alloc, relids);
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.31 2001/03/22 03:59:35 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.32 2001/03/22 06:16:14 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -860,13 +860,13 @@ make_pathkeys_for_mergeclauses(Query *root,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* When we are given multiple merge clauses, it's possible that
|
* When we are given multiple merge clauses, it's possible that
|
||||||
* some clauses refer to the same vars as earlier clauses.
|
* some clauses refer to the same vars as earlier clauses. There's
|
||||||
* There's no reason for us to specify sort keys like (A,B,A) when
|
* no reason for us to specify sort keys like (A,B,A) when (A,B)
|
||||||
* (A,B) will do --- and adding redundant sort keys makes add_path
|
* will do --- and adding redundant sort keys makes add_path think
|
||||||
* think that this sort order is different from ones that are
|
* that this sort order is different from ones that are really the
|
||||||
* really the same, so don't do it. Since we now have a
|
* same, so don't do it. Since we now have a canonicalized
|
||||||
* canonicalized pathkey, a simple ptrMember test is sufficient to
|
* pathkey, a simple ptrMember test is sufficient to detect
|
||||||
* detect redundant keys.
|
* redundant keys.
|
||||||
*/
|
*/
|
||||||
if (!ptrMember(pathkey, pathkeys))
|
if (!ptrMember(pathkey, pathkeys))
|
||||||
pathkeys = lappend(pathkeys, pathkey);
|
pathkeys = lappend(pathkeys, pathkey);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.182 2001/03/22 03:59:40 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.183 2001/03/22 06:16:15 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -129,9 +129,9 @@ transformStmt(ParseState *pstate, Node *parseTree)
|
|||||||
|
|
||||||
switch (nodeTag(parseTree))
|
switch (nodeTag(parseTree))
|
||||||
{
|
{
|
||||||
/*------------------------
|
|
||||||
|
/*
|
||||||
* Non-optimizable statements
|
* Non-optimizable statements
|
||||||
*------------------------
|
|
||||||
*/
|
*/
|
||||||
case T_CreateStmt:
|
case T_CreateStmt:
|
||||||
result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
|
result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
|
||||||
@@ -206,9 +206,8 @@ transformStmt(ParseState *pstate, Node *parseTree)
|
|||||||
result = transformAlterTableStmt(pstate, (AlterTableStmt *) parseTree);
|
result = transformAlterTableStmt(pstate, (AlterTableStmt *) parseTree);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*------------------------
|
/*
|
||||||
* Optimizable statements
|
* Optimizable statements
|
||||||
*------------------------
|
|
||||||
*/
|
*/
|
||||||
case T_InsertStmt:
|
case T_InsertStmt:
|
||||||
result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
|
result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
|
||||||
@@ -779,12 +778,11 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
|||||||
{
|
{
|
||||||
constraint = lfirst(clist);
|
constraint = lfirst(clist);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If this column constraint is a FOREIGN KEY
|
* If this column constraint is a FOREIGN KEY
|
||||||
* constraint, then we fill in the current attributes
|
* constraint, then we fill in the current attributes
|
||||||
* name and throw it into the list of FK constraints
|
* name and throw it into the list of FK constraints
|
||||||
* to be processed later.
|
* to be processed later.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (IsA(constraint, FkConstraint))
|
if (IsA(constraint, FkConstraint))
|
||||||
{
|
{
|
||||||
@@ -906,10 +904,10 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_FkConstraint:
|
case T_FkConstraint:
|
||||||
/* ----------
|
|
||||||
* Table level FOREIGN KEY constraints are already complete.
|
/*
|
||||||
* Just remember for later.
|
* Table level FOREIGN KEY constraints are already
|
||||||
* ----------
|
* complete. Just remember for later.
|
||||||
*/
|
*/
|
||||||
fkconstraints = lappend(fkconstraints, element);
|
fkconstraints = lappend(fkconstraints, element);
|
||||||
break;
|
break;
|
||||||
@@ -1806,9 +1804,9 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 15 august 1991 -- since 3.0 postgres does locking right, we
|
* 15 august 1991 -- since 3.0 postgres does locking right, we
|
||||||
* discovered that portals were violating locking protocol.
|
* discovered that portals were violating locking protocol. portal
|
||||||
* portal locks cannot span xacts. as a short-term fix, we
|
* locks cannot span xacts. as a short-term fix, we installed the
|
||||||
* installed the check here. -- mao
|
* check here. -- mao
|
||||||
*/
|
*/
|
||||||
if (!IsTransactionBlock())
|
if (!IsTransactionBlock())
|
||||||
elog(ERROR, "DECLARE CURSOR may only be used in begin/end transaction blocks");
|
elog(ERROR, "DECLARE CURSOR may only be used in begin/end transaction blocks");
|
||||||
@@ -2019,9 +2017,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 15 august 1991 -- since 3.0 postgres does locking right, we
|
* 15 august 1991 -- since 3.0 postgres does locking right, we
|
||||||
* discovered that portals were violating locking protocol.
|
* discovered that portals were violating locking protocol. portal
|
||||||
* portal locks cannot span xacts. as a short-term fix, we
|
* locks cannot span xacts. as a short-term fix, we installed the
|
||||||
* installed the check here. -- mao
|
* check here. -- mao
|
||||||
*/
|
*/
|
||||||
if (!IsTransactionBlock())
|
if (!IsTransactionBlock())
|
||||||
elog(ERROR, "DECLARE CURSOR may only be used in begin/end transaction blocks");
|
elog(ERROR, "DECLARE CURSOR may only be used in begin/end transaction blocks");
|
||||||
@@ -2713,9 +2711,8 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
|
|||||||
int i;
|
int i;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Open the referenced table and get the attributes list
|
* Open the referenced table and get the attributes list
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock);
|
pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock);
|
||||||
if (pkrel == NULL)
|
if (pkrel == NULL)
|
||||||
@@ -2723,12 +2720,10 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
|
|||||||
fkconstraint->pktable_name);
|
fkconstraint->pktable_name);
|
||||||
pkrel_attrs = pkrel->rd_att->attrs;
|
pkrel_attrs = pkrel->rd_att->attrs;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the list of index OIDs for the table from the relcache,
|
* Get the list of index OIDs for the table from the relcache, and
|
||||||
* and look up each one in the pg_index syscache for each unique
|
* look up each one in the pg_index syscache for each unique one, and
|
||||||
* one, and then compare the attributes we were given to those
|
* then compare the attributes we were given to those defined.
|
||||||
* defined.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
indexoidlist = RelationGetIndexList(pkrel);
|
indexoidlist = RelationGetIndexList(pkrel);
|
||||||
|
|
||||||
@@ -2812,9 +2807,8 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
|
|||||||
Form_pg_index indexStruct = NULL;
|
Form_pg_index indexStruct = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Open the referenced table and get the attributes list
|
* Open the referenced table and get the attributes list
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock);
|
pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock);
|
||||||
if (pkrel == NULL)
|
if (pkrel == NULL)
|
||||||
@@ -2822,11 +2816,10 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
|
|||||||
fkconstraint->pktable_name);
|
fkconstraint->pktable_name);
|
||||||
pkrel_attrs = pkrel->rd_att->attrs;
|
pkrel_attrs = pkrel->rd_att->attrs;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the list of index OIDs for the table from the relcache,
|
* Get the list of index OIDs for the table from the relcache, and
|
||||||
* and look up each one in the pg_index syscache until we find one
|
* look up each one in the pg_index syscache until we find one marked
|
||||||
* marked primary key (hopefully there isn't more than one such).
|
* primary key (hopefully there isn't more than one such).
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
indexoidlist = RelationGetIndexList(pkrel);
|
indexoidlist = RelationGetIndexList(pkrel);
|
||||||
|
|
||||||
@@ -2849,18 +2842,16 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
|
|||||||
|
|
||||||
freeList(indexoidlist);
|
freeList(indexoidlist);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Check that we found it
|
* Check that we found it
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (indexStruct == NULL)
|
if (indexStruct == NULL)
|
||||||
elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
|
elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
|
||||||
fkconstraint->pktable_name);
|
fkconstraint->pktable_name);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Now build the list of PK attributes from the indkey definition
|
* Now build the list of PK attributes from the indkey definition
|
||||||
* using the attribute names of the PK relation descriptor
|
* using the attribute names of the PK relation descriptor
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
|
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.78 2001/03/22 03:59:41 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.79 2001/03/22 06:16:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -519,9 +519,9 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
|
|||||||
*containedRels = nconc(l_containedRels, r_containedRels);
|
*containedRels = nconc(l_containedRels, r_containedRels);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for conflicting refnames in left and right subtrees.
|
* Check for conflicting refnames in left and right subtrees. Must
|
||||||
* Must do this because higher levels will assume I hand back a
|
* do this because higher levels will assume I hand back a self-
|
||||||
* self- consistent namespace subtree.
|
* consistent namespace subtree.
|
||||||
*/
|
*/
|
||||||
checkNameSpaceConflicts(pstate, j->larg, j->rarg);
|
checkNameSpaceConflicts(pstate, j->larg, j->rarg);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.59 2001/03/22 03:59:43 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.60 2001/03/22 06:16:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -61,9 +61,8 @@ InsertRule(char *rulname,
|
|||||||
elog(ERROR, "Attempt to insert rule \"%s\" failed: already exists",
|
elog(ERROR, "Attempt to insert rule \"%s\" failed: already exists",
|
||||||
rulname);
|
rulname);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Set up *nulls and *values arrays
|
* Set up *nulls and *values arrays
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
MemSet(nulls, ' ', sizeof(nulls));
|
MemSet(nulls, ' ', sizeof(nulls));
|
||||||
|
|
||||||
@@ -77,9 +76,8 @@ InsertRule(char *rulname,
|
|||||||
values[i++] = DirectFunctionCall1(textin, CStringGetDatum(evqual));
|
values[i++] = DirectFunctionCall1(textin, CStringGetDatum(evqual));
|
||||||
values[i++] = DirectFunctionCall1(textin, CStringGetDatum(actiontree));
|
values[i++] = DirectFunctionCall1(textin, CStringGetDatum(actiontree));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create a new pg_rewrite tuple
|
* create a new pg_rewrite tuple
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg_rewrite_desc = heap_openr(RewriteRelationName, RowExclusiveLock);
|
pg_rewrite_desc = heap_openr(RewriteRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
@@ -183,14 +181,13 @@ DefineQueryRewrite(RuleStmt *stmt)
|
|||||||
event_relation = heap_openr(event_obj->relname, AccessExclusiveLock);
|
event_relation = heap_openr(event_obj->relname, AccessExclusiveLock);
|
||||||
ev_relid = RelationGetRelid(event_relation);
|
ev_relid = RelationGetRelid(event_relation);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* The current rewrite handler is known to work on relation level
|
* The current rewrite handler is known to work on relation level
|
||||||
* rules only. And for SELECT events, it expects one non-nothing
|
* rules only. And for SELECT events, it expects one non-nothing
|
||||||
* action that is instead and returns exactly a tuple of the
|
* action that is instead and returns exactly a tuple of the rewritten
|
||||||
* rewritten relation. This restricts SELECT rules to views.
|
* relation. This restricts SELECT rules to views.
|
||||||
*
|
*
|
||||||
* Jan
|
* Jan
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (event_obj->attrs)
|
if (event_obj->attrs)
|
||||||
elog(ERROR, "attribute level rules currently not supported");
|
elog(ERROR, "attribute level rules currently not supported");
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.90 2001/03/22 03:59:44 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.91 2001/03/22 06:16:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -672,17 +672,15 @@ fireRules(Query *parsetree,
|
|||||||
{
|
{
|
||||||
Query *qual_product;
|
Query *qual_product;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If there are instead rules with qualifications,
|
* If there are instead rules with qualifications, the
|
||||||
* the original query is still performed. But all
|
* original query is still performed. But all the negated rule
|
||||||
* the negated rule qualifications of the instead
|
* qualifications of the instead rules are added so it does
|
||||||
* rules are added so it does its actions only
|
* its actions only in cases where the rule quals of all
|
||||||
* in cases where the rule quals of all instead
|
* instead rules are false. Think of it as the default action
|
||||||
* rules are false. Think of it as the default
|
* in a case. We save this in *qual_products so
|
||||||
* action in a case. We save this in *qual_products
|
* deepRewriteQuery() can add it to the query list after we
|
||||||
* so deepRewriteQuery() can add it to the query
|
* mangled it up enough.
|
||||||
* list after we mangled it up enough.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (*qual_products == NIL)
|
if (*qual_products == NIL)
|
||||||
qual_product = parsetree;
|
qual_product = parsetree;
|
||||||
@@ -722,10 +720,9 @@ fireRules(Query *parsetree,
|
|||||||
pfree(info);
|
pfree(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If this was an unqualified instead rule,
|
* If this was an unqualified instead rule, throw away an
|
||||||
* throw away an eventually saved 'default' parsetree
|
* eventually saved 'default' parsetree
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (event_qual == NULL && *instead_flag)
|
if (event_qual == NULL && *instead_flag)
|
||||||
*qual_products = NIL;
|
*qual_products = NIL;
|
||||||
@@ -842,23 +839,20 @@ deepRewriteQuery(Query *parsetree)
|
|||||||
rewritten = nconc(rewritten, newstuff);
|
rewritten = nconc(rewritten, newstuff);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* qual_products are the original query with the negated
|
* qual_products are the original query with the negated rule
|
||||||
* rule qualification of an instead rule
|
* qualification of an instead rule
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (qual_products != NIL)
|
if (qual_products != NIL)
|
||||||
rewritten = nconc(rewritten, qual_products);
|
rewritten = nconc(rewritten, qual_products);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* The original query is appended last (if no "instead" rule)
|
* The original query is appended last (if no "instead" rule) because
|
||||||
* because update and delete rule actions might not do
|
* update and delete rule actions might not do anything if they are
|
||||||
* anything if they are invoked after the update or
|
* invoked after the update or delete is performed. The command
|
||||||
* delete is performed. The command counter increment
|
* counter increment between the query execution makes the deleted
|
||||||
* between the query execution makes the deleted (and
|
* (and maybe the updated) tuples disappear so the scans for them in
|
||||||
* maybe the updated) tuples disappear so the scans
|
* the rule actions cannot find them.
|
||||||
* for them in the rule actions cannot find them.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (!instead)
|
if (!instead)
|
||||||
rewritten = lappend(rewritten, parsetree);
|
rewritten = lappend(rewritten, parsetree);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.64 2001/03/22 03:59:45 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.65 2001/03/22 06:16:16 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
*
|
*
|
||||||
@@ -146,15 +146,14 @@ proc_exit(int code)
|
|||||||
/* do our shared memory exits first */
|
/* do our shared memory exits first */
|
||||||
shmem_exit(code);
|
shmem_exit(code);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* call all the callbacks registered before calling exit().
|
* call all the callbacks registered before calling exit().
|
||||||
*
|
*
|
||||||
* Note that since we decrement on_proc_exit_index each time,
|
* Note that since we decrement on_proc_exit_index each time, if a
|
||||||
* if a callback calls elog(ERROR) or elog(FATAL) then it won't
|
* callback calls elog(ERROR) or elog(FATAL) then it won't be invoked
|
||||||
* be invoked again when control comes back here (nor will the
|
* again when control comes back here (nor will the
|
||||||
* previously-completed callbacks). So, an infinite loop
|
* previously-completed callbacks). So, an infinite loop should not
|
||||||
* should not be possible.
|
* be possible.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
while (--on_proc_exit_index >= 0)
|
while (--on_proc_exit_index >= 0)
|
||||||
(*on_proc_exit_list[on_proc_exit_index].function) (code,
|
(*on_proc_exit_list[on_proc_exit_index].function) (code,
|
||||||
@@ -177,12 +176,11 @@ shmem_exit(int code)
|
|||||||
if (DebugLvl > 1)
|
if (DebugLvl > 1)
|
||||||
elog(DEBUG, "shmem_exit(%d)", code);
|
elog(DEBUG, "shmem_exit(%d)", code);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* call all the registered callbacks.
|
* call all the registered callbacks.
|
||||||
*
|
*
|
||||||
* As with proc_exit(), we remove each callback from the list
|
* As with proc_exit(), we remove each callback from the list before
|
||||||
* before calling it, to avoid infinite loop in case of error.
|
* calling it, to avoid infinite loop in case of error.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
while (--on_shmem_exit_index >= 0)
|
while (--on_shmem_exit_index >= 0)
|
||||||
(*on_shmem_exit_list[on_shmem_exit_index].function) (code,
|
(*on_shmem_exit_list[on_shmem_exit_index].function) (code,
|
||||||
@@ -387,40 +385,39 @@ IpcSemaphoreLock(IpcSemaphoreId semId, int sem, bool interruptOK)
|
|||||||
sops.sem_flg = 0;
|
sops.sem_flg = 0;
|
||||||
sops.sem_num = sem;
|
sops.sem_num = sem;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Note: if errStatus is -1 and errno == EINTR then it means we
|
* Note: if errStatus is -1 and errno == EINTR then it means we
|
||||||
* returned from the operation prematurely because we were
|
* returned from the operation prematurely because we were sent a
|
||||||
* sent a signal. So we try and lock the semaphore again.
|
* signal. So we try and lock the semaphore again.
|
||||||
*
|
*
|
||||||
* Each time around the loop, we check for a cancel/die interrupt.
|
* Each time around the loop, we check for a cancel/die interrupt. We
|
||||||
* We assume that if such an interrupt comes in while we are waiting,
|
* assume that if such an interrupt comes in while we are waiting, it
|
||||||
* it will cause the semop() call to exit with errno == EINTR, so that
|
* will cause the semop() call to exit with errno == EINTR, so that we
|
||||||
* we will be able to service the interrupt (if not in a critical
|
* will be able to service the interrupt (if not in a critical section
|
||||||
* section already).
|
* already).
|
||||||
*
|
*
|
||||||
* Once we acquire the lock, we do NOT check for an interrupt before
|
* Once we acquire the lock, we do NOT check for an interrupt before
|
||||||
* returning. The caller needs to be able to record ownership of
|
* returning. The caller needs to be able to record ownership of the
|
||||||
* the lock before any interrupt can be accepted.
|
* lock before any interrupt can be accepted.
|
||||||
*
|
*
|
||||||
* There is a window of a few instructions between CHECK_FOR_INTERRUPTS
|
* There is a window of a few instructions between CHECK_FOR_INTERRUPTS
|
||||||
* and entering the semop() call. If a cancel/die interrupt occurs in
|
* and entering the semop() call. If a cancel/die interrupt occurs in
|
||||||
* that window, we would fail to notice it until after we acquire the
|
* that window, we would fail to notice it until after we acquire the
|
||||||
* lock (or get another interrupt to escape the semop()). We can avoid
|
* lock (or get another interrupt to escape the semop()). We can
|
||||||
* this problem by temporarily setting ImmediateInterruptOK = true
|
* avoid this problem by temporarily setting ImmediateInterruptOK =
|
||||||
* before we do CHECK_FOR_INTERRUPTS; then, a die() interrupt in this
|
* true before we do CHECK_FOR_INTERRUPTS; then, a die() interrupt in
|
||||||
* interval will execute directly. However, there is a huge pitfall:
|
* this interval will execute directly. However, there is a huge
|
||||||
* there is another window of a few instructions after the semop()
|
* pitfall: there is another window of a few instructions after the
|
||||||
* before we are able to reset ImmediateInterruptOK. If an interrupt
|
* semop() before we are able to reset ImmediateInterruptOK. If an
|
||||||
* occurs then, we'll lose control, which means that the lock has been
|
* interrupt occurs then, we'll lose control, which means that the
|
||||||
* acquired but our caller did not get a chance to record the fact.
|
* lock has been acquired but our caller did not get a chance to
|
||||||
* Therefore, we only set ImmediateInterruptOK if the caller tells us
|
* record the fact. Therefore, we only set ImmediateInterruptOK if the
|
||||||
* it's OK to do so, ie, the caller does not need to record acquiring
|
* caller tells us it's OK to do so, ie, the caller does not need to
|
||||||
* the lock. (This is currently true for lockmanager locks, since the
|
* record acquiring the lock. (This is currently true for lockmanager
|
||||||
* process that granted us the lock did all the necessary state updates.
|
* locks, since the process that granted us the lock did all the
|
||||||
* It's not true for SysV semaphores used to emulate spinlocks --- but
|
* necessary state updates. It's not true for SysV semaphores used to
|
||||||
* our performance on such platforms is so horrible anyway that I'm
|
* emulate spinlocks --- but our performance on such platforms is so
|
||||||
* not going to worry too much about it.)
|
* horrible anyway that I'm not going to worry too much about it.)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -452,12 +449,11 @@ IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem)
|
|||||||
sops.sem_num = sem;
|
sops.sem_num = sem;
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Note: if errStatus is -1 and errno == EINTR then it means we
|
* Note: if errStatus is -1 and errno == EINTR then it means we
|
||||||
* returned from the operation prematurely because we were
|
* returned from the operation prematurely because we were sent a
|
||||||
* sent a signal. So we try and unlock the semaphore again.
|
* signal. So we try and unlock the semaphore again. Not clear this
|
||||||
* Not clear this can really happen, but might as well cope.
|
* can really happen, but might as well cope.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -486,11 +482,10 @@ IpcSemaphoreTryLock(IpcSemaphoreId semId, int sem)
|
|||||||
sops.sem_flg = IPC_NOWAIT; /* but don't block */
|
sops.sem_flg = IPC_NOWAIT; /* but don't block */
|
||||||
sops.sem_num = sem;
|
sops.sem_num = sem;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Note: if errStatus is -1 and errno == EINTR then it means we
|
* Note: if errStatus is -1 and errno == EINTR then it means we
|
||||||
* returned from the operation prematurely because we were
|
* returned from the operation prematurely because we were sent a
|
||||||
* sent a signal. So we try and lock the semaphore again.
|
* signal. So we try and lock the semaphore again.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.99 2001/03/22 03:59:46 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.100 2001/03/22 06:16:17 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -265,18 +265,15 @@ InitProcess(void)
|
|||||||
MyProc->waitHolder = NULL;
|
MyProc->waitHolder = NULL;
|
||||||
SHMQueueInit(&(MyProc->procHolders));
|
SHMQueueInit(&(MyProc->procHolders));
|
||||||
|
|
||||||
/* ----------------------
|
/*
|
||||||
* Release the lock.
|
* Release the lock.
|
||||||
* ----------------------
|
|
||||||
*/
|
*/
|
||||||
SpinRelease(ProcStructLock);
|
SpinRelease(ProcStructLock);
|
||||||
|
|
||||||
/* -------------------------
|
/*
|
||||||
* Install ourselves in the shmem index table. The name to
|
* Install ourselves in the shmem index table. The name to use is
|
||||||
* use is determined by the OS-assigned process id. That
|
* determined by the OS-assigned process id. That allows the cleanup
|
||||||
* allows the cleanup process to find us after any untimely
|
* process to find us after any untimely exit.
|
||||||
* exit.
|
|
||||||
* -------------------------
|
|
||||||
*/
|
*/
|
||||||
location = MAKE_OFFSET(MyProc);
|
location = MAKE_OFFSET(MyProc);
|
||||||
if ((!ShmemPIDLookup(MyProcPid, &location)) ||
|
if ((!ShmemPIDLookup(MyProcPid, &location)) ||
|
||||||
@@ -531,23 +528,24 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ----------------------
|
/*
|
||||||
* Determine where to add myself in the wait queue.
|
* Determine where to add myself in the wait queue.
|
||||||
*
|
*
|
||||||
* Normally I should go at the end of the queue. However, if I already
|
* Normally I should go at the end of the queue. However, if I already
|
||||||
* hold locks that conflict with the request of any previous waiter,
|
* hold locks that conflict with the request of any previous waiter,
|
||||||
* put myself in the queue just in front of the first such waiter.
|
* put myself in the queue just in front of the first such waiter.
|
||||||
* This is not a necessary step, since deadlock detection would move
|
* This is not a necessary step, since deadlock detection would move
|
||||||
* me to before that waiter anyway; but it's relatively cheap to detect
|
* me to before that waiter anyway; but it's relatively cheap to
|
||||||
* such a conflict immediately, and avoid delaying till deadlock timeout.
|
* detect such a conflict immediately, and avoid delaying till
|
||||||
|
* deadlock timeout.
|
||||||
*
|
*
|
||||||
* Special case: if I find I should go in front of some waiter, check
|
* Special case: if I find I should go in front of some waiter, check to
|
||||||
* to see if I conflict with already-held locks or the requests before
|
* see if I conflict with already-held locks or the requests before
|
||||||
* that waiter. If not, then just grant myself the requested lock
|
* that waiter. If not, then just grant myself the requested lock
|
||||||
* immediately. This is the same as the test for immediate grant in
|
* immediately. This is the same as the test for immediate grant in
|
||||||
* LockAcquire, except we are only considering the part of the wait queue
|
* LockAcquire, except we are only considering the part of the wait
|
||||||
* before my insertion point.
|
* queue before my insertion point.
|
||||||
* ----------------------
|
*
|
||||||
*/
|
*/
|
||||||
if (myHeldLocks != 0)
|
if (myHeldLocks != 0)
|
||||||
{
|
{
|
||||||
@@ -598,9 +596,9 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
|
|||||||
proc = (PROC *) &(waitQueue->links);
|
proc = (PROC *) &(waitQueue->links);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------
|
/*
|
||||||
* Insert self into queue, ahead of the given proc (or at tail of queue).
|
* Insert self into queue, ahead of the given proc (or at tail of
|
||||||
* -------------------
|
* queue).
|
||||||
*/
|
*/
|
||||||
SHMQueueInsertBefore(&(proc->links), &(MyProc->links));
|
SHMQueueInsertBefore(&(proc->links), &(MyProc->links));
|
||||||
waitQueue->size++;
|
waitQueue->size++;
|
||||||
@@ -617,18 +615,17 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
|
|||||||
/* mark that we are waiting for a lock */
|
/* mark that we are waiting for a lock */
|
||||||
waitingForLock = true;
|
waitingForLock = true;
|
||||||
|
|
||||||
/* -------------------
|
/*
|
||||||
* Release the locktable's spin lock.
|
* Release the locktable's spin lock.
|
||||||
*
|
*
|
||||||
* NOTE: this may also cause us to exit critical-section state,
|
* NOTE: this may also cause us to exit critical-section state, possibly
|
||||||
* possibly allowing a cancel/die interrupt to be accepted.
|
* allowing a cancel/die interrupt to be accepted. This is OK because
|
||||||
* This is OK because we have recorded the fact that we are waiting for
|
* we have recorded the fact that we are waiting for a lock, and so
|
||||||
* a lock, and so LockWaitCancel will clean up if cancel/die happens.
|
* LockWaitCancel will clean up if cancel/die happens.
|
||||||
* -------------------
|
|
||||||
*/
|
*/
|
||||||
SpinRelease(spinlock);
|
SpinRelease(spinlock);
|
||||||
|
|
||||||
/* --------------
|
/*
|
||||||
* Set timer so we can wake up after awhile and check for a deadlock.
|
* Set timer so we can wake up after awhile and check for a deadlock.
|
||||||
* If a deadlock is detected, the handler releases the process's
|
* If a deadlock is detected, the handler releases the process's
|
||||||
* semaphore and sets MyProc->errType = STATUS_ERROR, allowing us to
|
* semaphore and sets MyProc->errType = STATUS_ERROR, allowing us to
|
||||||
@@ -637,9 +634,8 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
|
|||||||
* By delaying the check until we've waited for a bit, we can avoid
|
* By delaying the check until we've waited for a bit, we can avoid
|
||||||
* running the rather expensive deadlock-check code in most cases.
|
* running the rather expensive deadlock-check code in most cases.
|
||||||
*
|
*
|
||||||
* Need to zero out struct to set the interval and the microseconds fields
|
* Need to zero out struct to set the interval and the microseconds
|
||||||
* to 0.
|
* fields to 0.
|
||||||
* --------------
|
|
||||||
*/
|
*/
|
||||||
#ifndef __BEOS__
|
#ifndef __BEOS__
|
||||||
MemSet(&timeval, 0, sizeof(struct itimerval));
|
MemSet(&timeval, 0, sizeof(struct itimerval));
|
||||||
@@ -653,26 +649,24 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
|
|||||||
elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
|
elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* --------------
|
/*
|
||||||
* If someone wakes us between SpinRelease and IpcSemaphoreLock,
|
* If someone wakes us between SpinRelease and IpcSemaphoreLock,
|
||||||
* IpcSemaphoreLock will not block. The wakeup is "saved" by
|
* IpcSemaphoreLock will not block. The wakeup is "saved" by the
|
||||||
* the semaphore implementation. Note also that if HandleDeadLock
|
* semaphore implementation. Note also that if HandleDeadLock is
|
||||||
* is invoked but does not detect a deadlock, IpcSemaphoreLock()
|
* invoked but does not detect a deadlock, IpcSemaphoreLock() will
|
||||||
* will continue to wait. There used to be a loop here, but it
|
* continue to wait. There used to be a loop here, but it was useless
|
||||||
* was useless code...
|
* code...
|
||||||
*
|
*
|
||||||
* We pass interruptOK = true, which eliminates a window in which
|
* We pass interruptOK = true, which eliminates a window in which
|
||||||
* cancel/die interrupts would be held off undesirably. This is a
|
* cancel/die interrupts would be held off undesirably. This is a
|
||||||
* promise that we don't mind losing control to a cancel/die interrupt
|
* promise that we don't mind losing control to a cancel/die interrupt
|
||||||
* here. We don't, because we have no state-change work to do after
|
* here. We don't, because we have no state-change work to do after
|
||||||
* being granted the lock (the grantor did it all).
|
* being granted the lock (the grantor did it all).
|
||||||
* --------------
|
|
||||||
*/
|
*/
|
||||||
IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, true);
|
IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, true);
|
||||||
|
|
||||||
/* ---------------
|
/*
|
||||||
* Disable the timer, if it's still running
|
* Disable the timer, if it's still running
|
||||||
* ---------------
|
|
||||||
*/
|
*/
|
||||||
#ifndef __BEOS__
|
#ifndef __BEOS__
|
||||||
MemSet(&timeval, 0, sizeof(struct itimerval));
|
MemSet(&timeval, 0, sizeof(struct itimerval));
|
||||||
@@ -688,12 +682,11 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
|
|||||||
*/
|
*/
|
||||||
waitingForLock = false;
|
waitingForLock = false;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Re-acquire the locktable's spin lock.
|
* Re-acquire the locktable's spin lock.
|
||||||
*
|
*
|
||||||
* We could accept a cancel/die interrupt here. That's OK because
|
* We could accept a cancel/die interrupt here. That's OK because the
|
||||||
* the lock is now registered as being held by this process.
|
* lock is now registered as being held by this process.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
SpinAcquire(spinlock);
|
SpinAcquire(spinlock);
|
||||||
|
|
||||||
@@ -825,17 +818,18 @@ HandleDeadLock(SIGNAL_ARGS)
|
|||||||
*/
|
*/
|
||||||
LockLockTable();
|
LockLockTable();
|
||||||
|
|
||||||
/* ---------------------
|
/*
|
||||||
* Check to see if we've been awoken by anyone in the interim.
|
* Check to see if we've been awoken by anyone in the interim.
|
||||||
*
|
*
|
||||||
* If we have we can return and resume our transaction -- happy day.
|
* If we have we can return and resume our transaction -- happy day.
|
||||||
* Before we are awoken the process releasing the lock grants it to
|
* Before we are awoken the process releasing the lock grants it to us
|
||||||
* us so we know that we don't have to wait anymore.
|
* so we know that we don't have to wait anymore.
|
||||||
*
|
*
|
||||||
* We check by looking to see if we've been unlinked from the wait queue.
|
* We check by looking to see if we've been unlinked from the wait queue.
|
||||||
* This is quicker than checking our semaphore's state, since no kernel
|
* This is quicker than checking our semaphore's state, since no
|
||||||
* call is needed, and it is safe because we hold the locktable lock.
|
* kernel call is needed, and it is safe because we hold the locktable
|
||||||
* ---------------------
|
* lock.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
if (MyProc->links.prev == INVALID_OFFSET ||
|
if (MyProc->links.prev == INVALID_OFFSET ||
|
||||||
MyProc->links.next == INVALID_OFFSET)
|
MyProc->links.next == INVALID_OFFSET)
|
||||||
@@ -858,37 +852,34 @@ HandleDeadLock(SIGNAL_ARGS)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------
|
/*
|
||||||
* Oops. We have a deadlock.
|
* Oops. We have a deadlock.
|
||||||
*
|
*
|
||||||
* Get this process out of wait state.
|
* Get this process out of wait state.
|
||||||
* ------------------------
|
|
||||||
*/
|
*/
|
||||||
RemoveFromWaitQueue(MyProc);
|
RemoveFromWaitQueue(MyProc);
|
||||||
|
|
||||||
/* -------------
|
/*
|
||||||
* Set MyProc->errType to STATUS_ERROR so that ProcSleep will
|
* Set MyProc->errType to STATUS_ERROR so that ProcSleep will report
|
||||||
* report an error after we return from this signal handler.
|
* an error after we return from this signal handler.
|
||||||
* -------------
|
|
||||||
*/
|
*/
|
||||||
MyProc->errType = STATUS_ERROR;
|
MyProc->errType = STATUS_ERROR;
|
||||||
|
|
||||||
/* ------------------
|
/*
|
||||||
* Unlock my semaphore so that the interrupted ProcSleep() call can finish.
|
* Unlock my semaphore so that the interrupted ProcSleep() call can
|
||||||
* ------------------
|
* finish.
|
||||||
*/
|
*/
|
||||||
IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum);
|
IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum);
|
||||||
|
|
||||||
/* ------------------
|
/*
|
||||||
* We're done here. Transaction abort caused by the error that ProcSleep
|
* We're done here. Transaction abort caused by the error that
|
||||||
* will raise will cause any other locks we hold to be released, thus
|
* ProcSleep will raise will cause any other locks we hold to be
|
||||||
* allowing other processes to wake up; we don't need to do that here.
|
* released, thus allowing other processes to wake up; we don't need
|
||||||
* NOTE: an exception is that releasing locks we hold doesn't consider
|
* to do that here. NOTE: an exception is that releasing locks we hold
|
||||||
* the possibility of waiters that were blocked behind us on the lock
|
* doesn't consider the possibility of waiters that were blocked
|
||||||
* we just failed to get, and might now be wakable because we're not
|
* behind us on the lock we just failed to get, and might now be
|
||||||
* in front of them anymore. However, RemoveFromWaitQueue took care of
|
* wakable because we're not in front of them anymore. However,
|
||||||
* waking up any such processes.
|
* RemoveFromWaitQueue took care of waking up any such processes.
|
||||||
* ------------------
|
|
||||||
*/
|
*/
|
||||||
UnlockLockTable();
|
UnlockLockTable();
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.43 2001/03/22 03:59:47 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.44 2001/03/22 06:16:17 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -97,34 +97,31 @@ BeginCommand(char *pname,
|
|||||||
{
|
{
|
||||||
case Remote:
|
case Remote:
|
||||||
case RemoteInternal:
|
case RemoteInternal:
|
||||||
/* ----------------
|
|
||||||
* if this is a "retrieve into portal" query, done
|
/*
|
||||||
* because nothing needs to be sent to the fe.
|
* if this is a "retrieve into portal" query, done because
|
||||||
* ----------------
|
* nothing needs to be sent to the fe.
|
||||||
*/
|
*/
|
||||||
CommandInfo[0] = '\0';
|
CommandInfo[0] = '\0';
|
||||||
if (isIntoPortal)
|
if (isIntoPortal)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if portal name not specified for remote query,
|
* if portal name not specified for remote query, use the
|
||||||
* use the "blank" portal.
|
* "blank" portal.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (pname == NULL)
|
if (pname == NULL)
|
||||||
pname = "blank";
|
pname = "blank";
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* send fe info on tuples we're about to send
|
* send fe info on tuples we're about to send
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pq_puttextmessage('P', pname);
|
pq_puttextmessage('P', pname);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if this is a retrieve, then we send back the tuple
|
* if this is a retrieve, then we send back the tuple
|
||||||
* descriptor of the tuples. "retrieve into" is an
|
* descriptor of the tuples. "retrieve into" is an exception
|
||||||
* exception because no tuples are returned in that case.
|
* because no tuples are returned in that case.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (operation == CMD_SELECT && !isIntoRel)
|
if (operation == CMD_SELECT && !isIntoRel)
|
||||||
{
|
{
|
||||||
@@ -151,9 +148,9 @@ BeginCommand(char *pname,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Debug:
|
case Debug:
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* show the return type of the tuples
|
* show the return type of the tuples
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (pname == NULL)
|
if (pname == NULL)
|
||||||
pname = "blank";
|
pname = "blank";
|
||||||
@@ -213,9 +210,9 @@ EndCommand(char *commandTag, CommandDest dest)
|
|||||||
{
|
{
|
||||||
case Remote:
|
case Remote:
|
||||||
case RemoteInternal:
|
case RemoteInternal:
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* tell the fe that the query is over
|
* tell the fe that the query is over
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
sprintf(buf, "%s%s", commandTag, CommandInfo);
|
sprintf(buf, "%s%s", commandTag, CommandInfo);
|
||||||
pq_puttextmessage('C', buf);
|
pq_puttextmessage('C', buf);
|
||||||
@@ -277,9 +274,9 @@ NullCommand(CommandDest dest)
|
|||||||
{
|
{
|
||||||
case RemoteInternal:
|
case RemoteInternal:
|
||||||
case Remote:
|
case Remote:
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* tell the fe that we saw an empty query string
|
* tell the fe that we saw an empty query string
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pq_putbytes("I", 2);/* note we send I and \0 */
|
pq_putbytes("I", 2);/* note we send I and \0 */
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.47 2001/03/22 03:59:47 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.48 2001/03/22 06:16:17 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* This cruft is the server side of PQfn.
|
* This cruft is the server side of PQfn.
|
||||||
@@ -298,9 +298,9 @@ HandleFunctionRequest(void)
|
|||||||
* (including lookup of the given function ID) and elog if
|
* (including lookup of the given function ID) and elog if
|
||||||
* appropriate. Unfortunately, because we cannot even read the
|
* appropriate. Unfortunately, because we cannot even read the
|
||||||
* message properly without knowing whether the data types are
|
* message properly without knowing whether the data types are
|
||||||
* pass-by-ref or pass-by-value, it's not all that easy to do :-(.
|
* pass-by-ref or pass-by-value, it's not all that easy to do :-(. The
|
||||||
* The protocol should require the client to supply what it thinks is
|
* protocol should require the client to supply what it thinks is the
|
||||||
* the typbyval and typlen value for each arg, so that we can read the
|
* typbyval and typlen value for each arg, so that we can read the
|
||||||
* data without having to do any lookups. Then after we've read the
|
* data without having to do any lookups. Then after we've read the
|
||||||
* message, we should do the lookups, verify agreement of the actual
|
* message, we should do the lookups, verify agreement of the actual
|
||||||
* function arg types with what we received, and finally call the
|
* function arg types with what we received, and finally call the
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.213 2001/03/22 03:59:47 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.214 2001/03/22 06:16:17 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* this is the "main" module of the postgres backend and
|
* this is the "main" module of the postgres backend and
|
||||||
@@ -157,9 +157,8 @@ InteractiveBackend(StringInfo inBuf)
|
|||||||
bool end = false; /* end-of-input flag */
|
bool end = false; /* end-of-input flag */
|
||||||
bool backslashSeen = false; /* have we seen a \ ? */
|
bool backslashSeen = false; /* have we seen a \ ? */
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* display a prompt and obtain input from the user
|
* display a prompt and obtain input from the user
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
printf("backend> ");
|
printf("backend> ");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
@@ -172,10 +171,10 @@ InteractiveBackend(StringInfo inBuf)
|
|||||||
{
|
{
|
||||||
if (UseNewLine)
|
if (UseNewLine)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* if we are using \n as a delimiter, then read
|
/*
|
||||||
* characters until the \n.
|
* if we are using \n as a delimiter, then read characters
|
||||||
* ----------------
|
* until the \n.
|
||||||
*/
|
*/
|
||||||
while ((c = getc(stdin)) != EOF)
|
while ((c = getc(stdin)) != EOF)
|
||||||
{
|
{
|
||||||
@@ -208,9 +207,9 @@ InteractiveBackend(StringInfo inBuf)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* otherwise read characters until EOF.
|
* otherwise read characters until EOF.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
while ((c = getc(stdin)) != EOF)
|
while ((c = getc(stdin)) != EOF)
|
||||||
appendStringInfoChar(inBuf, (char) c);
|
appendStringInfoChar(inBuf, (char) c);
|
||||||
@@ -222,16 +221,14 @@ InteractiveBackend(StringInfo inBuf)
|
|||||||
if (end)
|
if (end)
|
||||||
return EOF;
|
return EOF;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* otherwise we have a user query so process it.
|
* otherwise we have a user query so process it.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* if the query echo flag was given, print the query..
|
* if the query echo flag was given, print the query..
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (EchoQuery)
|
if (EchoQuery)
|
||||||
printf("query: %s\n", inBuf->data);
|
printf("query: %s\n", inBuf->data);
|
||||||
@@ -260,9 +257,8 @@ SocketBackend(StringInfo inBuf)
|
|||||||
char qtype;
|
char qtype;
|
||||||
char result = '\0';
|
char result = '\0';
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* get input from the frontend
|
* get input from the frontend
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
qtype = '?';
|
qtype = '?';
|
||||||
if (pq_getbytes(&qtype, 1) == EOF)
|
if (pq_getbytes(&qtype, 1) == EOF)
|
||||||
@@ -270,9 +266,9 @@ SocketBackend(StringInfo inBuf)
|
|||||||
|
|
||||||
switch (qtype)
|
switch (qtype)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* 'Q': user entered a query
|
* 'Q': user entered a query
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case 'Q':
|
case 'Q':
|
||||||
if (pq_getstr(inBuf))
|
if (pq_getstr(inBuf))
|
||||||
@@ -280,9 +276,8 @@ SocketBackend(StringInfo inBuf)
|
|||||||
result = 'Q';
|
result = 'Q';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* 'F': calling user/system functions
|
* 'F': calling user/system functions
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case 'F':
|
case 'F':
|
||||||
if (pq_getstr(inBuf))
|
if (pq_getstr(inBuf))
|
||||||
@@ -290,20 +285,18 @@ SocketBackend(StringInfo inBuf)
|
|||||||
result = 'F';
|
result = 'F';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* 'X': frontend is exiting
|
* 'X': frontend is exiting
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case 'X':
|
case 'X':
|
||||||
result = 'X';
|
result = 'X';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* otherwise we got garbage from the frontend.
|
* otherwise we got garbage from the frontend.
|
||||||
*
|
*
|
||||||
* XXX are we certain that we want to do an elog(FATAL) here?
|
* XXX are we certain that we want to do an elog(FATAL) here?
|
||||||
* -cim 1/24/90
|
* -cim 1/24/90
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
default:
|
default:
|
||||||
elog(FATAL, "Socket command type %c unknown", qtype);
|
elog(FATAL, "Socket command type %c unknown", qtype);
|
||||||
@@ -350,15 +343,13 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */
|
|||||||
List *querytree_list;
|
List *querytree_list;
|
||||||
List *list_item;
|
List *list_item;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* (1) parse the request string into a list of raw parse trees.
|
* (1) parse the request string into a list of raw parse trees.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
raw_parsetree_list = pg_parse_query(query_string, typev, nargs);
|
raw_parsetree_list = pg_parse_query(query_string, typev, nargs);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* (2) Do parse analysis and rule rewrite.
|
* (2) Do parse analysis and rule rewrite.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
querytree_list = NIL;
|
querytree_list = NIL;
|
||||||
foreach(list_item, raw_parsetree_list)
|
foreach(list_item, raw_parsetree_list)
|
||||||
@@ -424,9 +415,8 @@ pg_analyze_and_rewrite(Node *parsetree)
|
|||||||
Query *querytree;
|
Query *querytree;
|
||||||
List *new_list;
|
List *new_list;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* (1) Perform parse analysis.
|
* (1) Perform parse analysis.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (Show_parser_stats)
|
if (Show_parser_stats)
|
||||||
ResetUsage();
|
ResetUsage();
|
||||||
@@ -440,12 +430,11 @@ pg_analyze_and_rewrite(Node *parsetree)
|
|||||||
ResetUsage();
|
ResetUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* (2) Rewrite the queries, as necessary
|
* (2) Rewrite the queries, as necessary
|
||||||
*
|
*
|
||||||
* rewritten queries are collected in new_list. Note there may be
|
* rewritten queries are collected in new_list. Note there may be more
|
||||||
* more or fewer than in the original list.
|
* or fewer than in the original list.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
new_list = NIL;
|
new_list = NIL;
|
||||||
foreach(list_item, querytree_list)
|
foreach(list_item, querytree_list)
|
||||||
@@ -567,9 +556,8 @@ pg_plan_query(Query *querytree)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Print plan if debugging.
|
* Print plan if debugging.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (Debug_print_plan)
|
if (Debug_print_plan)
|
||||||
{
|
{
|
||||||
@@ -704,10 +692,10 @@ pg_exec_query_string(char *query_string, /* string to execute */
|
|||||||
|
|
||||||
if (!allowit)
|
if (!allowit)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* the EndCommand() stuff is to tell the frontend
|
/*
|
||||||
* that the command ended. -cim 6/1/90
|
* the EndCommand() stuff is to tell the frontend that the
|
||||||
* ----------------
|
* command ended. -cim 6/1/90
|
||||||
*/
|
*/
|
||||||
char *tag = "*ABORT STATE*";
|
char *tag = "*ABORT STATE*";
|
||||||
|
|
||||||
@@ -773,9 +761,9 @@ pg_exec_query_string(char *query_string, /* string to execute */
|
|||||||
|
|
||||||
if (querytree->commandType == CMD_UTILITY)
|
if (querytree->commandType == CMD_UTILITY)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* process utility functions (create, destroy, etc..)
|
* process utility functions (create, destroy, etc..)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (Debug_print_query)
|
if (Debug_print_query)
|
||||||
elog(DEBUG, "ProcessUtility: %s", query_string);
|
elog(DEBUG, "ProcessUtility: %s", query_string);
|
||||||
@@ -786,9 +774,9 @@ pg_exec_query_string(char *query_string, /* string to execute */
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* process a plannable query.
|
* process a plannable query.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Plan *plan;
|
Plan *plan;
|
||||||
|
|
||||||
@@ -1201,18 +1189,18 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'B':
|
case 'B':
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* specify the size of buffer pool
|
* specify the size of buffer pool
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (secure)
|
if (secure)
|
||||||
NBuffers = atoi(optarg);
|
NBuffers = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'C':
|
case 'C':
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* don't print version string
|
* don't print version string
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Noversion = true;
|
Noversion = true;
|
||||||
break;
|
break;
|
||||||
@@ -1237,34 +1225,34 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'E':
|
case 'E':
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* E - echo the query the user entered
|
* E - echo the query the user entered
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
EchoQuery = true;
|
EchoQuery = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'e':
|
case 'e':
|
||||||
/* --------------------------
|
|
||||||
|
/*
|
||||||
* Use european date formats.
|
* Use european date formats.
|
||||||
* --------------------------
|
|
||||||
*/
|
*/
|
||||||
EuroDates = true;
|
EuroDates = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'F':
|
case 'F':
|
||||||
/* --------------------
|
|
||||||
|
/*
|
||||||
* turn off fsync
|
* turn off fsync
|
||||||
* --------------------
|
|
||||||
*/
|
*/
|
||||||
if (secure)
|
if (secure)
|
||||||
enableFsync = false;
|
enableFsync = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
/* -----------------
|
|
||||||
|
/*
|
||||||
* f - forbid generation of certain plans
|
* f - forbid generation of certain plans
|
||||||
* -----------------
|
|
||||||
*/
|
*/
|
||||||
switch (optarg[0])
|
switch (optarg[0])
|
||||||
{
|
{
|
||||||
@@ -1296,54 +1284,54 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'L':
|
case 'L':
|
||||||
/* --------------------
|
|
||||||
|
/*
|
||||||
* turn off locking
|
* turn off locking
|
||||||
* --------------------
|
|
||||||
*/
|
*/
|
||||||
if (secure)
|
if (secure)
|
||||||
lockingOff = 1;
|
lockingOff = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'N':
|
case 'N':
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* N - Don't use newline as a query delimiter
|
* N - Don't use newline as a query delimiter
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
UseNewLine = 0;
|
UseNewLine = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'O':
|
case 'O':
|
||||||
/* --------------------
|
|
||||||
|
/*
|
||||||
* allow system table structure modifications
|
* allow system table structure modifications
|
||||||
* --------------------
|
|
||||||
*/
|
*/
|
||||||
if (secure) /* XXX safe to allow from client??? */
|
if (secure) /* XXX safe to allow from client??? */
|
||||||
allowSystemTableMods = true;
|
allowSystemTableMods = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'P':
|
case 'P':
|
||||||
/* --------------------
|
|
||||||
|
/*
|
||||||
* ignore system indexes
|
* ignore system indexes
|
||||||
* --------------------
|
|
||||||
*/
|
*/
|
||||||
if (secure) /* XXX safe to allow from client??? */
|
if (secure) /* XXX safe to allow from client??? */
|
||||||
IgnoreSystemIndexes(true);
|
IgnoreSystemIndexes(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* o - send output (stdout and stderr) to the given file
|
* o - send output (stdout and stderr) to the given file
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (secure)
|
if (secure)
|
||||||
StrNCpy(OutputFileName, optarg, MAXPGPATH);
|
StrNCpy(OutputFileName, optarg, MAXPGPATH);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
/* ----------------
|
|
||||||
* p - special flag passed if backend was forked
|
/*
|
||||||
* by a postmaster.
|
* p - special flag passed if backend was forked by a
|
||||||
* ----------------
|
* postmaster.
|
||||||
*/
|
*/
|
||||||
if (secure)
|
if (secure)
|
||||||
{
|
{
|
||||||
@@ -1354,9 +1342,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'S':
|
case 'S':
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* S - amount of sort memory to use in 1k bytes
|
* S - amount of sort memory to use in 1k bytes
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
int S;
|
int S;
|
||||||
@@ -1368,15 +1356,15 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* s - report usage statistics (timings) after each query
|
* s - report usage statistics (timings) after each query
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
Show_query_stats = 1;
|
Show_query_stats = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
/* ----------------
|
/* ---------------
|
||||||
* tell postgres to report usage statistics (timings) for
|
* tell postgres to report usage statistics (timings) for
|
||||||
* each query
|
* each query
|
||||||
*
|
*
|
||||||
@@ -1411,9 +1399,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'W':
|
case 'W':
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* wait N seconds to allow attach from a debugger
|
* wait N seconds to allow attach from a debugger
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
sleep(atoi(optarg));
|
sleep(atoi(optarg));
|
||||||
break;
|
break;
|
||||||
@@ -1715,7 +1703,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
|
|||||||
if (!IsUnderPostmaster)
|
if (!IsUnderPostmaster)
|
||||||
{
|
{
|
||||||
puts("\nPOSTGRES backend interactive interface ");
|
puts("\nPOSTGRES backend interactive interface ");
|
||||||
puts("$Revision: 1.213 $ $Date: 2001/03/22 03:59:47 $\n");
|
puts("$Revision: 1.214 $ $Date: 2001/03/22 06:16:17 $\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1810,11 +1798,10 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
|
|||||||
|
|
||||||
parser_input = makeStringInfo();
|
parser_input = makeStringInfo();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* (1) tell the frontend we're ready for a new query.
|
* (1) tell the frontend we're ready for a new query.
|
||||||
*
|
*
|
||||||
* Note: this includes fflush()'ing the last of the prior output.
|
* Note: this includes fflush()'ing the last of the prior output.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ReadyForQuery(whereToSendOutput);
|
ReadyForQuery(whereToSendOutput);
|
||||||
|
|
||||||
@@ -1823,11 +1810,10 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
|
|||||||
else
|
else
|
||||||
set_ps_display("idle");
|
set_ps_display("idle");
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* (2) deal with pending asynchronous NOTIFY from other backends,
|
* (2) deal with pending asynchronous NOTIFY from other backends,
|
||||||
* and enable async.c's signal handler to execute NOTIFY directly.
|
* and enable async.c's signal handler to execute NOTIFY directly.
|
||||||
* Then set up other stuff needed before blocking for input.
|
* Then set up other stuff needed before blocking for input.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
QueryCancelPending = false; /* forget any earlier CANCEL
|
QueryCancelPending = false; /* forget any earlier CANCEL
|
||||||
* signal */
|
* signal */
|
||||||
@@ -1840,25 +1826,22 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
|
|||||||
QueryCancelPending = false;
|
QueryCancelPending = false;
|
||||||
CHECK_FOR_INTERRUPTS();
|
CHECK_FOR_INTERRUPTS();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* (3) read a command (loop blocks here)
|
* (3) read a command (loop blocks here)
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
firstchar = ReadCommand(parser_input);
|
firstchar = ReadCommand(parser_input);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* (4) disable async signal conditions again.
|
* (4) disable async signal conditions again.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ImmediateInterruptOK = false;
|
ImmediateInterruptOK = false;
|
||||||
QueryCancelPending = false; /* forget any CANCEL signal */
|
QueryCancelPending = false; /* forget any CANCEL signal */
|
||||||
|
|
||||||
DisableNotifyInterrupt();
|
DisableNotifyInterrupt();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* (5) check for any other interesting events that happened
|
* (5) check for any other interesting events that happened while
|
||||||
* while we slept.
|
* we slept.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (got_SIGHUP)
|
if (got_SIGHUP)
|
||||||
{
|
{
|
||||||
@@ -1866,15 +1849,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
|
|||||||
ProcessConfigFile(PGC_SIGHUP);
|
ProcessConfigFile(PGC_SIGHUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* (6) process the command.
|
* (6) process the command.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
switch (firstchar)
|
switch (firstchar)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* 'F' indicates a fastpath call.
|
* 'F' indicates a fastpath call.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case 'F':
|
case 'F':
|
||||||
/* start an xact for this function invocation */
|
/* start an xact for this function invocation */
|
||||||
@@ -1890,30 +1872,29 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
|
|||||||
finish_xact_command();
|
finish_xact_command();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* 'Q' indicates a user query
|
* 'Q' indicates a user query
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
case 'Q':
|
case 'Q':
|
||||||
if (strspn(parser_input->data, " \t\r\n") == parser_input->len)
|
if (strspn(parser_input->data, " \t\r\n") == parser_input->len)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* if there is nothing in the input buffer, don't bother
|
/*
|
||||||
* trying to parse and execute anything; just send
|
* if there is nothing in the input buffer, don't
|
||||||
* back a quick NullCommand response.
|
* bother trying to parse and execute anything; just
|
||||||
* ----------------
|
* send back a quick NullCommand response.
|
||||||
*/
|
*/
|
||||||
if (IsUnderPostmaster)
|
if (IsUnderPostmaster)
|
||||||
NullCommand(Remote);
|
NullCommand(Remote);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* otherwise, process the input string.
|
* otherwise, process the input string.
|
||||||
*
|
*
|
||||||
* Note: transaction command start/end is now done
|
* Note: transaction command start/end is now done within
|
||||||
* within pg_exec_query_string(), not here.
|
* pg_exec_query_string(), not here.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (Show_query_stats)
|
if (Show_query_stats)
|
||||||
ResetUsage();
|
ResetUsage();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.43 2001/03/22 03:59:48 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.44 2001/03/22 06:16:17 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -55,15 +55,13 @@ CreateExecutorState(void)
|
|||||||
{
|
{
|
||||||
EState *state;
|
EState *state;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create a new executor state
|
* create a new executor state
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
state = makeNode(EState);
|
state = makeNode(EState);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize the Executor State structure
|
* initialize the Executor State structure
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
state->es_direction = ForwardScanDirection;
|
state->es_direction = ForwardScanDirection;
|
||||||
state->es_range_table = NIL;
|
state->es_range_table = NIL;
|
||||||
@@ -85,9 +83,8 @@ CreateExecutorState(void)
|
|||||||
|
|
||||||
state->es_per_tuple_exprcontext = NULL;
|
state->es_per_tuple_exprcontext = NULL;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* return the executor state structure
|
* return the executor state structure
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@@ -137,9 +134,8 @@ PreparePortal(char *portalName)
|
|||||||
{
|
{
|
||||||
Portal portal;
|
Portal portal;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Check for already-in-use portal name.
|
* Check for already-in-use portal name.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
portal = GetPortalByName(portalName);
|
portal = GetPortalByName(portalName);
|
||||||
if (PortalIsValid(portal))
|
if (PortalIsValid(portal))
|
||||||
@@ -154,9 +150,8 @@ PreparePortal(char *portalName)
|
|||||||
PortalDrop(&portal);
|
PortalDrop(&portal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Create the new portal.
|
* Create the new portal.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
portal = CreatePortal(portalName);
|
portal = CreatePortal(portalName);
|
||||||
|
|
||||||
@@ -188,9 +183,8 @@ ProcessQuery(Query *parsetree,
|
|||||||
|
|
||||||
set_ps_display(tag = CreateOperationTag(operation));
|
set_ps_display(tag = CreateOperationTag(operation));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize portal/into relation status
|
* initialize portal/into relation status
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
isRetrieveIntoPortal = false;
|
isRetrieveIntoPortal = false;
|
||||||
isRetrieveIntoRelation = false;
|
isRetrieveIntoRelation = false;
|
||||||
@@ -219,10 +213,9 @@ ProcessQuery(Query *parsetree,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* If retrieving into a portal, set up the portal and copy
|
* If retrieving into a portal, set up the portal and copy the
|
||||||
* the parsetree and plan into its memory context.
|
* parsetree and plan into its memory context.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (isRetrieveIntoPortal)
|
if (isRetrieveIntoPortal)
|
||||||
{
|
{
|
||||||
@@ -238,40 +231,34 @@ ProcessQuery(Query *parsetree,
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Now we can create the QueryDesc object.
|
* Now we can create the QueryDesc object.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
queryDesc = CreateQueryDesc(parsetree, plan, dest);
|
queryDesc = CreateQueryDesc(parsetree, plan, dest);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* When performing a retrieve into, we override the normal
|
* When performing a retrieve into, we override the normal
|
||||||
* communication destination during the processing of the
|
* communication destination during the processing of the the query.
|
||||||
* the query. This only affects the tuple-output function
|
* This only affects the tuple-output function - the correct
|
||||||
* - the correct destination will still see BeginCommand()
|
* destination will still see BeginCommand() and EndCommand()
|
||||||
* and EndCommand() messages.
|
* messages.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (isRetrieveIntoRelation)
|
if (isRetrieveIntoRelation)
|
||||||
queryDesc->dest = None;
|
queryDesc->dest = None;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* create a default executor state.
|
* create a default executor state.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
state = CreateExecutorState();
|
state = CreateExecutorState();
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* call ExecStart to prepare the plan for execution
|
* call ExecStart to prepare the plan for execution
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
attinfo = ExecutorStart(queryDesc, state);
|
attinfo = ExecutorStart(queryDesc, state);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* report the query's result type information
|
* report the query's result type information back to the front end or
|
||||||
* back to the front end or to whatever destination
|
* to whatever destination we're dealing with.
|
||||||
* we're dealing with.
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
BeginCommand(NULL,
|
BeginCommand(NULL,
|
||||||
operation,
|
operation,
|
||||||
@@ -281,10 +268,9 @@ ProcessQuery(Query *parsetree,
|
|||||||
tag,
|
tag,
|
||||||
dest);
|
dest);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* If retrieve into portal, stop now; we do not run the plan
|
* If retrieve into portal, stop now; we do not run the plan until a
|
||||||
* until a FETCH command is received.
|
* FETCH command is received.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (isRetrieveIntoPortal)
|
if (isRetrieveIntoPortal)
|
||||||
{
|
{
|
||||||
@@ -302,25 +288,22 @@ ProcessQuery(Query *parsetree,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Now we get to the important call to ExecutorRun() where we
|
* Now we get to the important call to ExecutorRun() where we actually
|
||||||
* actually run the plan..
|
* run the plan..
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecutorRun(queryDesc, state, EXEC_RUN, 0L);
|
ExecutorRun(queryDesc, state, EXEC_RUN, 0L);
|
||||||
|
|
||||||
/* save infos for EndCommand */
|
/* save infos for EndCommand */
|
||||||
UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
|
UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Now, we close down all the scans and free allocated resources.
|
* Now, we close down all the scans and free allocated resources.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecutorEnd(queryDesc, state);
|
ExecutorEnd(queryDesc, state);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Notify the destination of end of processing.
|
* Notify the destination of end of processing.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
EndCommand(tag, dest);
|
EndCommand(tag, dest);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.108 2001/03/22 03:59:48 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.109 2001/03/22 06:16:17 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -384,21 +384,21 @@ ProcessUtility(Node *parsetree,
|
|||||||
*/
|
*/
|
||||||
if (stmt->column == NULL)
|
if (stmt->column == NULL)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* rename relation
|
* rename relation
|
||||||
*
|
*
|
||||||
* Note: we also rename the "type" tuple
|
* Note: we also rename the "type" tuple corresponding to
|
||||||
* corresponding to the relation.
|
* the relation.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
renamerel(relname, /* old name */
|
renamerel(relname, /* old name */
|
||||||
stmt->newname); /* new name */
|
stmt->newname); /* new name */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* rename attribute
|
* rename attribute
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
renameatt(relname, /* relname */
|
renameatt(relname, /* relname */
|
||||||
stmt->column, /* old att name */
|
stmt->column, /* old att name */
|
||||||
@@ -923,9 +923,8 @@ ProcessUtility(Node *parsetree,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* tell fe/be or whatever that we're done.
|
* tell fe/be or whatever that we're done.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
EndCommand(commandTag, dest);
|
EndCommand(commandTag, dest);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: tgRecipe.h,v 1.16 2001/03/22 03:59:48 momjian Exp $
|
* $Id: tgRecipe.h,v 1.17 2001/03/22 06:16:17 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -41,6 +41,7 @@ typedef struct
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
*
|
||||||
* geo-decls.h */
|
* geo-decls.h */
|
||||||
|
|
||||||
#endif /* TIOGA_FRONTEND */
|
#endif /* TIOGA_FRONTEND */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* -----------------------------------------------------------------------
|
/* -----------------------------------------------------------------------
|
||||||
* ascii.c
|
* ascii.c
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ascii.c,v 1.7 2001/03/22 03:59:49 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ascii.c,v 1.8 2001/03/22 06:16:17 momjian Exp $
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
@@ -80,27 +80,27 @@ pg_to_ascii(unsigned char *src, unsigned char *src_end, unsigned char *desc, int
|
|||||||
|
|
||||||
if (enc == LATIN1)
|
if (enc == LATIN1)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* ISO-8859-1 <range: 160 -- 255>
|
* ISO-8859-1 <range: 160 -- 255>
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ascii = " cL Y \"Ca -R 'u ., ?AAAAAAACEEEEIIII NOOOOOxOUUUUYTBaaaaaaaceeeeiiii nooooo/ouuuuyty";
|
ascii = " cL Y \"Ca -R 'u ., ?AAAAAAACEEEEIIII NOOOOOxOUUUUYTBaaaaaaaceeeeiiii nooooo/ouuuuyty";
|
||||||
range = RANGE_160;
|
range = RANGE_160;
|
||||||
}
|
}
|
||||||
else if (enc == LATIN2)
|
else if (enc == LATIN2)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* ISO-8859-2 <range: 160 -- 255>
|
* ISO-8859-2 <range: 160 -- 255>
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ascii = " A L LS \"SSTZ-ZZ a,l'ls ,sstz\"zzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTBraaaalccceeeeiiddnnoooo/ruuuuyt.";
|
ascii = " A L LS \"SSTZ-ZZ a,l'ls ,sstz\"zzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTBraaaalccceeeeiiddnnoooo/ruuuuyt.";
|
||||||
range = RANGE_160;
|
range = RANGE_160;
|
||||||
}
|
}
|
||||||
else if (enc == WIN1250)
|
else if (enc == WIN1250)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Window CP1250 <range: 128 -- 255>
|
* Window CP1250 <range: 128 -- 255>
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ascii = " ' \" %S<STZZ `'\"\".-- s>stzz L A \"CS -RZ ,l'u .,as L\"lzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTBraaaalccceeeeiiddnnoooo/ruuuuyt ";
|
ascii = " ' \" %S<STZZ `'\"\".-- s>stzz L A \"CS -RZ ,l'u .,as L\"lzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTBraaaalccceeeeiiddnnoooo/ruuuuyt ";
|
||||||
range = RANGE_128;
|
range = RANGE_128;
|
||||||
@@ -111,9 +111,8 @@ pg_to_ascii(unsigned char *src, unsigned char *src_end, unsigned char *desc, int
|
|||||||
pg_encoding_to_char(enc));
|
pg_encoding_to_char(enc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Encode
|
* Encode
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (x = src; x <= src_end; x++)
|
for (x = src; x <= src_end; x++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* -----------------------------------------------------------------------
|
/* -----------------------------------------------------------------------
|
||||||
* formatting.c
|
* formatting.c
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.34 2001/03/22 03:59:50 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.35 2001/03/22 06:16:17 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group
|
||||||
@@ -1132,9 +1132,8 @@ parse_format(FormatNode *node, char *str, KeyWord *kw,
|
|||||||
{
|
{
|
||||||
suffix = 0;
|
suffix = 0;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Prefix
|
* Prefix
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (ver == DCH_TYPE && (s = suff_search(str, suf, SUFFTYPE_PREFIX)) != NULL)
|
if (ver == DCH_TYPE && (s = suff_search(str, suf, SUFFTYPE_PREFIX)) != NULL)
|
||||||
{
|
{
|
||||||
@@ -1143,9 +1142,8 @@ parse_format(FormatNode *node, char *str, KeyWord *kw,
|
|||||||
str += s->len;
|
str += s->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Keyword
|
* Keyword
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (*str && (n->key = index_seq_search(str, kw, index)) != NULL)
|
if (*str && (n->key = index_seq_search(str, kw, index)) != NULL)
|
||||||
{
|
{
|
||||||
@@ -1156,16 +1154,14 @@ parse_format(FormatNode *node, char *str, KeyWord *kw,
|
|||||||
if (n->key->len)
|
if (n->key->len)
|
||||||
str += n->key->len;
|
str += n->key->len;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* NUM version: Prepare global NUMDesc struct
|
* NUM version: Prepare global NUMDesc struct
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (ver == NUM_TYPE)
|
if (ver == NUM_TYPE)
|
||||||
NUMDesc_prepare(Num, n);
|
NUMDesc_prepare(Num, n);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Postfix
|
* Postfix
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (ver == DCH_TYPE && *str && (s = suff_search(str, suf, SUFFTYPE_POSTFIX)) != NULL)
|
if (ver == DCH_TYPE && *str && (s = suff_search(str, suf, SUFFTYPE_POSTFIX)) != NULL)
|
||||||
{
|
{
|
||||||
@@ -1178,9 +1174,8 @@ parse_format(FormatNode *node, char *str, KeyWord *kw,
|
|||||||
else if (*str)
|
else if (*str)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Special characters '\' and '"'
|
* Special characters '\' and '"'
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (*str == '"' && last != '\\')
|
if (*str == '"' && last != '\\')
|
||||||
{
|
{
|
||||||
@@ -1258,9 +1253,8 @@ DCH_processor(FormatNode *node, char *inout, int flag)
|
|||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Zeroing global flags
|
* Zeroing global flags
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
DCH_global_flag = 0;
|
DCH_global_flag = 0;
|
||||||
|
|
||||||
@@ -1270,9 +1264,8 @@ DCH_processor(FormatNode *node, char *inout, int flag)
|
|||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Call node action function
|
* Call node action function
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
len = n->key->action(n->key->id, s, n->suffix, flag, n);
|
len = n->key->action(n->key->id, s, n->suffix, flag, n);
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
@@ -1284,18 +1277,17 @@ DCH_processor(FormatNode *node, char *inout, int flag)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Remove to output char from input in TO_CHAR
|
* Remove to output char from input in TO_CHAR
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (flag == TO_CHAR)
|
if (flag == TO_CHAR)
|
||||||
*s = n->character;
|
*s = n->character;
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Skip blank space in FROM_CHAR's input
|
* Skip blank space in FROM_CHAR's input
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (isspace((unsigned char) n->character) && IS_FX == 0)
|
if (isspace((unsigned char) n->character) && IS_FX == 0)
|
||||||
{
|
{
|
||||||
@@ -1893,11 +1885,10 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
|
|||||||
|
|
||||||
p_inout = inout;
|
p_inout = inout;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* In the FROM-char is not difference between "January" or "JANUARY"
|
* In the FROM-char is not difference between "January" or "JANUARY"
|
||||||
* or "january", all is before search convert to "first-upper".
|
* or "january", all is before search convert to "first-upper". This
|
||||||
* This convention is used for MONTH, MON, DAY, DY
|
* convention is used for MONTH, MON, DAY, DY
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (flag == FROM_CHAR)
|
if (flag == FROM_CHAR)
|
||||||
{
|
{
|
||||||
@@ -2459,9 +2450,8 @@ DCH_cache_getnew(char *str)
|
|||||||
ent->age = (++DCHCounter);
|
ent->age = (++DCHCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Cache is full - needs remove any older entry
|
* Cache is full - needs remove any older entry
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (n_DCHCache > DCH_CACHE_FIELDS)
|
if (n_DCHCache > DCH_CACHE_FIELDS)
|
||||||
{
|
{
|
||||||
@@ -2583,24 +2573,21 @@ timestamp_to_char(PG_FUNCTION_ARGS)
|
|||||||
tm->tm_wday = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1) % 7;
|
tm->tm_wday = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1) % 7;
|
||||||
tm->tm_yday = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(tm->tm_year, 1, 1) + 1;
|
tm->tm_yday = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(tm->tm_year, 1, 1) + 1;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Convert fmt to C string
|
* Convert fmt to C string
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
str = (char *) palloc(len + 1);
|
str = (char *) palloc(len + 1);
|
||||||
memcpy(str, VARDATA(fmt), len);
|
memcpy(str, VARDATA(fmt), len);
|
||||||
*(str + len) = '\0';
|
*(str + len) = '\0';
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Allocate result
|
* Allocate result
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
result = (text *) palloc((len * DCH_MAX_ITEM_SIZ) + 1 + VARHDRSZ);
|
result = (text *) palloc((len * DCH_MAX_ITEM_SIZ) + 1 + VARHDRSZ);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Allocate new memory if format picture is bigger than static cache
|
* Allocate new memory if format picture is bigger than static cache
|
||||||
* and not use cache (call parser always) - flag=1 show this variant
|
* and not use cache (call parser always) - flag=1 show this variant
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (len > DCH_CACHE_SIZE)
|
if (len > DCH_CACHE_SIZE)
|
||||||
{
|
{
|
||||||
@@ -2616,9 +2603,8 @@ timestamp_to_char(PG_FUNCTION_ARGS)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Use cache buffers
|
* Use cache buffers
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
DCHCacheEntry *ent;
|
DCHCacheEntry *ent;
|
||||||
|
|
||||||
@@ -2629,10 +2615,9 @@ timestamp_to_char(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
ent = DCH_cache_getnew(str);
|
ent = DCH_cache_getnew(str);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Not in the cache, must run parser and save a new
|
* Not in the cache, must run parser and save a new
|
||||||
* format-picture to the cache.
|
* format-picture to the cache.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
parse_format(ent->format, str, DCH_keywords,
|
parse_format(ent->format, str, DCH_keywords,
|
||||||
DCH_suff, DCH_index, DCH_TYPE, NULL);
|
DCH_suff, DCH_index, DCH_TYPE, NULL);
|
||||||
@@ -2654,10 +2639,9 @@ timestamp_to_char(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
pfree(str);
|
pfree(str);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* for result is allocated max memory, which current format-picture
|
* for result is allocated max memory, which current format-picture
|
||||||
* needs, now it must be re-allocate to result real size
|
* needs, now it must be re-allocate to result real size
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (!(len = strlen(VARDATA(result))))
|
if (!(len = strlen(VARDATA(result))))
|
||||||
{
|
{
|
||||||
@@ -2706,18 +2690,17 @@ to_timestamp(PG_FUNCTION_ARGS)
|
|||||||
if (len)
|
if (len)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Convert fmt to C string
|
* Convert fmt to C string
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
str = (char *) palloc(len + 1);
|
str = (char *) palloc(len + 1);
|
||||||
memcpy(str, VARDATA(fmt), len);
|
memcpy(str, VARDATA(fmt), len);
|
||||||
*(str + len) = '\0';
|
*(str + len) = '\0';
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Allocate new memory if format picture is bigger than static cache
|
* Allocate new memory if format picture is bigger than static
|
||||||
* and not use cache (call parser always) - flag=1 show this variant
|
* cache and not use cache (call parser always) - flag=1 show this
|
||||||
* ----------
|
* variant
|
||||||
*/
|
*/
|
||||||
if (len > DCH_CACHE_SIZE)
|
if (len > DCH_CACHE_SIZE)
|
||||||
{
|
{
|
||||||
@@ -2732,9 +2715,8 @@ to_timestamp(PG_FUNCTION_ARGS)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Use cache buffers
|
* Use cache buffers
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
DCHCacheEntry *ent;
|
DCHCacheEntry *ent;
|
||||||
|
|
||||||
@@ -2745,10 +2727,9 @@ to_timestamp(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
ent = DCH_cache_getnew(str);
|
ent = DCH_cache_getnew(str);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Not in the cache, must run parser and save a new
|
* Not in the cache, must run parser and save a new
|
||||||
* format-picture to the cache.
|
* format-picture to the cache.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
parse_format(ent->format, str, DCH_keywords,
|
parse_format(ent->format, str, DCH_keywords,
|
||||||
DCH_suff, DCH_index, DCH_TYPE, NULL);
|
DCH_suff, DCH_index, DCH_TYPE, NULL);
|
||||||
@@ -2762,17 +2743,15 @@ to_timestamp(PG_FUNCTION_ARGS)
|
|||||||
format = ent->format;
|
format = ent->format;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Call action for each node in FormatNode tree
|
* Call action for each node in FormatNode tree
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
#ifdef DEBUG_TO_FROM_CHAR
|
#ifdef DEBUG_TO_FROM_CHAR
|
||||||
/* dump_node(format, len); */
|
/* dump_node(format, len); */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Convert date to C string
|
* Convert date to C string
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
date_len = VARSIZE(date_txt) - VARHDRSZ;
|
date_len = VARSIZE(date_txt) - VARHDRSZ;
|
||||||
date_str = (char *) palloc(date_len + 1);
|
date_str = (char *) palloc(date_len + 1);
|
||||||
@@ -2787,10 +2766,9 @@ to_timestamp(PG_FUNCTION_ARGS)
|
|||||||
pfree(format);
|
pfree(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------
|
/*
|
||||||
* Convert values that user define for FROM_CHAR (to_date/to_timestamp)
|
* Convert values that user define for FROM_CHAR
|
||||||
* to standard 'tm'
|
* (to_date/to_timestamp) to standard 'tm'
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
#ifdef DEBUG_TO_FROM_CHAR
|
#ifdef DEBUG_TO_FROM_CHAR
|
||||||
NOTICE_TMFC;
|
NOTICE_TMFC;
|
||||||
@@ -3050,9 +3028,8 @@ NUM_cache_getnew(char *str)
|
|||||||
ent->age = (++NUMCounter);
|
ent->age = (++NUMCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Cache is full - needs remove any older entry
|
* Cache is full - needs remove any older entry
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (n_NUMCache > NUM_CACHE_FIELDS)
|
if (n_NUMCache > NUM_CACHE_FIELDS)
|
||||||
{
|
{
|
||||||
@@ -3156,18 +3133,16 @@ NUM_cache(int len, NUMDesc *Num, char *pars_str, int *flag)
|
|||||||
FormatNode *format = NULL;
|
FormatNode *format = NULL;
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Convert VARDATA() to string
|
* Convert VARDATA() to string
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
str = (char *) palloc(len + 1);
|
str = (char *) palloc(len + 1);
|
||||||
memcpy(str, pars_str, len);
|
memcpy(str, pars_str, len);
|
||||||
*(str + len) = '\0';
|
*(str + len) = '\0';
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Allocate new memory if format picture is bigger than static cache
|
* Allocate new memory if format picture is bigger than static cache
|
||||||
* and not use cache (call parser always) - flag=1 show this variant
|
* and not use cache (call parser always) - flag=1 show this variant
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (len > NUM_CACHE_SIZE)
|
if (len > NUM_CACHE_SIZE)
|
||||||
{
|
{
|
||||||
@@ -3186,9 +3161,8 @@ NUM_cache(int len, NUMDesc *Num, char *pars_str, int *flag)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Use cache buffers
|
* Use cache buffers
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
NUMCacheEntry *ent;
|
NUMCacheEntry *ent;
|
||||||
|
|
||||||
@@ -3199,10 +3173,9 @@ NUM_cache(int len, NUMDesc *Num, char *pars_str, int *flag)
|
|||||||
|
|
||||||
ent = NUM_cache_getnew(str);
|
ent = NUM_cache_getnew(str);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Not in the cache, must run parser and save a new
|
* Not in the cache, must run parser and save a new
|
||||||
* format-picture to the cache.
|
* format-picture to the cache.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
parse_format(ent->format, str, NUM_keywords,
|
parse_format(ent->format, str, NUM_keywords,
|
||||||
NULL, NUM_index, NUM_TYPE, &ent->Num);
|
NULL, NUM_index, NUM_TYPE, &ent->Num);
|
||||||
@@ -3213,9 +3186,8 @@ NUM_cache(int len, NUMDesc *Num, char *pars_str, int *flag)
|
|||||||
|
|
||||||
format = ent->format;
|
format = ent->format;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Copy cache to used struct
|
* Copy cache to used struct
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
Num->flag = ent->Num.flag;
|
Num->flag = ent->Num.flag;
|
||||||
Num->lsign = ent->Num.lsign;
|
Num->lsign = ent->Num.lsign;
|
||||||
@@ -3302,15 +3274,13 @@ NUM_prepare_locale(NUMProc *Np)
|
|||||||
|
|
||||||
struct lconv *lconv;
|
struct lconv *lconv;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get locales
|
* Get locales
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
lconv = PGLC_localeconv();
|
lconv = PGLC_localeconv();
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Positive / Negative number sign
|
* Positive / Negative number sign
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (lconv->negative_sign && *lconv->negative_sign)
|
if (lconv->negative_sign && *lconv->negative_sign)
|
||||||
Np->L_negative_sign = lconv->negative_sign;
|
Np->L_negative_sign = lconv->negative_sign;
|
||||||
@@ -3322,27 +3292,24 @@ NUM_prepare_locale(NUMProc *Np)
|
|||||||
else
|
else
|
||||||
Np->L_positive_sign = "+";
|
Np->L_positive_sign = "+";
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Number thousands separator
|
* Number thousands separator
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (lconv->thousands_sep && *lconv->thousands_sep)
|
if (lconv->thousands_sep && *lconv->thousands_sep)
|
||||||
Np->L_thousands_sep = lconv->thousands_sep;
|
Np->L_thousands_sep = lconv->thousands_sep;
|
||||||
else
|
else
|
||||||
Np->L_thousands_sep = ",";
|
Np->L_thousands_sep = ",";
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Number decimal point
|
* Number decimal point
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (lconv->decimal_point && *lconv->decimal_point)
|
if (lconv->decimal_point && *lconv->decimal_point)
|
||||||
Np->decimal = lconv->decimal_point;
|
Np->decimal = lconv->decimal_point;
|
||||||
else
|
else
|
||||||
Np->decimal = ".";
|
Np->decimal = ".";
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Currency symbol
|
* Currency symbol
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (lconv->currency_symbol && *lconv->currency_symbol)
|
if (lconv->currency_symbol && *lconv->currency_symbol)
|
||||||
Np->L_currency_symbol = lconv->currency_symbol;
|
Np->L_currency_symbol = lconv->currency_symbol;
|
||||||
@@ -3357,9 +3324,9 @@ NUM_prepare_locale(NUMProc *Np)
|
|||||||
{
|
{
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Default values
|
* Default values
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
Np->L_negative_sign = "-";
|
Np->L_negative_sign = "-";
|
||||||
Np->L_positive_sign = "+";
|
Np->L_positive_sign = "+";
|
||||||
@@ -3423,9 +3390,8 @@ NUM_numpart_from_char(NUMProc *Np, int id, int plen)
|
|||||||
if (OVERLOAD_TEST)
|
if (OVERLOAD_TEST)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* read sign
|
* read sign
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9 || NUM_S))
|
if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9 || NUM_S))
|
||||||
{
|
{
|
||||||
@@ -3433,9 +3399,9 @@ NUM_numpart_from_char(NUMProc *Np, int id, int plen)
|
|||||||
#ifdef DEBUG_TO_FROM_CHAR
|
#ifdef DEBUG_TO_FROM_CHAR
|
||||||
elog(DEBUG_elog_output, "Try read sign (%c).", *Np->inout_p);
|
elog(DEBUG_elog_output, "Try read sign (%c).", *Np->inout_p);
|
||||||
#endif
|
#endif
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* locale sign
|
* locale sign
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (IS_LSIGN(Np->Num))
|
if (IS_LSIGN(Np->Num))
|
||||||
{
|
{
|
||||||
@@ -3464,9 +3430,9 @@ NUM_numpart_from_char(NUMProc *Np, int id, int plen)
|
|||||||
#ifdef DEBUG_TO_FROM_CHAR
|
#ifdef DEBUG_TO_FROM_CHAR
|
||||||
elog(DEBUG_elog_output, "Try read sipmle sign (%c).", *Np->inout_p);
|
elog(DEBUG_elog_output, "Try read sipmle sign (%c).", *Np->inout_p);
|
||||||
#endif
|
#endif
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* simple + - < >
|
* simple + - < >
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) &&
|
if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) &&
|
||||||
*Np->inout_p == '<'))
|
*Np->inout_p == '<'))
|
||||||
@@ -3487,9 +3453,8 @@ NUM_numpart_from_char(NUMProc *Np, int id, int plen)
|
|||||||
if (OVERLOAD_TEST)
|
if (OVERLOAD_TEST)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* read digit
|
* read digit
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (isdigit((unsigned char) *Np->inout_p))
|
if (isdigit((unsigned char) *Np->inout_p))
|
||||||
{
|
{
|
||||||
@@ -3507,9 +3472,8 @@ NUM_numpart_from_char(NUMProc *Np, int id, int plen)
|
|||||||
elog(DEBUG_elog_output, "Read digit (%c).", *Np->inout_p);
|
elog(DEBUG_elog_output, "Read digit (%c).", *Np->inout_p);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* read decimal point
|
* read decimal point
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
else if (IS_DECIMAL(Np->Num))
|
else if (IS_DECIMAL(Np->Num))
|
||||||
@@ -3572,9 +3536,8 @@ NUM_numpart_to_char(NUMProc *Np, int id)
|
|||||||
#endif
|
#endif
|
||||||
Np->num_in = FALSE;
|
Np->num_in = FALSE;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Write sign
|
* Write sign
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (Np->num_curr == Np->sign_pos && Np->sign_wrote == FALSE)
|
if (Np->num_curr == Np->sign_pos && Np->sign_wrote == FALSE)
|
||||||
{
|
{
|
||||||
@@ -3585,9 +3548,8 @@ NUM_numpart_to_char(NUMProc *Np, int id)
|
|||||||
if (IS_LSIGN(Np->Num))
|
if (IS_LSIGN(Np->Num))
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Write locale SIGN
|
* Write locale SIGN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (Np->sign == '-')
|
if (Np->sign == '-')
|
||||||
strcpy(Np->inout_p, Np->L_negative_sign);
|
strcpy(Np->inout_p, Np->L_negative_sign);
|
||||||
@@ -3620,9 +3582,9 @@ NUM_numpart_to_char(NUMProc *Np, int id)
|
|||||||
(Np->num_curr == Np->num_count + (Np->num_pre ? 1 : 0)
|
(Np->num_curr == Np->num_count + (Np->num_pre ? 1 : 0)
|
||||||
+ (IS_DECIMAL(Np->Num) ? 1 : 0)))
|
+ (IS_DECIMAL(Np->Num) ? 1 : 0)))
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Write close BRACKET
|
* Write close BRACKET
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
#ifdef DEBUG_TO_FROM_CHAR
|
#ifdef DEBUG_TO_FROM_CHAR
|
||||||
elog(DEBUG_elog_output, "Writing bracket to position %d", Np->num_curr);
|
elog(DEBUG_elog_output, "Writing bracket to position %d", Np->num_curr);
|
||||||
@@ -3631,9 +3593,8 @@ NUM_numpart_to_char(NUMProc *Np, int id)
|
|||||||
++Np->inout_p;
|
++Np->inout_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* digits / FM / Zero / Dec. point
|
* digits / FM / Zero / Dec. point
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (id == NUM_9 || id == NUM_0 || id == NUM_D || id == NUM_DEC ||
|
if (id == NUM_9 || id == NUM_0 || id == NUM_D || id == NUM_DEC ||
|
||||||
(id == NUM_S && Np->num_curr < Np->num_pre))
|
(id == NUM_S && Np->num_curr < Np->num_pre))
|
||||||
@@ -3643,9 +3604,8 @@ NUM_numpart_to_char(NUMProc *Np, int id)
|
|||||||
(Np->Num->zero_start > Np->num_curr || !IS_ZERO(Np->Num)))
|
(Np->Num->zero_start > Np->num_curr || !IS_ZERO(Np->Num)))
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Write blank space
|
* Write blank space
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (!IS_FILLMODE(Np->Num))
|
if (!IS_FILLMODE(Np->Num))
|
||||||
{
|
{
|
||||||
@@ -3662,9 +3622,8 @@ NUM_numpart_to_char(NUMProc *Np, int id)
|
|||||||
Np->Num->zero_start <= Np->num_curr)
|
Np->Num->zero_start <= Np->num_curr)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Write ZERO
|
* Write ZERO
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
#ifdef DEBUG_TO_FROM_CHAR
|
#ifdef DEBUG_TO_FROM_CHAR
|
||||||
elog(DEBUG_elog_output, "Writing zero to position %d", Np->num_curr);
|
elog(DEBUG_elog_output, "Writing zero to position %d", Np->num_curr);
|
||||||
@@ -3677,9 +3636,8 @@ NUM_numpart_to_char(NUMProc *Np, int id)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Write Decinal point
|
* Write Decinal point
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (*Np->number_p == '.')
|
if (*Np->number_p == '.')
|
||||||
{
|
{
|
||||||
@@ -3708,9 +3666,8 @@ NUM_numpart_to_char(NUMProc *Np, int id)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Write Digits
|
* Write Digits
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (Np->last_relevant && Np->number_p > Np->last_relevant &&
|
if (Np->last_relevant && Np->number_p > Np->last_relevant &&
|
||||||
id != NUM_0)
|
id != NUM_0)
|
||||||
@@ -3775,9 +3732,8 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
|
|||||||
if (Np->Num->zero_start)
|
if (Np->Num->zero_start)
|
||||||
--Np->Num->zero_start;
|
--Np->Num->zero_start;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Roman correction
|
* Roman correction
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (IS_ROMAN(Np->Num))
|
if (IS_ROMAN(Np->Num))
|
||||||
{
|
{
|
||||||
@@ -3797,9 +3753,8 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
|
|||||||
Np->Num->flag |= NUM_F_ROMAN;
|
Np->Num->flag |= NUM_F_ROMAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Sign
|
* Sign
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (type == FROM_CHAR)
|
if (type == FROM_CHAR)
|
||||||
{
|
{
|
||||||
@@ -3833,9 +3788,8 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
|
|||||||
Np->sign_wrote = TRUE; /* needn't sign */
|
Np->sign_wrote = TRUE; /* needn't sign */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Count
|
* Count
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
Np->num_count = Np->Num->post + Np->Num->pre - 1;
|
Np->num_count = Np->Num->post + Np->Num->pre - 1;
|
||||||
|
|
||||||
@@ -3858,9 +3812,8 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
|
|||||||
if (!Np->sign_wrote)
|
if (!Np->sign_wrote)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Set SING position
|
* Set SING position
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (Np->Num->lsign == NUM_LSIGN_POST)
|
if (Np->Num->lsign == NUM_LSIGN_POST)
|
||||||
{
|
{
|
||||||
@@ -3875,9 +3828,8 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
|
|||||||
else
|
else
|
||||||
Np->sign_pos = Np->num_pre && !IS_FILLMODE(Np->Num) ? Np->num_pre : 0;
|
Np->sign_pos = Np->num_pre && !IS_FILLMODE(Np->Num) ? Np->num_pre : 0;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* terrible Ora format
|
* terrible Ora format
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (!IS_ZERO(Np->Num) && *Np->number == '0' &&
|
if (!IS_ZERO(Np->Num) && *Np->number == '0' &&
|
||||||
!IS_FILLMODE(Np->Num) && Np->Num->post != 0)
|
!IS_FILLMODE(Np->Num) && Np->Num->post != 0)
|
||||||
@@ -3924,15 +3876,13 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
|
|||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Locale
|
* Locale
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
NUM_prepare_locale(Np);
|
NUM_prepare_locale(Np);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Processor direct cycle
|
* Processor direct cycle
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (Np->type == FROM_CHAR)
|
if (Np->type == FROM_CHAR)
|
||||||
Np->number_p = Np->number + 1; /* first char is space for sign */
|
Np->number_p = Np->number + 1; /* first char is space for sign */
|
||||||
@@ -3944,24 +3894,22 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
|
|||||||
|
|
||||||
if (Np->type == FROM_CHAR)
|
if (Np->type == FROM_CHAR)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Check non-string inout end
|
* Check non-string inout end
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (Np->inout_p >= Np->inout + plen)
|
if (Np->inout_p >= Np->inout + plen)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Format pictures actions
|
* Format pictures actions
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (n->type == NODE_TYPE_ACTION)
|
if (n->type == NODE_TYPE_ACTION)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Create/reading digit/zero/blank/sing
|
* Create/reading digit/zero/blank/sing
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
switch (n->key->id)
|
switch (n->key->id)
|
||||||
{
|
{
|
||||||
@@ -4145,9 +4093,9 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Remove to output char from input in TO_CHAR
|
* Remove to output char from input in TO_CHAR
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (Np->type == TO_CHAR)
|
if (Np->type == TO_CHAR)
|
||||||
*Np->inout_p = n->character;
|
*Np->inout_p = n->character;
|
||||||
@@ -4169,9 +4117,8 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
|
|||||||
else
|
else
|
||||||
*Np->number_p = '\0';
|
*Np->number_p = '\0';
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Correction - precision of dec. number
|
* Correction - precision of dec. number
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
Np->Num->post = Np->read_post;
|
Np->Num->post = Np->read_post;
|
||||||
|
|
||||||
@@ -4213,10 +4160,9 @@ do { \
|
|||||||
if (flag) \
|
if (flag) \
|
||||||
pfree(format); \
|
pfree(format); \
|
||||||
\
|
\
|
||||||
/* ---------- \
|
/*
|
||||||
* for result is allocated max memory, which current format-picture\
|
* for result is allocated max memory, which current format-picture\
|
||||||
* needs, now it must be re-allocate to result real size \
|
* needs, now it must be re-allocate to result real size \
|
||||||
* ---------- \
|
|
||||||
*/ \
|
*/ \
|
||||||
if (!(len = strlen(VARDATA(result)))) \
|
if (!(len = strlen(VARDATA(result)))) \
|
||||||
{ \
|
{ \
|
||||||
@@ -4300,9 +4246,8 @@ numeric_to_char(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
NUM_TOCHAR_prepare;
|
NUM_TOCHAR_prepare;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* On DateType depend part (numeric)
|
* On DateType depend part (numeric)
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (IS_ROMAN(&Num))
|
if (IS_ROMAN(&Num))
|
||||||
{
|
{
|
||||||
@@ -4399,9 +4344,8 @@ int4_to_char(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
NUM_TOCHAR_prepare;
|
NUM_TOCHAR_prepare;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* On DateType depend part (int32)
|
* On DateType depend part (int32)
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (IS_ROMAN(&Num))
|
if (IS_ROMAN(&Num))
|
||||||
numstr = orgnum = int_to_roman(value);
|
numstr = orgnum = int_to_roman(value);
|
||||||
@@ -4481,9 +4425,8 @@ int8_to_char(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
NUM_TOCHAR_prepare;
|
NUM_TOCHAR_prepare;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* On DateType depend part (int32)
|
* On DateType depend part (int32)
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (IS_ROMAN(&Num))
|
if (IS_ROMAN(&Num))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*
|
*
|
||||||
* 1998 Jan Wieck
|
* 1998 Jan Wieck
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.38 2001/03/22 03:59:52 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.39 2001/03/22 06:16:17 momjian Exp $
|
||||||
*
|
*
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
@@ -201,17 +201,15 @@ numeric_in(PG_FUNCTION_ARGS)
|
|||||||
NumericVar value;
|
NumericVar value;
|
||||||
Numeric res;
|
Numeric res;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Check for NaN
|
* Check for NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (strcmp(str, "NaN") == 0)
|
if (strcmp(str, "NaN") == 0)
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Use set_var_from_str() to parse the input string
|
* Use set_var_from_str() to parse the input string and return it in
|
||||||
* and return it in the packed DB storage format
|
* the packed DB storage format
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&value);
|
init_var(&value);
|
||||||
set_var_from_str(str, &value);
|
set_var_from_str(str, &value);
|
||||||
@@ -238,21 +236,19 @@ numeric_out(PG_FUNCTION_ARGS)
|
|||||||
NumericVar x;
|
NumericVar x;
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
PG_RETURN_CSTRING(pstrdup("NaN"));
|
PG_RETURN_CSTRING(pstrdup("NaN"));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the number in the variable format.
|
* Get the number in the variable format.
|
||||||
*
|
*
|
||||||
* Even if we didn't need to change format, we'd still need to copy
|
* Even if we didn't need to change format, we'd still need to copy the
|
||||||
* the value to have a modifiable copy for rounding. set_var_from_num()
|
* value to have a modifiable copy for rounding. set_var_from_num()
|
||||||
* also guarantees there is extra digit space in case we produce a
|
* also guarantees there is extra digit space in case we produce a
|
||||||
* carry out from rounding.
|
* carry out from rounding.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&x);
|
init_var(&x);
|
||||||
set_var_from_num(num, &x);
|
set_var_from_num(num, &x);
|
||||||
@@ -285,17 +281,15 @@ numeric(PG_FUNCTION_ARGS)
|
|||||||
int maxweight;
|
int maxweight;
|
||||||
NumericVar var;
|
NumericVar var;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If the value isn't a valid type modifier, simply return a
|
* If the value isn't a valid type modifier, simply return a copy of
|
||||||
* copy of the input value
|
* the input value
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (typmod < (int32) (VARHDRSZ))
|
if (typmod < (int32) (VARHDRSZ))
|
||||||
{
|
{
|
||||||
@@ -304,20 +298,18 @@ numeric(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_NUMERIC(new);
|
PG_RETURN_NUMERIC(new);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the precision and scale out of the typmod value
|
* Get the precision and scale out of the typmod value
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
tmp_typmod = typmod - VARHDRSZ;
|
tmp_typmod = typmod - VARHDRSZ;
|
||||||
precision = (tmp_typmod >> 16) & 0xffff;
|
precision = (tmp_typmod >> 16) & 0xffff;
|
||||||
scale = tmp_typmod & 0xffff;
|
scale = tmp_typmod & 0xffff;
|
||||||
maxweight = precision - scale;
|
maxweight = precision - scale;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If the number is in bounds and due to the present result scale
|
* If the number is in bounds and due to the present result scale no
|
||||||
* no rounding could be necessary, just make a copy of the input
|
* rounding could be necessary, just make a copy of the input and
|
||||||
* and modify its scale fields.
|
* modify its scale fields.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (num->n_weight < maxweight && scale >= num->n_rscale)
|
if (num->n_weight < maxweight && scale >= num->n_rscale)
|
||||||
{
|
{
|
||||||
@@ -329,10 +321,9 @@ numeric(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_NUMERIC(new);
|
PG_RETURN_NUMERIC(new);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* We really need to fiddle with things - unpack the number into
|
* We really need to fiddle with things - unpack the number into a
|
||||||
* a variable and let apply_typmod() do it.
|
* variable and let apply_typmod() do it.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&var);
|
init_var(&var);
|
||||||
|
|
||||||
@@ -359,16 +350,14 @@ numeric_abs(PG_FUNCTION_ARGS)
|
|||||||
Numeric num = PG_GETARG_NUMERIC(0);
|
Numeric num = PG_GETARG_NUMERIC(0);
|
||||||
Numeric res;
|
Numeric res;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Do it the easy way directly on the packed format
|
* Do it the easy way directly on the packed format
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
res = (Numeric) palloc(num->varlen);
|
res = (Numeric) palloc(num->varlen);
|
||||||
memcpy(res, num, num->varlen);
|
memcpy(res, num, num->varlen);
|
||||||
@@ -385,25 +374,22 @@ numeric_uminus(PG_FUNCTION_ARGS)
|
|||||||
Numeric num = PG_GETARG_NUMERIC(0);
|
Numeric num = PG_GETARG_NUMERIC(0);
|
||||||
Numeric res;
|
Numeric res;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Do it the easy way directly on the packed format
|
* Do it the easy way directly on the packed format
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
res = (Numeric) palloc(num->varlen);
|
res = (Numeric) palloc(num->varlen);
|
||||||
memcpy(res, num, num->varlen);
|
memcpy(res, num, num->varlen);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* The packed format is known to be totally zero digit trimmed
|
* The packed format is known to be totally zero digit trimmed always.
|
||||||
* always. So we can identify a ZERO by the fact that there
|
* So we can identify a ZERO by the fact that there are no digits at
|
||||||
* are no digits at all. Do nothing to a zero.
|
* all. Do nothing to a zero.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (num->varlen != NUMERIC_HDRSZ)
|
if (num->varlen != NUMERIC_HDRSZ)
|
||||||
{
|
{
|
||||||
@@ -425,29 +411,27 @@ numeric_sign(PG_FUNCTION_ARGS)
|
|||||||
Numeric res;
|
Numeric res;
|
||||||
NumericVar result;
|
NumericVar result;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
init_var(&result);
|
init_var(&result);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* The packed format is known to be totally zero digit trimmed
|
* The packed format is known to be totally zero digit trimmed always.
|
||||||
* always. So we can identify a ZERO by the fact that there
|
* So we can identify a ZERO by the fact that there are no digits at
|
||||||
* are no digits at all.
|
* all.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (num->varlen == NUMERIC_HDRSZ)
|
if (num->varlen == NUMERIC_HDRSZ)
|
||||||
set_var_from_var(&const_zero, &result);
|
set_var_from_var(&const_zero, &result);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* And if there are some, we return a copy of ONE
|
/*
|
||||||
* with the sign of our argument
|
* And if there are some, we return a copy of ONE with the sign of
|
||||||
* ----------
|
* our argument
|
||||||
*/
|
*/
|
||||||
set_var_from_var(&const_one, &result);
|
set_var_from_var(&const_one, &result);
|
||||||
result.sign = NUMERIC_SIGN(num);
|
result.sign = NUMERIC_SIGN(num);
|
||||||
@@ -477,23 +461,21 @@ numeric_round(PG_FUNCTION_ARGS)
|
|||||||
NumericVar arg;
|
NumericVar arg;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Limit the scale value to avoid possible overflow in calculations below.
|
* Limit the scale value to avoid possible overflow in calculations
|
||||||
* ----------
|
* below.
|
||||||
*/
|
*/
|
||||||
scale = MIN(NUMERIC_MAX_RESULT_SCALE,
|
scale = MIN(NUMERIC_MAX_RESULT_SCALE,
|
||||||
MAX(-NUMERIC_MAX_RESULT_SCALE, scale));
|
MAX(-NUMERIC_MAX_RESULT_SCALE, scale));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Unpack the argument and round it at the proper digit position
|
* Unpack the argument and round it at the proper digit position
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg);
|
init_var(&arg);
|
||||||
set_var_from_num(num, &arg);
|
set_var_from_num(num, &arg);
|
||||||
@@ -533,17 +515,15 @@ numeric_round(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Set result's scale to something reasonable.
|
* Set result's scale to something reasonable.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
scale = MIN(NUMERIC_MAX_DISPLAY_SCALE, MAX(0, scale));
|
scale = MIN(NUMERIC_MAX_DISPLAY_SCALE, MAX(0, scale));
|
||||||
arg.rscale = scale;
|
arg.rscale = scale;
|
||||||
arg.dscale = scale;
|
arg.dscale = scale;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Return the rounded result
|
* Return the rounded result
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
res = make_result(&arg);
|
res = make_result(&arg);
|
||||||
|
|
||||||
@@ -568,40 +548,36 @@ numeric_trunc(PG_FUNCTION_ARGS)
|
|||||||
Numeric res;
|
Numeric res;
|
||||||
NumericVar arg;
|
NumericVar arg;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Limit the scale value to avoid possible overflow in calculations below.
|
* Limit the scale value to avoid possible overflow in calculations
|
||||||
* ----------
|
* below.
|
||||||
*/
|
*/
|
||||||
scale = MIN(NUMERIC_MAX_RESULT_SCALE,
|
scale = MIN(NUMERIC_MAX_RESULT_SCALE,
|
||||||
MAX(-NUMERIC_MAX_RESULT_SCALE, scale));
|
MAX(-NUMERIC_MAX_RESULT_SCALE, scale));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Unpack the argument and truncate it at the proper digit position
|
* Unpack the argument and truncate it at the proper digit position
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg);
|
init_var(&arg);
|
||||||
set_var_from_num(num, &arg);
|
set_var_from_num(num, &arg);
|
||||||
|
|
||||||
arg.ndigits = MIN(arg.ndigits, MAX(0, arg.weight + scale + 1));
|
arg.ndigits = MIN(arg.ndigits, MAX(0, arg.weight + scale + 1));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Set result's scale to something reasonable.
|
* Set result's scale to something reasonable.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
scale = MIN(NUMERIC_MAX_DISPLAY_SCALE, MAX(0, scale));
|
scale = MIN(NUMERIC_MAX_DISPLAY_SCALE, MAX(0, scale));
|
||||||
arg.rscale = scale;
|
arg.rscale = scale;
|
||||||
arg.dscale = scale;
|
arg.dscale = scale;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Return the truncated result
|
* Return the truncated result
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
res = make_result(&arg);
|
res = make_result(&arg);
|
||||||
|
|
||||||
@@ -931,18 +907,16 @@ numeric_add(PG_FUNCTION_ARGS)
|
|||||||
NumericVar result;
|
NumericVar result;
|
||||||
Numeric res;
|
Numeric res;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Unpack the values, let add_var() compute the result
|
* Unpack the values, let add_var() compute the result and return it.
|
||||||
* and return it. The internals of add_var() will automatically
|
* The internals of add_var() will automatically set the correct
|
||||||
* set the correct result and display scales in the result.
|
* result and display scales in the result.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg1);
|
init_var(&arg1);
|
||||||
init_var(&arg2);
|
init_var(&arg2);
|
||||||
@@ -978,17 +952,15 @@ numeric_sub(PG_FUNCTION_ARGS)
|
|||||||
NumericVar result;
|
NumericVar result;
|
||||||
Numeric res;
|
Numeric res;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Unpack the two arguments, let sub_var() compute the
|
* Unpack the two arguments, let sub_var() compute the result and
|
||||||
* result and return it.
|
* return it.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg1);
|
init_var(&arg1);
|
||||||
init_var(&arg2);
|
init_var(&arg2);
|
||||||
@@ -1024,22 +996,19 @@ numeric_mul(PG_FUNCTION_ARGS)
|
|||||||
NumericVar result;
|
NumericVar result;
|
||||||
Numeric res;
|
Numeric res;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Unpack the arguments, let mul_var() compute the result
|
* Unpack the arguments, let mul_var() compute the result and return
|
||||||
* and return it. Unlike add_var() and sub_var(), mul_var()
|
* it. Unlike add_var() and sub_var(), mul_var() will round the result
|
||||||
* will round the result to the scale stored in global_rscale.
|
* to the scale stored in global_rscale. In the case of numeric_mul(),
|
||||||
* In the case of numeric_mul(), which is invoked for the *
|
* which is invoked for the * operator on numerics, we set it to the
|
||||||
* operator on numerics, we set it to the exact representation
|
* exact representation for the product (rscale = sum(rscale of arg1,
|
||||||
* for the product (rscale = sum(rscale of arg1, rscale of arg2)
|
* rscale of arg2) and the same for the dscale).
|
||||||
* and the same for the dscale).
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg1);
|
init_var(&arg1);
|
||||||
init_var(&arg2);
|
init_var(&arg2);
|
||||||
@@ -1081,16 +1050,14 @@ numeric_div(PG_FUNCTION_ARGS)
|
|||||||
Numeric res;
|
Numeric res;
|
||||||
int res_dscale;
|
int res_dscale;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Unpack the arguments
|
* Unpack the arguments
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg1);
|
init_var(&arg1);
|
||||||
init_var(&arg2);
|
init_var(&arg2);
|
||||||
@@ -1122,9 +1089,8 @@ numeric_div(PG_FUNCTION_ARGS)
|
|||||||
global_rscale = MAX(global_rscale, res_dscale + 4);
|
global_rscale = MAX(global_rscale, res_dscale + 4);
|
||||||
global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
|
global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Do the divide, set the display scale and return the result
|
* Do the divide, set the display scale and return the result
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
div_var(&arg1, &arg2, &result);
|
div_var(&arg1, &arg2, &result);
|
||||||
|
|
||||||
@@ -1192,16 +1158,14 @@ numeric_inc(PG_FUNCTION_ARGS)
|
|||||||
NumericVar arg;
|
NumericVar arg;
|
||||||
Numeric res;
|
Numeric res;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Compute the result and return it
|
* Compute the result and return it
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg);
|
init_var(&arg);
|
||||||
|
|
||||||
@@ -1231,16 +1195,14 @@ numeric_smaller(PG_FUNCTION_ARGS)
|
|||||||
NumericVar arg2;
|
NumericVar arg2;
|
||||||
Numeric res;
|
Numeric res;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Unpack the values, and decide which is the smaller one
|
* Unpack the values, and decide which is the smaller one
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg1);
|
init_var(&arg1);
|
||||||
init_var(&arg2);
|
init_var(&arg2);
|
||||||
@@ -1275,16 +1237,14 @@ numeric_larger(PG_FUNCTION_ARGS)
|
|||||||
NumericVar arg2;
|
NumericVar arg2;
|
||||||
Numeric res;
|
Numeric res;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Unpack the values, and decide which is the larger one
|
* Unpack the values, and decide which is the larger one
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg1);
|
init_var(&arg1);
|
||||||
init_var(&arg2);
|
init_var(&arg2);
|
||||||
@@ -1327,17 +1287,15 @@ numeric_sqrt(PG_FUNCTION_ARGS)
|
|||||||
NumericVar result;
|
NumericVar result;
|
||||||
int res_dscale;
|
int res_dscale;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Unpack the argument, determine the scales like for divide,
|
* Unpack the argument, determine the scales like for divide, let
|
||||||
* let sqrt_var() do the calculation and return the result.
|
* sqrt_var() do the calculation and return the result.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg);
|
init_var(&arg);
|
||||||
init_var(&result);
|
init_var(&result);
|
||||||
@@ -1378,16 +1336,14 @@ numeric_exp(PG_FUNCTION_ARGS)
|
|||||||
NumericVar result;
|
NumericVar result;
|
||||||
int res_dscale;
|
int res_dscale;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Same procedure like for sqrt().
|
* Same procedure like for sqrt().
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg);
|
init_var(&arg);
|
||||||
init_var(&result);
|
init_var(&result);
|
||||||
@@ -1427,16 +1383,14 @@ numeric_ln(PG_FUNCTION_ARGS)
|
|||||||
NumericVar result;
|
NumericVar result;
|
||||||
int res_dscale;
|
int res_dscale;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Same procedure like for sqrt()
|
* Same procedure like for sqrt()
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg);
|
init_var(&arg);
|
||||||
init_var(&result);
|
init_var(&result);
|
||||||
@@ -1478,16 +1432,14 @@ numeric_log(PG_FUNCTION_ARGS)
|
|||||||
NumericVar result;
|
NumericVar result;
|
||||||
int res_dscale;
|
int res_dscale;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Initialize things and calculate scales
|
* Initialize things and calculate scales
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg1);
|
init_var(&arg1);
|
||||||
init_var(&arg2);
|
init_var(&arg2);
|
||||||
@@ -1501,9 +1453,8 @@ numeric_log(PG_FUNCTION_ARGS)
|
|||||||
global_rscale = MAX(global_rscale, res_dscale + 4);
|
global_rscale = MAX(global_rscale, res_dscale + 4);
|
||||||
global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
|
global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Call log_var() to compute and return the result
|
* Call log_var() to compute and return the result
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
log_var(&arg1, &arg2, &result);
|
log_var(&arg1, &arg2, &result);
|
||||||
|
|
||||||
@@ -1536,16 +1487,14 @@ numeric_power(PG_FUNCTION_ARGS)
|
|||||||
NumericVar result;
|
NumericVar result;
|
||||||
int res_dscale;
|
int res_dscale;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle NaN
|
* Handle NaN
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Initialize things and calculate scales
|
* Initialize things and calculate scales
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&arg1);
|
init_var(&arg1);
|
||||||
init_var(&arg2);
|
init_var(&arg2);
|
||||||
@@ -1559,9 +1508,8 @@ numeric_power(PG_FUNCTION_ARGS)
|
|||||||
global_rscale = MAX(global_rscale, res_dscale + 4);
|
global_rscale = MAX(global_rscale, res_dscale + 4);
|
||||||
global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
|
global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Call log_var() to compute and return the result
|
* Call log_var() to compute and return the result
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
power_var(&arg1, &arg2, &result);
|
power_var(&arg1, &arg2, &result);
|
||||||
|
|
||||||
@@ -1619,9 +1567,8 @@ numeric_int4(PG_FUNCTION_ARGS)
|
|||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
elog(ERROR, "Cannot convert NaN to int4");
|
elog(ERROR, "Cannot convert NaN to int4");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the number in the variable format so we can round to integer.
|
* Get the number in the variable format so we can round to integer.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&x);
|
init_var(&x);
|
||||||
set_var_from_num(num, &x);
|
set_var_from_num(num, &x);
|
||||||
@@ -1670,9 +1617,8 @@ numeric_int8(PG_FUNCTION_ARGS)
|
|||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
elog(ERROR, "Cannot convert NaN to int8");
|
elog(ERROR, "Cannot convert NaN to int8");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the number in the variable format so we can round to integer.
|
* Get the number in the variable format so we can round to integer.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&x);
|
init_var(&x);
|
||||||
set_var_from_num(num, &x);
|
set_var_from_num(num, &x);
|
||||||
@@ -1721,9 +1667,8 @@ numeric_int2(PG_FUNCTION_ARGS)
|
|||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
elog(ERROR, "Cannot convert NaN to int2");
|
elog(ERROR, "Cannot convert NaN to int2");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the number in the variable format so we can round to integer.
|
* Get the number in the variable format so we can round to integer.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(&x);
|
init_var(&x);
|
||||||
set_var_from_num(num, &x);
|
set_var_from_num(num, &x);
|
||||||
@@ -2512,10 +2457,8 @@ get_str_from_var(NumericVar *var, int dscale)
|
|||||||
int i;
|
int i;
|
||||||
int d;
|
int d;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Check if we must round up before printing the value and
|
* Check if we must round up before printing the value and do so.
|
||||||
* do so.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
i = dscale + var->weight + 1;
|
i = dscale + var->weight + 1;
|
||||||
if (i >= 0 && var->ndigits > i)
|
if (i >= 0 && var->ndigits > i)
|
||||||
@@ -2543,23 +2486,20 @@ get_str_from_var(NumericVar *var, int dscale)
|
|||||||
else
|
else
|
||||||
var->ndigits = MAX(0, MIN(i, var->ndigits));
|
var->ndigits = MAX(0, MIN(i, var->ndigits));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Allocate space for the result
|
* Allocate space for the result
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
str = palloc(MAX(0, dscale) + MAX(0, var->weight) + 4);
|
str = palloc(MAX(0, dscale) + MAX(0, var->weight) + 4);
|
||||||
cp = str;
|
cp = str;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Output a dash for negative values
|
* Output a dash for negative values
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (var->sign == NUMERIC_NEG)
|
if (var->sign == NUMERIC_NEG)
|
||||||
*cp++ = '-';
|
*cp++ = '-';
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Output all digits before the decimal point
|
* Output all digits before the decimal point
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
i = MAX(var->weight, 0);
|
i = MAX(var->weight, 0);
|
||||||
d = 0;
|
d = 0;
|
||||||
@@ -2573,10 +2513,9 @@ get_str_from_var(NumericVar *var, int dscale)
|
|||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If requested, output a decimal point and all the digits
|
* If requested, output a decimal point and all the digits that follow
|
||||||
* that follow it.
|
* it.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (dscale > 0)
|
if (dscale > 0)
|
||||||
{
|
{
|
||||||
@@ -2591,9 +2530,8 @@ get_str_from_var(NumericVar *var, int dscale)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* terminate the string and return it
|
* terminate the string and return it
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
*cp = '\0';
|
*cp = '\0';
|
||||||
return str;
|
return str;
|
||||||
@@ -2725,14 +2663,12 @@ apply_typmod(NumericVar *var, int32 typmod)
|
|||||||
else
|
else
|
||||||
var->ndigits = MAX(0, MIN(i, var->ndigits));
|
var->ndigits = MAX(0, MIN(i, var->ndigits));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Check for overflow - note we can't do this before rounding,
|
* Check for overflow - note we can't do this before rounding, because
|
||||||
* because rounding could raise the weight. Also note that the
|
* rounding could raise the weight. Also note that the var's weight
|
||||||
* var's weight could be inflated by leading zeroes, which will
|
* could be inflated by leading zeroes, which will be stripped before
|
||||||
* be stripped before storage but perhaps might not have been yet.
|
* storage but perhaps might not have been yet. In any case, we must
|
||||||
* In any case, we must recognize a true zero, whose weight doesn't
|
* recognize a true zero, whose weight doesn't mean anything.
|
||||||
* mean anything.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (var->weight >= maxweight)
|
if (var->weight >= maxweight)
|
||||||
{
|
{
|
||||||
@@ -2805,28 +2741,27 @@ cmp_var(NumericVar *var1, NumericVar *var2)
|
|||||||
static void
|
static void
|
||||||
add_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
add_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Decide on the signs of the two variables what to do
|
* Decide on the signs of the two variables what to do
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (var1->sign == NUMERIC_POS)
|
if (var1->sign == NUMERIC_POS)
|
||||||
{
|
{
|
||||||
if (var2->sign == NUMERIC_POS)
|
if (var2->sign == NUMERIC_POS)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* Both are positive
|
/*
|
||||||
* result = +(ABS(var1) + ABS(var2))
|
* Both are positive result = +(ABS(var1) + ABS(var2))
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
add_abs(var1, var2, result);
|
add_abs(var1, var2, result);
|
||||||
result->sign = NUMERIC_POS;
|
result->sign = NUMERIC_POS;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* var1 is positive, var2 is negative
|
/*
|
||||||
* Must compare absolute values
|
* var1 is positive, var2 is negative Must compare absolute
|
||||||
* ----------
|
* values
|
||||||
*/
|
*/
|
||||||
switch (cmp_abs(var1, var2))
|
switch (cmp_abs(var1, var2))
|
||||||
{
|
{
|
||||||
@@ -2930,9 +2865,9 @@ add_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
|||||||
static void
|
static void
|
||||||
sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Decide on the signs of the two variables what to do
|
* Decide on the signs of the two variables what to do
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (var1->sign == NUMERIC_POS)
|
if (var1->sign == NUMERIC_POS)
|
||||||
{
|
{
|
||||||
@@ -3157,17 +3092,15 @@ div_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
|||||||
int first_nextdigit;
|
int first_nextdigit;
|
||||||
int stat = 0;
|
int stat = 0;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* First of all division by zero check
|
* First of all division by zero check
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ndigits_tmp = var2->ndigits + 1;
|
ndigits_tmp = var2->ndigits + 1;
|
||||||
if (ndigits_tmp == 1)
|
if (ndigits_tmp == 1)
|
||||||
elog(ERROR, "division by zero on numeric");
|
elog(ERROR, "division by zero on numeric");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Determine the result sign, weight and number of digits to calculate
|
* Determine the result sign, weight and number of digits to calculate
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (var1->sign == var2->sign)
|
if (var1->sign == var2->sign)
|
||||||
res_sign = NUMERIC_POS;
|
res_sign = NUMERIC_POS;
|
||||||
@@ -3178,9 +3111,8 @@ div_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
|||||||
if (res_ndigits <= 0)
|
if (res_ndigits <= 0)
|
||||||
res_ndigits = 1;
|
res_ndigits = 1;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Now result zero check
|
* Now result zero check
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (var1->ndigits == 0)
|
if (var1->ndigits == 0)
|
||||||
{
|
{
|
||||||
@@ -3189,17 +3121,15 @@ div_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Initialize local variables
|
* Initialize local variables
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
init_var(÷nd);
|
init_var(÷nd);
|
||||||
for (i = 1; i < 10; i++)
|
for (i = 1; i < 10; i++)
|
||||||
init_var(&divisor[i]);
|
init_var(&divisor[i]);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Make a copy of the divisor which has one leading zero digit
|
* Make a copy of the divisor which has one leading zero digit
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
divisor[1].ndigits = ndigits_tmp;
|
divisor[1].ndigits = ndigits_tmp;
|
||||||
divisor[1].rscale = var2->ndigits;
|
divisor[1].rscale = var2->ndigits;
|
||||||
@@ -3209,9 +3139,8 @@ div_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
|||||||
divisor[1].digits[0] = 0;
|
divisor[1].digits[0] = 0;
|
||||||
memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1);
|
memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Make a copy of the dividend
|
* Make a copy of the dividend
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
dividend.ndigits = var1->ndigits;
|
dividend.ndigits = var1->ndigits;
|
||||||
dividend.weight = 0;
|
dividend.weight = 0;
|
||||||
@@ -3221,9 +3150,8 @@ div_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
|||||||
dividend.digits = dividend.buf;
|
dividend.digits = dividend.buf;
|
||||||
memcpy(dividend.digits, var1->digits, var1->ndigits);
|
memcpy(dividend.digits, var1->digits, var1->ndigits);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Setup the result
|
* Setup the result
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
digitbuf_free(result->buf);
|
digitbuf_free(result->buf);
|
||||||
result->buf = digitbuf_alloc(res_ndigits + 2);
|
result->buf = digitbuf_alloc(res_ndigits + 2);
|
||||||
@@ -3356,7 +3284,7 @@ mod_var(NumericVar *var1, NumericVar *var2, NumericVar *result)
|
|||||||
|
|
||||||
init_var(&tmp);
|
init_var(&tmp);
|
||||||
|
|
||||||
/* ----------
|
/* ---------
|
||||||
* We do this using the equation
|
* We do this using the equation
|
||||||
* mod(x,y) = x - trunc(x/y)*y
|
* mod(x,y) = x - trunc(x/y)*y
|
||||||
* We fiddle a bit with global_rscale to control result precision.
|
* We fiddle a bit with global_rscale to control result precision.
|
||||||
@@ -3470,9 +3398,8 @@ sqrt_var(NumericVar *arg, NumericVar *result)
|
|||||||
set_var_from_var(arg, &tmp_arg);
|
set_var_from_var(arg, &tmp_arg);
|
||||||
set_var_from_var(result, &last_val);
|
set_var_from_var(result, &last_val);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Initialize the result to the first guess
|
* Initialize the result to the first guess
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
digitbuf_free(result->buf);
|
digitbuf_free(result->buf);
|
||||||
result->buf = digitbuf_alloc(1);
|
result->buf = digitbuf_alloc(1);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* ----------
|
/* ----------
|
||||||
* pg_lzcompress.c -
|
* pg_lzcompress.c -
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_lzcompress.c,v 1.10 2001/03/22 03:59:52 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_lzcompress.c,v 1.11 2001/03/22 06:16:17 momjian Exp $
|
||||||
*
|
*
|
||||||
* This is an implementation of LZ compression for PostgreSQL.
|
* This is an implementation of LZ compression for PostgreSQL.
|
||||||
* It uses a simple history table and generates 2-3 byte tags
|
* It uses a simple history table and generates 2-3 byte tags
|
||||||
@@ -383,36 +383,33 @@ pglz_find_match(PGLZ_HistEntry **hstart, char *input, char *end,
|
|||||||
char *ip;
|
char *ip;
|
||||||
char *hp;
|
char *hp;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Traverse the linked history list until a good enough
|
* Traverse the linked history list until a good enough match is
|
||||||
* match is found.
|
* found.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
hent = hstart[pglz_hist_idx(input, end)];
|
hent = hstart[pglz_hist_idx(input, end)];
|
||||||
while (hent && len < good_match)
|
while (hent && len < good_match)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Be happy with lesser good matches the more entries we visited.
|
* Be happy with lesser good matches the more entries we visited.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
good_match -= (good_match * good_drop) / 100;
|
good_match -= (good_match * good_drop) / 100;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Stop if the offset does not fit into our tag anymore.
|
* Stop if the offset does not fit into our tag anymore.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
thisoff = (ip = input) - (hp = hent->pos);
|
thisoff = (ip = input) - (hp = hent->pos);
|
||||||
if (thisoff >= 0x0fff)
|
if (thisoff >= 0x0fff)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Determine length of match. A better match must be larger than
|
* Determine length of match. A better match must be larger than
|
||||||
* the best so far. And if we already have a match of 16 or more
|
* the best so far. And if we already have a match of 16 or more
|
||||||
* bytes, it's worth the call overhead to use memcmp() to check
|
* bytes, it's worth the call overhead to use memcmp() to check if
|
||||||
* if this match is equal for the same size. After that we must
|
* this match is equal for the same size. After that we must
|
||||||
* fallback to character by character comparision to know the
|
* fallback to character by character comparision to know the
|
||||||
* exact position where the diff occured.
|
* exact position where the diff occured.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (len >= 16)
|
if (len >= 16)
|
||||||
{
|
{
|
||||||
@@ -434,9 +431,8 @@ pglz_find_match(PGLZ_HistEntry **hstart, char *input, char *end,
|
|||||||
hp++;
|
hp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Remember this match as the best (if it is)
|
* Remember this match as the best (if it is)
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (thislen > len)
|
if (thislen > len)
|
||||||
{
|
{
|
||||||
@@ -444,17 +440,15 @@ pglz_find_match(PGLZ_HistEntry **hstart, char *input, char *end,
|
|||||||
off = thisoff;
|
off = thisoff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Advance to the next history entry
|
* Advance to the next history entry
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
hent = hent->next;
|
hent = hent->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Return match information only if it results at least in one
|
* Return match information only if it results at least in one byte
|
||||||
* byte reduction.
|
* reduction.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (len > 2)
|
if (len > 2)
|
||||||
{
|
{
|
||||||
@@ -495,23 +489,20 @@ pglz_compress(char *source, int32 slen, PGLZ_Header *dest, PGLZ_Strategy *strate
|
|||||||
int32 result_max;
|
int32 result_max;
|
||||||
int32 need_rate;
|
int32 need_rate;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Our fallback strategy is the default.
|
* Our fallback strategy is the default.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (strategy == NULL)
|
if (strategy == NULL)
|
||||||
strategy = PGLZ_strategy_default;
|
strategy = PGLZ_strategy_default;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Save the original source size in the header.
|
* Save the original source size in the header.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
dest->rawsize = slen;
|
dest->rawsize = slen;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If the strategy forbids compression (at all or if source chunk too
|
* If the strategy forbids compression (at all or if source chunk too
|
||||||
* small), copy input to output without compression.
|
* small), copy input to output without compression.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (strategy->match_size_good == 0)
|
if (strategy->match_size_good == 0)
|
||||||
{
|
{
|
||||||
@@ -527,9 +518,8 @@ pglz_compress(char *source, int32 slen, PGLZ_Header *dest, PGLZ_Strategy *strate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Limit the match size to the maximum implementation allowed value
|
* Limit the match size to the maximum implementation allowed value
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if ((good_match = strategy->match_size_good) > PGLZ_MAX_MATCH)
|
if ((good_match = strategy->match_size_good) > PGLZ_MAX_MATCH)
|
||||||
good_match = PGLZ_MAX_MATCH;
|
good_match = PGLZ_MAX_MATCH;
|
||||||
@@ -541,22 +531,19 @@ pglz_compress(char *source, int32 slen, PGLZ_Header *dest, PGLZ_Strategy *strate
|
|||||||
if (good_drop > 100)
|
if (good_drop > 100)
|
||||||
good_drop = 100;
|
good_drop = 100;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Initialize the history tables. For inputs smaller than
|
* Initialize the history tables. For inputs smaller than
|
||||||
* PGLZ_HISTORY_SIZE, we already have a big enough history
|
* PGLZ_HISTORY_SIZE, we already have a big enough history table on
|
||||||
* table on the stack frame.
|
* the stack frame.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
memset((void *) hist_start, 0, sizeof(hist_start));
|
memset((void *) hist_start, 0, sizeof(hist_start));
|
||||||
memset((void *) hist_entries, 0, sizeof(hist_entries));
|
memset((void *) hist_entries, 0, sizeof(hist_entries));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Compute the maximum result size allowed by the strategy.
|
* Compute the maximum result size allowed by the strategy. If the
|
||||||
* If the input size exceeds force_input_size, the max result size
|
* input size exceeds force_input_size, the max result size is the
|
||||||
* is the input size itself.
|
* input size itself. Otherwise, it is the input size minus the
|
||||||
* Otherwise, it is the input size minus the minimum wanted
|
* minimum wanted compression rate.
|
||||||
* compression rate.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (slen >= strategy->force_input_size)
|
if (slen >= strategy->force_input_size)
|
||||||
result_max = slen;
|
result_max = slen;
|
||||||
@@ -570,16 +557,15 @@ pglz_compress(char *source, int32 slen, PGLZ_Header *dest, PGLZ_Strategy *strate
|
|||||||
result_max = slen - ((slen * need_rate) / 100);
|
result_max = slen - ((slen * need_rate) / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Compress the source directly into the output buffer.
|
* Compress the source directly into the output buffer.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
while (dp < dend)
|
while (dp < dend)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* If we already exceeded the maximum result size, set no compression
|
/*
|
||||||
* flag and stop this. But don't check too often.
|
* If we already exceeded the maximum result size, set no
|
||||||
* ----------
|
* compression flag and stop this. But don't check too often.
|
||||||
*/
|
*/
|
||||||
if (bp - bstart >= result_max)
|
if (bp - bstart >= result_max)
|
||||||
{
|
{
|
||||||
@@ -587,17 +573,16 @@ pglz_compress(char *source, int32 slen, PGLZ_Header *dest, PGLZ_Strategy *strate
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Try to find a match in the history
|
* Try to find a match in the history
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (pglz_find_match(hist_start, dp, dend, &match_len,
|
if (pglz_find_match(hist_start, dp, dend, &match_len,
|
||||||
&match_off, good_match, good_drop))
|
&match_off, good_match, good_drop))
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* Create the tag and add history entries for
|
/*
|
||||||
* all matched characters.
|
* Create the tag and add history entries for all matched
|
||||||
* ----------
|
* characters.
|
||||||
*/
|
*/
|
||||||
pglz_out_tag(ctrlp, ctrlb, ctrl, bp, match_len, match_off);
|
pglz_out_tag(ctrlp, ctrlb, ctrl, bp, match_len, match_off);
|
||||||
while (match_len--)
|
while (match_len--)
|
||||||
@@ -609,9 +594,9 @@ pglz_compress(char *source, int32 slen, PGLZ_Header *dest, PGLZ_Strategy *strate
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* No match found. Copy one literal byte.
|
* No match found. Copy one literal byte.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
pglz_out_literal(ctrlp, ctrlb, ctrl, bp, *dp);
|
pglz_out_literal(ctrlp, ctrlb, ctrl, bp, *dp);
|
||||||
pglz_hist_add(hist_start, hist_entries, hist_next, dp, dend);
|
pglz_hist_add(hist_start, hist_entries, hist_next, dp, dend);
|
||||||
@@ -620,11 +605,10 @@ pglz_compress(char *source, int32 slen, PGLZ_Header *dest, PGLZ_Strategy *strate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If we are still in compressing mode, write out the last
|
* If we are still in compressing mode, write out the last control
|
||||||
* control byte and determine if the compression gained the
|
* byte and determine if the compression gained the rate requested by
|
||||||
* rate requested by the strategy.
|
* the strategy.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (do_compress)
|
if (do_compress)
|
||||||
{
|
{
|
||||||
@@ -635,12 +619,10 @@ pglz_compress(char *source, int32 slen, PGLZ_Header *dest, PGLZ_Strategy *strate
|
|||||||
do_compress = 0;
|
do_compress = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Done - if we successfully compressed and matched the
|
* Done - if we successfully compressed and matched the strategy's
|
||||||
* strategy's constraints, return the compressed result.
|
* constraints, return the compressed result. Otherwise copy the
|
||||||
* Otherwise copy the original source over it and return
|
* original source over it and return the original length.
|
||||||
* the original length.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (do_compress)
|
if (do_compress)
|
||||||
{
|
{
|
||||||
@@ -685,22 +667,22 @@ pglz_decompress(PGLZ_Header *source, char *dest)
|
|||||||
|
|
||||||
while (dp < dend)
|
while (dp < dend)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Read one control byte and process the next 8 items.
|
* Read one control byte and process the next 8 items.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ctrl = *dp++;
|
ctrl = *dp++;
|
||||||
for (ctrlc = 0; ctrlc < 8 && dp < dend; ctrlc++)
|
for (ctrlc = 0; ctrlc < 8 && dp < dend; ctrlc++)
|
||||||
{
|
{
|
||||||
if (ctrl & 1)
|
if (ctrl & 1)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* Otherwise it contains the match length minus 3
|
/*
|
||||||
* and the upper 4 bits of the offset. The next following
|
* Otherwise it contains the match length minus 3 and the
|
||||||
* byte contains the lower 8 bits of the offset. If
|
* upper 4 bits of the offset. The next following byte
|
||||||
* the length is coded as 18, another extension tag byte
|
* contains the lower 8 bits of the offset. If the length
|
||||||
* tells how much longer the match really was (0-255).
|
* is coded as 18, another extension tag byte tells how
|
||||||
* ----------
|
* much longer the match really was (0-255).
|
||||||
*/
|
*/
|
||||||
len = (dp[0] & 0x0f) + 3;
|
len = (dp[0] & 0x0f) + 3;
|
||||||
off = ((dp[0] & 0xf0) << 4) | dp[1];
|
off = ((dp[0] & 0xf0) << 4) | dp[1];
|
||||||
@@ -708,12 +690,11 @@ pglz_decompress(PGLZ_Header *source, char *dest)
|
|||||||
if (len == 18)
|
if (len == 18)
|
||||||
len += *dp++;
|
len += *dp++;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Now we copy the bytes specified by the tag from
|
* Now we copy the bytes specified by the tag from OUTPUT
|
||||||
* OUTPUT to OUTPUT. It is dangerous and platform
|
* to OUTPUT. It is dangerous and platform dependant to
|
||||||
* dependant to use memcpy() here, because the copied
|
* use memcpy() here, because the copied areas could
|
||||||
* areas could overlap extremely!
|
* overlap extremely!
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
while (len--)
|
while (len--)
|
||||||
{
|
{
|
||||||
@@ -723,25 +704,23 @@ pglz_decompress(PGLZ_Header *source, char *dest)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* An unset control bit means LITERAL BYTE. So we
|
/*
|
||||||
* just copy one from INPUT to OUTPUT.
|
* An unset control bit means LITERAL BYTE. So we just
|
||||||
* ----------
|
* copy one from INPUT to OUTPUT.
|
||||||
*/
|
*/
|
||||||
*bp++ = *dp++;
|
*bp++ = *dp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Advance the control bit
|
* Advance the control bit
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ctrl >>= 1;
|
ctrl >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* That's it.
|
* That's it.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
return (char *) bp - dest;
|
return (char *) bp - dest;
|
||||||
}
|
}
|
||||||
@@ -761,11 +740,10 @@ pglz_get_next_decomp_char_from_lzdata(PGLZ_DecompState *dstate)
|
|||||||
|
|
||||||
if (dstate->tocopy > 0)
|
if (dstate->tocopy > 0)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* Copy one byte from output to output until we did it
|
/*
|
||||||
* for the length specified by the last tag. Return that
|
* Copy one byte from output to output until we did it for the
|
||||||
* byte.
|
* length specified by the last tag. Return that byte.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
dstate->tocopy--;
|
dstate->tocopy--;
|
||||||
return (*(dstate->cp_out++) = *(dstate->cp_copy++));
|
return (*(dstate->cp_out++) = *(dstate->cp_copy++));
|
||||||
@@ -773,25 +751,24 @@ pglz_get_next_decomp_char_from_lzdata(PGLZ_DecompState *dstate)
|
|||||||
|
|
||||||
if (dstate->ctrl_count == 0)
|
if (dstate->ctrl_count == 0)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* Get the next control byte if we need to, but check
|
/*
|
||||||
* for EOF before.
|
* Get the next control byte if we need to, but check for EOF
|
||||||
* ----------
|
* before.
|
||||||
*/
|
*/
|
||||||
if (dstate->cp_in == dstate->cp_end)
|
if (dstate->cp_in == dstate->cp_end)
|
||||||
return EOF;
|
return EOF;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* This decompression method saves time only, if we stop near
|
* This decompression method saves time only, if we stop near the
|
||||||
* the beginning of the data (maybe because we're called by a
|
* beginning of the data (maybe because we're called by a
|
||||||
* comparision function and a difference occurs early). Otherwise,
|
* comparision function and a difference occurs early). Otherwise,
|
||||||
* all the checks, needed here, cause too much overhead.
|
* all the checks, needed here, cause too much overhead.
|
||||||
*
|
*
|
||||||
* Thus we decompress the entire rest at once into the temporary
|
* Thus we decompress the entire rest at once into the temporary
|
||||||
* buffer and change the decomp state to return the prepared
|
* buffer and change the decomp state to return the prepared data
|
||||||
* data from the buffer by the more simple calls to
|
* from the buffer by the more simple calls to
|
||||||
* pglz_get_next_decomp_char_from_plain().
|
* pglz_get_next_decomp_char_from_plain().
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (dstate->cp_out - dstate->temp_buf >= 256)
|
if (dstate->cp_out - dstate->temp_buf >= 256)
|
||||||
{
|
{
|
||||||
@@ -838,32 +815,29 @@ pglz_get_next_decomp_char_from_lzdata(PGLZ_DecompState *dstate)
|
|||||||
return (int) (*(dstate->cp_in++));
|
return (int) (*(dstate->cp_in++));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Not yet, get next control byte into decomp state.
|
* Not yet, get next control byte into decomp state.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
dstate->ctrl = (unsigned char) (*(dstate->cp_in++));
|
dstate->ctrl = (unsigned char) (*(dstate->cp_in++));
|
||||||
dstate->ctrl_count = 8;
|
dstate->ctrl_count = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Check for EOF in tag/literal byte data.
|
* Check for EOF in tag/literal byte data.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (dstate->cp_in == dstate->cp_end)
|
if (dstate->cp_in == dstate->cp_end)
|
||||||
return EOF;
|
return EOF;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Handle next control bit.
|
* Handle next control bit.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
dstate->ctrl_count--;
|
dstate->ctrl_count--;
|
||||||
if (dstate->ctrl & 0x01)
|
if (dstate->ctrl & 0x01)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* Bit is set, so tag is following. Setup copy information
|
/*
|
||||||
* and do the copy for the first byte as above.
|
* Bit is set, so tag is following. Setup copy information and do
|
||||||
* ----------
|
* the copy for the first byte as above.
|
||||||
*/
|
*/
|
||||||
int off;
|
int off;
|
||||||
|
|
||||||
@@ -879,9 +853,9 @@ pglz_get_next_decomp_char_from_lzdata(PGLZ_DecompState *dstate)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Bit is unset, so literal byte follows.
|
* Bit is unset, so literal byte follows.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
retval = (int) (*(dstate->cp_out++) = *(dstate->cp_in++));
|
retval = (int) (*(dstate->cp_out++) = *(dstate->cp_in++));
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
|||||||
* back to source text
|
* back to source text
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.74 2001/03/22 03:59:53 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.75 2001/03/22 06:16:18 momjian Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@@ -163,24 +163,21 @@ pg_get_ruledef(PG_FUNCTION_ARGS)
|
|||||||
StringInfoData buf;
|
StringInfoData buf;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* We need the rules name somewhere deep down: rulename is global
|
* We need the rules name somewhere deep down: rulename is global
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
rulename = pstrdup(NameStr(*rname));
|
rulename = pstrdup(NameStr(*rname));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Connect to SPI manager
|
* Connect to SPI manager
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (SPI_connect() != SPI_OK_CONNECT)
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
elog(ERROR, "get_ruledef: cannot connect to SPI manager");
|
elog(ERROR, "get_ruledef: cannot connect to SPI manager");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* On the first call prepare the plan to lookup pg_proc.
|
* On the first call prepare the plan to lookup pg_proc. We read
|
||||||
* We read pg_proc over the SPI manager instead of using
|
* pg_proc over the SPI manager instead of using the syscache to be
|
||||||
* the syscache to be checked for read access on pg_proc.
|
* checked for read access on pg_proc.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (plan_getrule == NULL)
|
if (plan_getrule == NULL)
|
||||||
{
|
{
|
||||||
@@ -194,9 +191,8 @@ pg_get_ruledef(PG_FUNCTION_ARGS)
|
|||||||
plan_getrule = SPI_saveplan(plan);
|
plan_getrule = SPI_saveplan(plan);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the pg_rewrite tuple for this rule
|
* Get the pg_rewrite tuple for this rule
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
args[0] = PointerGetDatum(rulename);
|
args[0] = PointerGetDatum(rulename);
|
||||||
nulls[0] = (rulename == NULL) ? 'n' : ' ';
|
nulls[0] = (rulename == NULL) ? 'n' : ' ';
|
||||||
@@ -217,9 +213,8 @@ pg_get_ruledef(PG_FUNCTION_ARGS)
|
|||||||
ruletup = SPI_tuptable->vals[0];
|
ruletup = SPI_tuptable->vals[0];
|
||||||
rulettc = SPI_tuptable->tupdesc;
|
rulettc = SPI_tuptable->tupdesc;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the rules definition and put it into executors memory
|
* Get the rules definition and put it into executors memory
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
initStringInfo(&buf);
|
initStringInfo(&buf);
|
||||||
make_ruledef(&buf, ruletup, rulettc);
|
make_ruledef(&buf, ruletup, rulettc);
|
||||||
@@ -229,16 +224,14 @@ pg_get_ruledef(PG_FUNCTION_ARGS)
|
|||||||
memcpy(VARDATA(ruledef), buf.data, buf.len);
|
memcpy(VARDATA(ruledef), buf.data, buf.len);
|
||||||
pfree(buf.data);
|
pfree(buf.data);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Disconnect from SPI manager
|
* Disconnect from SPI manager
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(ERROR, "get_ruledef: SPI_finish() failed");
|
elog(ERROR, "get_ruledef: SPI_finish() failed");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Easy - isn't it?
|
* Easy - isn't it?
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
PG_RETURN_TEXT_P(ruledef);
|
PG_RETURN_TEXT_P(ruledef);
|
||||||
}
|
}
|
||||||
@@ -263,24 +256,21 @@ pg_get_viewdef(PG_FUNCTION_ARGS)
|
|||||||
int len;
|
int len;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* We need the view name somewhere deep down
|
* We need the view name somewhere deep down
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
rulename = pstrdup(NameStr(*vname));
|
rulename = pstrdup(NameStr(*vname));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Connect to SPI manager
|
* Connect to SPI manager
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (SPI_connect() != SPI_OK_CONNECT)
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
elog(ERROR, "get_viewdef: cannot connect to SPI manager");
|
elog(ERROR, "get_viewdef: cannot connect to SPI manager");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* On the first call prepare the plan to lookup pg_proc.
|
* On the first call prepare the plan to lookup pg_proc. We read
|
||||||
* We read pg_proc over the SPI manager instead of using
|
* pg_proc over the SPI manager instead of using the syscache to be
|
||||||
* the syscache to be checked for read access on pg_proc.
|
* checked for read access on pg_proc.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (plan_getview == NULL)
|
if (plan_getview == NULL)
|
||||||
{
|
{
|
||||||
@@ -294,9 +284,9 @@ pg_get_viewdef(PG_FUNCTION_ARGS)
|
|||||||
plan_getview = SPI_saveplan(plan);
|
plan_getview = SPI_saveplan(plan);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the pg_rewrite tuple for this rule: rulename is actually viewname here
|
* Get the pg_rewrite tuple for this rule: rulename is actually
|
||||||
* ----------
|
* viewname here
|
||||||
*/
|
*/
|
||||||
name = MakeRetrieveViewRuleName(rulename);
|
name = MakeRetrieveViewRuleName(rulename);
|
||||||
args[0] = PointerGetDatum(name);
|
args[0] = PointerGetDatum(name);
|
||||||
@@ -309,9 +299,9 @@ pg_get_viewdef(PG_FUNCTION_ARGS)
|
|||||||
appendStringInfo(&buf, "Not a view");
|
appendStringInfo(&buf, "Not a view");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Get the rules definition and put it into executors memory
|
* Get the rules definition and put it into executors memory
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ruletup = SPI_tuptable->vals[0];
|
ruletup = SPI_tuptable->vals[0];
|
||||||
rulettc = SPI_tuptable->tupdesc;
|
rulettc = SPI_tuptable->tupdesc;
|
||||||
@@ -324,16 +314,14 @@ pg_get_viewdef(PG_FUNCTION_ARGS)
|
|||||||
pfree(buf.data);
|
pfree(buf.data);
|
||||||
pfree(name);
|
pfree(name);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Disconnect from SPI manager
|
* Disconnect from SPI manager
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(ERROR, "get_viewdef: SPI_finish() failed");
|
elog(ERROR, "get_viewdef: SPI_finish() failed");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Easy - isn't it?
|
* Easy - isn't it?
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
PG_RETURN_TEXT_P(ruledef);
|
PG_RETURN_TEXT_P(ruledef);
|
||||||
}
|
}
|
||||||
@@ -366,17 +354,14 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
|
|||||||
StringInfoData keybuf;
|
StringInfoData keybuf;
|
||||||
char *sep;
|
char *sep;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Connect to SPI manager
|
* Connect to SPI manager
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (SPI_connect() != SPI_OK_CONNECT)
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
elog(ERROR, "get_indexdef: cannot connect to SPI manager");
|
elog(ERROR, "get_indexdef: cannot connect to SPI manager");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* On the first call prepare the plans to lookup pg_am
|
* On the first call prepare the plans to lookup pg_am and pg_opclass.
|
||||||
* and pg_opclass.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (plan_getam == NULL)
|
if (plan_getam == NULL)
|
||||||
{
|
{
|
||||||
@@ -396,9 +381,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
|
|||||||
plan_getopclass = SPI_saveplan(plan);
|
plan_getopclass = SPI_saveplan(plan);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Fetch the pg_index tuple by the Oid of the index
|
* Fetch the pg_index tuple by the Oid of the index
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ht_idx = SearchSysCache(INDEXRELID,
|
ht_idx = SearchSysCache(INDEXRELID,
|
||||||
ObjectIdGetDatum(indexrelid),
|
ObjectIdGetDatum(indexrelid),
|
||||||
@@ -407,9 +391,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
|
|||||||
elog(ERROR, "syscache lookup for index %u failed", indexrelid);
|
elog(ERROR, "syscache lookup for index %u failed", indexrelid);
|
||||||
idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
|
idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Fetch the pg_class tuple of the index relation
|
* Fetch the pg_class tuple of the index relation
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ht_idxrel = SearchSysCache(RELOID,
|
ht_idxrel = SearchSysCache(RELOID,
|
||||||
ObjectIdGetDatum(idxrec->indexrelid),
|
ObjectIdGetDatum(idxrec->indexrelid),
|
||||||
@@ -418,9 +401,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
|
|||||||
elog(ERROR, "syscache lookup for relid %u failed", idxrec->indexrelid);
|
elog(ERROR, "syscache lookup for relid %u failed", idxrec->indexrelid);
|
||||||
idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
|
idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Fetch the pg_class tuple of the indexed relation
|
* Fetch the pg_class tuple of the indexed relation
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ht_indrel = SearchSysCache(RELOID,
|
ht_indrel = SearchSysCache(RELOID,
|
||||||
ObjectIdGetDatum(idxrec->indrelid),
|
ObjectIdGetDatum(idxrec->indrelid),
|
||||||
@@ -429,9 +411,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
|
|||||||
elog(ERROR, "syscache lookup for relid %u failed", idxrec->indrelid);
|
elog(ERROR, "syscache lookup for relid %u failed", idxrec->indrelid);
|
||||||
indrelrec = (Form_pg_class) GETSTRUCT(ht_indrel);
|
indrelrec = (Form_pg_class) GETSTRUCT(ht_indrel);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the am name for the index relation
|
* Get the am name for the index relation
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
spi_args[0] = ObjectIdGetDatum(idxrelrec->relam);
|
spi_args[0] = ObjectIdGetDatum(idxrelrec->relam);
|
||||||
spi_nulls[0] = ' ';
|
spi_nulls[0] = ' ';
|
||||||
@@ -447,9 +428,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
|
|||||||
spi_ttc = SPI_tuptable->tupdesc;
|
spi_ttc = SPI_tuptable->tupdesc;
|
||||||
spi_fno = SPI_fnumber(spi_ttc, "amname");
|
spi_fno = SPI_fnumber(spi_ttc, "amname");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Start the index definition
|
* Start the index definition
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
initStringInfo(&buf);
|
initStringInfo(&buf);
|
||||||
appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
|
appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
|
||||||
@@ -459,9 +439,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
|
|||||||
quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
|
quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
|
||||||
spi_fno)));
|
spi_fno)));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Collect the indexed attributes
|
* Collect the indexed attributes
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
initStringInfo(&keybuf);
|
initStringInfo(&keybuf);
|
||||||
sep = "";
|
sep = "";
|
||||||
@@ -473,17 +452,15 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
|
|||||||
appendStringInfo(&keybuf, sep);
|
appendStringInfo(&keybuf, sep);
|
||||||
sep = ", ";
|
sep = ", ";
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Add the indexed field name
|
* Add the indexed field name
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
appendStringInfo(&keybuf, "%s",
|
appendStringInfo(&keybuf, "%s",
|
||||||
quote_identifier(get_relid_attribute_name(idxrec->indrelid,
|
quote_identifier(get_relid_attribute_name(idxrec->indrelid,
|
||||||
idxrec->indkey[keyno])));
|
idxrec->indkey[keyno])));
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If not a functional index, add the operator class name
|
* If not a functional index, add the operator class name
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (idxrec->indproc == InvalidOid)
|
if (idxrec->indproc == InvalidOid)
|
||||||
{
|
{
|
||||||
@@ -504,9 +481,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* For functional index say 'func (attrs) opclass'
|
* For functional index say 'func (attrs) opclass'
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (idxrec->indproc != InvalidOid)
|
if (idxrec->indproc != InvalidOid)
|
||||||
{
|
{
|
||||||
@@ -541,21 +517,19 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
|
|||||||
ReleaseSysCache(proctup);
|
ReleaseSysCache(proctup);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* For the others say 'attr opclass [, ...]'
|
* For the others say 'attr opclass [, ...]'
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
appendStringInfo(&buf, "%s", keybuf.data);
|
appendStringInfo(&buf, "%s", keybuf.data);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Finish
|
* Finish
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
appendStringInfo(&buf, ")");
|
appendStringInfo(&buf, ")");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Create the result in upper executor memory, and free objects
|
* Create the result in upper executor memory, and free objects
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
len = buf.len + VARHDRSZ;
|
len = buf.len + VARHDRSZ;
|
||||||
indexdef = SPI_palloc(len);
|
indexdef = SPI_palloc(len);
|
||||||
@@ -568,9 +542,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
|
|||||||
ReleaseSysCache(ht_idxrel);
|
ReleaseSysCache(ht_idxrel);
|
||||||
ReleaseSysCache(ht_indrel);
|
ReleaseSysCache(ht_indrel);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Disconnect from SPI manager
|
* Disconnect from SPI manager
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(ERROR, "get_viewdef: SPI_finish() failed");
|
elog(ERROR, "get_viewdef: SPI_finish() failed");
|
||||||
@@ -592,16 +565,14 @@ pg_get_userbyid(PG_FUNCTION_ARGS)
|
|||||||
HeapTuple usertup;
|
HeapTuple usertup;
|
||||||
Form_pg_shadow user_rec;
|
Form_pg_shadow user_rec;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Allocate space for the result
|
* Allocate space for the result
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
result = (Name) palloc(NAMEDATALEN);
|
result = (Name) palloc(NAMEDATALEN);
|
||||||
memset(NameStr(*result), 0, NAMEDATALEN);
|
memset(NameStr(*result), 0, NAMEDATALEN);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the pg_shadow entry and print the result
|
* Get the pg_shadow entry and print the result
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
usertup = SearchSysCache(SHADOWSYSID,
|
usertup = SearchSysCache(SHADOWSYSID,
|
||||||
ObjectIdGetDatum(uid),
|
ObjectIdGetDatum(uid),
|
||||||
@@ -705,9 +676,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
|
|||||||
int fno;
|
int fno;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the attribute values from the rules tuple
|
* Get the attribute values from the rules tuple
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
fno = SPI_fnumber(rulettc, "ev_type");
|
fno = SPI_fnumber(rulettc, "ev_type");
|
||||||
ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
|
ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
|
||||||
@@ -730,9 +700,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
|
|||||||
actions = (List *) stringToNode(ev_action);
|
actions = (List *) stringToNode(ev_action);
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Build the rules definition text
|
* Build the rules definition text
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
appendStringInfo(buf, "CREATE RULE %s AS ON ",
|
appendStringInfo(buf, "CREATE RULE %s AS ON ",
|
||||||
quote_identifier(rulename));
|
quote_identifier(rulename));
|
||||||
@@ -852,9 +821,8 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
|
|||||||
int fno;
|
int fno;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the attribute values from the rules tuple
|
* Get the attribute values from the rules tuple
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
fno = SPI_fnumber(rulettc, "ev_type");
|
fno = SPI_fnumber(rulettc, "ev_type");
|
||||||
ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
|
ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
|
||||||
@@ -961,11 +929,10 @@ get_select_query_def(Query *query, deparse_context *context)
|
|||||||
char *sep;
|
char *sep;
|
||||||
List *l;
|
List *l;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If the Query node has a setOperations tree, then it's the top
|
* If the Query node has a setOperations tree, then it's the top level
|
||||||
* level of a UNION/INTERSECT/EXCEPT query; only the ORDER BY and
|
* of a UNION/INTERSECT/EXCEPT query; only the ORDER BY and LIMIT
|
||||||
* LIMIT fields are interesting in the top query itself.
|
* fields are interesting in the top query itself.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (query->setOperations)
|
if (query->setOperations)
|
||||||
{
|
{
|
||||||
@@ -1033,9 +1000,8 @@ get_basic_select_query(Query *query, deparse_context *context)
|
|||||||
char *sep;
|
char *sep;
|
||||||
List *l;
|
List *l;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Build up the query string - first we say SELECT
|
* Build up the query string - first we say SELECT
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
appendStringInfo(buf, "SELECT");
|
appendStringInfo(buf, "SELECT");
|
||||||
|
|
||||||
@@ -1230,10 +1196,9 @@ get_insert_query_def(Query *query, deparse_context *context)
|
|||||||
char *sep;
|
char *sep;
|
||||||
List *l;
|
List *l;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If it's an INSERT ... SELECT there will be a single subquery RTE
|
* If it's an INSERT ... SELECT there will be a single subquery RTE
|
||||||
* for the SELECT.
|
* for the SELECT.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
foreach(l, query->rtable)
|
foreach(l, query->rtable)
|
||||||
{
|
{
|
||||||
@@ -1245,9 +1210,8 @@ get_insert_query_def(Query *query, deparse_context *context)
|
|||||||
select_rte = rte;
|
select_rte = rte;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Start the query with INSERT INTO relname
|
* Start the query with INSERT INTO relname
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
rte = rt_fetch(query->resultRelation, query->rtable);
|
rte = rt_fetch(query->resultRelation, query->rtable);
|
||||||
appendStringInfo(buf, "INSERT INTO %s",
|
appendStringInfo(buf, "INSERT INTO %s",
|
||||||
@@ -1303,9 +1267,8 @@ get_update_query_def(Query *query, deparse_context *context)
|
|||||||
RangeTblEntry *rte;
|
RangeTblEntry *rte;
|
||||||
List *l;
|
List *l;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Start the query with UPDATE relname SET
|
* Start the query with UPDATE relname SET
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
rte = rt_fetch(query->resultRelation, query->rtable);
|
rte = rt_fetch(query->resultRelation, query->rtable);
|
||||||
appendStringInfo(buf, "UPDATE %s%s SET ",
|
appendStringInfo(buf, "UPDATE %s%s SET ",
|
||||||
@@ -1357,9 +1320,8 @@ get_delete_query_def(Query *query, deparse_context *context)
|
|||||||
StringInfo buf = context->buf;
|
StringInfo buf = context->buf;
|
||||||
RangeTblEntry *rte;
|
RangeTblEntry *rte;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Start the query with DELETE FROM relname
|
* Start the query with DELETE FROM relname
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
rte = rt_fetch(query->resultRelation, query->rtable);
|
rte = rt_fetch(query->resultRelation, query->rtable);
|
||||||
appendStringInfo(buf, "DELETE FROM %s%s",
|
appendStringInfo(buf, "DELETE FROM %s%s",
|
||||||
@@ -1681,14 +1643,13 @@ get_rule_expr(Node *node, deparse_context *context)
|
|||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Each level of get_rule_expr must emit an indivisible term
|
* Each level of get_rule_expr must emit an indivisible term
|
||||||
* (parenthesized if necessary) to ensure result is reparsed into
|
* (parenthesized if necessary) to ensure result is reparsed into the
|
||||||
* the same expression tree.
|
* same expression tree.
|
||||||
*
|
*
|
||||||
* There might be some work left here to support additional node types.
|
* There might be some work left here to support additional node types.
|
||||||
* Can we ever see Param nodes here?
|
* Can we ever see Param nodes here?
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
{
|
{
|
||||||
@@ -1722,9 +1683,8 @@ get_rule_expr(Node *node, deparse_context *context)
|
|||||||
Expr *expr = (Expr *) node;
|
Expr *expr = (Expr *) node;
|
||||||
List *args = expr->args;
|
List *args = expr->args;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Expr nodes have to be handled a bit detailed
|
* Expr nodes have to be handled a bit detailed
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
switch (expr->opType)
|
switch (expr->opType)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.82 2001/03/22 04:00:00 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.83 2001/03/22 06:16:18 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
@@ -151,17 +151,17 @@ ReverifyMyDatabase(const char *name)
|
|||||||
static void
|
static void
|
||||||
InitCommunication(void)
|
InitCommunication(void)
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
|
/*
|
||||||
* initialize shared memory and semaphores appropriately.
|
* initialize shared memory and semaphores appropriately.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (!IsUnderPostmaster) /* postmaster already did this */
|
if (!IsUnderPostmaster) /* postmaster already did this */
|
||||||
{
|
{
|
||||||
/* ----------------
|
|
||||||
* we're running a postgres backend by itself with
|
/*
|
||||||
* no front end or postmaster. Create private "shmem"
|
* we're running a postgres backend by itself with no front end or
|
||||||
* and semaphores. Setting MaxBackends = 16 is arbitrary.
|
* postmaster. Create private "shmem" and semaphores. Setting
|
||||||
* ----------------
|
* MaxBackends = 16 is arbitrary.
|
||||||
*/
|
*/
|
||||||
CreateSharedMemoryAndSemaphores(true, 16);
|
CreateSharedMemoryAndSemaphores(true, 16);
|
||||||
}
|
}
|
||||||
@@ -207,9 +207,8 @@ InitPostgres(const char *dbname, const char *username)
|
|||||||
|
|
||||||
SetDatabaseName(dbname);
|
SetDatabaseName(dbname);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* initialize the database id used for system caches and lock tables
|
* initialize the database id used for system caches and lock tables
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (bootstrap)
|
if (bootstrap)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.44 2001/03/22 04:00:06 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.45 2001/03/22 06:16:19 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -162,22 +162,20 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
|
|||||||
|
|
||||||
pfree(dbfname);
|
pfree(dbfname);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* read and examine every page in pg_database
|
* read and examine every page in pg_database
|
||||||
*
|
*
|
||||||
* Raw I/O! Read those tuples the hard way! Yow!
|
* Raw I/O! Read those tuples the hard way! Yow!
|
||||||
*
|
*
|
||||||
* Why don't we use the access methods or move this code
|
* Why don't we use the access methods or move this code someplace else?
|
||||||
* someplace else? This is really pg_database schema dependent
|
* This is really pg_database schema dependent code. Perhaps it
|
||||||
* code. Perhaps it should go in lib/catalog/pg_database?
|
* should go in lib/catalog/pg_database? -cim 10/3/90
|
||||||
* -cim 10/3/90
|
|
||||||
*
|
*
|
||||||
* mao replies 4 apr 91: yeah, maybe this should be moved to
|
* mao replies 4 apr 91: yeah, maybe this should be moved to
|
||||||
* lib/catalog. however, we CANNOT use the access methods since
|
* lib/catalog. however, we CANNOT use the access methods since those
|
||||||
* those use the buffer cache, which uses the relation cache, which
|
* use the buffer cache, which uses the relation cache, which requires
|
||||||
* requires that the dbid be set, which is what we're trying to do
|
* that the dbid be set, which is what we're trying to do here.
|
||||||
* here.
|
*
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
pg = (Page) palloc(BLCKSZ);
|
pg = (Page) palloc(BLCKSZ);
|
||||||
|
|
||||||
@@ -199,16 +197,17 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
|
|||||||
tup.t_datamcxt = NULL;
|
tup.t_datamcxt = NULL;
|
||||||
tup.t_data = (HeapTupleHeader) PageGetItem(pg, lpp);
|
tup.t_data = (HeapTupleHeader) PageGetItem(pg, lpp);
|
||||||
|
|
||||||
/*--------------------
|
/*
|
||||||
* Check to see if tuple is valid (committed).
|
* Check to see if tuple is valid (committed).
|
||||||
*
|
*
|
||||||
* XXX warning, will robinson: violation of transaction semantics
|
* XXX warning, will robinson: violation of transaction semantics
|
||||||
* happens right here. We cannot really determine if the tuple
|
* happens right here. We cannot really determine if the
|
||||||
* is valid without checking transaction commit status, and the
|
* tuple is valid without checking transaction commit status,
|
||||||
* only way to do that at init time is to paw over pg_log by hand,
|
* and the only way to do that at init time is to paw over
|
||||||
* too. Instead of checking, we assume that the inserting
|
* pg_log by hand, too. Instead of checking, we assume that
|
||||||
* transaction committed, and that any deleting transaction did
|
* the inserting transaction committed, and that any deleting
|
||||||
* also, unless shown otherwise by on-row commit status bits.
|
* transaction did also, unless shown otherwise by on-row
|
||||||
|
* commit status bits.
|
||||||
*
|
*
|
||||||
* All in all, this code is pretty shaky. We will cross-check
|
* All in all, this code is pretty shaky. We will cross-check
|
||||||
* our result in ReverifyMyDatabase() in postinit.c.
|
* our result in ReverifyMyDatabase() in postinit.c.
|
||||||
@@ -221,7 +220,6 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
|
|||||||
* XXX wouldn't it be better to let new backends read the
|
* XXX wouldn't it be better to let new backends read the
|
||||||
* database OID from a flat file, handled the same way we
|
* database OID from a flat file, handled the same way we
|
||||||
* handle the password relation?
|
* handle the password relation?
|
||||||
*--------------------
|
|
||||||
*/
|
*/
|
||||||
if (!PhonyHeapTupleSatisfiesNow(tup.t_data))
|
if (!PhonyHeapTupleSatisfiesNow(tup.t_data))
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: strat.h,v 1.20 2001/03/22 04:00:31 momjian Exp $
|
* $Id: strat.h,v 1.21 2001/03/22 06:16:20 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -38,6 +38,7 @@ typedef struct StrategyTransformMapData
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
*
|
||||||
* STRUCTURE */
|
* STRUCTURE */
|
||||||
|
|
||||||
typedef StrategyTransformMapData *StrategyTransformMap;
|
typedef StrategyTransformMapData *StrategyTransformMap;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: nodes.h,v 1.87 2001/03/22 04:00:51 momjian Exp $
|
* $Id: nodes.h,v 1.88 2001/03/22 06:16:20 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -25,9 +25,8 @@ typedef enum NodeTag
|
|||||||
{
|
{
|
||||||
T_Invalid = 0,
|
T_Invalid = 0,
|
||||||
|
|
||||||
/*---------------------
|
/*
|
||||||
* TAGS FOR PLAN NODES (plannodes.h)
|
* TAGS FOR PLAN NODES (plannodes.h)
|
||||||
*---------------------
|
|
||||||
*/
|
*/
|
||||||
T_Plan = 10,
|
T_Plan = 10,
|
||||||
T_Result,
|
T_Result,
|
||||||
@@ -51,9 +50,8 @@ typedef enum NodeTag
|
|||||||
T_TidScan,
|
T_TidScan,
|
||||||
T_SubqueryScan,
|
T_SubqueryScan,
|
||||||
|
|
||||||
/*---------------------
|
/*
|
||||||
* TAGS FOR PRIMITIVE NODES (primnodes.h)
|
* TAGS FOR PRIMITIVE NODES (primnodes.h)
|
||||||
*---------------------
|
|
||||||
*/
|
*/
|
||||||
T_Resdom = 100,
|
T_Resdom = 100,
|
||||||
T_Fjoin,
|
T_Fjoin,
|
||||||
@@ -73,9 +71,8 @@ typedef enum NodeTag
|
|||||||
T_FromExpr,
|
T_FromExpr,
|
||||||
T_JoinExpr,
|
T_JoinExpr,
|
||||||
|
|
||||||
/*---------------------
|
/*
|
||||||
* TAGS FOR PLANNER NODES (relation.h)
|
* TAGS FOR PLANNER NODES (relation.h)
|
||||||
*---------------------
|
|
||||||
*/
|
*/
|
||||||
T_RelOptInfo = 200,
|
T_RelOptInfo = 200,
|
||||||
T_Path,
|
T_Path,
|
||||||
@@ -91,9 +88,8 @@ typedef enum NodeTag
|
|||||||
T_Stream,
|
T_Stream,
|
||||||
T_IndexOptInfo,
|
T_IndexOptInfo,
|
||||||
|
|
||||||
/*---------------------
|
/*
|
||||||
* TAGS FOR EXECUTOR NODES (execnodes.h)
|
* TAGS FOR EXECUTOR NODES (execnodes.h)
|
||||||
*---------------------
|
|
||||||
*/
|
*/
|
||||||
T_IndexInfo = 300,
|
T_IndexInfo = 300,
|
||||||
T_ResultRelInfo,
|
T_ResultRelInfo,
|
||||||
@@ -125,16 +121,14 @@ typedef enum NodeTag
|
|||||||
T_SetOpState,
|
T_SetOpState,
|
||||||
T_LimitState,
|
T_LimitState,
|
||||||
|
|
||||||
/*---------------------
|
/*
|
||||||
* TAGS FOR MEMORY NODES (memnodes.h)
|
* TAGS FOR MEMORY NODES (memnodes.h)
|
||||||
*---------------------
|
|
||||||
*/
|
*/
|
||||||
T_MemoryContext = 400,
|
T_MemoryContext = 400,
|
||||||
T_AllocSetContext,
|
T_AllocSetContext,
|
||||||
|
|
||||||
/*---------------------
|
/*
|
||||||
* TAGS FOR VALUE NODES (pg_list.h)
|
* TAGS FOR VALUE NODES (pg_list.h)
|
||||||
*---------------------
|
|
||||||
*/
|
*/
|
||||||
T_Value = 500,
|
T_Value = 500,
|
||||||
T_List,
|
T_List,
|
||||||
@@ -144,9 +138,8 @@ typedef enum NodeTag
|
|||||||
T_BitString,
|
T_BitString,
|
||||||
T_Null,
|
T_Null,
|
||||||
|
|
||||||
/*---------------------
|
/*
|
||||||
* TAGS FOR PARSE TREE NODES (parsenodes.h)
|
* TAGS FOR PARSE TREE NODES (parsenodes.h)
|
||||||
*---------------------
|
|
||||||
*/
|
*/
|
||||||
T_Query = 600,
|
T_Query = 600,
|
||||||
T_InsertStmt,
|
T_InsertStmt,
|
||||||
@@ -236,9 +229,8 @@ typedef enum NodeTag
|
|||||||
* available */
|
* available */
|
||||||
T_FkConstraint,
|
T_FkConstraint,
|
||||||
|
|
||||||
/*---------------------
|
/*
|
||||||
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
|
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
|
||||||
*---------------------
|
|
||||||
*/
|
*/
|
||||||
T_TriggerData = 800, /* in commands/trigger.h */
|
T_TriggerData = 800, /* in commands/trigger.h */
|
||||||
T_ReturnSetInfo /* in nodes/execnodes.h */
|
T_ReturnSetInfo /* in nodes/execnodes.h */
|
||||||
|
|||||||
@@ -35,9 +35,8 @@ extern "C"
|
|||||||
/* stored into a host variable. */
|
/* stored into a host variable. */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 2: if 'W' a (hopefully) non-fatal notice occured *//* 3:
|
* 2: if 'W' a (hopefully) non-fatal notice occured
|
||||||
* empty
|
*//* 3: empty */
|
||||||
*/
|
|
||||||
/* 4: empty */
|
/* 4: empty */
|
||||||
/* 5: empty */
|
/* 5: empty */
|
||||||
/* 6: empty */
|
/* 6: empty */
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.161 2001/03/22 04:01:25 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.162 2001/03/22 06:16:20 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -275,18 +275,16 @@ PQconnectStart(const char *conninfo)
|
|||||||
PQconninfoOption *connOptions;
|
PQconninfoOption *connOptions;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Allocate memory for the conn structure
|
* Allocate memory for the conn structure
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
conn = makeEmptyPGconn();
|
conn = makeEmptyPGconn();
|
||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return (PGconn *) NULL;
|
return (PGconn *) NULL;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Parse the conninfo string
|
* Parse the conninfo string
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
connOptions = conninfo_parse(conninfo, &conn->errorMessage);
|
connOptions = conninfo_parse(conninfo, &conn->errorMessage);
|
||||||
if (connOptions == NULL)
|
if (connOptions == NULL)
|
||||||
@@ -320,15 +318,13 @@ PQconnectStart(const char *conninfo)
|
|||||||
conn->require_ssl = tmp ? (tmp[0] == '1' ? true : false) : false;
|
conn->require_ssl = tmp ? (tmp[0] == '1' ? true : false) : false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Free the option info - all is in conn now
|
* Free the option info - all is in conn now
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
PQconninfoFree(connOptions);
|
PQconninfoFree(connOptions);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Allow unix socket specification in the host name
|
* Allow unix socket specification in the host name
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (conn->pghost && conn->pghost[0] == '/')
|
if (conn->pghost && conn->pghost[0] == '/')
|
||||||
{
|
{
|
||||||
@@ -338,9 +334,8 @@ PQconnectStart(const char *conninfo)
|
|||||||
conn->pghost = NULL;
|
conn->pghost = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Connect to the database
|
* Connect to the database
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (!connectDBStart(conn))
|
if (!connectDBStart(conn))
|
||||||
{
|
{
|
||||||
@@ -448,10 +443,9 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
|
|||||||
else
|
else
|
||||||
conn->pgport = strdup(pgport);
|
conn->pgport = strdup(pgport);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* We don't allow unix socket path as a function parameter.
|
* We don't allow unix socket path as a function parameter. This
|
||||||
* This allows unix socket specification in the host name.
|
* allows unix socket specification in the host name.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (conn->pghost && conn->pghost[0] == '/')
|
if (conn->pghost && conn->pghost[0] == '/')
|
||||||
{
|
{
|
||||||
@@ -899,11 +893,11 @@ connectDBStart(PGconn *conn)
|
|||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Set the right options. Normally, we need nonblocking I/O, and we don't
|
* Set the right options. Normally, we need nonblocking I/O, and we
|
||||||
* want delay of outgoing data for AF_INET sockets. If we are using SSL,
|
* don't want delay of outgoing data for AF_INET sockets. If we are
|
||||||
* then we need the blocking I/O (XXX Can this be fixed?).
|
* using SSL, then we need the blocking I/O (XXX Can this be fixed?).
|
||||||
* ---------- */
|
*/
|
||||||
|
|
||||||
if (family == AF_INET)
|
if (family == AF_INET)
|
||||||
{
|
{
|
||||||
@@ -911,16 +905,16 @@ connectDBStart(PGconn *conn)
|
|||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Since I have no idea whether this is a valid thing to do under Windows
|
* Since I have no idea whether this is a valid thing to do under
|
||||||
* before a connection is made, and since I have no way of testing it, I
|
* Windows before a connection is made, and since I have no way of
|
||||||
* leave the code looking as below. When someone decides that they want
|
* testing it, I leave the code looking as below. When someone
|
||||||
* non-blocking connections under Windows, they can define
|
* decides that they want non-blocking connections under Windows, they
|
||||||
* WIN32_NON_BLOCKING_CONNECTIONS before compilation. If it works, then
|
* can define WIN32_NON_BLOCKING_CONNECTIONS before compilation. If
|
||||||
* this code can be cleaned up.
|
* it works, then this code can be cleaned up.
|
||||||
*
|
*
|
||||||
* Ewan Mellor <eem21@cam.ac.uk>.
|
* Ewan Mellor <eem21@cam.ac.uk>.
|
||||||
* ---------- */
|
*/
|
||||||
#if (!defined(WIN32) || defined(WIN32_NON_BLOCKING_CONNECTIONS)) && !defined(USE_SSL)
|
#if (!defined(WIN32) || defined(WIN32_NON_BLOCKING_CONNECTIONS)) && !defined(USE_SSL)
|
||||||
if (connectMakeNonblocking(conn) == 0)
|
if (connectMakeNonblocking(conn) == 0)
|
||||||
goto connect_errReturn;
|
goto connect_errReturn;
|
||||||
@@ -1430,16 +1424,17 @@ keep_going: /* We will come back to here until there
|
|||||||
|
|
||||||
case CONNECTION_AUTH_OK:
|
case CONNECTION_AUTH_OK:
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Now we expect to hear from the backend. A ReadyForQuery
|
* Now we expect to hear from the backend. A ReadyForQuery
|
||||||
* message indicates that startup is successful, but we might
|
* message indicates that startup is successful, but we
|
||||||
* also get an Error message indicating failure. (Notice
|
* might also get an Error message indicating failure.
|
||||||
* messages indicating nonfatal warnings are also allowed by
|
* (Notice messages indicating nonfatal warnings are also
|
||||||
* the protocol, as is a BackendKeyData message.) Easiest way
|
* allowed by the protocol, as is a BackendKeyData
|
||||||
* to handle this is to let PQgetResult() read the messages. We
|
* message.) Easiest way to handle this is to let
|
||||||
* just have to fake it out about the state of the connection,
|
* PQgetResult() read the messages. We just have to fake
|
||||||
* by setting asyncStatus = PGASYNC_BUSY (done above).
|
* it out about the state of the connection, by setting
|
||||||
*----------
|
* asyncStatus = PGASYNC_BUSY (done above).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (PQisBusy(conn))
|
if (PQisBusy(conn))
|
||||||
@@ -1522,13 +1517,13 @@ keep_going: /* We will come back to here until there
|
|||||||
/* Unreachable */
|
/* Unreachable */
|
||||||
|
|
||||||
error_return:
|
error_return:
|
||||||
/* ----------
|
|
||||||
* We used to close the socket at this point, but that makes it awkward
|
/*
|
||||||
* for those above us if they wish to remove this socket from their
|
* We used to close the socket at this point, but that makes it
|
||||||
* own records (an fd_set for example). We'll just have this socket
|
* awkward for those above us if they wish to remove this socket from
|
||||||
* closed when PQfinish is called (which is compulsory even after an
|
* their own records (an fd_set for example). We'll just have this
|
||||||
* error, since the connection structure must be freed).
|
* socket closed when PQfinish is called (which is compulsory even
|
||||||
* ----------
|
* after an error, since the connection structure must be freed).
|
||||||
*/
|
*/
|
||||||
return PGRES_POLLING_FAILED;
|
return PGRES_POLLING_FAILED;
|
||||||
}
|
}
|
||||||
@@ -2507,10 +2502,9 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Now we have the name and the value. Search
|
* Now we have the name and the value. Search for the param
|
||||||
* for the param record.
|
* record.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (option = options; option->keyword != NULL; option++)
|
for (option = options; option->keyword != NULL; option++)
|
||||||
{
|
{
|
||||||
@@ -2527,9 +2521,8 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Store the value
|
* Store the value
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (option->val)
|
if (option->val)
|
||||||
free(option->val);
|
free(option->val);
|
||||||
@@ -2548,19 +2541,17 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
|
|||||||
/* Done with the modifiable input string */
|
/* Done with the modifiable input string */
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the fallback resources for parameters not specified
|
* Get the fallback resources for parameters not specified in the
|
||||||
* in the conninfo string.
|
* conninfo string.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (option = options; option->keyword != NULL; option++)
|
for (option = options; option->keyword != NULL; option++)
|
||||||
{
|
{
|
||||||
if (option->val != NULL)
|
if (option->val != NULL)
|
||||||
continue; /* Value was in conninfo */
|
continue; /* Value was in conninfo */
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Try to get the environment variable fallback
|
* Try to get the environment variable fallback
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (option->envvar != NULL)
|
if (option->envvar != NULL)
|
||||||
{
|
{
|
||||||
@@ -2571,10 +2562,9 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* No environment variable specified or this one isn't set -
|
* No environment variable specified or this one isn't set - try
|
||||||
* try compiled in
|
* compiled in
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (option->compiled != NULL)
|
if (option->compiled != NULL)
|
||||||
{
|
{
|
||||||
@@ -2582,9 +2572,8 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Special handling for user
|
* Special handling for user
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (strcmp(option->keyword, "user") == 0)
|
if (strcmp(option->keyword, "user") == 0)
|
||||||
{
|
{
|
||||||
@@ -2593,9 +2582,8 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Special handling for dbname
|
* Special handling for dbname
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (strcmp(option->keyword, "dbname") == 0)
|
if (strcmp(option->keyword, "dbname") == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.33 2001/02/10 02:31:30 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.34 2001/03/22 06:16:20 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -518,9 +518,8 @@ lo_initialize(PGconn *conn)
|
|||||||
const char *fname;
|
const char *fname;
|
||||||
Oid foid;
|
Oid foid;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Allocate the structure to hold the functions OID's
|
* Allocate the structure to hold the functions OID's
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
|
lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
|
||||||
if (lobjfuncs == (PGlobjfuncs *) NULL)
|
if (lobjfuncs == (PGlobjfuncs *) NULL)
|
||||||
@@ -531,9 +530,8 @@ lo_initialize(PGconn *conn)
|
|||||||
}
|
}
|
||||||
MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
|
MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Execute the query to get all the functions at once
|
* Execute the query to get all the functions at once
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
res = PQexec(conn, "select proname, oid from pg_proc \
|
res = PQexec(conn, "select proname, oid from pg_proc \
|
||||||
where proname = 'lo_open' \
|
where proname = 'lo_open' \
|
||||||
@@ -559,9 +557,8 @@ lo_initialize(PGconn *conn)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Examine the result and put the OID's into the struct
|
* Examine the result and put the OID's into the struct
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
for (n = 0; n < PQntuples(res); n++)
|
for (n = 0; n < PQntuples(res); n++)
|
||||||
{
|
{
|
||||||
@@ -587,10 +584,9 @@ lo_initialize(PGconn *conn)
|
|||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Finally check that we really got all large object
|
* Finally check that we really got all large object interface
|
||||||
* interface functions.
|
* functions.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
if (lobjfuncs->fn_lo_open == 0)
|
if (lobjfuncs->fn_lo_open == 0)
|
||||||
{
|
{
|
||||||
@@ -649,9 +645,8 @@ lo_initialize(PGconn *conn)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* Put the structure into the connection control
|
* Put the structure into the connection control
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
conn->lobjfuncs = lobjfuncs;
|
conn->lobjfuncs = lobjfuncs;
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.9 2001/02/10 02:31:30 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.10 2001/03/22 06:16:20 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -173,11 +173,11 @@ printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/*----------
|
|
||||||
* Try to format the given string into the available space;
|
/*
|
||||||
* but if there's hardly any space, don't bother trying,
|
* Try to format the given string into the available space; but if
|
||||||
* just fall through to enlarge the buffer first.
|
* there's hardly any space, don't bother trying, just fall
|
||||||
*----------
|
* through to enlarge the buffer first.
|
||||||
*/
|
*/
|
||||||
if (str->maxlen > str->len + 16)
|
if (str->maxlen > str->len + 16)
|
||||||
{
|
{
|
||||||
@@ -222,11 +222,11 @@ appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/*----------
|
|
||||||
* Try to format the given string into the available space;
|
/*
|
||||||
* but if there's hardly any space, don't bother trying,
|
* Try to format the given string into the available space; but if
|
||||||
* just fall through to enlarge the buffer first.
|
* there's hardly any space, don't bother trying, just fall
|
||||||
*----------
|
* through to enlarge the buffer first.
|
||||||
*/
|
*/
|
||||||
if (str->maxlen > str->len + 16)
|
if (str->maxlen > str->len + 16)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -204,7 +204,8 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type)
|
|||||||
case PG_TYPE_CHAR2:
|
case PG_TYPE_CHAR2:
|
||||||
case PG_TYPE_CHAR4:
|
case PG_TYPE_CHAR4:
|
||||||
case PG_TYPE_CHAR8:
|
case PG_TYPE_CHAR8:
|
||||||
case PG_TYPE_NAME:return SQL_CHAR;
|
case PG_TYPE_NAME:
|
||||||
|
return SQL_CHAR;
|
||||||
|
|
||||||
case PG_TYPE_BPCHAR:
|
case PG_TYPE_BPCHAR:
|
||||||
return SQL_CHAR;
|
return SQL_CHAR;
|
||||||
@@ -272,7 +273,8 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
|
|||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case PG_TYPE_INT8:return SQL_C_CHAR;
|
case PG_TYPE_INT8:
|
||||||
|
return SQL_C_CHAR;
|
||||||
case PG_TYPE_NUMERIC:
|
case PG_TYPE_NUMERIC:
|
||||||
return SQL_C_CHAR;
|
return SQL_C_CHAR;
|
||||||
case PG_TYPE_INT2:
|
case PG_TYPE_INT2:
|
||||||
@@ -536,7 +538,8 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
|
||||||
case PG_TYPE_CHAR:return 1;
|
case PG_TYPE_CHAR:
|
||||||
|
return 1;
|
||||||
case PG_TYPE_CHAR2:
|
case PG_TYPE_CHAR2:
|
||||||
return 2;
|
return 2;
|
||||||
case PG_TYPE_CHAR4:
|
case PG_TYPE_CHAR4:
|
||||||
@@ -601,7 +604,8 @@ pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown
|
|||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case PG_TYPE_INT2:return 6;
|
case PG_TYPE_INT2:
|
||||||
|
return 6;
|
||||||
|
|
||||||
case PG_TYPE_OID:
|
case PG_TYPE_OID:
|
||||||
case PG_TYPE_XID:
|
case PG_TYPE_XID:
|
||||||
@@ -641,7 +645,8 @@ pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
|
||||||
case PG_TYPE_INT2:return 2;
|
case PG_TYPE_INT2:
|
||||||
|
return 2;
|
||||||
|
|
||||||
case PG_TYPE_OID:
|
case PG_TYPE_OID:
|
||||||
case PG_TYPE_XID:
|
case PG_TYPE_XID:
|
||||||
@@ -699,7 +704,8 @@ pgtype_scale(StatementClass *stmt, Int4 type, int col)
|
|||||||
*/
|
*/
|
||||||
case PG_TYPE_ABSTIME:
|
case PG_TYPE_ABSTIME:
|
||||||
case PG_TYPE_DATETIME:
|
case PG_TYPE_DATETIME:
|
||||||
case PG_TYPE_TIMESTAMP:return 0;
|
case PG_TYPE_TIMESTAMP:
|
||||||
|
return 0;
|
||||||
|
|
||||||
case PG_TYPE_NUMERIC:
|
case PG_TYPE_NUMERIC:
|
||||||
return getNumericScale(stmt, type, col);
|
return getNumericScale(stmt, type, col);
|
||||||
@@ -722,7 +728,8 @@ pgtype_radix(StatementClass *stmt, Int4 type)
|
|||||||
case PG_TYPE_NUMERIC:
|
case PG_TYPE_NUMERIC:
|
||||||
case PG_TYPE_FLOAT4:
|
case PG_TYPE_FLOAT4:
|
||||||
case PG_TYPE_MONEY:
|
case PG_TYPE_MONEY:
|
||||||
case PG_TYPE_FLOAT8:return 10;
|
case PG_TYPE_FLOAT8:
|
||||||
|
return 10;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
@@ -756,7 +763,8 @@ pgtype_auto_increment(StatementClass *stmt, Int4 type)
|
|||||||
case PG_TYPE_TIME:
|
case PG_TYPE_TIME:
|
||||||
case PG_TYPE_ABSTIME:
|
case PG_TYPE_ABSTIME:
|
||||||
case PG_TYPE_DATETIME:
|
case PG_TYPE_DATETIME:
|
||||||
case PG_TYPE_TIMESTAMP:return FALSE;
|
case PG_TYPE_TIMESTAMP:
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
@@ -777,7 +785,8 @@ pgtype_case_sensitive(StatementClass *stmt, Int4 type)
|
|||||||
case PG_TYPE_VARCHAR:
|
case PG_TYPE_VARCHAR:
|
||||||
case PG_TYPE_BPCHAR:
|
case PG_TYPE_BPCHAR:
|
||||||
case PG_TYPE_TEXT:
|
case PG_TYPE_TEXT:
|
||||||
case PG_TYPE_NAME:return TRUE;
|
case PG_TYPE_NAME:
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -789,7 +798,8 @@ pgtype_money(StatementClass *stmt, Int4 type)
|
|||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case PG_TYPE_MONEY:return TRUE;
|
case PG_TYPE_MONEY:
|
||||||
|
return TRUE;
|
||||||
default:
|
default:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -808,7 +818,8 @@ pgtype_searchable(StatementClass *stmt, Int4 type)
|
|||||||
case PG_TYPE_VARCHAR:
|
case PG_TYPE_VARCHAR:
|
||||||
case PG_TYPE_BPCHAR:
|
case PG_TYPE_BPCHAR:
|
||||||
case PG_TYPE_TEXT:
|
case PG_TYPE_TEXT:
|
||||||
case PG_TYPE_NAME:return SQL_SEARCHABLE;
|
case PG_TYPE_NAME:
|
||||||
|
return SQL_SEARCHABLE;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return SQL_ALL_EXCEPT_LIKE;
|
return SQL_ALL_EXCEPT_LIKE;
|
||||||
@@ -821,7 +832,8 @@ pgtype_unsigned(StatementClass *stmt, Int4 type)
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case PG_TYPE_OID:
|
case PG_TYPE_OID:
|
||||||
case PG_TYPE_XID:return TRUE;
|
case PG_TYPE_XID:
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
case PG_TYPE_INT2:
|
case PG_TYPE_INT2:
|
||||||
case PG_TYPE_INT4:
|
case PG_TYPE_INT4:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.27 2001/03/22 04:01:41 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.28 2001/03/22 06:16:21 momjian Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@@ -106,9 +106,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
int i;
|
int i;
|
||||||
int arg_varnos[FUNC_MAX_ARGS];
|
int arg_varnos[FUNC_MAX_ARGS];
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Initialize the compiler
|
* Initialize the compiler
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
plpgsql_ns_init();
|
plpgsql_ns_init();
|
||||||
plpgsql_ns_push(NULL);
|
plpgsql_ns_push(NULL);
|
||||||
@@ -119,9 +118,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc);
|
plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc);
|
||||||
datums_last = 0;
|
datums_last = 0;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Lookup the pg_proc tuple by Oid
|
* Lookup the pg_proc tuple by Oid
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
procTup = SearchSysCache(PROCOID,
|
procTup = SearchSysCache(PROCOID,
|
||||||
ObjectIdGetDatum(fn_oid),
|
ObjectIdGetDatum(fn_oid),
|
||||||
@@ -129,9 +127,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
if (!HeapTupleIsValid(procTup))
|
if (!HeapTupleIsValid(procTup))
|
||||||
elog(ERROR, "plpgsql: cache lookup for proc %u failed", fn_oid);
|
elog(ERROR, "plpgsql: cache lookup for proc %u failed", fn_oid);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Setup the scanner input and error info
|
* Setup the scanner input and error info
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
procStruct = (Form_pg_proc) GETSTRUCT(procTup);
|
procStruct = (Form_pg_proc) GETSTRUCT(procTup);
|
||||||
proc_source = DatumGetCString(DirectFunctionCall1(textout,
|
proc_source = DatumGetCString(DirectFunctionCall1(textout,
|
||||||
@@ -141,9 +138,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
NameGetDatum(&(procStruct->proname))));
|
NameGetDatum(&(procStruct->proname))));
|
||||||
plpgsql_error_lineno = 0;
|
plpgsql_error_lineno = 0;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Create the new function node
|
* Create the new function node
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
function = malloc(sizeof(PLpgSQL_function));
|
function = malloc(sizeof(PLpgSQL_function));
|
||||||
memset(function, 0, sizeof(PLpgSQL_function));
|
memset(function, 0, sizeof(PLpgSQL_function));
|
||||||
@@ -157,16 +153,15 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
switch (functype)
|
switch (functype)
|
||||||
{
|
{
|
||||||
case T_FUNCTION:
|
case T_FUNCTION:
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Normal function has a defined returntype
|
* Normal function has a defined returntype
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
function->fn_rettype = procStruct->prorettype;
|
function->fn_rettype = procStruct->prorettype;
|
||||||
function->fn_retset = procStruct->proretset;
|
function->fn_retset = procStruct->proretset;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Lookup the functions return type
|
* Lookup the functions return type
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
typeTup = SearchSysCache(TYPEOID,
|
typeTup = SearchSysCache(TYPEOID,
|
||||||
ObjectIdGetDatum(procStruct->prorettype),
|
ObjectIdGetDatum(procStruct->prorettype),
|
||||||
@@ -193,17 +188,15 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
}
|
}
|
||||||
ReleaseSysCache(typeTup);
|
ReleaseSysCache(typeTup);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Create the variables for the procedures parameters
|
* Create the variables for the procedures parameters
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < procStruct->pronargs; i++)
|
for (i = 0; i < procStruct->pronargs; i++)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the parameters type
|
* Get the parameters type
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
typeTup = SearchSysCache(TYPEOID,
|
typeTup = SearchSysCache(TYPEOID,
|
||||||
ObjectIdGetDatum(procStruct->proargtypes[i]),
|
ObjectIdGetDatum(procStruct->proargtypes[i]),
|
||||||
@@ -221,10 +214,10 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
|
|
||||||
if (typeStruct->typrelid != InvalidOid)
|
if (typeStruct->typrelid != InvalidOid)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* For tuple type parameters, we set up a record
|
/*
|
||||||
* of that type
|
* For tuple type parameters, we set up a record of
|
||||||
* ----------
|
* that type
|
||||||
*/
|
*/
|
||||||
sprintf(buf, "%s%%rowtype",
|
sprintf(buf, "%s%%rowtype",
|
||||||
DatumGetCString(DirectFunctionCall1(nameout,
|
DatumGetCString(DirectFunctionCall1(nameout,
|
||||||
@@ -248,9 +241,9 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Normal parameters get a var node
|
* Normal parameters get a var node
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
var = malloc(sizeof(PLpgSQL_var));
|
var = malloc(sizeof(PLpgSQL_var));
|
||||||
memset(var, 0, sizeof(PLpgSQL_var));
|
memset(var, 0, sizeof(PLpgSQL_var));
|
||||||
@@ -282,18 +275,17 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_TRIGGER:
|
case T_TRIGGER:
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Trigger procedures return type is unknown yet
|
* Trigger procedures return type is unknown yet
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
function->fn_rettype = InvalidOid;
|
function->fn_rettype = InvalidOid;
|
||||||
function->fn_retbyval = false;
|
function->fn_retbyval = false;
|
||||||
function->fn_retistuple = true;
|
function->fn_retistuple = true;
|
||||||
function->fn_retset = false;
|
function->fn_retset = false;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Add the record for referencing NEW
|
* Add the record for referencing NEW
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
rec = malloc(sizeof(PLpgSQL_rec));
|
rec = malloc(sizeof(PLpgSQL_rec));
|
||||||
memset(rec, 0, sizeof(PLpgSQL_rec));
|
memset(rec, 0, sizeof(PLpgSQL_rec));
|
||||||
@@ -303,9 +295,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, rec->refname);
|
plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, rec->refname);
|
||||||
function->new_varno = rec->recno;
|
function->new_varno = rec->recno;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Add the record for referencing OLD
|
* Add the record for referencing OLD
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
rec = malloc(sizeof(PLpgSQL_rec));
|
rec = malloc(sizeof(PLpgSQL_rec));
|
||||||
memset(rec, 0, sizeof(PLpgSQL_rec));
|
memset(rec, 0, sizeof(PLpgSQL_rec));
|
||||||
@@ -315,9 +306,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, rec->refname);
|
plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, rec->refname);
|
||||||
function->old_varno = rec->recno;
|
function->old_varno = rec->recno;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Add the variable tg_name
|
* Add the variable tg_name
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
var = malloc(sizeof(PLpgSQL_var));
|
var = malloc(sizeof(PLpgSQL_var));
|
||||||
memset(var, 0, sizeof(PLpgSQL_var));
|
memset(var, 0, sizeof(PLpgSQL_var));
|
||||||
@@ -335,9 +325,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
|
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
|
||||||
function->tg_name_varno = var->varno;
|
function->tg_name_varno = var->varno;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Add the variable tg_when
|
* Add the variable tg_when
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
var = malloc(sizeof(PLpgSQL_var));
|
var = malloc(sizeof(PLpgSQL_var));
|
||||||
memset(var, 0, sizeof(PLpgSQL_var));
|
memset(var, 0, sizeof(PLpgSQL_var));
|
||||||
@@ -355,9 +344,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
|
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
|
||||||
function->tg_when_varno = var->varno;
|
function->tg_when_varno = var->varno;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Add the variable tg_level
|
* Add the variable tg_level
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
var = malloc(sizeof(PLpgSQL_var));
|
var = malloc(sizeof(PLpgSQL_var));
|
||||||
memset(var, 0, sizeof(PLpgSQL_var));
|
memset(var, 0, sizeof(PLpgSQL_var));
|
||||||
@@ -375,9 +363,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
|
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
|
||||||
function->tg_level_varno = var->varno;
|
function->tg_level_varno = var->varno;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Add the variable tg_op
|
* Add the variable tg_op
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
var = malloc(sizeof(PLpgSQL_var));
|
var = malloc(sizeof(PLpgSQL_var));
|
||||||
memset(var, 0, sizeof(PLpgSQL_var));
|
memset(var, 0, sizeof(PLpgSQL_var));
|
||||||
@@ -395,9 +382,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
|
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
|
||||||
function->tg_op_varno = var->varno;
|
function->tg_op_varno = var->varno;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Add the variable tg_relid
|
* Add the variable tg_relid
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
var = malloc(sizeof(PLpgSQL_var));
|
var = malloc(sizeof(PLpgSQL_var));
|
||||||
memset(var, 0, sizeof(PLpgSQL_var));
|
memset(var, 0, sizeof(PLpgSQL_var));
|
||||||
@@ -415,9 +401,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
|
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
|
||||||
function->tg_relid_varno = var->varno;
|
function->tg_relid_varno = var->varno;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Add the variable tg_relname
|
* Add the variable tg_relname
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
var = malloc(sizeof(PLpgSQL_var));
|
var = malloc(sizeof(PLpgSQL_var));
|
||||||
memset(var, 0, sizeof(PLpgSQL_var));
|
memset(var, 0, sizeof(PLpgSQL_var));
|
||||||
@@ -435,9 +420,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
|
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
|
||||||
function->tg_relname_varno = var->varno;
|
function->tg_relname_varno = var->varno;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Add the variable tg_nargs
|
* Add the variable tg_nargs
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
var = malloc(sizeof(PLpgSQL_var));
|
var = malloc(sizeof(PLpgSQL_var));
|
||||||
memset(var, 0, sizeof(PLpgSQL_var));
|
memset(var, 0, sizeof(PLpgSQL_var));
|
||||||
@@ -463,10 +447,9 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Create the magic found variable indicating if the
|
* Create the magic found variable indicating if the last FOR or
|
||||||
* last FOR or SELECT statement returned data
|
* SELECT statement returned data
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
var = malloc(sizeof(PLpgSQL_var));
|
var = malloc(sizeof(PLpgSQL_var));
|
||||||
memset(var, 0, sizeof(PLpgSQL_var));
|
memset(var, 0, sizeof(PLpgSQL_var));
|
||||||
@@ -484,15 +467,13 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, strdup("found"));
|
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, strdup("found"));
|
||||||
function->found_varno = var->varno;
|
function->found_varno = var->varno;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Forget about the above created variables
|
* Forget about the above created variables
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
plpgsql_add_initdatums(NULL);
|
plpgsql_add_initdatums(NULL);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Now parse the functions text
|
* Now parse the functions text
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
parse_rc = plpgsql_yyparse();
|
parse_rc = plpgsql_yyparse();
|
||||||
if (parse_rc != 0)
|
if (parse_rc != 0)
|
||||||
@@ -501,9 +482,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
elog(ERROR, "plpgsql: parser returned %d ???", parse_rc);
|
elog(ERROR, "plpgsql: parser returned %d ???", parse_rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If that was successful, complete the functions info.
|
* If that was successful, complete the functions info.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
function->fn_nargs = procStruct->pronargs;
|
function->fn_nargs = procStruct->pronargs;
|
||||||
for (i = 0; i < function->fn_nargs; i++)
|
for (i = 0; i < function->fn_nargs; i++)
|
||||||
@@ -516,9 +496,8 @@ plpgsql_compile(Oid fn_oid, int functype)
|
|||||||
|
|
||||||
ReleaseSysCache(procTup);
|
ReleaseSysCache(procTup);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Finally return the compiled function
|
* Finally return the compiled function
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (plpgsql_DumpExecTree)
|
if (plpgsql_DumpExecTree)
|
||||||
plpgsql_dumptree(function);
|
plpgsql_dumptree(function);
|
||||||
@@ -541,15 +520,13 @@ plpgsql_parse_word(char *word)
|
|||||||
Form_pg_type typeStruct;
|
Form_pg_type typeStruct;
|
||||||
char *typeXlated;
|
char *typeXlated;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* We do our lookups case insensitive
|
* We do our lookups case insensitive
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
cp = plpgsql_tolower(word);
|
cp = plpgsql_tolower(word);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Special handling when compiling triggers
|
* Special handling when compiling triggers
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (plpgsql_curr_compile->fn_functype == T_TRIGGER)
|
if (plpgsql_curr_compile->fn_functype == T_TRIGGER)
|
||||||
{
|
{
|
||||||
@@ -575,9 +552,8 @@ plpgsql_parse_word(char *word)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Do a lookup on the compilers namestack
|
* Do a lookup on the compilers namestack
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
nse = plpgsql_ns_lookup(cp, NULL);
|
nse = plpgsql_ns_lookup(cp, NULL);
|
||||||
if (nse != NULL)
|
if (nse != NULL)
|
||||||
@@ -605,10 +581,9 @@ plpgsql_parse_word(char *word)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Try to find a data type with that name, but ignore
|
* Try to find a data type with that name, but ignore pg_type entries
|
||||||
* pg_type entries that are in fact class types.
|
* that are in fact class types.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
typeXlated = xlateSqlType(cp);
|
typeXlated = xlateSqlType(cp);
|
||||||
typeTup = SearchSysCache(TYPENAME,
|
typeTup = SearchSysCache(TYPENAME,
|
||||||
@@ -644,10 +619,9 @@ plpgsql_parse_word(char *word)
|
|||||||
return T_DTYPE;
|
return T_DTYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Nothing found - up to now it's a word without any
|
* Nothing found - up to now it's a word without any special meaning
|
||||||
* special meaning for us.
|
* for us.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
pfree(cp);
|
pfree(cp);
|
||||||
return T_WORD;
|
return T_WORD;
|
||||||
@@ -666,17 +640,15 @@ plpgsql_parse_dblword(char *string)
|
|||||||
char *word2;
|
char *word2;
|
||||||
PLpgSQL_nsitem *ns;
|
PLpgSQL_nsitem *ns;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Convert to lower case and separate the words
|
* Convert to lower case and separate the words
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
word1 = plpgsql_tolower(string);
|
word1 = plpgsql_tolower(string);
|
||||||
word2 = strchr(word1, '.');
|
word2 = strchr(word1, '.');
|
||||||
*word2++ = '\0';
|
*word2++ = '\0';
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Lookup the first word
|
* Lookup the first word
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ns = plpgsql_ns_lookup(word1, NULL);
|
ns = plpgsql_ns_lookup(word1, NULL);
|
||||||
if (ns == NULL)
|
if (ns == NULL)
|
||||||
@@ -688,13 +660,12 @@ plpgsql_parse_dblword(char *string)
|
|||||||
switch (ns->itemtype)
|
switch (ns->itemtype)
|
||||||
{
|
{
|
||||||
case PLPGSQL_NSTYPE_LABEL:
|
case PLPGSQL_NSTYPE_LABEL:
|
||||||
/* ----------
|
|
||||||
* First word is a label, so second word could be
|
/*
|
||||||
* a variable, record or row in that bodies namestack.
|
* First word is a label, so second word could be a variable,
|
||||||
* Anything else could only be something in a query
|
* record or row in that bodies namestack. Anything else could
|
||||||
* given to the SPI manager and T_ERROR will get eaten
|
* only be something in a query given to the SPI manager and
|
||||||
* up by the collector routines.
|
* T_ERROR will get eaten up by the collector routines.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ns = plpgsql_ns_lookup(word2, word1);
|
ns = plpgsql_ns_lookup(word2, word1);
|
||||||
if (ns == NULL)
|
if (ns == NULL)
|
||||||
@@ -726,10 +697,10 @@ plpgsql_parse_dblword(char *string)
|
|||||||
|
|
||||||
case PLPGSQL_NSTYPE_REC:
|
case PLPGSQL_NSTYPE_REC:
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* First word is a record name, so second word
|
/*
|
||||||
* must be a field in this record.
|
* First word is a record name, so second word must be a
|
||||||
* ----------
|
* field in this record.
|
||||||
*/
|
*/
|
||||||
PLpgSQL_recfield *new;
|
PLpgSQL_recfield *new;
|
||||||
|
|
||||||
@@ -747,10 +718,10 @@ plpgsql_parse_dblword(char *string)
|
|||||||
|
|
||||||
case PLPGSQL_NSTYPE_ROW:
|
case PLPGSQL_NSTYPE_ROW:
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* First word is a row name, so second word must
|
/*
|
||||||
* be a field in this row.
|
* First word is a row name, so second word must be a
|
||||||
* ----------
|
* field in this row.
|
||||||
*/
|
*/
|
||||||
PLpgSQL_row *row;
|
PLpgSQL_row *row;
|
||||||
int i;
|
int i;
|
||||||
@@ -792,9 +763,8 @@ plpgsql_parse_tripword(char *string)
|
|||||||
char *word3;
|
char *word3;
|
||||||
PLpgSQL_nsitem *ns;
|
PLpgSQL_nsitem *ns;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Convert to lower case and separate the words
|
* Convert to lower case and separate the words
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
word1 = plpgsql_tolower(string);
|
word1 = plpgsql_tolower(string);
|
||||||
word2 = strchr(word1, '.');
|
word2 = strchr(word1, '.');
|
||||||
@@ -802,9 +772,8 @@ plpgsql_parse_tripword(char *string)
|
|||||||
word3 = strchr(word2, '.');
|
word3 = strchr(word2, '.');
|
||||||
*word3++ = '\0';
|
*word3++ = '\0';
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Lookup the first word - it must be a label
|
* Lookup the first word - it must be a label
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ns = plpgsql_ns_lookup(word1, NULL);
|
ns = plpgsql_ns_lookup(word1, NULL);
|
||||||
if (ns == NULL)
|
if (ns == NULL)
|
||||||
@@ -818,10 +787,8 @@ plpgsql_parse_tripword(char *string)
|
|||||||
return T_ERROR;
|
return T_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* First word is a label, so second word could be
|
* First word is a label, so second word could be a record or row
|
||||||
* a record or row
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
ns = plpgsql_ns_lookup(word2, word1);
|
ns = plpgsql_ns_lookup(word2, word1);
|
||||||
if (ns == NULL)
|
if (ns == NULL)
|
||||||
@@ -834,10 +801,10 @@ plpgsql_parse_tripword(char *string)
|
|||||||
{
|
{
|
||||||
case PLPGSQL_NSTYPE_REC:
|
case PLPGSQL_NSTYPE_REC:
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* This word is a record name, so third word
|
/*
|
||||||
* must be a field in this record.
|
* This word is a record name, so third word must be a
|
||||||
* ----------
|
* field in this record.
|
||||||
*/
|
*/
|
||||||
PLpgSQL_recfield *new;
|
PLpgSQL_recfield *new;
|
||||||
|
|
||||||
@@ -855,10 +822,10 @@ plpgsql_parse_tripword(char *string)
|
|||||||
|
|
||||||
case PLPGSQL_NSTYPE_ROW:
|
case PLPGSQL_NSTYPE_ROW:
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
* This word is a row name, so third word must
|
/*
|
||||||
* be a field in this row.
|
* This word is a row name, so third word must be a field
|
||||||
* ----------
|
* in this row.
|
||||||
*/
|
*/
|
||||||
PLpgSQL_row *row;
|
PLpgSQL_row *row;
|
||||||
int i;
|
int i;
|
||||||
@@ -902,17 +869,15 @@ plpgsql_parse_wordtype(char *word)
|
|||||||
char *typeXlated;
|
char *typeXlated;
|
||||||
bool old_nsstate;
|
bool old_nsstate;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* We do our lookups case insensitive
|
* We do our lookups case insensitive
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
cp = plpgsql_tolower(word);
|
cp = plpgsql_tolower(word);
|
||||||
*(strchr(cp, '%')) = '\0';
|
*(strchr(cp, '%')) = '\0';
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Do a lookup on the compilers namestack.
|
* Do a lookup on the compilers namestack. But ensure it moves up to
|
||||||
* But ensure it moves up to the toplevel.
|
* the toplevel.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
old_nsstate = plpgsql_ns_setlocal(false);
|
old_nsstate = plpgsql_ns_setlocal(false);
|
||||||
nse = plpgsql_ns_lookup(cp, NULL);
|
nse = plpgsql_ns_lookup(cp, NULL);
|
||||||
@@ -932,11 +897,9 @@ plpgsql_parse_wordtype(char *word)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Word wasn't found on the namestack.
|
* Word wasn't found on the namestack. Try to find a data type with
|
||||||
* Try to find a data type with that name, but ignore
|
* that name, but ignore pg_type entries that are in fact class types.
|
||||||
* pg_type entries that are in fact class types.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
typeXlated = xlateSqlType(cp);
|
typeXlated = xlateSqlType(cp);
|
||||||
typeTup = SearchSysCache(TYPENAME,
|
typeTup = SearchSysCache(TYPENAME,
|
||||||
@@ -972,10 +935,9 @@ plpgsql_parse_wordtype(char *word)
|
|||||||
return T_DTYPE;
|
return T_DTYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Nothing found - up to now it's a word without any
|
* Nothing found - up to now it's a word without any special meaning
|
||||||
* special meaning for us.
|
* for us.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
pfree(cp);
|
pfree(cp);
|
||||||
return T_ERROR;
|
return T_ERROR;
|
||||||
@@ -1002,25 +964,22 @@ plpgsql_parse_dblwordtype(char *string)
|
|||||||
PLpgSQL_type *typ;
|
PLpgSQL_type *typ;
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Convert to lower case and separate the words
|
* Convert to lower case and separate the words
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
word1 = plpgsql_tolower(string);
|
word1 = plpgsql_tolower(string);
|
||||||
word2 = strchr(word1, '.');
|
word2 = strchr(word1, '.');
|
||||||
*word2++ = '\0';
|
*word2++ = '\0';
|
||||||
*(strchr(word2, '%')) = '\0';
|
*(strchr(word2, '%')) = '\0';
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Lookup the first word
|
* Lookup the first word
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
nse = plpgsql_ns_lookup(word1, NULL);
|
nse = plpgsql_ns_lookup(word1, NULL);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If this is a label lookup the second word in that
|
* If this is a label lookup the second word in that labels namestack
|
||||||
* labels namestack level
|
* level
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (nse != NULL)
|
if (nse != NULL)
|
||||||
{
|
{
|
||||||
@@ -1050,9 +1009,8 @@ plpgsql_parse_dblwordtype(char *string)
|
|||||||
return T_ERROR;
|
return T_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* First word could also be a table name
|
* First word could also be a table name
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
classtup = SearchSysCache(RELNAME,
|
classtup = SearchSysCache(RELNAME,
|
||||||
PointerGetDatum(word1),
|
PointerGetDatum(word1),
|
||||||
@@ -1063,9 +1021,8 @@ plpgsql_parse_dblwordtype(char *string)
|
|||||||
return T_ERROR;
|
return T_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* It must be a (shared) relation class
|
* It must be a (shared) relation class
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
classStruct = (Form_pg_class) GETSTRUCT(classtup);
|
classStruct = (Form_pg_class) GETSTRUCT(classtup);
|
||||||
if (classStruct->relkind != 'r' && classStruct->relkind != 's')
|
if (classStruct->relkind != 'r' && classStruct->relkind != 's')
|
||||||
@@ -1075,9 +1032,8 @@ plpgsql_parse_dblwordtype(char *string)
|
|||||||
return T_ERROR;
|
return T_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Fetch the named table field and it's type
|
* Fetch the named table field and it's type
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
attrtup = SearchSysCache(ATTNAME,
|
attrtup = SearchSysCache(ATTNAME,
|
||||||
ObjectIdGetDatum(classtup->t_data->t_oid),
|
ObjectIdGetDatum(classtup->t_data->t_oid),
|
||||||
@@ -1102,9 +1058,8 @@ plpgsql_parse_dblwordtype(char *string)
|
|||||||
}
|
}
|
||||||
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
|
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Found that - build a compiler type struct and return it
|
* Found that - build a compiler type struct and return it
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
|
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
|
||||||
|
|
||||||
@@ -1146,9 +1101,8 @@ plpgsql_parse_wordrowtype(char *string)
|
|||||||
PLpgSQL_row *row;
|
PLpgSQL_row *row;
|
||||||
PLpgSQL_var *var;
|
PLpgSQL_var *var;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Get the word in lower case and fetch the pg_class tuple.
|
* Get the word in lower case and fetch the pg_class tuple.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
word1 = plpgsql_tolower(string);
|
word1 = plpgsql_tolower(string);
|
||||||
cp = strchr(word1, '%');
|
cp = strchr(word1, '%');
|
||||||
@@ -1169,9 +1123,8 @@ plpgsql_parse_wordrowtype(char *string)
|
|||||||
elog(ERROR, "%s isn't a table", word1);
|
elog(ERROR, "%s isn't a table", word1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Fetch the tables pg_type tuple too
|
* Fetch the tables pg_type tuple too
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
typetup = SearchSysCache(TYPENAME,
|
typetup = SearchSysCache(TYPENAME,
|
||||||
PointerGetDatum(word1),
|
PointerGetDatum(word1),
|
||||||
@@ -1182,10 +1135,9 @@ plpgsql_parse_wordrowtype(char *string)
|
|||||||
elog(ERROR, "cache lookup for %s in pg_type failed", word1);
|
elog(ERROR, "cache lookup for %s in pg_type failed", word1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Create a row datum entry and all the required variables
|
* Create a row datum entry and all the required variables that it
|
||||||
* that it will point to.
|
* will point to.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
row = malloc(sizeof(PLpgSQL_row));
|
row = malloc(sizeof(PLpgSQL_row));
|
||||||
memset(row, 0, sizeof(PLpgSQL_row));
|
memset(row, 0, sizeof(PLpgSQL_row));
|
||||||
@@ -1200,9 +1152,9 @@ plpgsql_parse_wordrowtype(char *string)
|
|||||||
|
|
||||||
for (i = 0; i < row->nfields; i++)
|
for (i = 0; i < row->nfields; i++)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Get the attribute and it's type
|
* Get the attribute and it's type
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
attrtup = SearchSysCache(ATTNUM,
|
attrtup = SearchSysCache(ATTNUM,
|
||||||
ObjectIdGetDatum(classtup->t_data->t_oid),
|
ObjectIdGetDatum(classtup->t_data->t_oid),
|
||||||
@@ -1230,15 +1182,14 @@ plpgsql_parse_wordrowtype(char *string)
|
|||||||
}
|
}
|
||||||
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
|
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Create the internal variable
|
* Create the internal variable We know if the table definitions
|
||||||
* We know if the table definitions contain a default value
|
* contain a default value or if the field is declared in the
|
||||||
* or if the field is declared in the table as NOT NULL. But
|
* table as NOT NULL. But it's possible to create a table field as
|
||||||
* it's possible to create a table field as NOT NULL without
|
* NOT NULL without a default value and that would lead to
|
||||||
* a default value and that would lead to problems later when
|
* problems later when initializing the variables due to entering
|
||||||
* initializing the variables due to entering a block at
|
* a block at execution time. Thus we ignore this information for
|
||||||
* execution time. Thus we ignore this information for now.
|
* now.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
var = malloc(sizeof(PLpgSQL_var));
|
var = malloc(sizeof(PLpgSQL_var));
|
||||||
var->dtype = PLPGSQL_DTYPE_VAR;
|
var->dtype = PLPGSQL_DTYPE_VAR;
|
||||||
@@ -1265,9 +1216,8 @@ plpgsql_parse_wordrowtype(char *string)
|
|||||||
|
|
||||||
plpgsql_adddatum((PLpgSQL_datum *) var);
|
plpgsql_adddatum((PLpgSQL_datum *) var);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Add the variable to the row.
|
* Add the variable to the row.
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
row->fieldnames[i] = cp;
|
row->fieldnames[i] = cp;
|
||||||
row->varnos[i] = var->varno;
|
row->varnos[i] = var->varno;
|
||||||
@@ -1275,9 +1225,8 @@ plpgsql_parse_wordrowtype(char *string)
|
|||||||
|
|
||||||
ReleaseSysCache(classtup);
|
ReleaseSysCache(classtup);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Return the complete row definition
|
* Return the complete row definition
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
plpgsql_yylval.row = row;
|
plpgsql_yylval.row = row;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.11 2001/03/22 04:01:41 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.12 2001/03/22 06:16:21 momjian Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@@ -224,9 +224,8 @@ plpgsql_ns_lookup(char *name, char *label)
|
|||||||
PLpgSQL_ns *ns;
|
PLpgSQL_ns *ns;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If a label is specified, lookup only in that
|
* If a label is specified, lookup only in that
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (label != NULL)
|
if (label != NULL)
|
||||||
{
|
{
|
||||||
@@ -245,9 +244,8 @@ plpgsql_ns_lookup(char *name, char *label)
|
|||||||
return NULL; /* label not found */
|
return NULL; /* label not found */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* No label given, lookup for visible labels ignoring localmode
|
* No label given, lookup for visible labels ignoring localmode
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (ns = ns_current; ns != NULL; ns = ns->upper)
|
for (ns = ns_current; ns != NULL; ns = ns->upper)
|
||||||
{
|
{
|
||||||
@@ -255,9 +253,8 @@ plpgsql_ns_lookup(char *name, char *label)
|
|||||||
return ns->items[0];
|
return ns->items[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Finally lookup name in the namestack
|
* Finally lookup name in the namestack
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (ns = ns_current; ns != NULL; ns = ns->upper)
|
for (ns = ns_current; ns != NULL; ns = ns->upper)
|
||||||
{
|
{
|
||||||
@@ -287,13 +284,12 @@ plpgsql_ns_rename(char *oldname, char *newname)
|
|||||||
PLpgSQL_nsitem *newitem;
|
PLpgSQL_nsitem *newitem;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Lookup in the current namespace only
|
* Lookup in the current namespace only
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Lookup name in the namestack
|
* Lookup name in the namestack
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
for (ns = ns_current; ns != NULL; ns = ns->upper)
|
for (ns = ns_current; ns != NULL; ns = ns->upper)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.7 2001/03/22 04:01:42 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.8 2001/03/22 06:16:21 momjian Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@@ -75,24 +75,22 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
|
|||||||
PLpgSQL_function *func;
|
PLpgSQL_function *func;
|
||||||
Datum retval;
|
Datum retval;
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Connect to SPI manager
|
* Connect to SPI manager
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (SPI_connect() != SPI_OK_CONNECT)
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
elog(ERROR, "plpgsql: cannot connect to SPI manager");
|
elog(ERROR, "plpgsql: cannot connect to SPI manager");
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Check if we already compiled this function and saved the pointer
|
* Check if we already compiled this function and saved the pointer
|
||||||
* (ie, current FmgrInfo has been used before)
|
* (ie, current FmgrInfo has been used before)
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
func = (PLpgSQL_function *) fcinfo->flinfo->fn_extra;
|
func = (PLpgSQL_function *) fcinfo->flinfo->fn_extra;
|
||||||
if (func == NULL)
|
if (func == NULL)
|
||||||
{
|
{
|
||||||
/* ----------
|
|
||||||
|
/*
|
||||||
* Check if we already compiled this function
|
* Check if we already compiled this function
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
Oid funcOid = fcinfo->flinfo->fn_oid;
|
Oid funcOid = fcinfo->flinfo->fn_oid;
|
||||||
|
|
||||||
@@ -102,9 +100,8 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* If not, do so and add it to the compiled ones
|
* If not, do so and add it to the compiled ones
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (func == NULL)
|
if (func == NULL)
|
||||||
{
|
{
|
||||||
@@ -114,17 +111,15 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
|
|||||||
compiled_functions = func;
|
compiled_functions = func;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Save pointer in FmgrInfo to avoid search on subsequent calls
|
* Save pointer in FmgrInfo to avoid search on subsequent calls
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
fcinfo->flinfo->fn_extra = (void *) func;
|
fcinfo->flinfo->fn_extra = (void *) func;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Determine if called as function or trigger and
|
* Determine if called as function or trigger and call appropriate
|
||||||
* call appropriate subhandler
|
* subhandler
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (isTrigger)
|
if (isTrigger)
|
||||||
retval = PointerGetDatum(plpgsql_exec_trigger(func,
|
retval = PointerGetDatum(plpgsql_exec_trigger(func,
|
||||||
@@ -132,9 +127,8 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
|
|||||||
else
|
else
|
||||||
retval = plpgsql_exec_function(func, fcinfo);
|
retval = plpgsql_exec_function(func, fcinfo);
|
||||||
|
|
||||||
/* ----------
|
/*
|
||||||
* Disconnect from SPI manager
|
* Disconnect from SPI manager
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
if (SPI_finish() != SPI_OK_FINISH)
|
if (SPI_finish() != SPI_OK_FINISH)
|
||||||
elog(ERROR, "plpgsql: SPI_finish() failed");
|
elog(ERROR, "plpgsql: SPI_finish() failed");
|
||||||
|
|||||||
Reference in New Issue
Block a user