head	1.39;
access;
symbols
	release_4_2:1.39
	aix_ok:1.36
	Version_2_1:1.8;
locks; strict;
comment	@ * @;


1.39
date	94.06.28.18.03.46;	author aoki;	state Exp;
branches;
next	1.38;

1.38
date	94.02.07.11.26.36;	author aoki;	state Exp;
branches;
next	1.37;

1.37
date	94.01.13.17.26.48;	author jiangwu;	state Exp;
branches;
next	1.36;

1.36
date	93.09.20.20.39.01;	author aoki;	state Exp;
branches;
next	1.35;

1.35
date	93.07.24.20.34.30;	author aoki;	state Exp;
branches;
next	1.34;

1.34
date	93.06.16.05.05.24;	author aoki;	state Exp;
branches;
next	1.33;

1.33
date	93.05.24.19.27.30;	author marc;	state Exp;
branches;
next	1.32;

1.32
date	93.02.22.06.09.57;	author marc;	state Exp;
branches;
next	1.31;

1.31
date	93.02.22.04.15.39;	author marc;	state Exp;
branches;
next	1.30;

1.30
date	93.01.16.03.14.59;	author aoki;	state Exp;
branches;
next	1.29;

1.29
date	93.01.08.23.46.22;	author clarsen;	state Exp;
branches;
next	1.28;

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.39
log
@change exception.h to exc.h
@
text
@/* ----------------------------------------------------------------
 *   FILE
 *	fe-pqexec.c
 *	
 *   DESCRIPTION
 *	support for executing POSTGRES commands and functions
 *	from a frontend application.
 *
 *   SUPPORT ROUTINES
 *	pq_global_init, read_remark, EstablishComm, process_portal
 *
 *   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
 *	PQfsread,
 *	PQfswrite	- Special versions of PQfn intended for use by
 *			  the Inversion routines p_read/p_write.
 *
 *   NOTES
 *	These routines are NOT compiled into the postgres backend,
 *	rather they end up in libpq.a.
 *
 *   IDENTIFICATION
 *	$Header: /import/faerie/aoki/postgres/src/libpq/RCS/fe-pqexec.c,v 1.38 1994/02/07 11:26:36 aoki Exp aoki $
 * ----------------------------------------------------------------
 */

#include "tmp/c.h"

#include "tmp/simplelists.h"
#include "tmp/libpq-fe.h"
#include "tmp/fastpath.h"
#include "libpq/auth.h"
#include "tmp/postgres.h"
#include "fmgr.h"
#include "utils/exc.h"

#include <pwd.h>

RcsId ("$Header: /import/faerie/aoki/postgres/src/libpq/RCS/fe-pqexec.c,v 1.38 1994/02/07 11:26:36 aoki Exp aoki $");

/* ----------------------------------------------------------------
 * 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 DefaultTty	"/dev/null"
#define DefaultOption	""

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 */

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

/*
 * pq_username
 */
static
char *
pq_username()
{
    static char userbuf[17];
    char *user;
    struct passwd *pw;

    /*
     * this is not a security thing.  we check USER first because people
     * dork with USER as a convenience...
     */
    if (!(user = getenv("USER")) &&
	(!(pw = getpwuid(getuid())) || !(user = pw->pw_name))) {
	return((char *) NULL);
    }
    (void) strncpy(userbuf, user, 16);
    userbuf[16] = '\0';
    return(userbuf);
}

/*
 * pq_print_elog
 *	print a backend error message ("E" or "N").
 *
 *	if a function name 'where' is given, prepend that to the backend
 *	message.
 *
 *	elog() sends the xact id followed by the null-delimited string.
 *	some routines (like PQexec) have already read the xact id.
 *	if 'readxid' is true, we've already read the transaction id.
 *	if not, we need to read it from the input stream since it 
 *	precedes the actual error message.
 *
 * RETURNS:
 *	0 on success, -1 on failure.  failure generally indicates a fatal
 *	backend error.
 */
pq_print_elog(where, readxid)
    char *where;
    bool readxid;
{
    char errbuf[error_msg_length];
    int len = error_msg_length;
    
    /*
     * XXX we throw away the xact id here.. but then, elog sends garbage
     * anyway.  (see utils/error/elog.c)
     */
    if ((!readxid && pq_getint(sizeof(int)) == EOF) ||
	pq_getstr(errbuf, error_msg_length) == EOF) {
	(void) strcpy(PQerrormsg,
		      "FATAL: pq_print_elog: unexpected end of connection\n");
	fputs(PQerrormsg, stderr);
	pqdebug("%s", PQerrormsg);
	PQreset();
	return(-1);
    }
    
#define	WHERE_MSG ": detected at "

    (void) strncpy(PQerrormsg, errbuf, len);
    len -= strlen(errbuf);
    if (where) {
	(void) strncat(PQerrormsg, WHERE_MSG, len);
	len -= strlen(WHERE_MSG);
	(void) strncat(PQerrormsg, where, len);
	len -= strlen(where);
	(void) strncat(PQerrormsg, "\n", len);
    }
    fputs(PQerrormsg, stderr);
    pqdebug("%s", PQerrormsg);
    return(0);
}

#define INVALID_BE_ID	'?'

/*
 * pq_read_id
 *	read a single-character protocol identifier.
 *
 * RETURNS:
 *	EOF on success if EOF is reached
 *	0 on success if EOF is not reached
 *	1 on error (e.g., the backend appears to have died)
 */
int
pq_read_id(id, where)
    char *id;
    char *where;
{
    int at_eof = 0;
    unsigned len = error_msg_length;
    
    Assert(id);
    Assert(where);
    
    id[0] = INVALID_BE_ID;
    if (pq_getnchar(id, 0, 1) == EOF) {
	at_eof = EOF;
	if (id[0] == INVALID_BE_ID) {

#define DIE_MSG "FATAL: no response from backend: detected in "

	    /*
	     * we got zero bytes back from the read.
	     * this is the world's stupidest way to detect this, forced
	     * upon us by the crufty pq_getnchar interface.
	     */
	    (void) strncpy(PQerrormsg, DIE_MSG, len);
	    len -= strlen(DIE_MSG);
	    (void) strncat(PQerrormsg, where, len);
	    len -= strlen(where);
	    (void) strncat(PQerrormsg, "\n", len);
	    fputs(PQerrormsg, stderr);
	    pqdebug("%s", PQerrormsg);
	    return(1);
	}
    }
    return(at_eof);
}
    
/* ----------------
 * pq_global_init
 * 	If the global 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 (where applicable).
 *
 * RETURNS:
 *	0 on success, -1 on (fatal) error.
 * ----------------
 */

static
pq_global_init()
{
    char *tmpname;

    if (PQdatabase[0] == '\0') {
	if (!(tmpname = getenv("PGDATABASE")) &&
	    !(tmpname = fe_getauthname())) {
	    (void) strcpy(PQerrormsg, 
			  "FATAL: pq_global_init: unable to determine a database name!\n");
	    fputs(PQerrormsg, stderr);
	    pqdebug("%s", PQerrormsg);
	    return(-1);
	}
	PQdatabase[16] = '\0';
	strncpy(PQdatabase, tmpname, 16);
    }
    
    if (!PQhost) {
	if (!(tmpname = getenv("PGHOST"))) {
	    tmpname = DefaultHost;
	}
	if (!(PQhost = malloc(strlen(tmpname) + 1))) {
	    (void) strcpy(PQerrormsg,
			  "FATAL: pq_global_init: unable to allocate memory!\n");
	    fputs(PQerrormsg, stderr);
	    pqdebug("%s", PQerrormsg);
	    return(-1);
	}
	(void) strcpy(PQhost, tmpname);
    }
    
    if (!PQtty) {
	if (!(tmpname = getenv("PGTTY"))) {
	    tmpname = DefaultTty;
	}
	if (!(PQtty = malloc(strlen(tmpname) + 1))) {
	    (void) strcpy(PQerrormsg,
			  "FATAL: pq_global_init: unable to allocate memory!\n");
	    fputs(PQerrormsg, stderr);
	    pqdebug("%s", PQerrormsg);
	    return(-1);
	}
	(void) strcpy(PQtty, tmpname);
    }

    /*
     *  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) {
	PQoption = DefaultOption;
    }

    if (!PQport) {
	if (!(tmpname = getenv("PGPORT"))) {
	    tmpname = POSTPORT;
	}
	if (!(PQport = malloc(strlen(tmpname) + 1))) {
	    (void) strcpy(PQerrormsg,
			  "FATAL: pq_global_init: unable to allocate memory!\n");
	    fputs(PQerrormsg, stderr);
	    pqdebug("%s", PQerrormsg);
	    return(-1);
	}
	(void) strcpy(PQport, tmpname);
    }
    
    bzero((char *) PQerrormsg, sizeof(PQerrormsg));

    return(0);
}

/* ----------------
 * read_remark
 *	Read and discard remarks, then print pending NOTICEs.
 *
 *	XXX I can't find any place in the backend side of the protocol
 *	where "R" remarks are sent anymore.  we probably need this to
 *	clear any remaining elog(NOTICE) messages, though.  -pma 05/28/93
 * ----------------
 */
void
read_remark(id)
    char id[];
{
    char errbuf[error_msg_length];

    Assert(id);

    while (id[0] == 'R') {
	pq_getstr(errbuf, remark_length);
	if (pq_getnchar(id, 0, 1) == EOF)
	    return;
    }
    while (id[0] == 'N') {
	if (pq_print_elog((char *) NULL, false) < 0 ||
	    pq_getnchar(id, 0, 1) == EOF)
	    return;
    }
}

/* ----------------
 * EstablishComm
 *	Establishes a connection to a backend through the postmaster.
 *
 * RETURNS:
 *	0 on success, -1 on (fatal) error.
 * ----------------
 */
static
EstablishComm()
{
    extern void PQufs_init();

    if (!PQportset) { 
	if (pq_global_init() < 0) {
	    return(-1);
	}
	if (pq_connect(PQdatabase,
		       fe_getauthname(),
		       PQoption,
		       PQhost,
		       PQtty,
		       (char *) NULL,
		       (short) atoi(PQport)) == -1 ) {
	    (void) sprintf(PQerrormsg, 
			   "FATAL: Failed to connect to postmaster (host=%s, port=%s)\n",
			   PQhost, PQport);
	    pqdebug("%s", PQerrormsg);
	    (void) strcat(PQerrormsg, "\tIs the postmaster running?\n");
	    fputs(PQerrormsg, stderr);
	    return(-1);
	}
	pq_flush();
	PQufs_init();
	PQportset = 1;
    }
    return(0);
}

/* ----------------
 * process_portal
 * 	Process portal queries. 
 *
 * RETURNS:
 * 	The same values as PQexec().
 * ----------------
 */
static
char *
process_portal(rule_p)
    int rule_p;
{
    char pname[portal_name_length];
    char id;
    char command[command_length];
    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. */
	if (pq_read_id(&id, "process_portal") > 0) {
	    (void) strcpy(retbuf, "E");
	    return(retbuf);
	}
        read_remark(&id);
        pqdebug("Identifier is: %x", (char *) id);

        switch (id) {
        case 'E':
	    if (pq_print_elog((char *) NULL, false) < 0) {
		(void) strcpy(retbuf, "E");
		return(retbuf);
	    }
	    (void) strcpy(retbuf, "R");
	    return(retbuf);
        case 'N':
	    /*
	     * print the NOTICE and go back to processing return values.
	     * If we get an EOF (i.e. the backend quickdies) return "E" to
	     * the application.
	     */
	    if (pq_print_elog((char *) NULL, false) < 0) {
		(void) strcpy(retbuf, "E");
		return(retbuf);
	    }
	    break;
        case 'T':
	    /* Tuples are returned, dump data into a portal buffer. */
	    if (dump_data(pname, rule_p) == -1) {
		(void) strcpy(retbuf, "R");
		return(retbuf);
	    }
	    sprintf(retbuf, "P%s", pname);
	    return(retbuf);
	    /* Pending data inquiry - return nothing */
        case 'C':
	    /*
	     * Portal query command (e.g., retrieve, close),
	     * no tuple returned.
	     */
	    PQxactid = pq_getint(4);
	    pqdebug("process_portal: Transaction Id is: %d",
		    (char *) PQxactid);
	    pq_getstr(command, command_length);
	    pqdebug("process_portal: Query command: %s", command);

	    /* Process the portal commands. */
	    if (strcmp(command, "retrieve") == 0) {
	        pbuf_setup(pname);
		(void) strcpy(retbuf, "Cretrieve");
	    } else {
	        sprintf(retbuf, "C%s", command);
	    }
	    return(retbuf);
	case 'A':
	    /* I have no reason to believe that this will ever happen
	     * But just in case...
	     *   -- jw, 1/7/94
	     */	    
	    {
		char relname[NAMEDATALEN+1];
		extern int PQAsyncNotifyWaiting;
		
		PQAsyncNotifyWaiting = 1;
		pq_getstr(relname,NAMEDATALEN);
		relname[NAMEDATALEN] = '\0';
		pqdebug2("Asynchronous notification encountered. (%s, %d)",
			 relname, PQxactid);
		PQappendNotify(relname, PQxactid);
	    }
	    break;
        default:
	    sprintf(PQerrormsg,
		    "FATAL: process_portal: protocol error: id=%x\n",
		    id);
	    fputs(PQerrormsg, stderr);
	    pqdebug("%s", PQerrormsg);
	    PQreset();
	    (void) strcpy(retbuf, "E");
	    return(retbuf);
	}
    }
}

/* ----------------------------------------------------------------
 *			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;
}

/* ----------------
 *	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 id;

    for (i = 0; i < i_count; i++) {
	if (pq_read_id(&id, "PQFlushI") > 0)
	    return(-1);
	if (id != 'I') {
	    (void) strcpy(PQerrormsg,
			  "FATAL: PQFlushI: read bad protocol entity\n");
	    fputs(PQerrormsg, stderr);
	    pqdebug("%s", PQerrormsg);
	    PQreset();
	    return(-1);
	}
	pq_getint(4); /* throw this away */
    }
    return(0);
}

/* ----------------
 *	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.
 *
 * RETURNS
 *	NULL on failure.  PQerrormsg will be set.
 *	"G" if there is a return value.
 *	"V" if there is no return value.
 * ----------------
 */
char *
PQfn(fnid, result_buf, result_len, actual_result_len,
     result_type, args, nargs)
    int fnid;
    int *result_buf;
    int result_len;
    int *actual_result_len;
    int result_type;
    PQArgBlock *args;
    int nargs;
{
    char id;
    char command[command_length];
    int  actual_len;
    short i;
    char retbuf[command_length + 1];

    if (!PQportset && EstablishComm() < 0) {
	return((char *) NULL);
    }

    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	*/
    if (pq_read_id(&id, "PQfn") > 0)
	return((char *) NULL);
    if (id == 'E') {
	(void) pq_print_elog((char *) NULL, false);
	return ((char *) NULL);
    }

    read_remark(&id);
    fnid = pq_getint(4);
    pqdebug("The Identifier is: %x", (char *) id);

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

    if (id == 'V') {
	if (pq_read_id(&id, "PQfn") > 0)
	    return((char *) NULL);
    }
    for (;;) {
	switch (id) {
	case 'G':		/* 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)) {
		(void) sprintf(PQerrormsg,
			       "FATAL: PQfn: bogus return value (expected size %d, actually %d)\n",
			       result_len, actual_len);
		fputs(PQerrormsg, stderr);
		pqdebug("%s", PQerrormsg);
		PQreset();
		return((char *) NULL);
	    }
	    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 */
	    if (pq_read_id(&id, "PQfn") > 0)
		return((char *) NULL);
	    (void) strcpy(retbuf, "G");
	    return(retbuf);
	case 'E':
	    (void) pq_print_elog((char *) NULL, false);
	    return((char *) NULL);
	case 'N':
	    /* print notice and go back to processing return values */
	    (void) pq_print_elog((char *) NULL, false);
	    (void) pq_getnchar(&id, 0, 1);
	    if (pq_read_id(&id, "PQfn") > 0)
		return((char *) NULL);
	    break;
	case '0':		/* no return value */
	    (void) strcpy(retbuf, "V");
	    return(retbuf);
	default:
	    /* The backend violates the protocol. */
	    (void) sprintf(PQerrormsg,
			   "FATAL: PQfn: protocol error: id=%x\n",
			   id);
	    fputs(PQerrormsg, stderr);
	    pqdebug("%s", PQerrormsg);
	    PQreset();
	    return((char *) NULL);
	}
    }
    /*NOTREACHED*/
}

/*
 *  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.
 *
 *	These are NOT intended for direct use by users.  Use the
 *	documented interfaces (p_read and p_write) instead.
 */
int
PQfsread(fd, buf, nbytes)
    int fd;
    char *buf;
    int nbytes;
{
    int fnid;
    char id;
    char command[command_length];
    int  actual_len;
    short i;

    if (!PQportset && EstablishComm() < 0) {
	return(-1);
    }

    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 */
    if (pq_read_id(&id, "PQfsread") > 0)
	return(-1);
    if (id == 'E') {
	(void) pq_print_elog((char *) NULL, false);
	return(-1);
    }

    read_remark(&id);
    fnid = pq_getint(4);
    pqdebug("The Identifier is: %x", (char *) id);

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

    if (id == 'V')
	if (pq_read_id(&id, "PQfsread") > 0)
	    return(-1);
    for (;;) {
	switch (id) {
	case 'G':
	    nbytes = actual_len = pq_getint(4);
	    if (nbytes > 0)
		pq_getnchar((char *) buf, 0, nbytes);
	    if (pq_read_id(&id, "PQfsread") > 0)
		return(-1);
	    return(nbytes);
	case 'E':
	    (void) pq_print_elog((char *) NULL, false);
	    return(-1);
	case 'N':
	    /* print notice and go back to processing return values */
	    (void) pq_print_elog((char *) NULL, false);
	    if (pq_read_id(&id, "PQfsread") > 0)
		return(-1);
	    break;
	default:
	    /* The backend violates the protocol. */
	    sprintf(PQerrormsg,
		    "FATAL: PQfsread: protocol error: id=%x\n",
		    id);
	    fputs(PQerrormsg, stderr);
	    pqdebug("%s", PQerrormsg);
	    PQreset();
	    return(-1);
	}
    }
}

int
PQfswrite(fd, buf, nbytes)
    int fd;
    char *buf;
    int nbytes;
{
    int fnid;
    char id;
    char command[command_length];
    int  actual_len;
    short i;

    if (!PQportset && EstablishComm() < 0) {
	return(-1);
    }

    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 */
    if (pq_read_id(&id, "PQfswrite") > 0)
	return(-1);
    if (id == 'E') {
	(void) pq_print_elog((char *) NULL, false);
	return(-1);
    }

    read_remark(&id);
    fnid = pq_getint(4);
    pqdebug("The Identifier is: %x", (char *) id);

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

    if (id == 'V')
	if (pq_read_id(&id, "PQfswrite") > 0)
	    return(-1);
    for (;;) {
	switch (id) {
	case 'G':		/* simple return value */
	    actual_len = pq_getint(4);
	    if (actual_len != 4)
		libpq_raise(&ProtocolError,
			    form("wanted 4 bytes in PQfswrite, got %d\n",
				 actual_len));
	    nbytes = pq_getint(4);
	    if (pq_read_id(&id, "PQfswrite") > 0)
		return(-1);
	    return(nbytes);
	case 'E':
	    (void) pq_print_elog((char *) NULL, false);
	    return(-1);
	case 'N':
	    /* print notice and go back to processing return values */
	    (void) pq_print_elog((char *) NULL, false);
	    if (pq_read_id(&id, "PQfswrite") > 0)
		return(-1);
	    break;
	default:
	    /* The backend violates the protocol. */
	    sprintf(PQerrormsg,
		    "FATAL: PQfswrite: protocol error: id=%x\n",
		    id);
	    fputs(PQerrormsg, stderr);
	    pqdebug("%s", PQerrormsg);
	    PQreset();
	    return(-1);
	}
    }
}

/* ----------------
 *	PQexec -  Send a query to the POSTGRES backend.
 *
 * RETURNS:
 *	"E" on a fatal error (e.g., backend died).  A LIBPQ error
 *		message is stored in PQerrormsg.
 *	"R" on a non-fatal error (elog(WARN)).  The backend error 
 *		message is stored in PQerrormsg.
 *	"P<portal-name>" if tuples are available.
 *	"C<query-command>" if the command was successful but no tuples
 *		were returned.
 *	"BCOPY" if a "copy from" command was executed and the backend is
 *		sending data.
 *	"DCOPY" if a "copy to" command was executed and the backend is
 *		expecting data.
 * ----------------
 */
char *
PQexec(query)
    char *query;
{
    char id;
    char command[command_length];
    static char retbuf[command_length+1];

    if (!PQportset && EstablishComm() < 0) {
	(void) strcpy(retbuf, "E");
	return(retbuf);
    }

    /* 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.
	 */
    	/* Get the identifier. */
	if (pq_read_id(&id, "PQexec") > 0) {
	    (void) strcpy(retbuf, "E");
	    return(retbuf);
	}
    	read_remark(&id);
    	pqdebug("The Identifier is: %x", (char *) id);

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

    	switch (id) {
    	case 'I':
	    (void) strcpy(retbuf, "I");
	    return(retbuf);
    	case 'E':
	    if (pq_print_elog((char *) NULL, true) < 0) {
		(void) strcpy(retbuf, "E");
		return(retbuf);
	    }
	    (void) strcpy(retbuf, "R");
	    return(retbuf);
    	case 'N':
	    if (pq_print_elog((char *) NULL, true) < 0) {
		(void) strcpy(retbuf, "E");
		return(retbuf);
	    }
	    break;
    	case 'A':
	    {
		char relname[NAMEDATALEN+1];
		extern int PQAsyncNotifyWaiting;
		
		PQAsyncNotifyWaiting = 1;
		pq_getstr(relname,NAMEDATALEN);
		relname[NAMEDATALEN] = '\0';
		pqdebug2("Asynchronous notification encountered. (%s, %d)",
			 relname, PQxactid);
		PQappendNotify(relname, PQxactid);
	    }
	    break;
    	case 'P':
	    /* Synchronized (normal) portal. */
	    return(process_portal(0));
    	case 'C':
	    /* Query executed successfully but returned nothing. */
	    pq_getstr(command, command_length);
	    pqdebug("Query command: %s", command);
	    sprintf(retbuf, "C%s", command);
	    return(retbuf);
	case 'B':
	    /* Copy command began successfully - it is sending stuff back */
	    (void) strcpy(retbuf, "BCOPY");
	    return(retbuf);
	case 'D':
	    /* Copy command began successfully - it is waiting to receive */
	    (void) strcpy(retbuf, "DCOPY");
	    return(retbuf);
    	default:
	    (void) sprintf(PQerrormsg, 
			   "FATAL: PQexec: protocol error: id=%x\n",
			   id);
	    fputs(PQerrormsg, stderr);
	    pqdebug("%s", PQerrormsg);
	    PQreset();
	    (void) strcpy(retbuf, "E");
	    return(retbuf);
    	}
    }
}

/*
 * PQendcopy
 *	called while waiting for the backend to respond with success/failure
 *	to a "copy".
 *
 * RETURNS:
 *	0 on failure
 *	1 on success
 */
int
PQendcopy()
{
    char id;

    for (;;) {
	if (pq_read_id(&id, "PQendcopy") > 0)
	    return(0);
	switch (id) {
	case 'E':
	    (void) pq_print_elog((char *) NULL, false);
	    return(0);
	case 'N':
	    (void) pq_print_elog((char *) NULL, false);
	    break;
	case 'Z': /* backend finished the copy */
	    return(1);
	default:
	    (void) sprintf(PQerrormsg, 
			   "FATAL: PQendcopy: protocol error: id=%x\n",
			   id);
	    fputs(PQerrormsg, stderr);
	    pqdebug("%s", PQerrormsg);
	    PQreset();
	    return(0);
	}
    }
    /*NOTREACHED*/
}
@


1.38
log
@pqdebug is not varargs, guys
@
text
@d30 1
a30 1
 *	$Header: /faerie/aoki/postgres/src/libpq/RCS/fe-pqexec.c,v 1.37 1994/01/13 17:26:48 jiangwu Exp aoki $
d42 1
a42 1
#include "utils/exception.h"
d46 1
a46 1
RcsId ("$Header: /faerie/aoki/postgres/src/libpq/RCS/fe-pqexec.c,v 1.37 1994/01/13 17:26:48 jiangwu Exp aoki $");
@


1.37
log
@Added handling for async. notification message
-- jw, 1/13/94
@
text
@d30 1
a30 1
 *	$Header: /private/src/postgres/src/libpq/RCS/fe-pqexec.c,v 1.36 1993/09/20 20:39:01 aoki Exp jiangwu $
d46 1
a46 1
RcsId ("$Header: /private/src/postgres/src/libpq/RCS/fe-pqexec.c,v 1.36 1993/09/20 20:39:01 aoki Exp jiangwu $");
d455 1
a455 1
		char relname[16];
d459 4
a462 4
		pq_getstr(relname,16);
		pqdebug("%s notification encountered. (%s, %d)",
			"Asynchronized",
			relname, PQxactid);
d962 1
a962 1
		char relname[16];
d966 4
a969 4
		pq_getstr(relname,16);
		pqdebug("%s notification encountered. (%s, %d)",
			"Asynchronized",
			relname, PQxactid);
@


1.36
log
@whoops.  forgot to turn a strcpy into a sprintf
@
text
@d30 1
a30 1
 *	$Header: /home2/aoki/postgres/src/libpq/RCS/fe-pqexec.c,v 1.35 1993/07/24 20:34:30 aoki Exp $
d46 1
a46 1
RcsId ("$Header: /home2/aoki/postgres/src/libpq/RCS/fe-pqexec.c,v 1.35 1993/07/24 20:34:30 aoki Exp $");
d449 17
a960 8
	    (void) strcpy(PQerrormsg, 
			  "FATAL: PQexec: asynchronous portals not supported\n");
	    fputs(PQerrormsg, stderr);
	    pqdebug("%s", PQerrormsg);
	    PQreset();
	    (void) strcpy(retbuf, "E");
	    return(retbuf);
#if 0
a963 2
		int pid;
		PQAsyncNotifyWaiting = 0;
d965 1
a965 6
		/* Asynchronized portal. */
		/* No tuple transfer at this stage. */
		pqdebug("%s portal encountered.", "Asynchronized");
		/* Processed the same way as synchronized portal. */
		/*	    return
			    process_portal(1);*/
d967 4
a970 2
		pid =pq_getint(4);
		PQappendNotify(relname, pid);
a971 1
#endif
@


1.35
log
@added tmp/postgres.h (linux)
@
text
@d30 1
a30 1
 *	$Header: /home2/aoki/postgres/src/libpq/RCS/fe-pqexec.c,v 1.34 1993/06/16 05:05:24 aoki Exp aoki $
d46 1
a46 1
RcsId ("$Header: /home2/aoki/postgres/src/libpq/RCS/fe-pqexec.c,v 1.34 1993/06/16 05:05:24 aoki Exp aoki $");
d1027 3
a1029 3
	    (void) strcpy(PQerrormsg, 
			  "FATAL: PQendcopy: protocol error: id=%x\n",
			  id);
@


1.34
log
@removed references to vacuumd.
changed to use string POSTPORT
encapsulated elog message printing and reading of protocol id's
	(the latter checks the fd to see if the backend went away)
removed refs to initstr
removed calls to libpq_raise
now sets PQerrormsg all over the place
made internal routines static
modified PQexec/process_portal to return "E" on backend-death
@
text
@d30 1
a30 1
 *	$Header: /home2/aoki/postgres/src/libpq/RCS/fe-pqexec.c,v 1.33 1993/05/24 19:27:30 marc Exp aoki $
d40 1
d46 1
a46 1
RcsId ("$Header: /home2/aoki/postgres/src/libpq/RCS/fe-pqexec.c,v 1.33 1993/05/24 19:27:30 marc Exp aoki $");
@


1.33
log
@holy moly.  returning pointer to stack data from a function.  make static.
also, remove some unused variables.
@
text
@d10 1
a10 2
 *	read_initstr, read_remark, EstablishComm, process_portal,
 *	StringPointerSet
d21 4
a24 1
 *	
d30 1
a30 1
 *	$Header: /usr/local/devel/postgres/src/libpq/RCS/fe-pqexec.c,v 1.32 1993/02/22 06:09:57 marc Exp marc $
d39 1
d43 3
a45 1
RcsId ("$Header: /usr/local/devel/postgres/src/libpq/RCS/fe-pqexec.c,v 1.32 1993/02/22 06:09:57 marc Exp marc $");
a60 1
#define DefaultPort	"4321"
d63 1
a63 2
#define DefaultVacuum	"~/bin/vacuumd"
	
a76 4
/*char	*PQinitstr = NULL;	/* the initialization string passed 
				   to backend (obsolete 2/21/91 -mer) */

extern char *getenv();
d83 30
a112 2
/* ----------------
 *	read_initstr
d114 5
a118 2
 *	This is now a misnomer. PQinistr is no longer used and this routine
 *	really just initializes the PQ global variables if they need it.
d120 46
a165 2
 * 	Read in the initialization string to be passed to the POSTGRES backend.
 * 	The initstr has the format of
d167 46
a212 1
 *		USER,DATABASE,TTY,OPTION\n
d214 2
a215 3
 * 	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.
d219 2
a220 2
void
read_initstr()
d222 1
a222 1
    char *envDB;
d224 8
a231 9
    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);
d233 2
a235 2
    if ((PQhost == NULL) && ((PQhost = getenv("PGHOST")) == NULL))
	PQhost = DefaultHost;
d237 13
a249 2
    if ((PQtty == NULL) && ((PQtty = getenv("PGTTY")) == NULL))
	PQtty = DefaultTty;
d251 14
d274 3
d278 13
a290 2
    if (PQoption == NULL)
	PQoption = DefaultOption;
d292 1
a292 5
    if (PQport == NULL) {
	if (getenv("PGPORT") == NULL)
	   PQport = DefaultPort;
	else PQport = getenv("PGPORT");
    }
d294 1
a294 7
/* 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);
 */
d298 6
a303 1
 *	read_remark - Read and discard remarks. 
d310 1
a310 2
    char remarks[remark_length];
    char errormsg[error_msg_length];
d312 2
d315 8
a322 9
	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;
d327 5
a331 1
 *	EstablishComm
a334 1
void
d340 17
a356 7
	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)\nIs the postmaster running?",
		   PQhost, PQport));
a357 1

d362 1
d366 1
a366 2
 *	process_portal
 *	
d368 3
a370 1
 * 	Return values are the same as PQexec().
d373 1
a373 1

d379 1
a379 2
    char id[2];
    char errormsg[error_msg_length];
a380 1
    char PQcommand[portal_name_length+1];
d382 1
a382 1
 
d394 6
a399 3
        pq_getnchar(id, 0, 1);
        read_remark(id);
        pqdebug("Identifier is: %c", (char *)id[0]);
d401 1
a401 1
        switch (id[0]) {
d403 5
a407 5
	    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");
d409 1
a409 2

        case 'N': /* print notice and go back to processing return values */
d411 3
a413 1
	     * If we get an EOF (i.e. backend quickdies) return an R to the fe
d415 4
a418 5
	    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);
a419 1
	    
d422 3
a424 3
	    if (dump_data(pname, rule_p) == -1)
	    {
		    return("R");
d426 1
a426 2
	    sprintf(PQcommand, "P%s", pname);
	    strcpy(retbuf, PQcommand);
a427 1
	
d434 3
a436 2
	    PQxactid = pq_getint (4);
	    pqdebug("Transaction Id is: %d", (char *)PQxactid);
d438 2
a439 2
	    pqdebug("Query command: %s", command);
	
a441 1
	        /* Allocate a portal buffer, if portal table is full, error. */
d443 2
a444 7
	        return
		    "Cretrieve";
	    } 
	    else if (strcmp (command, "close") == 0) 
	        return
		    "Cclose";
	    else {
a445 2
	        return
		    retbuf;
d447 1
a447 1

d449 8
a456 34
	    {
	        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;
d473 1
a473 1
    return PQdatabase;
a497 6
/*
 *  if (PQinitstr != NULL)
 *      pq_free(PQinitstr);
 *
 *  PQinitstr = NULL;
 */
d509 1
a509 1
    
d526 1
a526 1
    char holder[1];
d529 10
a538 3
	pq_getnchar(holder, 0, 1);
	if (holder[0] != 'I')
	    fprintf(stderr, "PQFlushI: read bad protocol entity");
d541 1
d550 2
a551 2
 *      actual_result_len: actual length returned. (differs from result_len for
 *                      varlena structures.
d557 5
d568 1
a568 1
    int *result_buf;    /* can't use void, dec compiler barfs */
d570 1
a570 1
     int *actual_result_len;
d575 1
a575 2
    char id[2];
    char errormsg[error_msg_length];
a576 1
    void EstablishComm();
d579 5
a584 3
    if (!PQportset)
	EstablishComm();
    
d590 2
a591 2
    
    for (i=0; i < nargs; ++i) { /*	len.int4 + contents	*/
d593 3
a595 3
	if (args[i].isint)
	  pq_putint(args[i].u.integer, 4);
	else if (args[i].len == VAR_LENGTH_ARG) {
d597 1
a597 1
	} else
d599 1
d605 4
a608 13

    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);
d612 1
a612 1
    read_remark(id);
d614 2
a615 2
    pqdebug("The Identifier is: %c", (char *)id[0]);
    
d617 1
a617 1
    pqdebug("The Transaction Id is: %d", (char *)PQxactid);
d619 4
a622 2
    if (id[0] == 'V')
	pq_getnchar(id, 0, 1);
d624 2
a625 2
	switch (id[0]) {
	  case 'G':		/* PQFN: simple return value	*/
d627 3
a629 1
	    pqdebug2("LENGTH act/usr %ld/%ld\n", (char*)actual_len, (char*)result_len);
d632 5
a636 1
		pqdebug("RESET CALLED FROM CASE G", (char *)0);
d638 8
a645 1
		libpq_raise(&ProtocolError, form ((int)"Buffer Too Small: %s", id));
a646 6
	    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);
d648 1
a648 1
	      *actual_result_len = actual_len;
d651 7
a657 8
	      ((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);
d659 5
a663 8
	    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)
d666 4
a669 5

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

	    default:
d671 5
a675 2
	    pqdebug("RESET CALLED FROM CASE G", (char *)0);
	    pqdebug("Protocol Error, bad form, got '%c'", (char *)id[0]);
d677 1
a677 2
	    libpq_raise(&ProtocolError, form((int)"Unexpected identifier: %s", id));
	    return(NULL);
d680 1
d691 3
a694 1

d702 1
a702 2
    char id[2];
    char errormsg[error_msg_length];
a703 1
    void EstablishComm();
d707 4
a710 3
    if (!PQportset)
	EstablishComm();
    
d729 6
a734 15
    /* 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);
d737 1
a737 1
    read_remark(id);
d739 2
a740 2
    pqdebug("The Identifier is: %c", (char *)id[0]);
    
d742 1
a742 1
    pqdebug("The Transaction Id is: %d", (char *)PQxactid);
d744 3
a746 2
    if (id[0] == 'V')
	pq_getnchar(id, 0, 1);
d748 2
a749 9
	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...).
	     */

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

d752 3
a754 2
		pq_getnchar((char *)buf, 0, nbytes);
	    pq_getnchar(id, 0, 1);
d756 8
a763 6
	    
	  case 'E':
	    pq_getstr(errormsg, error_msg_length);
	    pqdebug("%s error encountered.", errormsg);
	    fprintf(stderr,"%s", errormsg);
	    return (-1);
d765 1
a765 9

	  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:
d767 5
a771 2
	    pqdebug("RESET CALLED FROM CASE G", (char *)0);
	    pqdebug("Protocol Error, bad form, got '%c'", (char *)id[0]);
a772 1
	    libpq_raise(&ProtocolError, form((int)"Unexpected identifier: %s", id));
d785 1
a785 2
    char id[2];
    char errormsg[error_msg_length];
a786 1
    void EstablishComm();
d790 4
a793 3
    if (!PQportset)
	EstablishComm();
    
d799 1
a799 1
    
d803 5
a807 5
/*
* The method of transmitting varlenas is:
* Send vl_len-4
* Send data consisting of vl_len-4 bytes.
*/
d810 1
a810 1
	/* The fe/be protocol does NOT transmit varlenas this way */
d817 6
a822 14
    /* 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);
d825 1
a825 1
    read_remark(id);
d827 2
a828 2
    pqdebug("The Identifier is: %c", (char *)id[0]);
    
d830 1
a830 1
    pqdebug("The Transaction Id is: %d", (char *)PQxactid);
d832 3
a834 3
    if (id[0] == 'V')
	pq_getnchar(id, 0, 1);

d836 2
a837 2
	switch (id[0]) {
	  case 'G':		/* PQFN: simple return value	*/
d841 2
a842 2
			    form((int) "wanted 4 bytes in PQfswrite, got %d\n",
			    actual_len));
d844 11
a854 8
	    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);
d856 1
a856 9

	  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:
d858 5
a862 2
	    pqdebug("RESET CALLED FROM CASE G", (char *)0);
	    pqdebug("Protocol Error, bad form, got '%c'", (char *)id[0]);
d864 1
a864 2
	    libpq_raise(&ProtocolError, form((int)"Unexpected identifier: %s", id));
	    return(NULL);
d870 1
a870 1
 *	PQexec -  Send a query to the POSTGRES backend
d872 12
a883 5
 * 	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".
a885 1

d890 1
a890 2
    char id[2];
    char errormsg[error_msg_length];
d892 1
a892 2
    static char PQcommand[command_length+1];
    void EstablishComm();
d894 4
a897 3
    /* If the communication is not established, establish it. */
    if (!PQportset)
	EstablishComm();
d908 2
a909 2

    	/* Process return values from the backend. 
a912 2
    	id[0] = '?';

d914 6
a919 4
    	pq_getnchar(id,0,1); 

    	read_remark(id);
    	pqdebug("The Identifier is: %c", (char *)id[0]);
d923 1
a923 1
    	pqdebug("The Transaction Id is: %d", (char *)PQxactid);
d925 1
a925 1
    	switch (id[0]) {
d927 2
a928 2
	    return("I");
	    
d930 11
a940 13
	    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);
d942 26
a967 17

    	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);
	}
d971 1
a971 3
	    return
		process_portal(0);
	    
d973 5
a977 7
	    /* Query executed successfully. */
	    pq_getstr (command, command_length);
	    pqdebug ("Query command: %s", command);
	    sprintf (PQcommand, "C%s", command);
	    return
		PQcommand;

d979 3
a981 3
	    /* Copy command began successfully - it is sending stuff back...  */
	    return "BCOPY";

d983 3
a985 3
	    /* Copy command began successfully - it is waiting to receive... */
	    return "DCOPY";

d987 8
a994 8
	    /* 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);
d999 9
a1009 1

d1011 1
a1011 2
    char id[2];
    char errormsg[error_msg_length];
d1013 21
a1033 34
    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);
        }
d1035 1
@


1.32
log
@need a newline
@
text
@d28 1
a28 1
 *	$Header: /usr/local/devel/postgres/src/libpq/RCS/fe-pqexec.c,v 1.31 1993/02/22 04:15:39 marc Exp marc $
d40 1
a40 1
RcsId ("$Header: /usr/local/devel/postgres/src/libpq/RCS/fe-pqexec.c,v 1.31 1993/02/22 04:15:39 marc Exp marc $");
a440 1
    char PQcommand[command_length+1];
a566 1
    char PQcommand[command_length+1];
a674 1
    char PQcommand[command_length+1];
d786 1
a786 1
    char PQcommand[command_length+1];
@


1.31
log
@less cryptic error message
@
text
@d28 1
a28 1
 *	$Header: /usr/local/devel/postgres/src/libpq/RCS/fe-pqexec.c,v 1.30 1993/01/16 03:14:59 aoki Exp marc $
d40 1
a40 1
RcsId ("$Header: /usr/local/devel/postgres/src/libpq/RCS/fe-pqexec.c,v 1.30 1993/01/16 03:14:59 aoki Exp marc $");
d191 1
a191 1
	      form((int)"Failed to connect to backend (host=%s, port=%s), is postmaster running?",
@


1.30
log
@removed references to utils/fmgr.h and parser/parse.h
@
text
@d28 1
a28 1
 *	$Header: /home2/aoki/postgres/src/libpq/RCS/fe-pqexec.c,v 1.29 1993/01/08 23:46:22 clarsen Exp aoki $
d40 1
a40 1
RcsId ("$Header: /home2/aoki/postgres/src/libpq/RCS/fe-pqexec.c,v 1.29 1993/01/08 23:46:22 clarsen Exp aoki $");
d191 1
a191 1
	      form((int)"Failed to connect to backend (host=%s, port=%s)",
@


1.29
log
@add attribute caching
@
text
@d28 1
a28 1
 *	$Header: /home/postgres/clarsen/p1/src/libpq/RCS/fe-pqexec.c,v 1.28 1992/08/29 22:05:01 mao Exp clarsen $
d37 1
a37 1
#include "utils/fmgr.h"
d40 1
a40 1
RcsId ("$Header: /home/postgres/clarsen/p1/src/libpq/RCS/fe-pqexec.c,v 1.28 1992/08/29 22:05:01 mao Exp clarsen $");
@


1.28
log
@PQfn() and its derivatives shouldn't try to read data past an 'E' on
the protocol stream.
@
text
@d28 1
a28 1
 *	$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.27 1992/08/07 00:38:18 mao Exp mao $
d40 1
a40 1
RcsId ("$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.27 1992/08/07 00:38:18 mao Exp mao $");
d183 2
d196 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");
@
