head	1.14;
access;
symbols
	Version_2_1:1.7;
locks; strict;
comment	@ * @;


1.14
date	92.05.06.06.02.28;	author mer;	state Exp;
branches;
next	1.13;

1.13
date	92.05.05.18.53.14;	author mer;	state Exp;
branches;
next	1.12;

1.12
date	92.03.06.22.18.14;	author clarsen;	state Exp;
branches;
next	1.11;

1.11
date	92.02.27.20.38.47;	author clarsen;	state Exp;
branches;
next	1.10;

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

1.9
date	91.11.11.22.59.03;	author hong;	state Exp;
branches;
next	1.8;

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

1.7
date	91.03.09.03.12.53;	author kemnitz;	state Exp;
branches;
next	1.6;

1.6
date	91.03.08.19.48.41;	author kemnitz;	state Exp;
branches;
next	1.5;

1.5
date	91.02.23.23.05.48;	author cimarron;	state Exp;
branches;
next	1.4;

1.4
date	91.02.20.00.41.19;	author cimarron;	state Exp;
branches;
next	1.3;

1.3
date	91.02.11.17.17.33;	author cimarron;	state Exp;
branches;
next	1.2;

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

1.1
date	91.02.10.18.19.46;	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.14
log
@append oid change - returns valid oid only when exactly 1 tuple appended
@
text
@/* ----------------------------------------------------------------
 *   FILE
 *	dest.c
 *	
 *   DESCRIPTION
 *	support for various communication destinations - see lib/H/tcop/dest.h
 *
 *   INTERFACE ROUTINES
 * 	BeginCommand - prepare destination for tuples of the given type
 * 	EndCommand - tell destination that no more tuples will arrive
 * 	NullCommand - tell dest that the last of a query sequence was processed
 *	
 *   NOTES
 *	These routines do the appropriate work before and after
 *	tuples are returned by a query to keep the backend and the
 *	"destination" portals synchronized.
 *
 *   IDENTIFICATION
 *	$Header: /users/mer/pg/src/tcop/RCS/dest.c,v 1.13 1992/05/05 18:53:14 mer Exp mer $
 * ----------------------------------------------------------------
 */

#include "tmp/postgres.h"

RcsId("$Header: /users/mer/pg/src/tcop/RCS/dest.c,v 1.13 1992/05/05 18:53:14 mer Exp mer $");

#include "parser/parse.h"
#include "access/htup.h"
#include "tmp/simplelists.h"
#include "tmp/libpq-be.h"
#include "access/printtup.h"
#include "tmp/portal.h"
#include "utils/log.h"

#include "nodes/pg_lisp.h"
#include "tcop/dest.h"

#include "catalog/pg_type.h"
#include "utils/mcxt.h"

/* ----------------
 *	output functions
 * ----------------
 */
void
donothing(tuple, attrdesc)
    List tuple;
    List attrdesc;
{
}

void
(*DestToFunction(dest))()
    CommandDest	dest;
{
    switch (dest) {
    case RemoteInternal:
	return printtup_internal;
	break;

    case Remote:
	return printtup;
	break;
	
    case Local:
	return be_printtup;
	break;
	
    case Debug:
	return debugtup;
	break;
	
    case None:
    default:
	return donothing;
	break;
    }	

    /*
     * never gets here, but DECstation lint appears to be stupid...
     */

    return donothing;
}

#define IS_APPEND_TAG(tag) (*tag == 'A' && *(tag+1) == 'P')

/* ----------------
 * 	EndCommand - tell destination that no more tuples will arrive
 * ----------------
 */
void
EndCommand(commandTag, dest)
    String  	commandTag;
    CommandDest	dest;
{
    char buf[64];

    switch (dest) {
    case RemoteInternal:
    case Remote:
	/* ----------------
	 *	tell the fe that the query is over
	 * ----------------
	 */
	pq_putnchar("C", 1);
	pq_putint(0, 4);
	if (IS_APPEND_TAG(commandTag))
	{
	    sprintf(buf, "%s %d", commandTag, GetAppendOid());
	    pq_putstr(buf);
	}
	else
	    pq_putstr(commandTag);
	pq_flush();
	break;

    case Local:
    case Debug:
	break;
    case CopyEnd:
    pq_putnchar("Z", 1);
	pq_flush();
	break;
    case None:
    default:
	break;
    }
}

/*
 * These are necessary to sync communications between fe/be processes doing
 * COPY rel TO stdout
 * 
 * or 
 *
 * COPY rel FROM stdin
 *
 */

void
SendCopyBegin()
{
	pq_putnchar("B", 1);
	pq_putint(0, 4);
	pq_flush();
}

void
ReceiveCopyBegin()
{
	pq_putnchar("D", 1);
	pq_putint(0, 4);
	pq_flush();
}

/* ----------------
 * 	NullCommand - tell dest that the last of a query sequence was processed
 * 
 * 	Necessary to implement the hacky FE/BE interface to handle
 *	multiple-return queries.
 * ----------------
 */
void
NullCommand(dest)
    CommandDest	dest;
{
    switch (dest) {
    case RemoteInternal:
    case Remote: {
	/* Do any asynchronous notification.  If front end wants to poll,
	   it can send null queries to call this function.
	   */
	PQNotifyList *nPtr;
	extern GlobalMemory notifyContext;
	MemoryContext orig;

	if (notifyContext == NULL) {
	    notifyContext = CreateGlobalMemory("notify");
	}
	orig = MemoryContextSwitchTo((MemoryContext)notifyContext);

	for (nPtr = PQnotifies() ;
	     nPtr != NULL;
	     nPtr = (PQNotifyList *)SLGetSucc(&nPtr->Node)) {
	    pq_putnchar("A",1);
	    pq_putint(0, 4);
	    pq_putstr(nPtr->relname);
	    pq_putint(nPtr->be_pid,4);
	    PQremoveNotify(nPtr);
	}
	pq_flush();
	PQcleanNotify();	/* garbage collect */
	(void) MemoryContextSwitchTo(orig);

	/* ----------------
	 *	tell the fe that the last of the queries has finished
	 * ----------------
	 */
	pq_putnchar("I", 1);
	pq_putint(0, 4);
	pq_flush();
    }
	break;

    case Local:
    case Debug:
    case None:
    default:
	break;
    }	
}

/* ----------------
 * 	BeginCommand - prepare destination for tuples of the given type
 * ----------------
 */
void
BeginCommand(pname, operation, attinfo, isIntoRel, isIntoPortal, tag, dest)
    char 	*pname;
    int		operation;
    LispValue 	attinfo;
    bool	isIntoRel;
    bool	isIntoPortal;
    char	*tag;
    CommandDest	dest;
{
    PortalEntry	*entry;
    struct attribute **attrs;
    int    natts;
    int    i;
    char   *p;
    
    natts = CInteger(CAR(attinfo));
    attrs  = (struct attribute **) CADR(attinfo);

    switch (dest) {
    case RemoteInternal:
    case Remote:
	/* ----------------
	 *	if this is a "retrieve portal" query, just return
	 *	because nothing needs to be sent to the fe.
	 * ----------------
	 */
        ResetAppendOid();
	if (isIntoPortal)
	    return;
	    
	/* ----------------
	 *	if portal name not specified for remote query,
	 *	use the "blank" portal.
	 * ----------------
	 */
	if (pname == NULL)
	    pname = "blank";
	
	/* ----------------
	 *	send fe info on tuples we're about to send
	 * ----------------
	 */
	pq_flush();
	pq_putnchar("P", 1);	/* new portal.. */
	pq_putint(0, 4);	/* xid */
	pq_putstr(pname);	/* portal name */
	
	/* ----------------
	 *	if this is a retrieve, then we send back the tuple
	 *	descriptor of the tuples.  "retrieve into" is an
	 *	exception because no tuples are returned in that case.
	 * ----------------
	 */
	if (operation == RETRIEVE && !isIntoRel) {
	    pq_putnchar("T", 1);	/* type info to follow.. */
	    pq_putint(natts, 2);	/* number of attributes in tuples */
    
	    for (i = 0; i < natts; ++i) {
		pq_putstr(attrs[i]->attname);	/* if 16 char name oops.. */
		pq_putint((int) attrs[i]->atttypid, 4);
		pq_putint(attrs[i]->attlen, 2);
	    }
	}
	pq_flush();
	break;
	
    case Local:
	/* ----------------
	 *	prepare local portal buffer for query results
	 *	and setup result for PQexec()
	 * ----------------
	 */
	entry = be_currentportal();
	if (pname != NULL)
	    pbuf_setportalinfo(entry, pname);
	
	if (operation == RETRIEVE && !isIntoRel) {
	    be_typeinit(entry, attrs, natts);
	    p = (char *) palloc(strlen(entry->name)+2);
	    p[0] = 'P';
	    strcpy(p+1,entry->name);
	} else {
	    p = (char *) palloc(strlen(tag)+2);
	    p[0] = 'C';
	    strcpy(p+1,tag);
	}
	entry->result = p;
	break;
	
    case Debug:
	/* ----------------
	 *	show the return type of the tuples
	 * ----------------
	 */
	if (pname == NULL)
	    pname = "blank";
	
	showatts(pname, natts, attrs);
	break;
	
    case None:
    default:
	break;
    }
}

static ObjectId AppendOid;

void
ResetAppendOid()
{
    AppendOid = InvalidObjectId;
}

#define MULTI_TUPLE_APPEND -1

void
UpdateAppendOid(newoid)
    ObjectId newoid;
{
    /*
     * First update after AppendOid was reset (at command beginning).
     */
    if (AppendOid == InvalidObjectId)
	AppendOid = newoid;
    /*
     * Already detected a multiple tuple append, return a void oid ;)
     */
    else if (AppendOid == MULTI_TUPLE_APPEND)
	return;
    /*
     * Oid has been assigned once before, tag this as a multiple tuple
     * append.
     */
    else
	AppendOid = MULTI_TUPLE_APPEND;
}

ObjectId
GetAppendOid()
{
    if (AppendOid == MULTI_TUPLE_APPEND)
	return InvalidObjectId;
    return AppendOid;
}
@


1.13
log
@add some trivial functionality to return last oid of newly append tuples
@
text
@d19 1
a19 1
 *	$Header: /users/mer/pg/src/tcop/RCS/dest.c,v 1.12 1992/03/06 22:18:14 clarsen Exp mer $
d25 1
a25 1
RcsId("$Header: /users/mer/pg/src/tcop/RCS/dest.c,v 1.12 1992/03/06 22:18:14 clarsen Exp mer $");
d86 1
a86 1
#define IS_APPEND_TAG(tag) (*tag == 'A')
d110 1
a110 1
	    sprintf(buf, "%s %d", commandTag, GetLastOid());
d245 1
a245 1
        ResetLastOid();
d325 1
a325 1
static ObjectId LastOid;
d328 1
a328 1
ResetLastOid()
d330 1
a330 1
    LastOid = InvalidObjectId;
d333 2
d336 1
a336 1
UpdateLastOid(newoid)
d339 16
a354 1
    LastOid = newoid;
d358 1
a358 1
GetLastOid()
d360 3
a362 1
    return LastOid;
@


1.12
log
@Binary Portals
@
text
@d19 1
a19 1
 *	$Header: RCS/dest.c,v 1.11 92/02/27 20:38:47 clarsen Exp Locker: clarsen $
d25 1
a25 1
RcsId("$Header: RCS/dest.c,v 1.11 92/02/27 20:38:47 clarsen Exp Locker: clarsen $");
d86 2
d97 2
d108 7
a114 1
	pq_putstr(commandTag);
d245 1
d323 21
@


1.11
log
@diff. type
@
text
@d19 1
a19 1
 *	$Header: RCS/dest.c,v 1.10 92/02/25 15:31:27 clarsen Exp Locker: clarsen $
d25 1
a25 1
RcsId("$Header: RCS/dest.c,v 1.10 92/02/25 15:31:27 clarsen Exp Locker: clarsen $");
d57 4
d96 1
d159 1
d228 1
@


1.10
log
@async portals.
@
text
@d19 1
a19 1
 *	$Header: RCS/dest.c,v 1.9 91/11/11 22:59:03 hong Exp Locker: clarsen $
d25 1
a25 1
RcsId("$Header: RCS/dest.c,v 1.9 91/11/11 22:59:03 hong Exp Locker: clarsen $");
d159 1
a159 1
	extern MemoryContext notifyContext;
@


1.9
log
@for prototyping
@
text
@d19 1
a19 1
 *	$Header: RCS/dest.c,v 1.8 91/05/23 18:49:01 kemnitz Exp Locker: hong $
d25 1
a25 1
RcsId("$Header: RCS/dest.c,v 1.8 91/05/23 18:49:01 kemnitz Exp Locker: hong $");
d29 1
d39 1
d154 26
a179 1
    case Remote:
d187 1
@


1.8
log
@got rid of lint warning "has return(e); and return;"
@
text
@d19 1
a19 1
 *	$Header: RCS/dest.c,v 1.7 91/03/09 03:12:53 kemnitz Exp Locker: kemnitz $
d25 1
a25 1
RcsId("$Header: RCS/dest.c,v 1.7 91/03/09 03:12:53 kemnitz Exp Locker: kemnitz $");
a26 1
#include "tcop/dest.h"
d28 1
d30 1
d35 1
a49 8
/* ----------------
 * 	DestToFunction - return the proper "output" function for dest
 * ----------------
 */
extern void debugtup();
extern void printtup();
extern void be_printtup();

a277 1

@


1.7
log
@fixed problem in switch.
@
text
@d19 1
a19 1
 *	$Header: RCS/dest.c,v 1.6 91/03/08 19:48:41 kemnitz Exp Locker: kemnitz $
d25 1
a25 1
RcsId("$Header: RCS/dest.c,v 1.6 91/03/08 19:48:41 kemnitz Exp Locker: kemnitz $");
d78 6
@


1.6
log
@New copy command protocols.
@
text
@d19 1
a19 1
 *	$Header: RCS/dest.c,v 1.5 91/02/23 23:05:48 cimarron Exp Locker: kemnitz $
d25 1
a25 1
RcsId("$Header: RCS/dest.c,v 1.5 91/02/23 23:05:48 cimarron Exp Locker: kemnitz $");
d103 1
@


1.5
log
@PQexec() now works correctly in the backend
@
text
@d19 1
a19 1
 *	$Header: RCS/dest.c,v 1.4 91/02/20 00:41:19 cimarron Exp Locker: cimarron $
d25 1
a25 1
RcsId("$Header: RCS/dest.c,v 1.4 91/02/20 00:41:19 cimarron Exp Locker: cimarron $");
d103 4
d111 26
@


1.4
log
@added support for "Local" tuple destinations via be_printtup
@
text
@d19 1
a19 1
 *	$Header: RCS/dest.c,v 1.3 91/02/11 17:17:33 cimarron Exp Locker: cimarron $
d25 1
a25 1
RcsId("$Header: RCS/dest.c,v 1.3 91/02/11 17:17:33 cimarron Exp Locker: cimarron $");
d29 1
a29 1
#include "tmp/libpq.h"
d48 4
a55 4
/* ----------------
 * 	DestToFunction - return the proper "output" function for dest
 * ----------------
 */
d81 59
d144 1
a144 1
BeginCommand(pname, attinfo, operation, isInto, dest)
d146 1
d148 3
a150 2
    int		operation;
    bool	isInto;
d157 2
a158 1

d165 8
d195 1
a195 1
	if (operation == RETRIEVE && !isInto) {
d211 1
d214 5
a218 2
	entry = (PortalEntry *) be_newportal(pname);
	if (operation == RETRIEVE && !isInto)
d220 9
a228 1
	be_portalpush(entry);
a247 58
/* ----------------
 * 	EndCommand - tell destination that no more tuples will arrive
 * ----------------
 */
void
EndCommand(commandTag, dest)
    String  	commandTag;
    CommandDest	dest;
{
    switch (dest) {
    case Remote:
	/* ----------------
	 *	tell the fe that the query is over
	 * ----------------
	 */
	pq_putnchar("C", 1);
	pq_putint(0, 4);
	pq_putstr(commandTag);
	pq_flush();
	break;

    case Local:
    case Debug:
    case None:
    default:
	break;
    }
}

/* ----------------
 * 	NullCommand - tell dest that the last of a query sequence was processed
 * 
 * 	Necessary to implement the hacky FE/BE interface to handle
 *	multiple-return queries.
 * ----------------
 */
void
NullCommand(dest)
    CommandDest	dest;
{
    switch (dest) {
    case Remote:
	/* ----------------
	 *	tell the fe that the last of the queries has finished
	 * ----------------
	 */
	pq_putnchar("I", 1);
	pq_putint(0, 4);
	pq_flush();
	break;

    case Local:
    case Debug:
    case None:
    default:
	break;
    }	
}
@


1.3
log
@changed ExecMain interface to use new "communication destination"
code instead of old hacky lisp interface.
@
text
@d6 1
a6 1
 *	support for various command destinations - see lib/H/tcop/dest.h
d19 1
a19 1
 *	$Header: RCS/dest.c,v 1.2 91/02/11 15:37:53 cimarron Exp Locker: cimarron $
d25 1
a25 1
RcsId("$Header: RCS/dest.c,v 1.2 91/02/11 15:37:53 cimarron Exp Locker: cimarron $");
d29 2
a31 1
#include "tmp/portal.h"
d50 1
d66 1
a66 1
	return donothing;
d92 1
d94 2
a95 2
    int natts;
    int i;
d103 8
d139 8
d154 3
d172 1
a172 1
    String  commandTag;
@


1.2
log
@moved some communication processing from pquery.c to 
BeginCommand() in dest.c and fixed a problem with storing
dest in the query descriptor.
@
text
@d19 1
a19 1
 *	$Header: RCS/dest.c,v 1.1 91/02/10 18:19:46 cimarron Exp Locker: cimarron $
d25 1
a25 1
RcsId("$Header: RCS/dest.c,v 1.1 91/02/10 18:19:46 cimarron Exp Locker: cimarron $");
d35 42
@


1.1
log
@Initial revision
@
text
@d19 1
a19 1
 *	$Header$
d25 1
a25 1
RcsId("$Header: RCS/slaves.c,v 1.6 90/09/10 20:45:02 hong Exp Locker: hong $");
d28 1
a36 35
 *	initport
 *
 *	XXX change all these "P"'s and "T"'s to use #define constants
 * ----------------
 */
void
initport(name, natts, attinfo)
    char		*name;
    int			natts;
    struct attribute	*attinfo[];
{
    register int	i;
    
    /* ----------------
     *	send fe info on tuples we're about to send
     * ----------------
     */
    pq_putnchar("P", 1);	/* new portal.. */
    pq_putint(0, 4);		/* xid */
    pq_putstr(name);		/* portal name */
    pq_putnchar("T", 1);	/* type info to follow.. */
    pq_putint(natts, 2);	/* number of attributes in tuples */
    
    /* ----------------
     *	send tuple attribute types to fe
     * ----------------
     */
    for (i = 0; i < natts; ++i) {
	pq_putstr(attinfo[i]->attname);	/* if 16 char name oops.. */
	pq_putint((int) attinfo[i]->atttypid, 4);
	pq_putint(attinfo[i]->attlen, 2);
    }
}

/* ----------------
d41 1
a41 1
BeginCommand(pname, attinfo, dest)
d44 2
d49 2
a50 1
    int nattrs;
d52 1
a52 1
    nattrs = CInteger(CAR(attinfo));
d57 4
d62 20
a81 1
	initport(pname, nattrs, attrs);
d89 5
a93 1
	showatts(pname, nattrs, attrs);
d113 4
d144 4
@
