head	1.11;
access;
symbols
	Version_2_1:1.3;
locks; strict;
comment	@ * @;


1.11
date	92.07.15.05.11.02;	author mao;	state Exp;
branches;
next	1.10;

1.10
date	92.04.21.13.14.21;	author clarsen;	state Exp;
branches;
next	1.9;

1.9
date	92.03.06.22.18.04;	author clarsen;	state Exp;
branches;
next	1.8;

1.8
date	92.02.25.15.29.22;	author clarsen;	state Exp;
branches;
next	1.7;

1.7
date	91.11.18.22.40.13;	author hong;	state Exp;
branches;
next	1.6;

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

1.5
date	91.04.01.16.19.57;	author kemnitz;	state Exp;
branches;
next	1.4;

1.4
date	91.03.21.21.53.10;	author kemnitz;	state Exp;
branches;
next	1.3;

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

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

1.1
date	91.02.09.20.41.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.11
log
@restoring changes made by case that i erroneously backed out.  case's
message was:  add attribute length information.
@
text
@/* ----------------------------------------------------------------
 *   FILE
 *	fe-dumpdata.c
 *	
 *   DESCRIPTION
 *	Dump the returned tuples into a frontend buffer
 *
 *   INTERFACE ROUTINES
 *	dump_type 	- Dump the attributes
 *	dump_tuple 	- Dump a tuple
 *	finish_dump 	- End of a command (data stream)
 *	dump_data 	- Read and process the data stream from backend
 *
 *   NOTES
 *
 *   IDENTIFICATION
 *	$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-dumpdata.c,v 1.11 1992/07/15 02:01:27 clarsen Exp $
 * ----------------------------------------------------------------
 */

#include "tmp/c.h"

#include "tmp/simplelists.h"
#include "tmp/libpq-fe.h"
#include "utils/exc.h"

RcsId("$Header: /private/mao/postgres/src/lib/libpq/RCS/fe-dumpdata.c,v 1.11 1992/07/15 02:01:27 clarsen Exp $");

/* Define constants. */

#define BYTELEN 8
#define MAXBYTES 128	/* MAXFIELDS / BYTELEN */
#define MAXFIELDS 512

/* --------------------------------
 *	dump_type - Dump the attributes
 * --------------------------------
 */
void
dump_type(types, nfields)
    TypeBlock *types;
    int nfields;
{
    int i;
    TypeBlock *type;

    type = types;

    for (i = 0; i < nfields; i++) {
	pq_getstr(type->name, NameLength);
	type->adtid = pq_getint(4);
	type->adtsize = pq_getint(2);
	type++;
    }
}

/* --------------------------------
 *	dump_tuple - Dump a tuple
 * --------------------------------
 */
void
dump_tuple(values,lengths, nfields)
    char **values;
     int *lengths;
    int nfields;
{
    char 	bitmap[MAXFIELDS];
    int 	bitmap_index = 0;
    int 	i;
    unsigned 	nbytes;		/* the number of bytes in bitmap */
    char 	bmap;		/* One byte of the bitmap */
    int 	bitcnt = 0; 	/* number of bits examined in current byte */
    int 	vlen;		/* length of the current field value */
    
    nbytes = nfields / BYTELEN;
    if ((nfields % BYTELEN) > 0) 
	nbytes++;

    pq_getnchar(bitmap, 0, nbytes);
    bmap = bitmap[bitmap_index];
    
    /* Read in all the attribute values. */
    for (i = 0; i < nfields; i++) {
	/* If the field value is absent, do nothing. */
	if (!(bmap & 0200))
	    values[i] = NULL;
	else {
	    /* Get the value length (the first four bytes are for length). */
	    vlen = pq_getint(4) - 4;
	    /* Allocate storage for the value. */
	    values[i] = pbuf_addValues(vlen + 1);
	    /* Read in the value. */
	    pq_getnchar(values[i], 0, vlen);
	    lengths[i] = vlen;
	    /* Put an end of string there to make life easier. */
	    values[i][vlen] = '\0';
	    pqdebug("%s", values[i]);
	}

	/* Get the approriate bitmap. */
	bitcnt++;
	if (bitcnt == BYTELEN) {
	    bitmap_index++;
	    bmap = bitmap[bitmap_index];
	    bitcnt = 0;
	} else 
	    bmap <<= 1;
    }
}
/* --------------------------------
 *	dump_tuple_internal - Dump a tuple in internal format
 * --------------------------------
 */
void
dump_tuple_internal(values, lengths, nfields)
    char **values;
     int *lengths;
    int nfields;
{
    char 	bitmap[MAXFIELDS];
    int 	bitmap_index = 0;
    int 	i;
    unsigned 	nbytes;		/* the number of bytes in bitmap */
    char 	bmap;		/* One byte of the bitmap */
    int 	bitcnt = 0; 	/* number of bits examined in current byte */
    int 	vlen;		/* length of the current field value */
    
    nbytes = nfields / BYTELEN;
    if ((nfields % BYTELEN) > 0) 
	nbytes++;

    pq_getnchar(bitmap, 0, nbytes);
    bmap = bitmap[bitmap_index];
    
    /* Read in all the attribute values. */
    for (i = 0; i < nfields; i++) {
	/* If the field value is absent, do nothing. */
	if (!(bmap & 0200))
	    values[i] = NULL;
	else {
	    /* For each attribute, we get:
	       Length (4 bytes),
	       Data (n bytes)
	       */
	    
	    vlen = pq_getint(4);
	    /* Allocate storage for the value. */
	    values[i] = pbuf_addValues(vlen + 1);
	    /* Read in the value. */
	    pq_getnchar(values[i], 0, vlen);
	    lengths[i] = vlen;
	    /* Put an end of string there to make life easier. */
	    values[i][vlen] = '\0';
	    pqdebug("%s", values[i]);
	}

	/* Get the approriate bitmap. */
	bitcnt++;
	if (bitcnt == BYTELEN) {
	    bitmap_index++;
	    bmap = bitmap[bitmap_index];
	    bitcnt = 0;
	} else 
	    bmap <<= 1;
    }
}

/* --------------------------------
 *	finish_dump - End of a command (data stream)
 * --------------------------------
 */
void
finish_dump()
{
    char command[command_length];
    int temp;
    
    temp = pq_getint(4);
    pq_getstr(command, command_length);
    
    pqdebug("return code is %d",(char *)temp);
    pqdebug("command is %s",command);
}

/* --------------------------------
 *	dump_data - Read and process the data stream from backend
 * --------------------------------
 */
int 
dump_data(portal_name, rule_p)
    char *portal_name;
    int rule_p;
{
    char 	 id[2];
    char 	 pname[portal_name_length];
    PortalEntry  *entry = NULL;
    PortalBuffer *portal = NULL;
    GroupBuffer  *group = NULL;
    TypeBlock 	 *types = NULL;
    TupleBlock 	 *tuples = NULL;

    int ntuples = 0;	/* the number of tuples in current group */
    int nfields = 0;	/* the number of fields in current group */

    strcpy(pname, portal_name);

    /* If portal buffer is not allocated, do it now. */
    /* if ((portal = PQparray(pname)) == NULL) */
    entry = pbuf_setup(pname);
    portal = entry->portal;
    
    /* If an asynchronized portal, set the flag. */
    if (rule_p)
	portal->rule_p = 1;

    /* Dump_data is called only when id[0] = 'T'. */
    id[0] = 'T';
    
    /* Process the data stream. */
    while (1) {
	switch (id[0]) {
	case 'T':
	    /* A new tuple group. */
	    
	    /* If this is not the first group, record the number of 
	       tuples in the previous group. */
	    if (group != NULL) {
		group->no_tuples = ntuples;
		/* Add the number of tuples in last group to the total. */
		portal->no_tuples += ntuples;
	    }
	    
	    /* Increment the number of tuple groups. */
	    portal->no_groups++;
	    group = pbuf_addGroup(portal);
	    
	    /* Read in the number of fields (attributes) for this group. */
	    nfields = group->no_fields = pq_getint(2);
	    if (nfields > 0) {
	        types = group->types = pbuf_addTypes(nfields);
	        dump_type(types, nfields);
	    }
	    break;

	case 'B':
	    /* A tuple in internal (binary) format. */
	    
	    /* If no tuple block yet, allocate one. */
	    /* If the current block is full, allocate another one. */
	    if (group->tuples == NULL) {
		tuples = group->tuples = pbuf_addTuples();
		tuples->tuple_index = 0;
	    } else if (tuples->tuple_index == TupleBlockSize) {
		tuples->next = pbuf_addTuples();
		tuples = tuples->next;
		tuples->tuple_index = 0;
	    }
		
	    /* Allocate space for a tuple. */
	    tuples->values[tuples->tuple_index] =pbuf_addTuple(nfields);
	    tuples->lengths[tuples->tuple_index] = pbuf_addTupleValueLengths(nfields);

	    /* Dump a tuple internal format. */
	    dump_tuple_internal(tuples->values[tuples->tuple_index],
				tuples->lengths[tuples->tuple_index],
				nfields);
	    ntuples++;
	    tuples->tuple_index++;
	    break;

	case 'D':
	    /* A tuple. */
	    
	    /* If no tuple block yet, allocate one. */
	    /* If the current block is full, allocate another one. */
	    if (group->tuples == NULL) {
		tuples = group->tuples = pbuf_addTuples();
		tuples->tuple_index = 0;
	    } else if (tuples->tuple_index == TupleBlockSize) {
		tuples->next = pbuf_addTuples();
		tuples = tuples->next;
		tuples->tuple_index = 0;
	    }
		
	    /* Allocate space for a tuple. */
	    tuples->values[tuples->tuple_index] =pbuf_addTuple(nfields);
	    tuples->lengths[tuples->tuple_index] = pbuf_addTupleValueLengths(nfields);
	    
	    /* Dump a tuple. */
	    dump_tuple(tuples->values[tuples->tuple_index],
		       tuples->lengths[tuples->tuple_index],
		       nfields);
	    ntuples++;
	    tuples->tuple_index++;
	    break;
#if 0
	case 'A':
	    /* Tuples returned by alerters. */
	    /* Finish up with the current portal. */
	    group->no_tuples = ntuples;
	    portal->no_tuples += ntuples;

	    /* Process the asynchronized portal. */
	    /* This part of the protocol is not very clear. */
	    pq_getint(4);
	    pq_getstr(pname, portal_name_length);
	    pqdebug("Asynchronized portal: %s", pname);
	    
	    entry = pbuf_setup(pname);
	    portal = entry->portal;
	    portal->rule_p = 1;
	    group = NULL;
	    ntuples = 0;
	    nfields = 0;
	    tuples = NULL;
	    break;
#endif

	case 'C':
	    /* Command, end of the data stream. */
	    /* Record the number of tuples in the last group. */
	    group->no_tuples = ntuples;
	    portal->no_tuples += ntuples;
	    finish_dump();
	    return(1);
	    
	case 'E':
		/* YES - THIS CAN HAPPEN - for instance when dynamic loading fails!!! */

	    pq_getstr(PQerrormsg, error_msg_length);
	    pqdebug("%s error encountered.", PQerrormsg);

		/*
		 * use PQerrormsg[4] because there is garbage in the first four bytes..
		 */
	    bcopy(&PQerrormsg[4],PQerrormsg,strlen(PQerrormsg)-4);
	    fprintf(stderr,"%s\n", PQerrormsg);
	    fflush(stderr);
		return(-1);
	case 'N':
	    pq_getstr(PQerrormsg, error_msg_length);
	    pqdebug("%s error encountered.", PQerrormsg);

		/*
		 * use errormsg[4] because there is garbage in the first four bytes..
		 */
	    bcopy(&PQerrormsg[4],PQerrormsg,strlen(PQerrormsg)-4);
	    fprintf(stderr,"%s\n", PQerrormsg);
	    fflush(stderr);
		break;
	default:
	    {
		char s[40];

		/* This should never happen. */
		sprintf(s, "Unexpected identfier in dump_data: %c", id[0]);
		libpq_raise(&ProtocolError, form((int)s));
	    }
	}
	
    	pq_getnchar(id,0,1); 
    	read_remark(id);
	pqdebug("The identifier is: %c", (char *)id[0]);
    }
}
@


1.10
log
@Put error messages in PQerrormsg
@
text
@d17 1
a17 1
 *	$Header: RCS/fe-dumpdata.c,v 1.9 92/03/06 22:18:04 clarsen Exp $
d27 1
a27 1
RcsId("$Header: RCS/fe-dumpdata.c,v 1.9 92/03/06 22:18:04 clarsen Exp $");
d62 1
a62 1
dump_tuple(values, nfields)
d64 1
d94 1
d115 1
a115 1
dump_tuple_internal(values, nfields)
d117 1
d151 1
d261 2
a262 1
	    
d264 3
a266 1
	    dump_tuple_internal(tuples->values[tuples->tuple_index], nfields);
d287 1
d290 3
a292 1
	    dump_tuple(tuples->values[tuples->tuple_index], nfields);
@


1.9
log
@Binary Portals
@
text
@d17 1
a17 1
 *	$Header: RCS/fe-dumpdata.c,v 1.8 92/02/25 15:29:22 clarsen Exp Locker: clarsen $
d27 1
a27 1
RcsId("$Header: RCS/fe-dumpdata.c,v 1.8 92/02/25 15:29:22 clarsen Exp Locker: clarsen $");
a196 1
    char errormsg[error_msg_length];
d320 2
a321 2
	    pq_getstr(errormsg, error_msg_length);
	    pqdebug("%s error encountered.", errormsg);
d324 1
a324 1
		 * use errormsg[4] because there is garbage in the first four bytes..
d326 2
a327 2

	    fprintf(stderr,"%s\n", & errormsg[4]);
d331 2
a332 2
	    pq_getstr(errormsg, error_msg_length);
	    pqdebug("%s error encountered.", errormsg);
d337 2
a338 2

	    fprintf(stderr,"%s\n", & errormsg[4]);
@


1.8
log
@async portals.
@
text
@d17 1
a17 1
 *	$Header: RCS/fe-dumpdata.c,v 1.7 91/11/18 22:40:13 hong Exp Locker: clarsen $
d27 1
a27 1
RcsId("$Header: RCS/fe-dumpdata.c,v 1.7 91/11/18 22:40:13 hong Exp Locker: clarsen $");
d108 20
d129 35
d240 23
@


1.7
log
@incorrect parameter passing to libpq_raise(), trying to
cast a struct to a pointer.
@
text
@d17 1
a17 1
 *	$Header: RCS/fe-dumpdata.c,v 1.6 91/11/18 17:34:08 mer Exp Locker: hong $
d23 1
d27 1
a27 1
RcsId("$Header: RCS/fe-dumpdata.c,v 1.6 91/11/18 17:34:08 mer Exp Locker: hong $");
d209 1
a209 1

d230 1
@


1.6
log
@prototyping (last time?)
@
text
@d17 1
a17 1
 *	$Header: /users/mer/postgres/src/lib/libpq/RCS/fe-dumpdata.c,v 1.5 1991/04/01 16:19:57 kemnitz Exp mer $
d26 1
a26 1
RcsId("$Header: /users/mer/postgres/src/lib/libpq/RCS/fe-dumpdata.c,v 1.5 1991/04/01 16:19:57 kemnitz Exp mer $");
d268 1
a268 1
		libpq_raise(ProtocolError, form((int)s));
@


1.5
log
@Checked in fix to dump_data so that it handles NOTICES properly.
@
text
@d17 1
a17 1
 *	$Header: RCS/fe-dumpdata.c,v 1.4 91/03/21 21:53:10 kemnitz Exp Locker: kemnitz $
d26 1
a26 1
RcsId("$Header: RCS/fe-dumpdata.c,v 1.4 91/03/21 21:53:10 kemnitz Exp Locker: kemnitz $");
d121 1
a121 1
    pqdebug("return code is %d",temp);
d268 1
a268 1
		libpq_raise(ProtocolError, form(s));
d274 1
a274 1
	pqdebug("The identifier is: %c", id[0]);
@


1.4
log
@Now can handle error messages gotten while processing portals.
@
text
@d17 1
a17 1
 *	$Header: RCS/fe-dumpdata.c,v 1.3 91/02/28 10:27:34 mer Exp Locker: kemnitz $
d26 1
a26 1
RcsId("$Header: RCS/fe-dumpdata.c,v 1.3 91/02/28 10:27:34 mer Exp Locker: kemnitz $");
d141 1
a238 1
	{
d241 2
a242 1
	    char errormsg[error_msg_length];
d244 8
d261 1
a261 2
		return(-1);
	}
@


1.3
log
@wasn't reading the next protocol character from backend

@
text
@d17 1
a17 1
 *	$Header: RCS/fe-dumpdata.c,v 1.2 91/02/20 00:34:24 cimarron Exp Locker: mer $
d26 1
a26 1
RcsId("$Header: RCS/fe-dumpdata.c,v 1.2 91/02/20 00:34:24 cimarron Exp Locker: mer $");
d237 6
a242 4
	  case 'E':
	    {
	    /* weirdness, apparently this shouldn't have happened. */
	    static char errormsg[80];
d246 7
a252 3
	    fprintf(stdout,"%s\n", &(id[1]));
	    fflush(stdout);
	    exit(1);
@


1.2
log
@changed fe routines to use new portal support
@
text
@d17 1
a17 1
 *	$Header: RCS/fe-dumpdata.c,v 1.1 91/02/09 20:41:52 cimarron Exp Locker: cimarron $
d26 1
a26 1
RcsId("$Header: RCS/fe-dumpdata.c,v 1.1 91/02/09 20:41:52 cimarron Exp Locker: cimarron $");
d258 2
@


1.1
log
@Initial revision
@
text
@d9 4
d17 1
a17 1
 *	$Header$
d23 1
a23 1
#include "tmp/libpq.h"
d26 1
a26 1
RcsId("$Header: RCS/dumpdata.c,v 1.7 91/01/11 14:13:03 mao Exp Locker: cimarron $");
d89 1
a89 1
	    values[i] = addValues(vlen + 1);
d136 2
a137 1
    PortalBuffer *portal;
d139 2
a140 2
    TypeBlock 	 *types;
    TupleBlock 	 *tuples;
a143 1
    int tuple_index = 0; /* index of next avail entry in current tuple block */
d149 2
a150 1
	portal = portal_setup(pname);
d175 1
a175 1
	    group = addGroup(portal);
d180 1
a180 1
	        types = group->types = addTypes(nfields);
d189 1
d191 4
a194 6
		tuples = group->tuples = addTuples();
		tuple_index = 0;
	    } 
	    /* If the current block is full, allocate another one. */
	    else if (tuple_index == TupleBlockSize) {
		tuples->next = addTuples();
d196 1
a196 1
		tuple_index = 0;
d200 2
a201 1
	    tuples->values[tuple_index] = addTuple(nfields);
d203 1
a203 1
	    dump_tuple(tuples->values[tuple_index], nfields);
d205 1
a205 1
	    tuple_index++;
d219 3
a221 1
	    portal = portal_setup(pname);
d226 1
a226 1
	    tuple_index = 0;
d236 1
a256 4
	
	if (pq_getnchar(id, 0, 1) == -1) 
	    libpq_raise(ProtocolError,
			form("Communication terminated by backend."));
@
