1
0
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:
Bruce Momjian
1997-09-07 05:04:48 +00:00
parent 8fecd4febf
commit 1ccd423235
687 changed files with 150775 additions and 136888 deletions

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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