head	1.28;
access;
symbols
	Version_2_1:1.8;
locks; strict;
comment	@ * @;


1.28
date	92.08.29.22.05.01;	author mao;	state Exp;
branches;
next	1.27;

1.27
date	92.08.07.00.38.18;	author mao;	state Exp;
branches;
next	1.26;

1.26
date	92.08.03.18.14.55;	author mer;	state Exp;
branches;
next	1.25;

1.25
date	92.07.29.21.19.14;	author mao;	state Exp;
branches;
next	1.24;

1.24
date	92.06.25.23.53.49;	author mao;	state Exp;
branches;
next	1.23;

1.23
date	92.06.15.08.25.27;	author dpassage;	state Exp;
branches;
next	1.22;

1.22
date	92.06.12.06.15.41;	author mao;	state Exp;
branches;
next	1.21;

1.21
date	92.05.07.23.23.00;	author clarsen;	state Exp;
branches;
next	1.20;

1.20
date	92.05.05.16.15.24;	author clarsen;	state Exp;
branches;
next	1.19;

1.19
date	92.02.25.15.29.27;	author clarsen;	state Exp;
branches;
next	1.18;

1.18
date	92.01.13.18.29.37;	author mer;	state Exp;
branches;
next	1.17;

1.17
date	92.01.09.22.47.11;	author mer;	state Exp;
branches;
next	1.16;

1.16
date	92.01.02.22.02.44;	author clarsen;	state Exp;
branches;
next	1.15;

1.15
date	91.11.18.22.40.44;	author hong;	state Exp;
branches;
next	1.14;

1.14
date	91.11.18.16.52.08;	author clarsen;	state Exp;
branches;
next	1.13;

1.13
date	91.11.13.08.55.28;	author clarsen;	state Exp;
branches;
next	1.12;

1.12
date	91.08.12.21.40.31;	author mao;	state Exp;
branches;
next	1.11;

1.11
date	91.05.23.18.23.55;	author kemnitz;	state Exp;
branches;
next	1.10;

1.10
date	91.05.22.22.22.48;	author kemnitz;	state Exp;
branches;
next	1.9;

1.9
date	91.03.21.21.52.26;	author kemnitz;	state Exp;
branches;
next	1.8;

1.8
date	91.03.08.19.55.28;	author kemnitz;	state Exp;
branches;
next	1.7;

1.7
date	91.03.06.18.35.17;	author mao;	state Exp;
branches;
next	1.6;

1.6
date	91.03.05.13.11.27;	author mer;	state Exp;
branches;
next	1.5;

1.5
date	91.03.05.13.00.18;	author mao;	state Exp;
branches;
next	1.4;

1.4
date	91.02.28.10.47.02;	author mer;	state Exp;
branches;
next	1.3;

1.3
date	91.02.22.17.06.48;	author mer;	state Exp;
branches;
next	1.2;

1.2
date	91.02.20.00.35.06;	author cimarron;	state Exp;
branches;
next	1.1;

1.1
date	91.02.09.20.43.52;	author cimarron;	state Exp;
branches;
next	;


desc
@reorganization of libpq routines to provide
PQexec and PQfn functionality from both the front
end applications and the postgres backend.
@


1.28
log
@PQfn() and its derivatives shouldn't try to read data past an 'E' on
the protocol stream.
@
text
@/* ----------------------------------------------------------------
 *   FILE
 *	fe-pqexec.c
 *	
 *   DESCRIPTION
 *	support for executing POSTGRES commands and functions
 *	from a frontend application.
 *
 *   SUPPORT ROUTINES
 *	read_initstr, read_remark, EstablishComm, process_portal,
 *	StringPointerSet
 *
 *   INTERFACE ROUTINES
 *	PQdb 		- Return the current database being accessed. 
 *	PQsetdb 	- Make the specified database the current database. 
 *	PQreset 	- Reset the communication port with the backend. 
 *	PQfinish 	- Close communication ports with the backend. 
 *	PQFlushI 	- Used for flushing out "poll" queries by the monitor.
 *
 * >>	PQfn 		- Send a function call to the POSTGRES backend.
 * >>	PQexec 		- Send a query to the POSTGRES backend
 *	
 *   NOTES
 *	These routines are NOT compiled into the postgres backend,
 *	rather they end up in libpq.a.
 *
 *   IDENTIFICATION
 *	$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.27 1992/08/07 00:38:18 mao Exp mao $
 * ----------------------------------------------------------------
 */

#include "tmp/c.h"

#include "tmp/simplelists.h"
#include "tmp/libpq-fe.h"
#include "tmp/fastpath.h"
#include "utils/fmgr.h"
#include "utils/exception.h"

RcsId ("$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.27 1992/08/07 00:38:18 mao Exp mao $");

/* ----------------------------------------------------------------
 * Declare Global Variables.  
 *
 * 	The Values of the first four varialbes can be changed by setting
 *	the approriate environment variables.
 *
 *	PQhost:		PGHOST
 *	PQdatabase:	PGDATABASE
 *	PQport:		PGPORT
 *	PQtty:		PGTTY
 * ----------------------------------------------------------------
 */

#define DefaultHost	"localhost"
#define DefaultPort	"4321"
#define DefaultTty	"/dev/null"
#define DefaultOption	""
#define DefaultVacuum	"~/bin/vacuumd"
	
char 	*PQhost;		/* the machine on which POSTGRES backend 
				   is running */
char 	*PQport = NULL;		/* the communication port with the 
				   POSTGRES backend */
char	*PQtty;			/* the tty on PQhost backend message 
				   is displayed */
char	*PQoption;		/* the optional arguments to POSTGRES 
				   backend */
char 	PQdatabase[17] = {0};	/* the POSTGRES database to access */
int 	PQportset = 0;		/* 1 if the communication with backend
				   is set */
int	PQxactid = 0;		/* the transaction id of the current 
				   transaction */
/*char	*PQinitstr = NULL;	/* the initialization string passed 
				   to backend (obsolete 2/21/91 -mer) */

extern char *getenv();

/* ----------------------------------------------------------------
 *			PQ utility routines
 * ----------------------------------------------------------------
 */

/* ----------------
 *	read_initstr
 *
 *	This is now a misnomer. PQinistr is no longer used and this routine
 *	really just initializes the PQ global variables if they need it.
 *
 * 	Read in the initialization string to be passed to the POSTGRES backend.
 * 	The initstr has the format of
 *
 *		USER,DATABASE,TTY,OPTION\n
 *
 * 	If the variables do not have values yet, read in the values from the 
 * 	environment variables.  If the environment variable does not have a
 * 	value, use the default value.
 * ----------------
 */

void
read_initstr()
{
    char *envDB;

    if (PQdatabase[0] == NULL) 
    {
	if ((envDB = getenv ("PGDATABASE")) == NULL)
	    libpq_raise(&ProtocolError,
			form((int)"Fatal Error -- No database is specified."));
	else
	{
	    PQdatabase[16] = '\0';
	    strncpy(PQdatabase, envDB, 16);
	}
    }
    if ((PQhost == NULL) && ((PQhost = getenv("PGHOST")) == NULL))
	PQhost = DefaultHost;
    
    if ((PQtty == NULL) && ((PQtty = getenv("PGTTY")) == NULL))
	PQtty = DefaultTty;
    
    /*
     *  As of release 4, PQoption is no longer taken from the environment
     *  var PGOPTION if it's not already defined.  This change was made
     *  in order to be consistent with the documentation and to make frew
     *  happy.
     *
     *  In general, users shouldn't be screwing around with PQoption, in
     *  any case.
     */

    if (PQoption == NULL)
	PQoption = DefaultOption;
    
    if (PQport == NULL) {
	if (getenv("PGPORT") == NULL)
	   PQport = DefaultPort;
	else PQport = getenv("PGPORT");
    }

/* The function of PQinitstr is now done via a message to the postmaster
 *
 *  PQinitstr = addValues(initstr_length);
 *  
 *  sprintf(PQinitstr, "%s,%s,%s,%s\n",
 *	    getenv("USER"), PQdatabase, PQtty, PQoption);
 */
}

/* ----------------
 *	read_remark - Read and discard remarks. 
 * ----------------
 */
void
read_remark(id)
    char id[];
{
    char remarks[remark_length];
    char errormsg[error_msg_length];

    while (id[0] == 'R') {
	pq_getstr(remarks, remark_length);
	if (pq_getnchar(id, 0, 1) == EOF) 
	   return;
    }
    while(id[0] == 'N') {
        pq_getstr(errormsg,error_msg_length);
        fprintf(stderr,"%s",&errormsg[0]+4);
        if (pq_getnchar(id, 0, 1) == EOF)
	   return;
    }
}

/* ----------------
 *	EstablishComm
 * ----------------
 */
static
void
EstablishComm()
{
    if (!PQportset) { 
	read_initstr();

	if (pq_connect(PQdatabase, getenv("USER"), PQoption, PQhost, PQtty,
			(char *) NULL, (short)atoi(PQport) ) == -1 ) {
	    libpq_raise(&ProtocolError,
	      form((int)"Failed to connect to backend (host=%s, port=%s)",
		   PQhost, PQport));
	}

	pq_flush();
	PQportset = 1;
    }
}

/* ----------------
 *	process_portal
 *	
 * 	Process portal queries. 
 * 	Return values are the same as PQexec().
 * ----------------
 */

char *
process_portal(rule_p)
    int rule_p;
{
    char pname[portal_name_length];
    char id[2];
    char errormsg[error_msg_length];
    char command[command_length];
    char PQcommand[portal_name_length+1];
    static char retbuf[portal_name_length + 1];
 
    /* Read in the portal name. */
    pq_getstr(pname, portal_name_length);
    pqdebug("Portal name = %s", pname);

    /*
     * This for loop is necessary so that NOTICES out of portal processing
     * stuff are handled properly.
     */

    for (;;) {
        /* Read in the identifier following the portal name. */
        pq_getnchar(id, 0, 1);
        read_remark(id);
        pqdebug("Identifier is: %c", (char *)id[0]);

        switch (id[0]) {
        case 'E':
	    pq_getstr(errormsg, error_msg_length);
	    pqdebug("%s error encountered.", errormsg);
	    /* get past gunk at front of errmsg */
	    fprintf(stderr,"%s", &errormsg[0] + 4);
	    strcpy(retbuf, "R");
	    return(retbuf);

        case 'N': /* print notice and go back to processing return values */
	    /*
	     * If we get an EOF (i.e. backend quickdies) return an R to the fe
	     */
	    if (pq_getstr(errormsg, error_msg_length) == EOF)
		return ("R");
	    pqdebug("%s notice encountered.", errormsg);
	    /* get past gunk at front of errmsg */
	    fprintf(stderr,"%s", &errormsg[0] + 4);
	    break;
	    
        case 'T':
	    /* Tuples are returned, dump data into a portal buffer. */
	    if (dump_data(pname, rule_p) == -1)
	    {
		    return("R");
	    }
	    sprintf(PQcommand, "P%s", pname);
	    strcpy(retbuf, PQcommand);
	    return(retbuf);
	
	    /* Pending data inquiry - return nothing */
        case 'C':
	    /*
	     * Portal query command (e.g., retrieve, close),
	     * no tuple returned.
	     */
	    PQxactid = pq_getint (4);
	    pqdebug("Transaction Id is: %d", (char *)PQxactid);
	    pq_getstr(command, command_length);
	    pqdebug("Query command: %s", command);
	
	    /* Process the portal commands. */
	    if (strcmp(command, "retrieve") == 0) {
	        /* Allocate a portal buffer, if portal table is full, error. */
	        pbuf_setup(pname);
	        return
		    "Cretrieve";
	    } 
	    else if (strcmp (command, "close") == 0) 
	        return
		    "Cclose";
	    else {
	        sprintf(retbuf, "C%s", command);
	        return
		    retbuf;
	    }

        default:
	    {
	        char s[45];

	        PQreset();
	        sprintf(s, "Unexpected identifier in process_portal: %c", id[0]);
	        libpq_raise(&ProtocolError, form ((int)s));
	    }
	}
    }
}

/* ----------------
 *	StringPointerSet
 * ----------------
 */
static
void
StringPointerSet(stringInOutP, newString, environmentString, defaultString)
    String	*stringInOutP;
    String	newString;
    String	environmentString;
    String	defaultString;
{
    Assert(PointerIsValid(stringInOutP));
    Assert(!PointerIsValid(*stringInOutP));
    Assert(PointerIsValid(environmentString));
    
    if (PointerIsValid(newString)) {
	*stringInOutP = newString;
    } else {
	*stringInOutP = getenv(environmentString);
	
	if (!PointerIsValid(*stringInOutP)) {
	    *stringInOutP = defaultString;
	}
    }
}

/* ----------------------------------------------------------------
 *			PQ interface routines
 * ----------------------------------------------------------------
 */

/* --------------------------------
 *	PQdb - Return the current database being accessed. 
 * --------------------------------
 */
char *
PQdb()
{
    return PQdatabase;
}

/* ----------------
 *	PQsetdb - Make the specified database the current database. 
 * ----------------
 */
void
PQsetdb(dbname)
    char *dbname;
{
    PQreset();
    PQdatabase[16] = '\0';
    strncpy(PQdatabase, dbname, 16);
}

/* ----------------
 *	PQreset - Reset the communication port with the backend. 
 * ----------------
 */
void
PQreset()
{
    pq_close();
    PQportset = 0;
/*
 *  if (PQinitstr != NULL)
 *      pq_free(PQinitstr);
 *
 *  PQinitstr = NULL;
 */
}

/* ----------------
 *	PQfinish - Close communication ports with the backend. 
 * ----------------
 */
void
PQfinish()
{
    if (!PQportset)
	return;
    
    pq_putnchar("X", 1);	/* exiting */
    pq_flush();
    pq_close();

    PQportset = 0;
}

/* ----------------
 *	PQFlushI - Used for flushing out "poll" queries by the monitor.
 * ----------------
 */
int
PQFlushI(i_count)
    int i_count;
{
    int i;
    char holder[1];

    for (i = 0; i < i_count; i++) {
	pq_getnchar(holder, 0, 1);
	if (holder[0] != 'I')
	    fprintf(stderr, "PQFlushI: read bad protocol entity");
	pq_getint(4); /* throw this away */
    }
}

/* ----------------
 *	PQfn -  Send a function call to the POSTGRES backend.
 *
 *	fnid		: function id
 * 	result_buf      : pointer to result buffer (&int if integer)
 * 	result_len	: length of return value.
 *      actual_result_len: actual length returned. (differs from result_len for
 *                      varlena structures.
 *      result_type     : If the result is an integer, this must be 1,
 *                        If result is opaque, this must be 2.
 * 	args		: pointer to a NULL terminated arg array.
 *			  (length, if integer, and result-pointer)
 * 	nargs		: # of arguments in args array.
 * ----------------
 */
char *
PQfn(fnid, result_buf, result_len, actual_result_len,
     result_type, args, nargs)
    int fnid;
    int *result_buf;    /* can't use void, dec compiler barfs */
    int result_len;
     int *actual_result_len;
    int result_type;
    PQArgBlock *args;
    int nargs;
{
    char id[2];
    char errormsg[error_msg_length];
    char command[command_length];
    char PQcommand[command_length+1];
    void EstablishComm();
    int  actual_len;
    short i;

    if (!PQportset)
	EstablishComm();
    
    pq_putnchar("F", 1);	/*	function		*/
    pq_putint(PQxactid, 4);	/*	transaction id ?	*/
    pq_putint(fnid, 4);		/*	function id		*/
    pq_putint(result_len, 4);	/*	length of return value  */
    pq_putint(nargs, 4);	/*	# of args		*/
    
    for (i=0; i < nargs; ++i) { /*	len.int4 + contents	*/
	pq_putint(args[i].len, 4);
	if (args[i].isint)
	  pq_putint(args[i].u.integer, 4);
	else if (args[i].len == VAR_LENGTH_ARG) {
            pq_putstr((char *)args[i].u.ptr);
	} else
	    pq_putnchar((char *)args[i].u.ptr, args[i].len);
    }

    pq_flush();

    /* process return value from the backend	*/

    id[0] = '?';

    pq_getnchar(id, 0, 1);
    if (id[0] == 'E') {
	int len;
        char buf[1024];

	if ((len = pq_getint(4)) >= sizeof(buf))
	    len = sizeof(buf) - 1;
	pq_getstr(buf,len);

	fprintf(stderr, "Error: %s",buf);
	return ((char *) NULL);
    }

    read_remark(id);
    fnid = pq_getint(4);
    pqdebug("The Identifier is: %c", (char *)id[0]);
    
    /* Read in the transaction id. */
    pqdebug("The Transaction Id is: %d", (char *)PQxactid);

    if (id[0] == 'V')
	pq_getnchar(id, 0, 1);
    for (;;) {
	switch (id[0]) {
	  case 'G':		/* PQFN: simple return value	*/
	    actual_len = pq_getint(4);
	    pqdebug2("LENGTH act/usr %ld/%ld\n", (char*)actual_len, (char*)result_len);
	    if ((actual_len != VAR_LENGTH_RESULT) &&
                (actual_len < 0 || actual_len > result_len)) {
		pqdebug("RESET CALLED FROM CASE G", (char *)0);
		PQreset();
		libpq_raise(&ProtocolError, form ((int)"Buffer Too Small: %s", id));
	    }
	    if (result_type == 1)
	      *(int *)result_buf = pq_getint(4);
	    else if (actual_len == VAR_LENGTH_RESULT) {
		pq_getstr((char *)result_buf,MAX_STRING_LENGTH);
	    } else
	      pq_getnchar((char *)result_buf, 0, actual_len);
	    if (actual_result_len != NULL)
	      *actual_result_len = actual_len;
	    if ((result_type != 2) && /* not a binary result */
		(actual_len != result_len)) /* if wouldn't overflow the buf */
	      ((char *)result_buf)[actual_len] = 0; /* add a \0 */
	    pq_getnchar(id, 0, 1);
	    return("G");
	    
	  case 'E':
	    pq_getstr(errormsg, error_msg_length);
	    pqdebug("%s error encountered.", errormsg);
	    fprintf(stderr,"%s", errormsg);
	    return((char *) NULL);
	    break;

	  case 'N':		/* print notice and go back to processing return values */
	    pq_getstr(errormsg, error_msg_length);
	    pqdebug("%s notice encountered.", errormsg);
	    fprintf(stderr,"%s", errormsg);
	    pq_getnchar(id, 0, 1);
	    if (pq_getnchar(id, 0, 1) == EOF)
		return((char *) NULL);
	    break;

	  case '0':		/* PQFN: no return value	*/
	    return("V");

	    default:
	    /* The backend violates the protocol. */
	    pqdebug("RESET CALLED FROM CASE G", (char *)0);
	    pqdebug("Protocol Error, bad form, got '%c'", (char *)id[0]);
	    PQreset();
	    libpq_raise(&ProtocolError, form((int)"Unexpected identifier: %s", id));
	    return(NULL);
	}
    }
}

/*
 *  PQfsread, PQfswrite -- special-purpose versions of PQfn for file
 *			   system (POSTGRES large object) read and
 *			   write routines.
 *
 *	We need these special versions because the user expects a standard
 *	unix file system interface, and postgres wants to use varlenas
 *	all over the place.
 */

int
PQfsread(fd, buf, nbytes)
    int fd;
    char *buf;
    int nbytes;
{
    int fnid;
    char id[2];
    char errormsg[error_msg_length];
    char command[command_length];
    char PQcommand[command_length+1];
    void EstablishComm();
    int  actual_len;
    short i;

    if (!PQportset)
	EstablishComm();
    
    pq_putnchar("F", 1);	/* function */
    pq_putint(PQxactid, 4);	/* transaction id? */
    pq_putint(F_LOREAD, 4);	/* function id */

    /* size of return value -- += sizeof(int) because we expect a varlena */
    pq_putint(nbytes + sizeof(int), 4);

    pq_putint(2, 4);		/* nargs */

    /* now put arguments */
    pq_putint(4, 4);		/* length of fd */
    pq_putint(fd, 4);

    pq_putint(4, 4);		/* length of nbytes */
    pq_putint(nbytes, 4);

    pq_flush();

    /* process return value from the backend	*/

    id[0] = '?';

    pq_getnchar(id, 0, 1);
    if (id[0] == 'E') {
	int len;
        char buf[1024];

	if ((len = pq_getint(4)) >= sizeof(buf))
	    len = sizeof(buf) - 1;
	pq_getstr(buf,len);

	fprintf(stderr, "Error: %s",buf);
	return (-1);
    }

    read_remark(id);
    fnid = pq_getint(4);
    pqdebug("The Identifier is: %c", (char *)id[0]);
    
    /* Read in the transaction id. */
    pqdebug("The Transaction Id is: %d", (char *)PQxactid);

    if (id[0] == 'V')
	pq_getnchar(id, 0, 1);
    for (;;) {
	switch (id[0]) {
	  case 'G':

	    /*
	     *  We know exactly what the return stream looks like, here:
	     *  it's a length, followed by a varlena (which includes the
	     *  length again...).
	     */

	    nbytes = actual_len = pq_getint(4);
#if 0	    
	/* fe/be does NOT transmit varlenas this way */
	    nbytes = pq_getint(4);
	    nbytes -= sizeof(long);	/* compensate for varlena vl->len */
#endif

	    if (nbytes > 0)
		pq_getnchar((char *)buf, 0, nbytes);
	    pq_getnchar(id, 0, 1);
	    return(nbytes);
	    
	  case 'E':
	    pq_getstr(errormsg, error_msg_length);
	    pqdebug("%s error encountered.", errormsg);
	    fprintf(stderr,"%s", errormsg);
	    return (-1);
	    break;

	  case 'N':		/* print notice and go back to processing return values */
	    pq_getstr(errormsg, error_msg_length);
	    pqdebug("%s notice encountered.", errormsg);
	    fprintf(stderr,"%s", errormsg);
	    pq_getnchar(id, 0, 1);
	    break;

	  default:
	    /* The backend violates the protocol. */
	    pqdebug("RESET CALLED FROM CASE G", (char *)0);
	    pqdebug("Protocol Error, bad form, got '%c'", (char *)id[0]);
	    PQreset();
	    libpq_raise(&ProtocolError, form((int)"Unexpected identifier: %s", id));
	    return(-1);
	}
    }
}

int
PQfswrite(fd, buf, nbytes)
    int fd;
    char *buf;
    int nbytes;
{
    int fnid;
    char id[2];
    char errormsg[error_msg_length];
    char command[command_length];
    char PQcommand[command_length+1];
    void EstablishComm();
    int  actual_len;
    short i;

    if (!PQportset)
	EstablishComm();
    
    pq_putnchar("F", 1);	/*	function		*/
    pq_putint(PQxactid, 4);	/*	transaction id ?	*/
    pq_putint(F_LOWRITE, 4);	/*	function id		*/
    pq_putint(4, 4);		/*	length of return value  */
    pq_putint(2, 4);		/*	# of args		*/
    
    /* now put arguments */
    pq_putint(4, 4);		/* size of fd */
    pq_putint(fd, 4);
/*
* The method of transmitting varlenas is:
* Send vl_len-4
* Send data consisting of vl_len-4 bytes.
*/
    pq_putint(nbytes, 4);	/* size of varlena */
#if 0
	/* The fe/be protocol does NOT transmit varlenas this way */
    pq_putint(nbytes + 4, 4);	/* vl_len */
#endif
    pq_putnchar(buf, nbytes);	/* vl_dat */

    pq_flush();

    /* process return value from the backend	*/
    id[0] = '?';

    pq_getnchar(id, 0, 1);
    if (id[0] == 'E') {
	int len;
        char buf[1024];

	if ((len = pq_getint(4)) >= sizeof(buf))
	    len = sizeof(buf) - 1;
	pq_getstr(buf,len);

	fprintf(stderr, "Error: %s",buf);
	return (-1);
    }

    read_remark(id);
    fnid = pq_getint(4);
    pqdebug("The Identifier is: %c", (char *)id[0]);
    
    /* Read in the transaction id. */
    pqdebug("The Transaction Id is: %d", (char *)PQxactid);

    if (id[0] == 'V')
	pq_getnchar(id, 0, 1);

    for (;;) {
	switch (id[0]) {
	  case 'G':		/* PQFN: simple return value	*/
	    actual_len = pq_getint(4);
	    if (actual_len != 4)
		libpq_raise(&ProtocolError,
			    form((int) "wanted 4 bytes in PQfswrite, got %d\n",
			    actual_len));
	    nbytes = pq_getint(4);
	    pq_getnchar(id, 0, 1);
	    return (nbytes);
	    
	  case 'E':
	    pq_getstr(errormsg, error_msg_length);
	    pqdebug("%s error encountered.", errormsg);
	    fprintf(stderr,"%s", errormsg);
	    return (-1);
	    break;

	  case 'N': /* print notice and go back to processing return values */
	    pq_getstr(errormsg, error_msg_length);
	    pqdebug("%s notice encountered.", errormsg);
	    fprintf(stderr,"%s", errormsg);
	    pq_getnchar(id, 0, 1);
	    break;

	    default:
	    /* The backend violates the protocol. */
	    pqdebug("RESET CALLED FROM CASE G", (char *)0);
	    pqdebug("Protocol Error, bad form, got '%c'", (char *)id[0]);
	    PQreset();
	    libpq_raise(&ProtocolError, form((int)"Unexpected identifier: %s", id));
	    return(NULL);
	}
    }
}

/* ----------------
 *	PQexec -  Send a query to the POSTGRES backend
 *
 * 	The return value is a string.  
 * 	If there is an error: return "E error-message".
 * 	If tuples are fetched from the backend, return "P portal-name".
 * 	If a query is executed successfully but no tuples fetched, 
 * 	return "C query-command".
 * ----------------
 */

char *
PQexec(query)
    char *query;
{
    char id[2];
    char errormsg[error_msg_length];
    char command[command_length];
    char PQcommand[command_length+1];
    void EstablishComm();

    /* If the communication is not established, establish it. */
    if (!PQportset)
	EstablishComm();

    /* Send a query to backend. */
    pq_putnchar("Q", 1);
    pq_putint(PQxactid, 4);
    pq_putstr(query);
    pqdebug("The query sent to the backend: %s", query);
    pq_flush();

    /* forever (or at least until we get something besides a notice) */
    for (;;) {  

    	/* Process return values from the backend. 
	 * The code in this function is the implementation of
	 * the communication protocol.
	 */
    	id[0] = '?';

    	/* Get the identifier. */
    	pq_getnchar(id,0,1); 

    	read_remark(id);
    	pqdebug("The Identifier is: %c", (char *)id[0]);

    	/* Read in the transaction id. */
    	PQxactid = pq_getint(4);
    	pqdebug("The Transaction Id is: %d", (char *)PQxactid);

    	switch (id[0]) {
    	case 'I':
	    return("I");
	    
    	case 'E':
	    pq_getstr(errormsg, error_msg_length);
	    pqdebug("%s error encountered.", errormsg);
	    fprintf(stderr,"%s", errormsg);
	    return("R");
	    
    	case 'N': /* print notice and go back to processing return values */
	    /*
	     * If we get an EOF (i.e. backend quickdies) return an R to the fe
	     */
	    if (pq_getstr(errormsg, error_msg_length) == EOF)
		return ("R");
	    pqdebug("%s notice encountered.", errormsg);
	    fprintf(stderr,"%s", errormsg);
	    break;

    	case 'A': {
	    char relname[16];
	    extern int PQAsyncNotifyWaiting;
	    int pid;
	    PQAsyncNotifyWaiting = 0;
	    
	    /* Asynchronized portal. */
	    /* No tuple transfer at this stage. */
	    pqdebug("%s portal encountered.", "Asynchronized");
	    /* Processed the same way as synchronized portal. */
/*	    return
		process_portal(1);*/
	    pq_getstr(relname,16);
	    pid =pq_getint(4);
	    PQappendNotify(relname,pid);
	}
	    break;
    	case 'P':
	    /* Synchronized (normal) portal. */
	    return
		process_portal(0);
	    
    	case 'C':
	    /* Query executed successfully. */
	    pq_getstr (command, command_length);
	    pqdebug ("Query command: %s", command);
	    sprintf (PQcommand, "C%s", command);
	    return
		PQcommand;

	case 'B':
	    /* Copy command began successfully - it is sending stuff back...  */
	    return "BCOPY";

	case 'D':
	    /* Copy command began successfully - it is waiting to receive... */
	    return "DCOPY";

    	default:
	    /* The backend violates the protocol. */
	    if (id[0] == '?')
	    	libpq_raise(&ProtocolError, 
			form((int)"No response from the backend, exiting...\n"));
	    else
	    	libpq_raise(&ProtocolError, 
		   form((int)"Unexpected response from the backend, exiting...\n"));
	    exit(1);
    	}
    }
}

int
PQendcopy()

{
    char id[2];
    char errormsg[error_msg_length];

    for (;;) 
    {
		id[0] = '?';

        pq_getnchar(id,0,1); 

        switch(id[0])
        {
            case 'N':

                pq_getstr(errormsg, error_msg_length);
                pqdebug("%s notice encountered.", errormsg);
                fprintf(stderr,"%s", errormsg);
                break;

            case 'E':
                pq_getstr(errormsg, error_msg_length);
                pqdebug("%s notice encountered.", errormsg);
                fprintf(stderr,"%s", errormsg);
                return(0);

            case 'Z': /* backend finished the copy */
                return(1);

            default:
                /* The backend violates the protocol. */
                if (id[0] == '?')
                    libpq_raise(&ProtocolError, 
                        form((int)"No response from the backend, exiting...\n"));
                else
                    libpq_raise(&ProtocolError, 
                    form((int)"Unexpected response from the backend, exiting...\n"));
                exit(1);
        }
    }
}
@


1.27
log
@don't put newlines on error messages from the backend -- they come
with newlines attached
@
text
@d28 1
a28 1
 *	$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.26 1992/08/03 18:14:55 mer Exp mao $
d40 1
a40 1
RcsId ("$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.26 1992/08/03 18:14:55 mer Exp mao $");
a233 1
	    /* An error, return 0. */
d469 1
a469 1
    while (id[0] == 'E') {
d478 1
a478 2
	if (pq_getnchar(id, 0, 1) == EOF)
	    return ((char *) NULL);
d515 1
a515 1
	  case 'E':		/* print error and go back to processing return values */
d519 1
a519 2
	    if (pq_getnchar(id, 0, 1) == EOF)
		return((char *) NULL);
d596 1
a596 1
    while (id[0] == 'E') {
d605 1
a605 2
	if (pq_getnchar(id, 0, 1) == EOF)
	    return (-1);
d639 1
a639 1
	  case 'E':		/* print error and go back to processing return values */
d643 1
a643 1
	    pq_getnchar(id, 0, 1);
d709 1
a709 1
    while (id[0] == 'E') {
d718 1
a718 2
	if (pq_getnchar(id, 0, 1) == EOF)
	    return (-1);
d743 1
a743 1
	  case 'E': /* print error and go back to processing return values */
d747 1
a747 1
	    pq_getnchar(id, 0, 1);
a823 1
	    /* An error, return 0. */
a826 2
	    /* PQportset = 0;
	       EstablishComm(); */
a912 1

@


1.26
log
@make sure we don't loop reading notices from a backend quickdie
@
text
@d28 1
a28 1
 *	$Header: /private/mer/pg/src/lib/libpq/RCS/fe-pqexec.c,v 1.25 1992/07/29 21:19:14 mao Exp mer $
d40 1
a40 1
RcsId ("$Header: /private/mer/pg/src/lib/libpq/RCS/fe-pqexec.c,v 1.25 1992/07/29 21:19:14 mao Exp mer $");
d169 1
a169 1
        fprintf(stderr,"%s \n",&errormsg[0]+4);
d238 1
a238 1
	    fprintf(stderr,"%s \n", &errormsg[0] + 4);
d250 1
a250 1
	    fprintf(stderr,"%s \n", &errormsg[0] + 4);
d520 1
a520 1
	    fprintf(stderr,"%s \n", errormsg);
d528 1
a528 1
	    fprintf(stderr,"%s \n", errormsg);
d646 1
a646 1
	    fprintf(stderr,"%s \n", errormsg);
d653 1
a653 1
	    fprintf(stderr,"%s \n", errormsg);
d751 1
a751 1
	    fprintf(stderr,"%s \n", errormsg);
d758 1
a758 1
	    fprintf(stderr,"%s \n", errormsg);
d832 1
a832 1
	    fprintf(stderr,"%s \n", errormsg);
d844 1
a844 1
	    fprintf(stderr,"%s \n", errormsg);
d917 1
a917 1
                fprintf(stderr,"%s \n", errormsg);
d924 1
a924 1
                fprintf(stderr,"%s \n", errormsg);
@


1.25
log
@fix up error message printing, handling of errors in PQfn and friends
@
text
@d28 1
a28 1
 *	$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.24 1992/06/25 23:53:49 mao Exp $
d40 1
a40 1
RcsId ("$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.24 1992/06/25 23:53:49 mao Exp $");
d243 5
a247 1
	    pq_getstr(errormsg, error_msg_length);
d838 5
a842 1
	    pq_getstr(errormsg, error_msg_length);
@


1.24
log
@change behavior of libpq with respect to PGOPTION env var -- do what the
documentation claims we do.
@
text
@d28 1
a28 1
 *	$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.23 1992/06/15 08:25:27 dpassage Exp mao $
d40 1
a40 1
RcsId ("$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.23 1992/06/15 08:25:27 dpassage Exp mao $");
d169 1
a169 1
        fprintf(stdout,"%s \n",&errormsg[0]+4);
d238 1
a238 1
	    fprintf(stdout,"%s \n", &errormsg[0] + 4);
d246 1
a246 1
	    fprintf(stdout,"%s \n", &errormsg[0] + 4);
d466 2
a467 1
    if (id[0] == 'E') {
d469 8
a476 2
        pq_getstr(buf,sizeof(buf));
        printf ("Error: %s\n",buf);
d516 3
a518 2
	    fprintf(stdout,"%s \n", errormsg);
	    pq_getnchar(id, 0, 1);
d524 1
a524 1
	    fprintf(stdout,"%s \n", errormsg);
d526 2
d595 2
a596 1
    if (id[0] == 'E') {
d598 8
a605 2
        pq_getstr(buf,sizeof(buf));
        printf ("Error: %s\n",buf);
d642 1
a642 1
	    fprintf(stdout,"%s \n", errormsg);
d649 1
a649 1
	    fprintf(stdout,"%s \n", errormsg);
d709 2
a710 1
    if (id[0] == 'E') {
d712 8
a719 2
        pq_getstr(buf,sizeof(buf));
        printf ("Error: %s\n",buf);
d747 1
a747 1
	    fprintf(stdout,"%s \n", errormsg);
d754 1
a754 1
	    fprintf(stdout,"%s \n", errormsg);
d828 1
a828 1
	    fprintf(stdout,"%s \n", errormsg);
d836 1
a836 1
	    fprintf(stdout,"%s \n", errormsg);
d909 1
a909 1
                fprintf(stdout,"%s \n", errormsg);
d916 1
a916 1
                fprintf(stdout,"%s \n", errormsg);
@


1.23
log
@fix transmission of varlena's in fe/be protocol
@
text
@d28 1
a28 1
 *	$Header: /private/dpassage/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.22 1992/06/12 06:15:41 mao Exp dpassage $
d40 1
a40 1
RcsId ("$Header: /private/dpassage/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.22 1992/06/12 06:15:41 mao Exp dpassage $");
a51 1
 *	PQoption:	PGOPTION
d123 11
a133 1
    if ((PQoption == NULL) && ((PQoption = getenv("PGOPTION")) == NULL))
d141 1
a141 1
    
@


1.22
log
@bug fixes, interface standardization
@
text
@d28 1
a28 1
 *	$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.21 1992/05/07 23:23:00 clarsen Exp $
d40 1
a40 1
RcsId ("$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.21 1992/05/07 23:23:00 clarsen Exp $");
d601 3
a603 1
	    actual_len = pq_getint(4);
d606 2
d665 8
a672 1
    pq_putint(nbytes + 4, 4);	/* size of varlena */
d674 1
@


1.21
log
@remove 4.1 syntax error.
@
text
@d28 1
a28 1
 *	$Header: /home/postgres/clarsen/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.20 1992/05/05 16:15:24 clarsen Exp clarsen $
d37 1
d40 1
a40 1
RcsId ("$Header: /home/postgres/clarsen/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.20 1992/05/05 16:15:24 clarsen Exp clarsen $");
d525 198
d824 7
a830 9
		case 'B':
		/* Copy command began successfully - it is sending stuff back...  */
		return
		"BCOPY";

		case 'D':
		/* Copy command began successfully - it is waiting to receive... */
		return
		"DCOPY";
@


1.20
log
@don't loop infinitely on EOF
@
text
@d28 1
a28 1
 *	$Header: /private/clarsen/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.19 1992/02/25 15:29:27 clarsen Exp clarsen $
d39 1
a39 1
RcsId ("$Header: /private/clarsen/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.19 1992/02/25 15:29:27 clarsen Exp clarsen $");
d154 2
a155 1
	pq_getnchar(id, 0, 1) == EOF ? return;
d160 2
a161 1
        pq_getnchar(id, 0, 1) == EOF ? return;
@


1.19
log
@async portals.
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.18 92/01/13 18:29:37 mer Exp Locker: clarsen $
d39 1
a39 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.18 92/01/13 18:29:37 mer Exp Locker: clarsen $");
d154 1
a154 1
	pq_getnchar(id, 0, 1);
d159 1
a159 1
        pq_getnchar(id, 0, 1);
@


1.18
log
@don't loop on 'E' since only one comes from backend
@
text
@d28 1
a28 1
 *	$Header: /users/mer/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.17 1992/01/09 22:47:11 mer Exp mer $
d34 1
d39 1
a39 1
RcsId ("$Header: /users/mer/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.17 1992/01/09 22:47:11 mer Exp mer $");
d592 6
a598 1
    	case 'A':
d600 1
d603 7
a609 3
	    return
		process_portal(1);
	    
@


1.17
log
@make PQdatabase an array so as not to rely on dbname param being in
stable storage for PQsetdb() routine
@
text
@d28 1
a28 1
 *	$Header: /users/mer/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.16 1992/01/02 22:02:44 clarsen Exp mer $
d38 1
a38 1
RcsId ("$Header: /users/mer/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.16 1992/01/02 22:02:44 clarsen Exp mer $");
a153 5
    }
    while(id[0] == 'E') {
        pq_getstr(errormsg,error_msg_length);
        fprintf(stdout,"%s \n",&errormsg[0]+4);
        pq_getnchar(id, 0, 1);
@


1.16
log
@parse notice and error messages correctly.
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.15 91/11/18 22:40:44 hong Exp Locker: clarsenp $
d38 1
a38 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.15 91/11/18 22:40:44 hong Exp Locker: clarsenp $");
d68 1
a68 1
char 	*PQdatabase;	 	/* the POSTGRES database to access */
d103 13
a115 5
    if ((PQdatabase == NULL) 
	&& ((PQdatabase = getenv ("PGDATABASE")) == NULL)) 
	libpq_raise(&ProtocolError,
		    form((int)"Fatal Error -- No database is specified."));
    
d341 2
a342 1
    PQdatabase = dbname;
@


1.15
log
@incorrect parameter passing to libpq_raise(), trying to
cast a struct to a pointer.
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.14 91/11/18 16:52:08 clarsen Exp Locker: hong $
d38 1
a38 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.14 91/11/18 16:52:08 clarsen Exp Locker: hong $");
d147 5
d488 7
@


1.14
log
@
postgres fs additions
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.13 91/11/13 08:55:28 clarsen Exp Locker: clarsen $
d38 1
a38 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.13 91/11/13 08:55:28 clarsen Exp Locker: clarsen $");
d105 1
a105 1
	libpq_raise(ProtocolError,
d167 1
a167 1
	    libpq_raise(ProtocolError,
d271 1
a271 1
	        libpq_raise(ProtocolError, form ((int)s));
d468 1
a468 1
		libpq_raise(ProtocolError, form ((int)"Buffer Too Small: %s", id));
d499 1
a499 1
	    libpq_raise(ProtocolError, form((int)"Unexpected identifier: %s", id));
d609 1
a609 1
	    	libpq_raise(ProtocolError, 
d612 1
a612 1
	    	libpq_raise(ProtocolError, 
d654 1
a654 1
                    libpq_raise(ProtocolError, 
d657 1
a657 1
                    libpq_raise(ProtocolError, 
@


1.13
log
@prototypes
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.12 91/08/12 21:40:31 mao Exp Locker: clarsen $
d35 1
d38 1
a38 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.12 91/08/12 21:40:31 mao Exp Locker: clarsen $");
d141 1
d147 5
d390 4
a393 1
 * 	result_is_int	: If the result is an integer, this must be non-zero
d400 2
a401 1
PQfn(fnid, result_buf, result_len, result_is_int, args, nargs)
d403 1
a403 1
    int *result_buf;	/* can't use void, dec compiler barfs */
d405 2
a406 1
    int result_is_int;
d430 4
a433 2
	    pq_putint(args[i].u.integer, 4);
	else
d444 6
d459 24
d484 12
a495 5
    switch (id[0]) {
    case 'G':		/* PQFN: simple return value	*/
	actual_len = pq_getint(4);
	pqdebug2("LENGTH act/usr %ld/%ld\n", (char*)actual_len, (char*)result_len);
	if (actual_len < 0 || actual_len > result_len) {
d497 1
d499 2
a500 1
	    libpq_raise(ProtocolError, form ((int)"Buffer Too Small: %s", id));
a501 19
	if (result_is_int)
	    *(int *)result_buf = pq_getint(4);
	else
	    pq_getnchar((char *)result_buf, 0, actual_len);
	if (actual_len != result_len)	/* if wouldn't overflow the buf */
	    ((char *)result_buf)[actual_len] = 0;	/* add a \0 */
	pq_getnchar(id, 0, 1);
	return("G");

    case '0':		/* PQFN: no return value	*/
	return("V");

    default:
	/* The backend violates the protocol. */
	pqdebug("RESET CALLED FROM CASE G", (char *)0);
	pqdebug("Protocol Error, bad form, got '%c'", (char *)id[0]);
	PQreset();
	libpq_raise(ProtocolError, form((int)"Unexpected identifier: %s", id));
	return(NULL);
@


1.12
log
@fix comm protocol to shut down channel cleanly on exit of monitor
@
text
@d28 1
a28 1
 *	$Header: /local/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.11 1991/05/23 18:23:55 kemnitz Exp mao $
d37 1
a37 1
RcsId ("$Header: /local/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.11 1991/05/23 18:23:55 kemnitz Exp mao $");
d105 1
a105 1
		    form("Fatal Error -- No database is specified."));
d161 1
a161 1
	      form("Failed to connect to backend (host=%s, port=%s)",
d202 1
a202 1
        pqdebug("Identifier is: %c", id[0]);
d238 1
a238 1
	    pqdebug("Transaction Id is: %d", PQxactid);
d264 1
a264 1
	        libpq_raise(ProtocolError, form (s));
d420 1
a420 1
	    pq_putnchar(args[i].u.ptr, args[i].len);
d432 1
a432 1
    pqdebug("The Identifier is: %c", id[0]);
d435 1
a435 1
    pqdebug("The Transaction Id is: %d", PQxactid);
d443 1
a443 1
	pqdebug2("LENGTH act/usr %ld/%ld\n", actual_len, result_len);
d445 1
a445 1
	    pqdebug("RESET CALLED FROM CASE G", 0);
d447 1
a447 1
	    libpq_raise(ProtocolError, form ("Buffer Too Small: %s", id));
d452 1
a452 1
	    pq_getnchar(result_buf, 0, actual_len);
d463 2
a464 2
	pqdebug("RESET CALLED FROM CASE G", 0);
	pqdebug("Protocol Error, bad form, got '%c'", id[0]);
d466 1
a466 1
	libpq_raise(ProtocolError, form("Unexpected identifier: %s", id));
d517 1
a517 1
    	pqdebug("The Identifier is: %c", id[0]);
d521 1
a521 1
    	pqdebug("The Transaction Id is: %d", PQxactid);
d576 1
a576 1
			form("No response from the backend, exiting...\n"));
d579 1
a579 1
		   form("Unexpected response from the backend, exiting...\n"));
d621 1
a621 1
                        form("No response from the backend, exiting...\n"));
d624 1
a624 1
                    form("Unexpected response from the backend, exiting...\n"));
@


1.11
log
@got rid of lint warning "has return(e); and return;"
@
text
@d11 1
a11 1
 *	StringPointerSet, InitVacuumDemon
d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.10 91/05/22 22:22:48 kemnitz Exp Locker: kemnitz $
d37 1
a37 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.10 91/05/22 22:22:48 kemnitz Exp Locker: kemnitz $");
a296 43
/* ----------------
 *	InitVacuumDemon
 * ----------------
 */
void
InitVacuumDemon(host, database, terminal, option, port, vacuum)
    String	host;
    String	database;
    String	terminal;
    String	option;
    String	port;
    String	vacuum;
{
    String	path = NULL;
    
    Assert(!PQportset);
    Assert(!PointerIsValid(PQdatabase));
    
    StringPointerSet(&PQhost, host, "PGHOST", DefaultHost);
    
    if (!PointerIsValid(database)) {
	database = getenv ("PGDATABASE");
    }
    if (!PointerIsValid(database)) {
	libpq_raise(ProtocolError,
		    form("InitVacuumDemon: No database specified"));
    }
    PQsetdb(database);
    
    StringPointerSet(&PQtty, terminal, "PGTTY", DefaultTty);
    StringPointerSet(&PQoption, option, "PGOPTION", DefaultOption);
    StringPointerSet(&PQport, port, "PGPORT", DefaultPort);
    StringPointerSet(&path, vacuum, "PGVACUUM", DefaultVacuum);
    
    if (pq_connect(PQdatabase, getenv("USER"), PQoption, PQhost, PQtty,
		   path, (short) atoi(PQport)) == -1 ) {
	    libpq_raise(ProtocolError,
		    form("Fatal Error -- No POSTGRES backend to connect to"));
    }
    pq_flush();
    PQportset = 1;
}

d348 5
d354 1
@


1.10
log
@process-portal now handles ERRORs and NOTICEs properly.
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.9 91/03/21 21:52:26 kemnitz Exp Locker: kemnitz $
d37 1
a37 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.9 91/03/21 21:52:26 kemnitz Exp Locker: kemnitz $");
d504 1
@


1.9
log
@Now can deal with error messages gotten from portals.
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.8 91/03/08 19:55:28 kemnitz Exp Locker: kemnitz $
d37 1
a37 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.8 91/03/08 19:55:28 kemnitz Exp Locker: kemnitz $");
d173 1
a173 1
 * 	Process protal queries. 
d184 1
a184 1
    char *errormsg;
d188 1
a188 1
    
d193 4
a196 4
    /* Read in the identifier following the portal name. */
    pq_getnchar(id, 0, 1);
    read_remark(id);
    pqdebug("Identifier is: %c", id[0]);
d198 32
a229 10
    switch (id[0]) {
    case 'T':
	/* Tuples are returned, dump data into a portal buffer. */
	if (dump_data(pname, rule_p) == -1)
	{
		return("R");
	}
	sprintf(PQcommand, "P%s", pname);
	strcpy(retbuf, PQcommand);
	return(retbuf);
d231 10
a240 7
	/* Pending data inquiry - return nothing */
    case 'C':
	/* Portal query command (e.g., retrieve, close), no tuple returned. */
	PQxactid = pq_getint (4);
	pqdebug("Transaction Id is: %d", PQxactid);
	pq_getstr(command, command_length);
	pqdebug("Query command: %s", command);
d242 15
a256 15
	/* Process the portal commands. */
	if (strcmp(command, "retrieve") == 0) {
	    /* Allocate a portal buffer, if portal table is full, error. */
	    pbuf_setup(pname);
	    return
		"Cretrieve";
	} 
	else if (strcmp (command, "close") == 0) 
	    return
		"Cclose";
	else {
	    sprintf(retbuf, "C%s", command);
	    return
		retbuf;
	}
d258 3
a260 3
    default:
	{
	    char s[45];
d262 4
a265 3
	    PQreset();
	    sprintf(s, "Unexpected identifier in process_portal: %c", id[0]);
	    libpq_raise(ProtocolError, form (s));
d269 1
a269 1
	
@


1.8
log
@added stuff to deal with copy command protocols.
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.7 91/03/06 18:35:17 mao Exp Locker: kemnitz $
d37 1
a37 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.7 91/03/06 18:35:17 mao Exp Locker: kemnitz $");
d201 4
a204 1
	dump_data(pname, rule_p);
d232 1
a232 1
	
@


1.7
log
@spelling error
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.6 91/03/05 13:11:27 mer Exp Locker: mao $
d37 1
a37 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.6 91/03/05 13:11:27 mer Exp Locker: mao $");
d568 11
a578 1
	    
d589 45
@


1.6
log
@cosmetic error message change
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.5 91/03/05 13:00:18 mao Exp Locker: mer $
d37 1
a37 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.5 91/03/05 13:00:18 mao Exp Locker: mer $");
d573 1
a573 1
			form("No response from the backend, exitting...\n"));
d576 1
a576 1
		   form("Unexpected response from the backend, exitting...\n"));
@


1.5
log
@get vacuumd daemon and vcontrol working
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.4 91/02/28 10:47:02 mer Exp Locker: mao $
d37 1
a37 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.4 91/02/28 10:47:02 mer Exp Locker: mao $");
d571 6
a576 2
	    libpq_raise(ProtocolError, 
		form("Fatal errors in the backend, exitting...\n"));
@


1.4
log
@added functionality to support backend debug output redirection
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.3 91/02/22 17:06:48 mer Exp Locker: mer $
d37 1
a37 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.3 91/02/22 17:06:48 mer Exp Locker: mer $");
d158 2
a159 6
	if ( pq_connect( PQdatabase, 
		getenv("USER"), 
		PQoption, 
		PQhost, 
		PQtty,
		(short)atoi(PQport) ) == -1 ) {
d164 1
a164 6
	
/*	Now a message.
 *
 *	pqdebug("\nInitstr sent to the backend: %s", PQinitstr);
 *	pq_putstr(PQinitstr);
 */
d302 2
a303 11
/*    
 *  PQinitstr = pbuf_addValues(initstr_length);
 *  sprintf(PQinitstr, "%s,%s,%s,%s,%s\n", getenv ("USER"),
 *	    PQdatabase, PQtty, PQoption, path);
 */
    
    if ( pq_connect( PQdatabase, 
	getenv("USER"), 
	PQoption, 
	PQhost, 
	(short)atoi(PQport) ) == -1 ) {
a306 5
    
/*
 *  pqdebug("\nInitstr sent to the backend: %s", PQinitstr);
 *  pq_putstr(PQinitstr);
 */
@


1.3
log
@modified for new postmaster interface
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.2 91/02/20 00:35:06 cimarron Exp Locker: mer $
d37 1
a37 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.2 91/02/20 00:35:06 cimarron Exp Locker: mer $");
d162 1
@


1.2
log
@changed fe routines to use new portal support
@
text
@d28 1
a28 1
 *	$Header: RCS/fe-pqexec.c,v 1.1 91/02/09 20:43:52 cimarron Exp Locker: cimarron $
d37 1
a37 1
RcsId ("$Header: RCS/fe-pqexec.c,v 1.1 91/02/09 20:43:52 cimarron Exp Locker: cimarron $");
d72 2
a73 2
char	*PQinitstr = NULL;	/* the initialization string passed 
				   to backend */
d85 3
d122 7
a128 4
    PQinitstr = pbuf_addValues(initstr_length);
    
    sprintf(PQinitstr, "%s,%s,%s,%s\n",
	    getenv("USER"), PQdatabase, PQtty, PQoption);
d155 8
a162 4
    if (!PQportset) {
	if (PQinitstr == NULL)
	    read_initstr();
	if (pq_connect(PQhost, PQport) == -1) 
d166 1
d168 5
a172 2
	pqdebug("\nInitstr sent to the backend: %s", PQinitstr);
	pq_putstr(PQinitstr);
d310 5
a314 3
    PQinitstr = pbuf_addValues(initstr_length);
    sprintf(PQinitstr, "%s,%s,%s,%s,%s\n", getenv ("USER"),
	    PQdatabase, PQtty, PQoption, path);
d316 6
a321 2
    if (pq_connect (PQhost, PQport) == -1) 
	libpq_raise(ProtocolError,
d323 1
d325 4
a328 2
    pqdebug("\nInitstr sent to the backend: %s", PQinitstr);
    pq_putstr(PQinitstr);
d369 6
a374 4
    if (PQinitstr != NULL)
        pbuf_free(PQinitstr);
    
    PQinitstr = NULL;
d522 1
a522 1
    /* If the communication is not established, send PQinitstr to backend. */
d593 3
a595 9
	    PQreset ();
	    fprintf(stdout,
	      "Unexpected Identifier. Trying to reestablish communication\n");
	    fprintf(stdout, "Identifier is : %c \n", id[0]);
	    
	    fflush(stdout);
	    PQportset = 0;
	    EstablishComm();
	    return "R";
@


1.1
log
@Initial revision
@
text
@d10 2
a11 3
 *	pqdebug, pqdebug2, read_initstr, read_remark
 *	EstablishComm, process_portal, StringPointerSet
 *	InitVacuumDemon
a13 2
 *	PQtrace		- turn on pqdebug tracing
 *	PQuntrace	- turn off pqdebug tracing
d28 1
a28 1
 *	$Header$
d34 1
a34 1
#include "tmp/libpq.h"
d37 1
a37 1
RcsId ("$Header: RCS/pqexec.c,v 1.16 91/02/06 15:14:30 mer Exp Locker: cimarron $");
a73 1
int	PQtracep = 0;		/* 1 to print out debugging message */
a74 2
FILE    *debug_port;

a80 9
void
pqdebug (target, msg)
char *target, *msg;
{
    if (PQtracep) {
	fprintf(debug_port, target, msg);
	fprintf(debug_port, "\n");
    }
}
a81 10
void
pqdebug2(target, msg1, msg2)
char *target, *msg1, *msg2;
{
    if (PQtracep) {
	printf(target, msg1, msg2);
	printf("\n");
    }
}

d119 1
a119 1
    PQinitstr = addValues(initstr_length);
d211 1
a211 1
	    portal_setup(pname);
d296 1
a296 1
    PQinitstr = addValues (initstr_length);
a313 9
/* --------------------------------
 *	PQtrace() / PQuntrace()
 * --------------------------------
 */
void
PQtrace()
{
    PQtracep = 1;
}
a314 6
void
PQuntrace()
{
    PQtracep = 0;
}

d347 1
a347 1
        pq_free(PQinitstr);
a464 27

    case 'E': 		/* An error, return 0.  	*/
	pq_getstr(errormsg, error_msg_length);
	pqdebug("%s error encountered.", errormsg);
	/* XXX fall through??? Fix this -cim 2/9/91  */
	
    case 'A': 		/* Asynchronized portal. 	*/
	pq_getint(4);	/* throw away xactid		*/
	pqdebug("%s portal encountered.", "Asynchronized");
	return
	    process_portal(1);

    case 'P': 		/* Synchronized (normal) portal. */
	pq_getint(4);	/* throw away xactid		*/
	return
	    process_portal(0);

    case 'C': 		/* Query executed successfully.  */
	pq_getint(4);	/* throw away xactid		*/
	pq_getstr(command, command_length);
	pqdebug("Query command: %s", command);
	sprintf(PQcommand, "C%s", command);
	return
	    PQcommand;

    case 'I':   /* End of queries query */
	return("I");
@
