mirror of
https://github.com/postgres/postgres.git
synced 2025-11-12 05:01:15 +03:00
Massive commit to run PGINDENT on all *.c and *.h files.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,29 +1,29 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* dest.c--
|
||||
* support for various communication destinations - see lib/H/tcop/dest.h
|
||||
* support for various communication destinations - see lib/H/tcop/dest.h
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.10 1997/08/29 09:04:18 vadim Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.11 1997/09/07 04:49:31 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* INTERFACE ROUTINES
|
||||
* BeginCommand - prepare destination for tuples of the given type
|
||||
* EndCommand - tell destination that no more tuples will arrive
|
||||
* NullCommand - tell dest that the last of a query sequence was processed
|
||||
*
|
||||
* NOTES
|
||||
* These routines do the appropriate work before and after
|
||||
* tuples are returned by a query to keep the backend and the
|
||||
* "destination" portals synchronized.
|
||||
* INTERFACE ROUTINES
|
||||
* BeginCommand - prepare destination for tuples of the given type
|
||||
* EndCommand - tell destination that no more tuples will arrive
|
||||
* NullCommand - tell dest that the last of a query sequence was processed
|
||||
*
|
||||
* NOTES
|
||||
* These routines do the appropriate work before and after
|
||||
* tuples are returned by a query to keep the backend and the
|
||||
* "destination" portals synchronized.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h> /* for sprintf() */
|
||||
#include <stdio.h> /* for sprintf() */
|
||||
#include <string.h>
|
||||
|
||||
#include "postgres.h"
|
||||
@@ -43,10 +43,10 @@
|
||||
|
||||
#include "commands/async.h"
|
||||
|
||||
static char CommandInfo[32] = {0};
|
||||
static char CommandInfo[32] = {0};
|
||||
|
||||
/* ----------------
|
||||
* output functions
|
||||
* output functions
|
||||
* ----------------
|
||||
*/
|
||||
static void
|
||||
@@ -54,85 +54,88 @@ donothing(HeapTuple tuple, TupleDesc attrdesc)
|
||||
{
|
||||
}
|
||||
|
||||
extern void spi_printtup (HeapTuple tuple, TupleDesc tupdesc);
|
||||
extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc);
|
||||
|
||||
void (*DestToFunction(CommandDest dest))(HeapTuple, TupleDesc)
|
||||
void (*
|
||||
DestToFunction(CommandDest dest)) (HeapTuple, TupleDesc)
|
||||
{
|
||||
switch (dest) {
|
||||
case RemoteInternal:
|
||||
return printtup_internal;
|
||||
break;
|
||||
|
||||
case Remote:
|
||||
return printtup;
|
||||
break;
|
||||
|
||||
case Local:
|
||||
return be_printtup;
|
||||
break;
|
||||
|
||||
case Debug:
|
||||
return debugtup;
|
||||
break;
|
||||
|
||||
case SPI:
|
||||
return spi_printtup;
|
||||
break;
|
||||
|
||||
case None:
|
||||
default:
|
||||
switch (dest)
|
||||
{
|
||||
case RemoteInternal:
|
||||
return printtup_internal;
|
||||
break;
|
||||
|
||||
case Remote:
|
||||
return printtup;
|
||||
break;
|
||||
|
||||
case Local:
|
||||
return be_printtup;
|
||||
break;
|
||||
|
||||
case Debug:
|
||||
return debugtup;
|
||||
break;
|
||||
|
||||
case SPI:
|
||||
return spi_printtup;
|
||||
break;
|
||||
|
||||
case None:
|
||||
default:
|
||||
return donothing;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* never gets here, but DECstation lint appears to be stupid...
|
||||
*/
|
||||
|
||||
return donothing;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* never gets here, but DECstation lint appears to be stupid...
|
||||
*/
|
||||
|
||||
return donothing;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* EndCommand - tell destination that no more tuples will arrive
|
||||
* EndCommand - tell destination that no more tuples will arrive
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
EndCommand(char *commandTag, CommandDest dest)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
switch (dest) {
|
||||
case RemoteInternal:
|
||||
case Remote:
|
||||
/* ----------------
|
||||
* tell the fe that the query is over
|
||||
* ----------------
|
||||
*/
|
||||
pq_putnchar("C", 1);
|
||||
sprintf(buf, "%s%s", commandTag, CommandInfo);
|
||||
CommandInfo[0] = 0;
|
||||
pq_putstr(buf);
|
||||
pq_flush();
|
||||
break;
|
||||
|
||||
case Local:
|
||||
case Debug:
|
||||
break;
|
||||
case CopyEnd:
|
||||
pq_putnchar("Z", 1);
|
||||
pq_flush();
|
||||
break;
|
||||
case None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
char buf[64];
|
||||
|
||||
switch (dest)
|
||||
{
|
||||
case RemoteInternal:
|
||||
case Remote:
|
||||
/* ----------------
|
||||
* tell the fe that the query is over
|
||||
* ----------------
|
||||
*/
|
||||
pq_putnchar("C", 1);
|
||||
sprintf(buf, "%s%s", commandTag, CommandInfo);
|
||||
CommandInfo[0] = 0;
|
||||
pq_putstr(buf);
|
||||
pq_flush();
|
||||
break;
|
||||
|
||||
case Local:
|
||||
case Debug:
|
||||
break;
|
||||
case CopyEnd:
|
||||
pq_putnchar("Z", 1);
|
||||
pq_flush();
|
||||
break;
|
||||
case None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* These are necessary to sync communications between fe/be processes doing
|
||||
* COPY rel TO stdout
|
||||
*
|
||||
* or
|
||||
*
|
||||
* or
|
||||
*
|
||||
* COPY rel FROM stdin
|
||||
*
|
||||
@@ -140,198 +143,211 @@ EndCommand(char *commandTag, CommandDest dest)
|
||||
void
|
||||
SendCopyBegin(void)
|
||||
{
|
||||
pq_putnchar("B", 1);
|
||||
/* pq_putint(0, 4); */
|
||||
pq_flush();
|
||||
pq_putnchar("B", 1);
|
||||
/* pq_putint(0, 4); */
|
||||
pq_flush();
|
||||
}
|
||||
|
||||
void
|
||||
ReceiveCopyBegin(void)
|
||||
{
|
||||
pq_putnchar("D", 1);
|
||||
/* pq_putint(0, 4); */
|
||||
pq_flush();
|
||||
pq_putnchar("D", 1);
|
||||
/* pq_putint(0, 4); */
|
||||
pq_flush();
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* NullCommand - tell dest that the last of a query sequence was processed
|
||||
*
|
||||
* Necessary to implement the hacky FE/BE interface to handle
|
||||
* multiple-return queries.
|
||||
* NullCommand - tell dest that the last of a query sequence was processed
|
||||
*
|
||||
* Necessary to implement the hacky FE/BE interface to handle
|
||||
* multiple-return queries.
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
NullCommand(CommandDest dest)
|
||||
{
|
||||
switch (dest) {
|
||||
case RemoteInternal:
|
||||
case Remote: {
|
||||
switch (dest)
|
||||
{
|
||||
case RemoteInternal:
|
||||
case Remote:
|
||||
{
|
||||
#if 0
|
||||
/* Do any asynchronous notification. If front end wants to poll,
|
||||
it can send null queries to call this function.
|
||||
*/
|
||||
PQNotifyList *nPtr;
|
||||
MemoryContext orig;
|
||||
|
||||
if (notifyContext == NULL) {
|
||||
notifyContext = CreateGlobalMemory("notify");
|
||||
}
|
||||
orig = MemoryContextSwitchTo((MemoryContext)notifyContext);
|
||||
|
||||
for (nPtr = PQnotifies() ;
|
||||
nPtr != NULL;
|
||||
nPtr = (PQNotifyList *)SLGetSucc(&nPtr->Node)) {
|
||||
pq_putnchar("A",1);
|
||||
pq_putint(0, 4);
|
||||
pq_putstr(nPtr->relname);
|
||||
pq_putint(nPtr->be_pid,4);
|
||||
PQremoveNotify(nPtr);
|
||||
}
|
||||
pq_flush();
|
||||
PQcleanNotify(); /* garbage collect */
|
||||
MemoryContextSwitchTo(orig);
|
||||
|
||||
/*
|
||||
* Do any asynchronous notification. If front end wants to
|
||||
* poll, it can send null queries to call this function.
|
||||
*/
|
||||
PQNotifyList *nPtr;
|
||||
MemoryContext orig;
|
||||
|
||||
if (notifyContext == NULL)
|
||||
{
|
||||
notifyContext = CreateGlobalMemory("notify");
|
||||
}
|
||||
orig = MemoryContextSwitchTo((MemoryContext) notifyContext);
|
||||
|
||||
for (nPtr = PQnotifies();
|
||||
nPtr != NULL;
|
||||
nPtr = (PQNotifyList *) SLGetSucc(&nPtr->Node))
|
||||
{
|
||||
pq_putnchar("A", 1);
|
||||
pq_putint(0, 4);
|
||||
pq_putstr(nPtr->relname);
|
||||
pq_putint(nPtr->be_pid, 4);
|
||||
PQremoveNotify(nPtr);
|
||||
}
|
||||
pq_flush();
|
||||
PQcleanNotify(); /* garbage collect */
|
||||
MemoryContextSwitchTo(orig);
|
||||
#endif
|
||||
/* ----------------
|
||||
* tell the fe that the last of the queries has finished
|
||||
* ----------------
|
||||
*/
|
||||
/* pq_putnchar("I", 1); */
|
||||
pq_putstr("I");
|
||||
/* pq_putint(0, 4);*/
|
||||
pq_flush();
|
||||
}
|
||||
break;
|
||||
|
||||
case Local:
|
||||
case Debug:
|
||||
case None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* ----------------
|
||||
* tell the fe that the last of the queries has finished
|
||||
* ----------------
|
||||
*/
|
||||
/* pq_putnchar("I", 1); */
|
||||
pq_putstr("I");
|
||||
/* pq_putint(0, 4); */
|
||||
pq_flush();
|
||||
}
|
||||
break;
|
||||
|
||||
case Local:
|
||||
case Debug:
|
||||
case None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* BeginCommand - prepare destination for tuples of the given type
|
||||
* BeginCommand - prepare destination for tuples of the given type
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
BeginCommand(char *pname,
|
||||
int operation,
|
||||
TupleDesc tupdesc,
|
||||
bool isIntoRel,
|
||||
bool isIntoPortal,
|
||||
char *tag,
|
||||
CommandDest dest)
|
||||
int operation,
|
||||
TupleDesc tupdesc,
|
||||
bool isIntoRel,
|
||||
bool isIntoPortal,
|
||||
char *tag,
|
||||
CommandDest dest)
|
||||
{
|
||||
PortalEntry *entry;
|
||||
AttributeTupleForm *attrs = tupdesc->attrs;
|
||||
int natts = tupdesc->natts;
|
||||
int i;
|
||||
char *p;
|
||||
PortalEntry *entry;
|
||||
AttributeTupleForm *attrs = tupdesc->attrs;
|
||||
int natts = tupdesc->natts;
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
switch (dest) {
|
||||
case RemoteInternal:
|
||||
case Remote:
|
||||
/* ----------------
|
||||
* if this is a "retrieve portal" query, just return
|
||||
* because nothing needs to be sent to the fe.
|
||||
* ----------------
|
||||
*/
|
||||
CommandInfo[0] = 0;
|
||||
if (isIntoPortal)
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* if portal name not specified for remote query,
|
||||
* use the "blank" portal.
|
||||
* ----------------
|
||||
*/
|
||||
if (pname == NULL)
|
||||
pname = "blank";
|
||||
|
||||
/* ----------------
|
||||
* send fe info on tuples we're about to send
|
||||
* ----------------
|
||||
*/
|
||||
pq_flush();
|
||||
pq_putnchar("P", 1); /* new portal.. */
|
||||
pq_putstr(pname); /* portal name */
|
||||
|
||||
/* ----------------
|
||||
* if this is a retrieve, then we send back the tuple
|
||||
* descriptor of the tuples. "retrieve into" is an
|
||||
* exception because no tuples are returned in that case.
|
||||
* ----------------
|
||||
*/
|
||||
if (operation == CMD_SELECT && !isIntoRel) {
|
||||
pq_putnchar("T", 1); /* type info to follow.. */
|
||||
pq_putint(natts, 2); /* number of attributes in tuples */
|
||||
|
||||
for (i = 0; i < natts; ++i) {
|
||||
pq_putstr(attrs[i]->attname.data);/* if 16 char name oops.. */
|
||||
pq_putint((int) attrs[i]->atttypid, 4);
|
||||
pq_putint(attrs[i]->attlen, 2);
|
||||
}
|
||||
switch (dest)
|
||||
{
|
||||
case RemoteInternal:
|
||||
case Remote:
|
||||
/* ----------------
|
||||
* if this is a "retrieve portal" query, just return
|
||||
* because nothing needs to be sent to the fe.
|
||||
* ----------------
|
||||
*/
|
||||
CommandInfo[0] = 0;
|
||||
if (isIntoPortal)
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* if portal name not specified for remote query,
|
||||
* use the "blank" portal.
|
||||
* ----------------
|
||||
*/
|
||||
if (pname == NULL)
|
||||
pname = "blank";
|
||||
|
||||
/* ----------------
|
||||
* send fe info on tuples we're about to send
|
||||
* ----------------
|
||||
*/
|
||||
pq_flush();
|
||||
pq_putnchar("P", 1); /* new portal.. */
|
||||
pq_putstr(pname); /* portal name */
|
||||
|
||||
/* ----------------
|
||||
* if this is a retrieve, then we send back the tuple
|
||||
* descriptor of the tuples. "retrieve into" is an
|
||||
* exception because no tuples are returned in that case.
|
||||
* ----------------
|
||||
*/
|
||||
if (operation == CMD_SELECT && !isIntoRel)
|
||||
{
|
||||
pq_putnchar("T", 1);/* type info to follow.. */
|
||||
pq_putint(natts, 2);/* number of attributes in tuples */
|
||||
|
||||
for (i = 0; i < natts; ++i)
|
||||
{
|
||||
pq_putstr(attrs[i]->attname.data); /* if 16 char name
|
||||
* oops.. */
|
||||
pq_putint((int) attrs[i]->atttypid, 4);
|
||||
pq_putint(attrs[i]->attlen, 2);
|
||||
}
|
||||
}
|
||||
pq_flush();
|
||||
break;
|
||||
|
||||
case Local:
|
||||
/* ----------------
|
||||
* prepare local portal buffer for query results
|
||||
* and setup result for PQexec()
|
||||
* ----------------
|
||||
*/
|
||||
entry = be_currentportal();
|
||||
if (pname != NULL)
|
||||
pbuf_setportalinfo(entry, pname);
|
||||
|
||||
if (operation == CMD_SELECT && !isIntoRel)
|
||||
{
|
||||
be_typeinit(entry, tupdesc, natts);
|
||||
p = (char *) palloc(strlen(entry->name) + 2);
|
||||
p[0] = 'P';
|
||||
strcpy(p + 1, entry->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = (char *) palloc(strlen(tag) + 2);
|
||||
p[0] = 'C';
|
||||
strcpy(p + 1, tag);
|
||||
}
|
||||
entry->result = p;
|
||||
break;
|
||||
|
||||
case Debug:
|
||||
/* ----------------
|
||||
* show the return type of the tuples
|
||||
* ----------------
|
||||
*/
|
||||
if (pname == NULL)
|
||||
pname = "blank";
|
||||
|
||||
showatts(pname, tupdesc);
|
||||
break;
|
||||
|
||||
case None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pq_flush();
|
||||
break;
|
||||
|
||||
case Local:
|
||||
/* ----------------
|
||||
* prepare local portal buffer for query results
|
||||
* and setup result for PQexec()
|
||||
* ----------------
|
||||
*/
|
||||
entry = be_currentportal();
|
||||
if (pname != NULL)
|
||||
pbuf_setportalinfo(entry, pname);
|
||||
|
||||
if (operation == CMD_SELECT && !isIntoRel) {
|
||||
be_typeinit(entry, tupdesc, natts);
|
||||
p = (char *) palloc(strlen(entry->name)+2);
|
||||
p[0] = 'P';
|
||||
strcpy(p+1,entry->name);
|
||||
} else {
|
||||
p = (char *) palloc(strlen(tag)+2);
|
||||
p[0] = 'C';
|
||||
strcpy(p+1,tag);
|
||||
}
|
||||
entry->result = p;
|
||||
break;
|
||||
|
||||
case Debug:
|
||||
/* ----------------
|
||||
* show the return type of the tuples
|
||||
* ----------------
|
||||
*/
|
||||
if (pname == NULL)
|
||||
pname = "blank";
|
||||
|
||||
showatts(pname, tupdesc);
|
||||
break;
|
||||
|
||||
case None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UpdateCommandInfo (int operation, Oid lastoid, uint32 tuples)
|
||||
UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples)
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case CMD_INSERT :
|
||||
if ( tuples > 1 )
|
||||
lastoid = InvalidOid;
|
||||
sprintf (CommandInfo, " %u %u", lastoid, tuples);
|
||||
break;
|
||||
case CMD_DELETE :
|
||||
case CMD_UPDATE :
|
||||
sprintf (CommandInfo, " %u", tuples);
|
||||
break;
|
||||
default :
|
||||
CommandInfo[0] = 0;
|
||||
}
|
||||
return;
|
||||
switch (operation)
|
||||
{
|
||||
case CMD_INSERT:
|
||||
if (tuples > 1)
|
||||
lastoid = InvalidOid;
|
||||
sprintf(CommandInfo, " %u %u", lastoid, tuples);
|
||||
break;
|
||||
case CMD_DELETE:
|
||||
case CMD_UPDATE:
|
||||
sprintf(CommandInfo, " %u", tuples);
|
||||
break;
|
||||
default:
|
||||
CommandInfo[0] = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,59 +1,59 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* fastpath.c--
|
||||
* routines to handle function requests from the frontend
|
||||
* routines to handle function requests from the frontend
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.4 1997/03/12 21:07:50 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.5 1997/09/07 04:49:32 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This cruft is the server side of PQfn.
|
||||
* This cruft is the server side of PQfn.
|
||||
*
|
||||
* - jolly 07/11/95:
|
||||
* - jolly 07/11/95:
|
||||
*
|
||||
* no longer rely on return sizes provided by the frontend. Always
|
||||
* use the true lengths for the catalogs. Assume that the frontend
|
||||
* has allocated enough space to handle the result value returned.
|
||||
*
|
||||
* trust that the user knows what he is doing with the args. If the
|
||||
* sys catalog says it is a varlena, assume that the user is only sending
|
||||
* down VARDATA and that the argsize is the VARSIZE. If the arg is
|
||||
* fixed len, assume that the argsize given by the user is correct.
|
||||
*
|
||||
* if the function returns by value, then only send 4 bytes value
|
||||
* back to the frontend. If the return returns by reference,
|
||||
* send down only the data portion and set the return size appropriately.
|
||||
*
|
||||
* OLD COMMENTS FOLLOW
|
||||
* no longer rely on return sizes provided by the frontend. Always
|
||||
* use the true lengths for the catalogs. Assume that the frontend
|
||||
* has allocated enough space to handle the result value returned.
|
||||
*
|
||||
* The VAR_LENGTH_{ARGS,RESULT} stuff is limited to MAX_STRING_LENGTH
|
||||
* (see src/backend/tmp/fastpath.h) for no obvious reason. Since its
|
||||
* primary use (for us) is for Inversion path names, it should probably
|
||||
* be increased to 256 (MAXPATHLEN for Inversion, hidden in pg_type
|
||||
* as well as utils/adt/filename.c).
|
||||
* trust that the user knows what he is doing with the args. If the
|
||||
* sys catalog says it is a varlena, assume that the user is only sending
|
||||
* down VARDATA and that the argsize is the VARSIZE. If the arg is
|
||||
* fixed len, assume that the argsize given by the user is correct.
|
||||
*
|
||||
* Quoth PMA on 08/15/93:
|
||||
* if the function returns by value, then only send 4 bytes value
|
||||
* back to the frontend. If the return returns by reference,
|
||||
* send down only the data portion and set the return size appropriately.
|
||||
*
|
||||
* This code has been almost completely rewritten with an eye to
|
||||
* keeping it as compatible as possible with the previous (broken)
|
||||
* implementation.
|
||||
* OLD COMMENTS FOLLOW
|
||||
*
|
||||
* The previous implementation would assume (1) that any value of
|
||||
* length <= 4 bytes was passed-by-value, and that any other value
|
||||
* was a struct varlena (by-reference). There was NO way to pass a
|
||||
* fixed-length by-reference argument (like char16) or a struct
|
||||
* varlena of size <= 4 bytes.
|
||||
*
|
||||
* The new implementation checks the catalogs to determine whether
|
||||
* a value is by-value (type "0" is null-delimited character string,
|
||||
* as it is for, e.g., the parser). The only other item obtained
|
||||
* from the catalogs is whether or not the value should be placed in
|
||||
* a struct varlena or not. Otherwise, the size given by the
|
||||
* frontend is assumed to be correct (probably a bad decision, but
|
||||
* we do strange things in the name of compatibility).
|
||||
* The VAR_LENGTH_{ARGS,RESULT} stuff is limited to MAX_STRING_LENGTH
|
||||
* (see src/backend/tmp/fastpath.h) for no obvious reason. Since its
|
||||
* primary use (for us) is for Inversion path names, it should probably
|
||||
* be increased to 256 (MAXPATHLEN for Inversion, hidden in pg_type
|
||||
* as well as utils/adt/filename.c).
|
||||
*
|
||||
* Quoth PMA on 08/15/93:
|
||||
*
|
||||
* This code has been almost completely rewritten with an eye to
|
||||
* keeping it as compatible as possible with the previous (broken)
|
||||
* implementation.
|
||||
*
|
||||
* The previous implementation would assume (1) that any value of
|
||||
* length <= 4 bytes was passed-by-value, and that any other value
|
||||
* was a struct varlena (by-reference). There was NO way to pass a
|
||||
* fixed-length by-reference argument (like char16) or a struct
|
||||
* varlena of size <= 4 bytes.
|
||||
*
|
||||
* The new implementation checks the catalogs to determine whether
|
||||
* a value is by-value (type "0" is null-delimited character string,
|
||||
* as it is for, e.g., the parser). The only other item obtained
|
||||
* from the catalogs is whether or not the value should be placed in
|
||||
* a struct varlena or not. Otherwise, the size given by the
|
||||
* frontend is assumed to be correct (probably a bad decision, but
|
||||
* we do strange things in the name of compatibility).
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -65,11 +65,11 @@
|
||||
|
||||
#include "utils/palloc.h"
|
||||
#include "fmgr.h"
|
||||
#include "utils/builtins.h" /* for oideq */
|
||||
#include "utils/builtins.h" /* for oideq */
|
||||
#include "tcop/fastpath.h"
|
||||
#include "libpq/libpq.h"
|
||||
|
||||
#include "access/xact.h" /* for TransactionId/CommandId protos */
|
||||
#include "access/xact.h" /* for TransactionId/CommandId protos */
|
||||
|
||||
#include "utils/syscache.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
@@ -77,90 +77,98 @@
|
||||
|
||||
|
||||
/* ----------------
|
||||
* SendFunctionResult
|
||||
* SendFunctionResult
|
||||
* ----------------
|
||||
*/
|
||||
static void
|
||||
SendFunctionResult(Oid fid, /* function id */
|
||||
char *retval, /* actual return value */
|
||||
bool retbyval,
|
||||
int retlen /* the length according to the catalogs */
|
||||
)
|
||||
SendFunctionResult(Oid fid, /* function id */
|
||||
char *retval,/* actual return value */
|
||||
bool retbyval,
|
||||
int retlen /* the length according to the catalogs */
|
||||
)
|
||||
{
|
||||
pq_putnchar("V", 1);
|
||||
|
||||
if (retlen != 0) {
|
||||
pq_putnchar("G", 1);
|
||||
if (retbyval) { /* by-value */
|
||||
pq_putint(retlen, 4);
|
||||
pq_putint((int)(Datum)retval, retlen);
|
||||
} else { /* by-reference ... */
|
||||
if (retlen < 0) { /* ... varlena */
|
||||
pq_putint(VARSIZE(retval) - VARHDRSZ, 4);
|
||||
pq_putnchar(VARDATA(retval), VARSIZE(retval) - VARHDRSZ);
|
||||
} else { /* ... fixed */
|
||||
pq_putint(retlen, 4);
|
||||
pq_putnchar(retval, retlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
pq_putnchar("V", 1);
|
||||
|
||||
pq_putnchar("0", 1);
|
||||
pq_flush();
|
||||
if (retlen != 0)
|
||||
{
|
||||
pq_putnchar("G", 1);
|
||||
if (retbyval)
|
||||
{ /* by-value */
|
||||
pq_putint(retlen, 4);
|
||||
pq_putint((int) (Datum) retval, retlen);
|
||||
}
|
||||
else
|
||||
{ /* by-reference ... */
|
||||
if (retlen < 0)
|
||||
{ /* ... varlena */
|
||||
pq_putint(VARSIZE(retval) - VARHDRSZ, 4);
|
||||
pq_putnchar(VARDATA(retval), VARSIZE(retval) - VARHDRSZ);
|
||||
}
|
||||
else
|
||||
{ /* ... fixed */
|
||||
pq_putint(retlen, 4);
|
||||
pq_putnchar(retval, retlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pq_putnchar("0", 1);
|
||||
pq_flush();
|
||||
}
|
||||
|
||||
/*
|
||||
* This structure saves enough state so that one can avoid having to
|
||||
* do catalog lookups over and over again. (Each RPC can require up
|
||||
* do catalog lookups over and over again. (Each RPC can require up
|
||||
* to MAXFMGRARGS+2 lookups, which is quite tedious.)
|
||||
*
|
||||
* The previous incarnation of this code just assumed that any argument
|
||||
* of size <= 4 was by value; this is not correct. There is no cheap
|
||||
* of size <= 4 was by value; this is not correct. There is no cheap
|
||||
* way to determine function argument length etc.; one must simply pay
|
||||
* the price of catalog lookups.
|
||||
*/
|
||||
struct fp_info {
|
||||
Oid funcid;
|
||||
int nargs;
|
||||
bool argbyval[MAXFMGRARGS];
|
||||
int32 arglen[MAXFMGRARGS]; /* signed (for varlena) */
|
||||
bool retbyval;
|
||||
int32 retlen; /* signed (for varlena) */
|
||||
TransactionId xid;
|
||||
CommandId cid;
|
||||
struct fp_info
|
||||
{
|
||||
Oid funcid;
|
||||
int nargs;
|
||||
bool argbyval[MAXFMGRARGS];
|
||||
int32 arglen[MAXFMGRARGS]; /* signed (for varlena) */
|
||||
bool retbyval;
|
||||
int32 retlen; /* signed (for varlena) */
|
||||
TransactionId xid;
|
||||
CommandId cid;
|
||||
};
|
||||
|
||||
/*
|
||||
* We implement one-back caching here. If we need to do more, we can.
|
||||
* We implement one-back caching here. If we need to do more, we can.
|
||||
* Most routines in tight loops (like PQfswrite -> F_LOWRITE) will do
|
||||
* the same thing repeatedly.
|
||||
*/
|
||||
static struct fp_info last_fp = { InvalidOid };
|
||||
static struct fp_info last_fp = {InvalidOid};
|
||||
|
||||
/*
|
||||
* valid_fp_info
|
||||
*
|
||||
* RETURNS:
|
||||
* 1 if the state in 'fip' is valid
|
||||
* 0 otherwise
|
||||
* 1 if the state in 'fip' is valid
|
||||
* 0 otherwise
|
||||
*
|
||||
* "valid" means:
|
||||
* The saved state was either uninitialized, for another function,
|
||||
* or from a previous command. (Commands can do updates, which
|
||||
* may invalidate catalog entries for subsequent commands. This
|
||||
* or from a previous command. (Commands can do updates, which
|
||||
* may invalidate catalog entries for subsequent commands. This
|
||||
* is overly pessimistic but since there is no smarter invalidation
|
||||
* scheme...).
|
||||
*/
|
||||
static int
|
||||
valid_fp_info(Oid func_id, struct fp_info *fip)
|
||||
valid_fp_info(Oid func_id, struct fp_info * fip)
|
||||
{
|
||||
Assert(OidIsValid(func_id));
|
||||
Assert(fip != (struct fp_info *) NULL);
|
||||
|
||||
return(OidIsValid(fip->funcid) &&
|
||||
oideq(func_id, fip->funcid) &&
|
||||
TransactionIdIsCurrentTransactionId(fip->xid) &&
|
||||
CommandIdIsCurrentCommandId(fip->cid));
|
||||
Assert(OidIsValid(func_id));
|
||||
Assert(fip != (struct fp_info *) NULL);
|
||||
|
||||
return (OidIsValid(fip->funcid) &&
|
||||
oideq(func_id, fip->funcid) &&
|
||||
TransactionIdIsCurrentTransactionId(fip->xid) &&
|
||||
CommandIdIsCurrentCommandId(fip->cid));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -170,79 +178,86 @@ valid_fp_info(Oid func_id, struct fp_info *fip)
|
||||
* function 'func_id'.
|
||||
*
|
||||
* RETURNS:
|
||||
* The correct information in 'fip'. Sets 'fip->funcid' to
|
||||
* InvalidOid if an exception occurs.
|
||||
* The correct information in 'fip'. Sets 'fip->funcid' to
|
||||
* InvalidOid if an exception occurs.
|
||||
*/
|
||||
static void
|
||||
update_fp_info(Oid func_id, struct fp_info *fip)
|
||||
update_fp_info(Oid func_id, struct fp_info * fip)
|
||||
{
|
||||
Oid *argtypes; /* an oid8 */
|
||||
Oid rettype;
|
||||
HeapTuple func_htp, type_htp;
|
||||
TypeTupleForm tp;
|
||||
Form_pg_proc pp;
|
||||
int i;
|
||||
|
||||
Assert(OidIsValid(func_id));
|
||||
Assert(fip != (struct fp_info *) NULL);
|
||||
Oid *argtypes; /* an oid8 */
|
||||
Oid rettype;
|
||||
HeapTuple func_htp,
|
||||
type_htp;
|
||||
TypeTupleForm tp;
|
||||
Form_pg_proc pp;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Since the validity of this structure is determined by whether
|
||||
* the funcid is OK, we clear the funcid here. It must not be
|
||||
* set to the correct value until we are about to return with
|
||||
* a good struct fp_info, since we can be interrupted (i.e., with
|
||||
* an elog(WARN, ...)) at any time.
|
||||
*/
|
||||
memset((char *) fip, 0, (int) sizeof(struct fp_info));
|
||||
fip->funcid = InvalidOid;
|
||||
Assert(OidIsValid(func_id));
|
||||
Assert(fip != (struct fp_info *) NULL);
|
||||
|
||||
func_htp = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(func_id),
|
||||
0,0,0);
|
||||
if (!HeapTupleIsValid(func_htp)) {
|
||||
elog(WARN, "update_fp_info: cache lookup for function %d failed",
|
||||
func_id);
|
||||
}
|
||||
pp = (Form_pg_proc) GETSTRUCT(func_htp);
|
||||
fip->nargs = pp->pronargs;
|
||||
rettype = pp->prorettype;
|
||||
argtypes = pp->proargtypes;
|
||||
/*
|
||||
* Since the validity of this structure is determined by whether the
|
||||
* funcid is OK, we clear the funcid here. It must not be set to the
|
||||
* correct value until we are about to return with a good struct
|
||||
* fp_info, since we can be interrupted (i.e., with an elog(WARN,
|
||||
* ...)) at any time.
|
||||
*/
|
||||
memset((char *) fip, 0, (int) sizeof(struct fp_info));
|
||||
fip->funcid = InvalidOid;
|
||||
|
||||
for (i = 0; i < fip->nargs; ++i) {
|
||||
if (OidIsValid(argtypes[i])) {
|
||||
type_htp = SearchSysCacheTuple(TYPOID,
|
||||
ObjectIdGetDatum(argtypes[i]),
|
||||
0,0,0);
|
||||
if (!HeapTupleIsValid(type_htp)) {
|
||||
elog(WARN, "update_fp_info: bad argument type %d for %d",
|
||||
argtypes[i], func_id);
|
||||
}
|
||||
tp = (TypeTupleForm) GETSTRUCT(type_htp);
|
||||
fip->argbyval[i] = tp->typbyval;
|
||||
fip->arglen[i] = tp->typlen;
|
||||
} /* else it had better be VAR_LENGTH_ARG */
|
||||
}
|
||||
|
||||
if (OidIsValid(rettype)) {
|
||||
type_htp = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(rettype),
|
||||
0,0,0);
|
||||
if (!HeapTupleIsValid(type_htp)) {
|
||||
elog(WARN, "update_fp_info: bad return type %d for %d",
|
||||
rettype, func_id);
|
||||
func_htp = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(func_id),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(func_htp))
|
||||
{
|
||||
elog(WARN, "update_fp_info: cache lookup for function %d failed",
|
||||
func_id);
|
||||
}
|
||||
tp = (TypeTupleForm) GETSTRUCT(type_htp);
|
||||
fip->retbyval = tp->typbyval;
|
||||
fip->retlen = tp->typlen;
|
||||
} /* else it had better by VAR_LENGTH_RESULT */
|
||||
pp = (Form_pg_proc) GETSTRUCT(func_htp);
|
||||
fip->nargs = pp->pronargs;
|
||||
rettype = pp->prorettype;
|
||||
argtypes = pp->proargtypes;
|
||||
|
||||
fip->xid = GetCurrentTransactionId();
|
||||
fip->cid = GetCurrentCommandId();
|
||||
for (i = 0; i < fip->nargs; ++i)
|
||||
{
|
||||
if (OidIsValid(argtypes[i]))
|
||||
{
|
||||
type_htp = SearchSysCacheTuple(TYPOID,
|
||||
ObjectIdGetDatum(argtypes[i]),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(type_htp))
|
||||
{
|
||||
elog(WARN, "update_fp_info: bad argument type %d for %d",
|
||||
argtypes[i], func_id);
|
||||
}
|
||||
tp = (TypeTupleForm) GETSTRUCT(type_htp);
|
||||
fip->argbyval[i] = tp->typbyval;
|
||||
fip->arglen[i] = tp->typlen;
|
||||
} /* else it had better be VAR_LENGTH_ARG */
|
||||
}
|
||||
|
||||
/*
|
||||
* This must be last!
|
||||
*/
|
||||
fip->funcid = func_id;
|
||||
if (OidIsValid(rettype))
|
||||
{
|
||||
type_htp = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(rettype),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(type_htp))
|
||||
{
|
||||
elog(WARN, "update_fp_info: bad return type %d for %d",
|
||||
rettype, func_id);
|
||||
}
|
||||
tp = (TypeTupleForm) GETSTRUCT(type_htp);
|
||||
fip->retbyval = tp->typbyval;
|
||||
fip->retlen = tp->typlen;
|
||||
} /* else it had better by VAR_LENGTH_RESULT */
|
||||
|
||||
fip->xid = GetCurrentTransactionId();
|
||||
fip->cid = GetCurrentCommandId();
|
||||
|
||||
/*
|
||||
* This must be last!
|
||||
*/
|
||||
fip->funcid = func_id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* HandleFunctionRequest
|
||||
@@ -251,104 +266,119 @@ update_fp_info(Oid func_id, struct fp_info *fip)
|
||||
* This corresponds to the libpq protocol symbol "F".
|
||||
*
|
||||
* RETURNS:
|
||||
* nothing of significance.
|
||||
* All errors result in elog(WARN,...).
|
||||
* nothing of significance.
|
||||
* All errors result in elog(WARN,...).
|
||||
*/
|
||||
int
|
||||
HandleFunctionRequest()
|
||||
{
|
||||
Oid fid;
|
||||
int argsize;
|
||||
int nargs;
|
||||
char *arg[8];
|
||||
char *retval;
|
||||
int i;
|
||||
uint32 palloced;
|
||||
char *p;
|
||||
struct fp_info *fip;
|
||||
Oid fid;
|
||||
int argsize;
|
||||
int nargs;
|
||||
char *arg[8];
|
||||
char *retval;
|
||||
int i;
|
||||
uint32 palloced;
|
||||
char *p;
|
||||
struct fp_info *fip;
|
||||
|
||||
fid = (Oid) pq_getint(4); /* function oid */
|
||||
nargs = pq_getint(4); /* # of arguments */
|
||||
fid = (Oid) pq_getint(4); /* function oid */
|
||||
nargs = pq_getint(4); /* # of arguments */
|
||||
|
||||
/*
|
||||
* This is where the one-back caching is done.
|
||||
* If you want to save more state, make this a loop around an array.
|
||||
*/
|
||||
fip = &last_fp;
|
||||
if (!valid_fp_info(fid, fip)) {
|
||||
update_fp_info(fid, fip);
|
||||
}
|
||||
|
||||
if (fip->nargs != nargs) {
|
||||
elog(WARN, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)",
|
||||
nargs, fip->nargs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy arguments into arg vector. If we palloc() an argument, we need
|
||||
* to remember, so that we pfree() it after the call.
|
||||
*/
|
||||
palloced = 0x0;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
if (i >= nargs) {
|
||||
arg[i] = (char *) NULL;
|
||||
} else {
|
||||
argsize = pq_getint(4);
|
||||
|
||||
Assert(argsize > 0);
|
||||
if (fip->argbyval[i]) { /* by-value */
|
||||
Assert(argsize <= 4);
|
||||
arg[i] = (char *) pq_getint(argsize);
|
||||
} else { /* by-reference ... */
|
||||
if (fip->arglen[i] < 0) { /* ... varlena */
|
||||
if (!(p = palloc(argsize + VARHDRSZ))) {
|
||||
elog(WARN, "HandleFunctionRequest: palloc failed");
|
||||
}
|
||||
VARSIZE(p) = argsize + VARHDRSZ;
|
||||
pq_getnchar(VARDATA(p), 0, argsize);
|
||||
} else { /* ... fixed */
|
||||
/* XXX cross our fingers and trust "argsize" */
|
||||
if (!(p = palloc(argsize))) {
|
||||
elog(WARN, "HandleFunctionRequest: palloc failed");
|
||||
}
|
||||
pq_getnchar(p, 0, argsize);
|
||||
}
|
||||
palloced |= (1 << i);
|
||||
arg[i] = p;
|
||||
}
|
||||
/*
|
||||
* This is where the one-back caching is done. If you want to save
|
||||
* more state, make this a loop around an array.
|
||||
*/
|
||||
fip = &last_fp;
|
||||
if (!valid_fp_info(fid, fip))
|
||||
{
|
||||
update_fp_info(fid, fip);
|
||||
}
|
||||
|
||||
if (fip->nargs != nargs)
|
||||
{
|
||||
elog(WARN, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)",
|
||||
nargs, fip->nargs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy arguments into arg vector. If we palloc() an argument, we
|
||||
* need to remember, so that we pfree() it after the call.
|
||||
*/
|
||||
palloced = 0x0;
|
||||
for (i = 0; i < 8; ++i)
|
||||
{
|
||||
if (i >= nargs)
|
||||
{
|
||||
arg[i] = (char *) NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
argsize = pq_getint(4);
|
||||
|
||||
Assert(argsize > 0);
|
||||
if (fip->argbyval[i])
|
||||
{ /* by-value */
|
||||
Assert(argsize <= 4);
|
||||
arg[i] = (char *) pq_getint(argsize);
|
||||
}
|
||||
else
|
||||
{ /* by-reference ... */
|
||||
if (fip->arglen[i] < 0)
|
||||
{ /* ... varlena */
|
||||
if (!(p = palloc(argsize + VARHDRSZ)))
|
||||
{
|
||||
elog(WARN, "HandleFunctionRequest: palloc failed");
|
||||
}
|
||||
VARSIZE(p) = argsize + VARHDRSZ;
|
||||
pq_getnchar(VARDATA(p), 0, argsize);
|
||||
}
|
||||
else
|
||||
{ /* ... fixed */
|
||||
/* XXX cross our fingers and trust "argsize" */
|
||||
if (!(p = palloc(argsize)))
|
||||
{
|
||||
elog(WARN, "HandleFunctionRequest: palloc failed");
|
||||
}
|
||||
pq_getnchar(p, 0, argsize);
|
||||
}
|
||||
palloced |= (1 << i);
|
||||
arg[i] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_FASTPATH
|
||||
retval = fmgr(fid,
|
||||
arg[0], arg[1], arg[2], arg[3],
|
||||
arg[4], arg[5], arg[6], arg[7]);
|
||||
retval = fmgr(fid,
|
||||
arg[0], arg[1], arg[2], arg[3],
|
||||
arg[4], arg[5], arg[6], arg[7]);
|
||||
|
||||
#else
|
||||
retval = NULL;
|
||||
#endif /* NO_FASTPATH */
|
||||
retval = NULL;
|
||||
#endif /* NO_FASTPATH */
|
||||
|
||||
/* free palloc'ed arguments */
|
||||
for (i = 0; i < nargs; ++i) {
|
||||
if (palloced & (1 << i))
|
||||
pfree(arg[i]);
|
||||
}
|
||||
/* free palloc'ed arguments */
|
||||
for (i = 0; i < nargs; ++i)
|
||||
{
|
||||
if (palloced & (1 << i))
|
||||
pfree(arg[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is an ordinary query (not a retrieve portal p ...), then
|
||||
* we return the data to the user. If the return value was palloc'ed,
|
||||
* then it must also be freed.
|
||||
*/
|
||||
/*
|
||||
* If this is an ordinary query (not a retrieve portal p ...), then we
|
||||
* return the data to the user. If the return value was palloc'ed,
|
||||
* then it must also be freed.
|
||||
*/
|
||||
#ifndef NO_FASTPATH
|
||||
SendFunctionResult(fid, retval, fip->retbyval, fip->retlen);
|
||||
SendFunctionResult(fid, retval, fip->retbyval, fip->retlen);
|
||||
#else
|
||||
SendFunctionResult(fid, retval, fip->retbyval, 0);
|
||||
#endif /* NO_FASTPATH */
|
||||
SendFunctionResult(fid, retval, fip->retbyval, 0);
|
||||
#endif /* NO_FASTPATH */
|
||||
|
||||
if (!fip->retbyval)
|
||||
pfree(retval);
|
||||
if (!fip->retbyval)
|
||||
pfree(retval);
|
||||
|
||||
|
||||
|
||||
return(0);
|
||||
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pquery.c--
|
||||
* POSTGRES process query command code
|
||||
* POSTGRES process query command code
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.7 1997/08/27 09:03:15 vadim Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.8 1997/09/07 04:49:35 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -38,332 +38,341 @@
|
||||
|
||||
#include "commands/command.h"
|
||||
|
||||
static char* CreateOperationTag(int operationType);
|
||||
static void ProcessQueryDesc(QueryDesc *queryDesc);
|
||||
static char *CreateOperationTag(int operationType);
|
||||
static void ProcessQueryDesc(QueryDesc * queryDesc);
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* CreateQueryDesc
|
||||
* CreateQueryDesc
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
QueryDesc *
|
||||
CreateQueryDesc(Query *parsetree,
|
||||
Plan *plantree,
|
||||
CommandDest dest)
|
||||
QueryDesc *
|
||||
CreateQueryDesc(Query * parsetree,
|
||||
Plan * plantree,
|
||||
CommandDest dest)
|
||||
{
|
||||
QueryDesc *qd = (QueryDesc *)palloc(sizeof(QueryDesc));
|
||||
|
||||
qd->operation = parsetree->commandType; /* operation */
|
||||
qd->parsetree = parsetree; /* parse tree */
|
||||
qd->plantree = plantree; /* plan */
|
||||
qd->dest = dest; /* output dest */
|
||||
return qd;
|
||||
QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
|
||||
|
||||
qd->operation = parsetree->commandType; /* operation */
|
||||
qd->parsetree = parsetree; /* parse tree */
|
||||
qd->plantree = plantree; /* plan */
|
||||
qd->dest = dest; /* output dest */
|
||||
return qd;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* CreateExecutorState
|
||||
* CreateExecutorState
|
||||
*
|
||||
* Note: this may someday take parameters -cim 9/18/89
|
||||
* Note: this may someday take parameters -cim 9/18/89
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
EState *
|
||||
EState *
|
||||
CreateExecutorState(void)
|
||||
{
|
||||
EState *state;
|
||||
extern int NBuffers;
|
||||
long *refcount;
|
||||
|
||||
/* ----------------
|
||||
* create a new executor state
|
||||
* ----------------
|
||||
*/
|
||||
state = makeNode(EState);
|
||||
|
||||
/* ----------------
|
||||
* initialize the Executor State structure
|
||||
* ----------------
|
||||
*/
|
||||
state->es_direction = ForwardScanDirection;
|
||||
state->es_range_table = NIL;
|
||||
EState *state;
|
||||
extern int NBuffers;
|
||||
long *refcount;
|
||||
|
||||
state->es_into_relation_descriptor = NULL;
|
||||
state->es_result_relation_info = NULL;
|
||||
|
||||
state->es_param_list_info = NULL;
|
||||
|
||||
state->es_BaseId = 0;
|
||||
state->es_tupleTable = NULL;
|
||||
|
||||
state->es_junkFilter = NULL;
|
||||
|
||||
refcount = (long *) palloc(NBuffers * sizeof(long));
|
||||
memset((char *) refcount, 0, NBuffers * sizeof(long));
|
||||
state->es_refcount = (int *) refcount;
|
||||
|
||||
/* ----------------
|
||||
* return the executor state structure
|
||||
* ----------------
|
||||
*/
|
||||
return state;
|
||||
/* ----------------
|
||||
* create a new executor state
|
||||
* ----------------
|
||||
*/
|
||||
state = makeNode(EState);
|
||||
|
||||
/* ----------------
|
||||
* initialize the Executor State structure
|
||||
* ----------------
|
||||
*/
|
||||
state->es_direction = ForwardScanDirection;
|
||||
state->es_range_table = NIL;
|
||||
|
||||
state->es_into_relation_descriptor = NULL;
|
||||
state->es_result_relation_info = NULL;
|
||||
|
||||
state->es_param_list_info = NULL;
|
||||
|
||||
state->es_BaseId = 0;
|
||||
state->es_tupleTable = NULL;
|
||||
|
||||
state->es_junkFilter = NULL;
|
||||
|
||||
refcount = (long *) palloc(NBuffers * sizeof(long));
|
||||
memset((char *) refcount, 0, NBuffers * sizeof(long));
|
||||
state->es_refcount = (int *) refcount;
|
||||
|
||||
/* ----------------
|
||||
* return the executor state structure
|
||||
* ----------------
|
||||
*/
|
||||
return state;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* CreateOperationTag
|
||||
* CreateOperationTag
|
||||
*
|
||||
* utility to get a string representation of the
|
||||
* query operation.
|
||||
* utility to get a string representation of the
|
||||
* query operation.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static char*
|
||||
static char *
|
||||
CreateOperationTag(int operationType)
|
||||
{
|
||||
char* tag;
|
||||
|
||||
switch (operationType) {
|
||||
case CMD_SELECT:
|
||||
tag = "SELECT";
|
||||
break;
|
||||
case CMD_INSERT:
|
||||
tag = "INSERT";
|
||||
break;
|
||||
case CMD_DELETE:
|
||||
tag = "DELETE";
|
||||
break;
|
||||
case CMD_UPDATE:
|
||||
tag = "UPDATE";
|
||||
break;
|
||||
default:
|
||||
elog(DEBUG, "CreateOperationTag: unknown operation type %d",
|
||||
operationType);
|
||||
tag = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return tag;
|
||||
char *tag;
|
||||
|
||||
switch (operationType)
|
||||
{
|
||||
case CMD_SELECT:
|
||||
tag = "SELECT";
|
||||
break;
|
||||
case CMD_INSERT:
|
||||
tag = "INSERT";
|
||||
break;
|
||||
case CMD_DELETE:
|
||||
tag = "DELETE";
|
||||
break;
|
||||
case CMD_UPDATE:
|
||||
tag = "UPDATE";
|
||||
break;
|
||||
default:
|
||||
elog(DEBUG, "CreateOperationTag: unknown operation type %d",
|
||||
operationType);
|
||||
tag = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* ProcessPortal
|
||||
* ProcessPortal
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
void
|
||||
ProcessPortal(char* portalName,
|
||||
Query *parseTree,
|
||||
Plan *plan,
|
||||
EState *state,
|
||||
TupleDesc attinfo,
|
||||
CommandDest dest)
|
||||
ProcessPortal(char *portalName,
|
||||
Query * parseTree,
|
||||
Plan * plan,
|
||||
EState * state,
|
||||
TupleDesc attinfo,
|
||||
CommandDest dest)
|
||||
{
|
||||
Portal portal;
|
||||
MemoryContext portalContext;
|
||||
|
||||
/* ----------------
|
||||
* convert the current blank portal into the user-specified
|
||||
* portal and initialize the state and query descriptor.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
if (PortalNameIsSpecial(portalName))
|
||||
elog(WARN,
|
||||
"The portal name %s is reserved for internal use",
|
||||
portalName);
|
||||
|
||||
portal = BlankPortalAssignName(portalName);
|
||||
|
||||
PortalSetQuery(portal,
|
||||
CreateQueryDesc(parseTree, plan, dest),
|
||||
attinfo,
|
||||
state,
|
||||
PortalCleanup);
|
||||
|
||||
/* ----------------
|
||||
* now create a new blank portal and switch to it.
|
||||
* Otherwise, the new named portal will be cleaned.
|
||||
*
|
||||
* Note: portals will only be supported within a BEGIN...END
|
||||
* block in the near future. Later, someone will fix it to
|
||||
* do what is possible across transaction boundries. -hirohama
|
||||
* ----------------
|
||||
*/
|
||||
portalContext = (MemoryContext)
|
||||
PortalGetHeapMemory(GetPortalByName(NULL));
|
||||
|
||||
MemoryContextSwitchTo(portalContext);
|
||||
|
||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||
Portal portal;
|
||||
MemoryContext portalContext;
|
||||
|
||||
/* ----------------
|
||||
* convert the current blank portal into the user-specified
|
||||
* portal and initialize the state and query descriptor.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
if (PortalNameIsSpecial(portalName))
|
||||
elog(WARN,
|
||||
"The portal name %s is reserved for internal use",
|
||||
portalName);
|
||||
|
||||
portal = BlankPortalAssignName(portalName);
|
||||
|
||||
PortalSetQuery(portal,
|
||||
CreateQueryDesc(parseTree, plan, dest),
|
||||
attinfo,
|
||||
state,
|
||||
PortalCleanup);
|
||||
|
||||
/* ----------------
|
||||
* now create a new blank portal and switch to it.
|
||||
* Otherwise, the new named portal will be cleaned.
|
||||
*
|
||||
* Note: portals will only be supported within a BEGIN...END
|
||||
* block in the near future. Later, someone will fix it to
|
||||
* do what is possible across transaction boundries. -hirohama
|
||||
* ----------------
|
||||
*/
|
||||
portalContext = (MemoryContext)
|
||||
PortalGetHeapMemory(GetPortalByName(NULL));
|
||||
|
||||
MemoryContextSwitchTo(portalContext);
|
||||
|
||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ProcessQueryDesc
|
||||
* ProcessQueryDesc
|
||||
*
|
||||
* Read the comments for ProcessQuery() below...
|
||||
* Read the comments for ProcessQuery() below...
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
ProcessQueryDesc(QueryDesc *queryDesc)
|
||||
ProcessQueryDesc(QueryDesc * queryDesc)
|
||||
{
|
||||
Query *parseTree;
|
||||
Plan *plan;
|
||||
int operation;
|
||||
char* tag;
|
||||
EState *state;
|
||||
TupleDesc attinfo;
|
||||
|
||||
bool isRetrieveIntoPortal;
|
||||
bool isRetrieveIntoRelation;
|
||||
char* intoName = NULL;
|
||||
CommandDest dest;
|
||||
|
||||
/* ----------------
|
||||
* get info from the query desc
|
||||
* ----------------
|
||||
*/
|
||||
parseTree = queryDesc->parsetree;
|
||||
plan = queryDesc->plantree;
|
||||
|
||||
operation = queryDesc->operation;
|
||||
tag = CreateOperationTag(operation);
|
||||
dest = queryDesc->dest;
|
||||
|
||||
/* ----------------
|
||||
* initialize portal/into relation status
|
||||
* ----------------
|
||||
*/
|
||||
isRetrieveIntoPortal = false;
|
||||
isRetrieveIntoRelation = false;
|
||||
|
||||
if (operation == CMD_SELECT) {
|
||||
if (parseTree->isPortal) {
|
||||
isRetrieveIntoPortal = true;
|
||||
intoName = parseTree->into;
|
||||
if (parseTree->isBinary) {
|
||||
/*
|
||||
* For internal format portals, we change Remote
|
||||
* (externalized form) to RemoteInternal (internalized
|
||||
* form)
|
||||
*/
|
||||
dest = queryDesc->dest = RemoteInternal;
|
||||
}
|
||||
} else if (parseTree->into != NULL) {
|
||||
/* select into table */
|
||||
isRetrieveIntoRelation = true;
|
||||
Query *parseTree;
|
||||
Plan *plan;
|
||||
int operation;
|
||||
char *tag;
|
||||
EState *state;
|
||||
TupleDesc attinfo;
|
||||
|
||||
bool isRetrieveIntoPortal;
|
||||
bool isRetrieveIntoRelation;
|
||||
char *intoName = NULL;
|
||||
CommandDest dest;
|
||||
|
||||
/* ----------------
|
||||
* get info from the query desc
|
||||
* ----------------
|
||||
*/
|
||||
parseTree = queryDesc->parsetree;
|
||||
plan = queryDesc->plantree;
|
||||
|
||||
operation = queryDesc->operation;
|
||||
tag = CreateOperationTag(operation);
|
||||
dest = queryDesc->dest;
|
||||
|
||||
/* ----------------
|
||||
* initialize portal/into relation status
|
||||
* ----------------
|
||||
*/
|
||||
isRetrieveIntoPortal = false;
|
||||
isRetrieveIntoRelation = false;
|
||||
|
||||
if (operation == CMD_SELECT)
|
||||
{
|
||||
if (parseTree->isPortal)
|
||||
{
|
||||
isRetrieveIntoPortal = true;
|
||||
intoName = parseTree->into;
|
||||
if (parseTree->isBinary)
|
||||
{
|
||||
|
||||
/*
|
||||
* For internal format portals, we change Remote
|
||||
* (externalized form) to RemoteInternal (internalized
|
||||
* form)
|
||||
*/
|
||||
dest = queryDesc->dest = RemoteInternal;
|
||||
}
|
||||
}
|
||||
else if (parseTree->into != NULL)
|
||||
{
|
||||
/* select into table */
|
||||
isRetrieveIntoRelation = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* when performing a retrieve into, we override the normal
|
||||
* communication destination during the processing of the
|
||||
* the query. This only affects the tuple-output function
|
||||
* - the correct destination will still see BeginCommand()
|
||||
* and EndCommand() messages.
|
||||
* ----------------
|
||||
*/
|
||||
if (isRetrieveIntoRelation)
|
||||
queryDesc->dest = (int) None;
|
||||
|
||||
/* ----------------
|
||||
* create a default executor state..
|
||||
* ----------------
|
||||
*/
|
||||
state = CreateExecutorState();
|
||||
|
||||
/* ----------------
|
||||
* call ExecStart to prepare the plan for execution
|
||||
* ----------------
|
||||
*/
|
||||
attinfo = ExecutorStart(queryDesc, state);
|
||||
|
||||
/* ----------------
|
||||
* report the query's result type information
|
||||
* back to the front end or to whatever destination
|
||||
* we're dealing with.
|
||||
* ----------------
|
||||
*/
|
||||
BeginCommand(NULL,
|
||||
operation,
|
||||
attinfo,
|
||||
isRetrieveIntoRelation,
|
||||
isRetrieveIntoPortal,
|
||||
tag,
|
||||
dest);
|
||||
|
||||
/* ----------------
|
||||
* Named portals do not do a "fetch all" initially, so now
|
||||
* we return since ExecMain has been called with EXEC_START
|
||||
* to initialize the query plan.
|
||||
*
|
||||
* Note: ProcessPortal transforms the current "blank" portal
|
||||
* into a named portal and creates a new blank portal so
|
||||
* everything we allocated in the current "blank" memory
|
||||
* context will be preserved across queries. -cim 2/22/91
|
||||
* ----------------
|
||||
*/
|
||||
if (isRetrieveIntoPortal) {
|
||||
PortalExecutorHeapMemory = NULL;
|
||||
|
||||
ProcessPortal(intoName,
|
||||
parseTree,
|
||||
plan,
|
||||
state,
|
||||
attinfo,
|
||||
dest);
|
||||
|
||||
/* ----------------
|
||||
* when performing a retrieve into, we override the normal
|
||||
* communication destination during the processing of the
|
||||
* the query. This only affects the tuple-output function
|
||||
* - the correct destination will still see BeginCommand()
|
||||
* and EndCommand() messages.
|
||||
* ----------------
|
||||
*/
|
||||
if (isRetrieveIntoRelation)
|
||||
queryDesc->dest = (int) None;
|
||||
|
||||
/* ----------------
|
||||
* create a default executor state..
|
||||
* ----------------
|
||||
*/
|
||||
state = CreateExecutorState();
|
||||
|
||||
/* ----------------
|
||||
* call ExecStart to prepare the plan for execution
|
||||
* ----------------
|
||||
*/
|
||||
attinfo = ExecutorStart(queryDesc, state);
|
||||
|
||||
/* ----------------
|
||||
* report the query's result type information
|
||||
* back to the front end or to whatever destination
|
||||
* we're dealing with.
|
||||
* ----------------
|
||||
*/
|
||||
BeginCommand(NULL,
|
||||
operation,
|
||||
attinfo,
|
||||
isRetrieveIntoRelation,
|
||||
isRetrieveIntoPortal,
|
||||
tag,
|
||||
dest);
|
||||
|
||||
/* ----------------
|
||||
* Named portals do not do a "fetch all" initially, so now
|
||||
* we return since ExecMain has been called with EXEC_START
|
||||
* to initialize the query plan.
|
||||
*
|
||||
* Note: ProcessPortal transforms the current "blank" portal
|
||||
* into a named portal and creates a new blank portal so
|
||||
* everything we allocated in the current "blank" memory
|
||||
* context will be preserved across queries. -cim 2/22/91
|
||||
* ----------------
|
||||
*/
|
||||
if (isRetrieveIntoPortal)
|
||||
{
|
||||
PortalExecutorHeapMemory = NULL;
|
||||
|
||||
ProcessPortal(intoName,
|
||||
parseTree,
|
||||
plan,
|
||||
state,
|
||||
attinfo,
|
||||
dest);
|
||||
|
||||
EndCommand(tag, dest);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* Now we get to the important call to ExecutorRun() where we
|
||||
* actually run the plan..
|
||||
* ----------------
|
||||
*/
|
||||
ExecutorRun(queryDesc, state, EXEC_RUN, 0);
|
||||
|
||||
/* save infos for EndCommand */
|
||||
UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
|
||||
|
||||
/* ----------------
|
||||
* now, we close down all the scans and free allocated resources...
|
||||
* with ExecutorEnd()
|
||||
* ----------------
|
||||
*/
|
||||
ExecutorEnd(queryDesc, state);
|
||||
|
||||
/* ----------------
|
||||
* Notify the destination of end of processing.
|
||||
* ----------------
|
||||
*/
|
||||
EndCommand(tag, dest);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* Now we get to the important call to ExecutorRun() where we
|
||||
* actually run the plan..
|
||||
* ----------------
|
||||
*/
|
||||
ExecutorRun(queryDesc, state, EXEC_RUN, 0);
|
||||
|
||||
/* save infos for EndCommand */
|
||||
UpdateCommandInfo (operation, state->es_lastoid, state->es_processed);
|
||||
|
||||
/* ----------------
|
||||
* now, we close down all the scans and free allocated resources...
|
||||
* with ExecutorEnd()
|
||||
* ----------------
|
||||
*/
|
||||
ExecutorEnd(queryDesc, state);
|
||||
|
||||
/* ----------------
|
||||
* Notify the destination of end of processing.
|
||||
* ----------------
|
||||
*/
|
||||
EndCommand(tag, dest);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ProcessQuery
|
||||
* ProcessQuery
|
||||
*
|
||||
* Execute a plan, the non-parallel version
|
||||
* Execute a plan, the non-parallel version
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ProcessQuery(Query *parsetree,
|
||||
Plan *plan,
|
||||
char *argv[],
|
||||
Oid *typev,
|
||||
int nargs,
|
||||
CommandDest dest)
|
||||
ProcessQuery(Query * parsetree,
|
||||
Plan * plan,
|
||||
char *argv[],
|
||||
Oid * typev,
|
||||
int nargs,
|
||||
CommandDest dest)
|
||||
{
|
||||
QueryDesc *queryDesc;
|
||||
extern int dontExecute; /* from postgres.c */
|
||||
extern void print_plan (Plan* p, Query* parsetree); /* from print.c */
|
||||
QueryDesc *queryDesc;
|
||||
extern int dontExecute;/* from postgres.c */
|
||||
extern void print_plan(Plan * p, Query * parsetree); /* from print.c */
|
||||
|
||||
queryDesc = CreateQueryDesc(parsetree, plan, dest);
|
||||
queryDesc = CreateQueryDesc(parsetree, plan, dest);
|
||||
|
||||
if (dontExecute) {
|
||||
/* don't execute it, just show the query plan */
|
||||
print_plan(plan, parsetree);
|
||||
} else
|
||||
ProcessQueryDesc(queryDesc);
|
||||
if (dontExecute)
|
||||
{
|
||||
/* don't execute it, just show the query plan */
|
||||
print_plan(plan, parsetree);
|
||||
}
|
||||
else
|
||||
ProcessQueryDesc(queryDesc);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
* Routines for handling of 'SET var TO', 'SHOW var' and 'RESET var'
|
||||
* statements.
|
||||
*
|
||||
* $Id: variable.c,v 1.13 1997/08/12 20:15:50 momjian Exp $
|
||||
* $Id: variable.c,v 1.14 1997/09/07 04:49:37 momjian Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -15,421 +15,471 @@
|
||||
#include "utils/builtins.h"
|
||||
#include "optimizer/internal.h"
|
||||
|
||||
extern Cost _cpu_page_wight_;
|
||||
extern Cost _cpu_index_page_wight_;
|
||||
extern bool _use_geqo_;
|
||||
extern int32 _use_geqo_rels_;
|
||||
extern bool _use_right_sided_plans_;
|
||||
extern Cost _cpu_page_wight_;
|
||||
extern Cost _cpu_index_page_wight_;
|
||||
extern bool _use_geqo_;
|
||||
extern int32 _use_geqo_rels_;
|
||||
extern bool _use_right_sided_plans_;
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
#if USE_EURODATES
|
||||
#define DATE_EURO TRUE
|
||||
#define DATE_EURO TRUE
|
||||
#else
|
||||
#define DATE_EURO FALSE
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
struct PGVariables PGVariables =
|
||||
{
|
||||
{DATE_EURO, Date_Postgres}
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static const char *
|
||||
get_token(char **tok, char **val, const char *str)
|
||||
{
|
||||
const char *start;
|
||||
int len = 0;
|
||||
|
||||
*tok = NULL;
|
||||
if (val != NULL)
|
||||
*val = NULL;
|
||||
|
||||
if (!(*str))
|
||||
return NULL;
|
||||
|
||||
/* skip white spaces */
|
||||
while (isspace(*str))
|
||||
str++;
|
||||
if (*str == ',' || *str == '=')
|
||||
elog(WARN, "Syntax error near (%s): empty setting", str);
|
||||
|
||||
/* end of string? then return NULL */
|
||||
if (!(*str))
|
||||
return NULL;
|
||||
|
||||
/* OK, at beginning of non-NULL string... */
|
||||
start = str;
|
||||
|
||||
/*
|
||||
* count chars in token until we hit white space or comma or '=' or
|
||||
* end of string
|
||||
*/
|
||||
while (*str && (!isspace(*str))
|
||||
&& *str != ',' && *str != '=')
|
||||
{
|
||||
{ DATE_EURO, Date_Postgres }
|
||||
str++;
|
||||
len++;
|
||||
}
|
||||
|
||||
*tok = (char *) PALLOC(len + 1);
|
||||
strNcpy(*tok, start, len);
|
||||
|
||||
/* skip white spaces */
|
||||
while (isspace(*str))
|
||||
str++;
|
||||
|
||||
/* end of string? */
|
||||
if (!(*str))
|
||||
{
|
||||
return (str);
|
||||
|
||||
/* delimiter? */
|
||||
}
|
||||
else if (*str == ',')
|
||||
{
|
||||
return (++str);
|
||||
|
||||
}
|
||||
else if ((val == NULL) || (*str != '='))
|
||||
{
|
||||
elog(WARN, "Syntax error near (%s)", str);
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static const char *get_token(char **tok, char **val, const char *str)
|
||||
{
|
||||
const char *start;
|
||||
int len = 0;
|
||||
str++; /* '=': get value */
|
||||
len = 0;
|
||||
|
||||
*tok = NULL;
|
||||
if (val != NULL) *val = NULL;
|
||||
/* skip white spaces */
|
||||
while (isspace(*str))
|
||||
str++;
|
||||
|
||||
if ( !(*str) )
|
||||
return NULL;
|
||||
if (*str == ',' || !(*str))
|
||||
elog(WARN, "Syntax error near (=%s)", str);
|
||||
|
||||
/* skip white spaces */
|
||||
while (isspace(*str)) str++;
|
||||
if ( *str == ',' || *str == '=' )
|
||||
elog(WARN, "Syntax error near (%s): empty setting", str);
|
||||
start = str;
|
||||
|
||||
/* end of string? then return NULL */
|
||||
if ( !(*str) )
|
||||
return NULL;
|
||||
/*
|
||||
* count chars in token's value until we hit white space or comma or
|
||||
* end of string
|
||||
*/
|
||||
while (*str && (!isspace(*str)) && *str != ',')
|
||||
{
|
||||
str++;
|
||||
len++;
|
||||
}
|
||||
|
||||
/* OK, at beginning of non-NULL string... */
|
||||
start = str;
|
||||
*val = (char *) PALLOC(len + 1);
|
||||
strNcpy(*val, start, len);
|
||||
|
||||
/*
|
||||
* count chars in token until we hit white space or comma
|
||||
* or '=' or end of string
|
||||
*/
|
||||
while ( *str && (! isspace(*str))
|
||||
&& *str != ',' && *str != '=' )
|
||||
{
|
||||
str++;
|
||||
len++;
|
||||
}
|
||||
|
||||
*tok = (char*) PALLOC(len + 1);
|
||||
strNcpy (*tok, start, len);
|
||||
/* skip white spaces */
|
||||
while (isspace(*str))
|
||||
str++;
|
||||
|
||||
/* skip white spaces */
|
||||
while ( isspace(*str)) str++;
|
||||
if (!(*str))
|
||||
return (NULL);
|
||||
if (*str == ',')
|
||||
return (++str);
|
||||
|
||||
/* end of string? */
|
||||
if ( !(*str) ) {
|
||||
return(str);
|
||||
|
||||
/* delimiter? */
|
||||
} else if ( *str == ',' ) {
|
||||
return (++str);
|
||||
|
||||
} else if ((val == NULL) || ( *str != '=' )) {
|
||||
elog(WARN, "Syntax error near (%s)", str);
|
||||
};
|
||||
|
||||
str++; /* '=': get value */
|
||||
len = 0;
|
||||
|
||||
/* skip white spaces */
|
||||
while ( isspace(*str)) str++;
|
||||
|
||||
if ( *str == ',' || !(*str) )
|
||||
elog(WARN, "Syntax error near (=%s)", str);
|
||||
|
||||
start = str;
|
||||
|
||||
/*
|
||||
* count chars in token's value until we hit white space or comma
|
||||
* or end of string
|
||||
*/
|
||||
while ( *str && (! isspace(*str)) && *str != ',' )
|
||||
{
|
||||
str++;
|
||||
len++;
|
||||
}
|
||||
|
||||
*val = (char*) PALLOC(len + 1);
|
||||
strNcpy (*val, start, len);
|
||||
|
||||
/* skip white spaces */
|
||||
while ( isspace(*str)) str++;
|
||||
|
||||
if ( !(*str) )
|
||||
return (NULL);
|
||||
if ( *str == ',' )
|
||||
return (++str);
|
||||
|
||||
elog(WARN, "Syntax error near (%s)", str);
|
||||
|
||||
return str;
|
||||
return str;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static bool parse_null(const char *value)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool show_null(const char *value)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool reset_null(const char *value)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool parse_geqo (const char *value)
|
||||
static bool
|
||||
parse_null(const char *value)
|
||||
{
|
||||
const char *rest;
|
||||
char *tok, *val;
|
||||
|
||||
rest = get_token (&tok, &val, value);
|
||||
if ( tok == NULL )
|
||||
elog(WARN, "Value undefined");
|
||||
|
||||
if (( rest ) && ( *rest != '\0' ))
|
||||
elog(WARN, "Unable to parse '%s'", value);
|
||||
|
||||
if ( strcasecmp (tok, "on") == 0 )
|
||||
{
|
||||
int32 geqo_rels = GEQO_RELS;
|
||||
|
||||
if ( val != NULL )
|
||||
{
|
||||
geqo_rels = pg_atoi (val, sizeof(int32), '\0');
|
||||
if ( geqo_rels <= 1 )
|
||||
elog(WARN, "Bad value for # of relations (%s)", val);
|
||||
PFREE(val);
|
||||
}
|
||||
_use_geqo_ = true;
|
||||
_use_geqo_rels_ = geqo_rels;
|
||||
}
|
||||
else if ( strcasecmp (tok, "off") == 0 )
|
||||
{
|
||||
if (( val != NULL ) && ( *val != '\0' ))
|
||||
elog(WARN, "%s does not allow a parameter",tok);
|
||||
_use_geqo_ = false;
|
||||
}
|
||||
else
|
||||
elog(WARN, "Bad value for GEQO (%s)", value);
|
||||
|
||||
PFREE(tok);
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool show_geqo ()
|
||||
static bool
|
||||
show_null(const char *value)
|
||||
{
|
||||
|
||||
if ( _use_geqo_ )
|
||||
elog (NOTICE, "GEQO is ON beginning with %d relations", _use_geqo_rels_);
|
||||
else
|
||||
elog (NOTICE, "GEQO is OFF");
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool reset_geqo ()
|
||||
static bool
|
||||
reset_null(const char *value)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_geqo(const char *value)
|
||||
{
|
||||
const char *rest;
|
||||
char *tok,
|
||||
*val;
|
||||
|
||||
rest = get_token(&tok, &val, value);
|
||||
if (tok == NULL)
|
||||
elog(WARN, "Value undefined");
|
||||
|
||||
if ((rest) && (*rest != '\0'))
|
||||
elog(WARN, "Unable to parse '%s'", value);
|
||||
|
||||
if (strcasecmp(tok, "on") == 0)
|
||||
{
|
||||
int32 geqo_rels = GEQO_RELS;
|
||||
|
||||
if (val != NULL)
|
||||
{
|
||||
geqo_rels = pg_atoi(val, sizeof(int32), '\0');
|
||||
if (geqo_rels <= 1)
|
||||
elog(WARN, "Bad value for # of relations (%s)", val);
|
||||
PFREE(val);
|
||||
}
|
||||
_use_geqo_ = true;
|
||||
_use_geqo_rels_ = geqo_rels;
|
||||
}
|
||||
else if (strcasecmp(tok, "off") == 0)
|
||||
{
|
||||
if ((val != NULL) && (*val != '\0'))
|
||||
elog(WARN, "%s does not allow a parameter", tok);
|
||||
_use_geqo_ = false;
|
||||
}
|
||||
else
|
||||
elog(WARN, "Bad value for GEQO (%s)", value);
|
||||
|
||||
PFREE(tok);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool
|
||||
show_geqo()
|
||||
{
|
||||
|
||||
if (_use_geqo_)
|
||||
elog(NOTICE, "GEQO is ON beginning with %d relations", _use_geqo_rels_);
|
||||
else
|
||||
elog(NOTICE, "GEQO is OFF");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool
|
||||
reset_geqo()
|
||||
{
|
||||
|
||||
#ifdef GEQO
|
||||
_use_geqo_ = true;
|
||||
_use_geqo_ = true;
|
||||
#else
|
||||
_use_geqo_ = false;
|
||||
_use_geqo_ = false;
|
||||
#endif
|
||||
_use_geqo_rels_ = GEQO_RELS;
|
||||
return TRUE;
|
||||
_use_geqo_rels_ = GEQO_RELS;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool parse_r_plans (const char *value)
|
||||
static bool
|
||||
parse_r_plans(const char *value)
|
||||
{
|
||||
|
||||
if ( strcasecmp (value, "on") == 0 )
|
||||
_use_right_sided_plans_ = true;
|
||||
else if ( strcasecmp (value, "off") == 0 )
|
||||
_use_right_sided_plans_ = false;
|
||||
else
|
||||
elog(WARN, "Bad value for Right-sided Plans (%s)", value);
|
||||
|
||||
return TRUE;
|
||||
if (strcasecmp(value, "on") == 0)
|
||||
_use_right_sided_plans_ = true;
|
||||
else if (strcasecmp(value, "off") == 0)
|
||||
_use_right_sided_plans_ = false;
|
||||
else
|
||||
elog(WARN, "Bad value for Right-sided Plans (%s)", value);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool show_r_plans ()
|
||||
static bool
|
||||
show_r_plans()
|
||||
{
|
||||
|
||||
if ( _use_right_sided_plans_ )
|
||||
elog (NOTICE, "Right-sided Plans are ON");
|
||||
else
|
||||
elog (NOTICE, "Right-sided Plans are OFF");
|
||||
return TRUE;
|
||||
if (_use_right_sided_plans_)
|
||||
elog(NOTICE, "Right-sided Plans are ON");
|
||||
else
|
||||
elog(NOTICE, "Right-sided Plans are OFF");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool reset_r_plans ()
|
||||
static bool
|
||||
reset_r_plans()
|
||||
{
|
||||
|
||||
#ifdef USE_RIGHT_SIDED_PLANS
|
||||
_use_right_sided_plans_ = true;
|
||||
_use_right_sided_plans_ = true;
|
||||
#else
|
||||
_use_right_sided_plans_ = false;
|
||||
_use_right_sided_plans_ = false;
|
||||
#endif
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool parse_cost_heap (const char *value)
|
||||
static bool
|
||||
parse_cost_heap(const char *value)
|
||||
{
|
||||
float32 res = float4in ((char*)value);
|
||||
|
||||
_cpu_page_wight_ = *res;
|
||||
|
||||
return TRUE;
|
||||
float32 res = float4in((char *) value);
|
||||
|
||||
_cpu_page_wight_ = *res;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool show_cost_heap ()
|
||||
static bool
|
||||
show_cost_heap()
|
||||
{
|
||||
|
||||
elog (NOTICE, "COST_HEAP is %f", _cpu_page_wight_);
|
||||
return TRUE;
|
||||
elog(NOTICE, "COST_HEAP is %f", _cpu_page_wight_);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool reset_cost_heap ()
|
||||
static bool
|
||||
reset_cost_heap()
|
||||
{
|
||||
_cpu_page_wight_ = _CPU_PAGE_WEIGHT_;
|
||||
return TRUE;
|
||||
_cpu_page_wight_ = _CPU_PAGE_WEIGHT_;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool parse_cost_index (const char *value)
|
||||
static bool
|
||||
parse_cost_index(const char *value)
|
||||
{
|
||||
float32 res = float4in ((char*)value);
|
||||
|
||||
_cpu_index_page_wight_ = *res;
|
||||
|
||||
return TRUE;
|
||||
float32 res = float4in((char *) value);
|
||||
|
||||
_cpu_index_page_wight_ = *res;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool show_cost_index ()
|
||||
static bool
|
||||
show_cost_index()
|
||||
{
|
||||
|
||||
elog (NOTICE, "COST_INDEX is %f", _cpu_index_page_wight_);
|
||||
return TRUE;
|
||||
elog(NOTICE, "COST_INDEX is %f", _cpu_index_page_wight_);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool reset_cost_index ()
|
||||
static bool
|
||||
reset_cost_index()
|
||||
{
|
||||
_cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_;
|
||||
return TRUE;
|
||||
_cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool parse_date(const char *value)
|
||||
static bool
|
||||
parse_date(const char *value)
|
||||
{
|
||||
char *tok;
|
||||
int dcnt = 0, ecnt = 0;
|
||||
char *tok;
|
||||
int dcnt = 0,
|
||||
ecnt = 0;
|
||||
|
||||
while((value = get_token(&tok, NULL, value)) != 0)
|
||||
while ((value = get_token(&tok, NULL, value)) != 0)
|
||||
{
|
||||
/* Ugh. Somebody ought to write a table driven version -- mjl */
|
||||
|
||||
if(!strcasecmp(tok, "iso"))
|
||||
{
|
||||
if (!strcasecmp(tok, "iso"))
|
||||
{
|
||||
DateStyle = USE_ISO_DATES;
|
||||
dcnt++;
|
||||
}
|
||||
else if(!strcasecmp(tok, "sql"))
|
||||
{
|
||||
}
|
||||
else if (!strcasecmp(tok, "sql"))
|
||||
{
|
||||
DateStyle = USE_SQL_DATES;
|
||||
dcnt++;
|
||||
}
|
||||
else if(!strcasecmp(tok, "postgres"))
|
||||
{
|
||||
}
|
||||
else if (!strcasecmp(tok, "postgres"))
|
||||
{
|
||||
DateStyle = USE_POSTGRES_DATES;
|
||||
dcnt++;
|
||||
}
|
||||
else if(!strncasecmp(tok, "euro", 4))
|
||||
{
|
||||
}
|
||||
else if (!strncasecmp(tok, "euro", 4))
|
||||
{
|
||||
EuroDates = TRUE;
|
||||
ecnt++;
|
||||
}
|
||||
else if((!strcasecmp(tok, "us"))
|
||||
|| (!strncasecmp(tok, "noneuro", 7)))
|
||||
{
|
||||
}
|
||||
else if ((!strcasecmp(tok, "us"))
|
||||
|| (!strncasecmp(tok, "noneuro", 7)))
|
||||
{
|
||||
EuroDates = FALSE;
|
||||
ecnt++;
|
||||
}
|
||||
else if(!strcasecmp(tok, "default"))
|
||||
{
|
||||
}
|
||||
else if (!strcasecmp(tok, "default"))
|
||||
{
|
||||
DateStyle = USE_POSTGRES_DATES;
|
||||
EuroDates = FALSE;
|
||||
ecnt++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
elog(WARN, "Bad value for date style (%s)", tok);
|
||||
}
|
||||
}
|
||||
PFREE(tok);
|
||||
}
|
||||
|
||||
if(dcnt > 1 || ecnt > 1)
|
||||
if (dcnt > 1 || ecnt > 1)
|
||||
elog(NOTICE, "Conflicting settings for date");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool show_date()
|
||||
{
|
||||
char buf[64];
|
||||
static bool
|
||||
show_date()
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
strcpy( buf, "DateStyle is ");
|
||||
switch (DateStyle) {
|
||||
strcpy(buf, "DateStyle is ");
|
||||
switch (DateStyle)
|
||||
{
|
||||
case USE_ISO_DATES:
|
||||
strcat( buf, "ISO");
|
||||
strcat(buf, "ISO");
|
||||
break;
|
||||
case USE_SQL_DATES:
|
||||
strcat( buf, "SQL");
|
||||
strcat(buf, "SQL");
|
||||
break;
|
||||
default:
|
||||
strcat( buf, "Postgres");
|
||||
strcat(buf, "Postgres");
|
||||
break;
|
||||
};
|
||||
strcat( buf, " with ");
|
||||
strcat( buf, ((EuroDates)? "European": "US (NonEuropean)"));
|
||||
strcat( buf, " conventions");
|
||||
strcat(buf, " with ");
|
||||
strcat(buf, ((EuroDates) ? "European" : "US (NonEuropean)"));
|
||||
strcat(buf, " conventions");
|
||||
|
||||
elog(NOTICE, buf, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static bool reset_date()
|
||||
{
|
||||
static bool
|
||||
reset_date()
|
||||
{
|
||||
DateStyle = USE_POSTGRES_DATES;
|
||||
EuroDates = FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
struct VariableParsers
|
||||
{
|
||||
const char *name;
|
||||
bool(*parser) (const char *);
|
||||
bool(*show) ();
|
||||
bool(*reset) ();
|
||||
} VariableParsers[] =
|
||||
|
||||
{
|
||||
{
|
||||
const char *name;
|
||||
bool (*parser)(const char *);
|
||||
bool (*show)();
|
||||
bool (*reset)();
|
||||
} VariableParsers[] =
|
||||
"datestyle", parse_date, show_date, reset_date
|
||||
},
|
||||
{
|
||||
{ "datestyle", parse_date, show_date, reset_date },
|
||||
{ "timezone", parse_null, show_null, reset_null },
|
||||
{ "cost_heap", parse_cost_heap,
|
||||
show_cost_heap, reset_cost_heap },
|
||||
{ "cost_index", parse_cost_index,
|
||||
show_cost_index, reset_cost_index },
|
||||
{ "geqo", parse_geqo, show_geqo, reset_geqo },
|
||||
{ "r_plans", parse_r_plans, show_r_plans, reset_r_plans },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
"timezone", parse_null, show_null, reset_null
|
||||
},
|
||||
{
|
||||
"cost_heap", parse_cost_heap,
|
||||
show_cost_heap, reset_cost_heap
|
||||
},
|
||||
{
|
||||
"cost_index", parse_cost_index,
|
||||
show_cost_index, reset_cost_index
|
||||
},
|
||||
{
|
||||
"geqo", parse_geqo, show_geqo, reset_geqo
|
||||
},
|
||||
{
|
||||
"r_plans", parse_r_plans, show_r_plans, reset_r_plans
|
||||
},
|
||||
{
|
||||
NULL, NULL, NULL
|
||||
}
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
bool SetPGVariable(const char *name, const char *value)
|
||||
{
|
||||
bool
|
||||
SetPGVariable(const char *name, const char *value)
|
||||
{
|
||||
struct VariableParsers *vp;
|
||||
|
||||
for(vp = VariableParsers; vp->name; vp++)
|
||||
{
|
||||
if(!strcasecmp(vp->name, name))
|
||||
return (vp->parser)(value);
|
||||
}
|
||||
for (vp = VariableParsers; vp->name; vp++)
|
||||
{
|
||||
if (!strcasecmp(vp->name, name))
|
||||
return (vp->parser) (value);
|
||||
}
|
||||
|
||||
elog(NOTICE, "Unrecognized variable %s", name);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
bool GetPGVariable(const char *name)
|
||||
{
|
||||
bool
|
||||
GetPGVariable(const char *name)
|
||||
{
|
||||
struct VariableParsers *vp;
|
||||
|
||||
for(vp = VariableParsers; vp->name; vp++)
|
||||
{
|
||||
if(!strcasecmp(vp->name, name))
|
||||
return (vp->show)();
|
||||
}
|
||||
for (vp = VariableParsers; vp->name; vp++)
|
||||
{
|
||||
if (!strcasecmp(vp->name, name))
|
||||
return (vp->show) ();
|
||||
}
|
||||
|
||||
elog(NOTICE, "Unrecognized variable %s", name);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
bool ResetPGVariable(const char *name)
|
||||
{
|
||||
bool
|
||||
ResetPGVariable(const char *name)
|
||||
{
|
||||
struct VariableParsers *vp;
|
||||
|
||||
for(vp = VariableParsers; vp->name; vp++)
|
||||
{
|
||||
if(!strcasecmp(vp->name, name))
|
||||
return (vp->reset)();
|
||||
}
|
||||
for (vp = VariableParsers; vp->name; vp++)
|
||||
{
|
||||
if (!strcasecmp(vp->name, name))
|
||||
return (vp->reset) ();
|
||||
}
|
||||
|
||||
elog(NOTICE, "Unrecognized variable %s", name);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user