mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Postgres95 1.01 Distribution - Virgin Sources
This commit is contained in:
		
							
								
								
									
										26
									
								
								src/backend/libpq/Makefile.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/backend/libpq/Makefile.inc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
#-------------------------------------------------------------------------
 | 
			
		||||
#
 | 
			
		||||
# Makefile.inc--
 | 
			
		||||
#    Makefile for the (backend side) libpq module
 | 
			
		||||
#
 | 
			
		||||
# Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
#
 | 
			
		||||
#
 | 
			
		||||
# IDENTIFICATION
 | 
			
		||||
#    $Header: /cvsroot/pgsql/src/backend/libpq/Attic/Makefile.inc,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $
 | 
			
		||||
#
 | 
			
		||||
#-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# The frontend libpq interfaces to the backend through these files.
 | 
			
		||||
#
 | 
			
		||||
VPATH:= $(VPATH):$(CURDIR)/libpq
 | 
			
		||||
 | 
			
		||||
SRCS_LIBPQ= be-dumpdata.c be-fsstubs.c be-pqexec.c
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# These files are shared with the frontend library.
 | 
			
		||||
#
 | 
			
		||||
SRCS_LIBPQ+= auth.c pqcomm.c portal.c portalbuf.c pqpacket.c pqsignal.c
 | 
			
		||||
 | 
			
		||||
HEADERS+= auth.h be-fsstubs.h libpq-be.h libpq-fs.h libpq.h pqcomm.h pqsignal.h
 | 
			
		||||
							
								
								
									
										668
									
								
								src/backend/libpq/auth.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										668
									
								
								src/backend/libpq/auth.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,668 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * auth.c--
 | 
			
		||||
 *    Routines to handle network authentication
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *    $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
/*
 | 
			
		||||
 * INTERFACE ROUTINES
 | 
			
		||||
 *
 | 
			
		||||
 *     backend (postmaster) routines:
 | 
			
		||||
 *	be_recvauth		receive authentication information
 | 
			
		||||
 *	be_setauthsvc		do/do not permit an authentication service
 | 
			
		||||
 *	be_getauthsvc		is an authentication service permitted?
 | 
			
		||||
 *
 | 
			
		||||
 *   NOTES
 | 
			
		||||
 *	To add a new authentication system:
 | 
			
		||||
 *	0. If you can't do your authentication over an existing socket,
 | 
			
		||||
 *	   you lose -- get ready to hack around this framework instead of 
 | 
			
		||||
 *	   using it.  Otherwise, you can assume you have an initialized
 | 
			
		||||
 *	   and empty connection to work with.  (Please don't leave leftover
 | 
			
		||||
 *	   gunk in the connection after the authentication transactions, or
 | 
			
		||||
 *	   the POSTGRES routines that follow will be very unhappy.)
 | 
			
		||||
 *	1. Write a set of routines that:
 | 
			
		||||
 *		let a client figure out what user/principal name to use
 | 
			
		||||
 *		send authentication information (client side)
 | 
			
		||||
 *		receive authentication information (server side)
 | 
			
		||||
 *	   You can include both routines in this file, using #ifdef FRONTEND
 | 
			
		||||
 *	   to separate them.
 | 
			
		||||
 *	2. Edit libpq/pqcomm.h and assign a MsgType for your protocol.
 | 
			
		||||
 *	3. Edit the static "struct authsvc" array and the generic 
 | 
			
		||||
 *	   {be,fe}_{get,set}auth{name,svc} routines in this file to reflect 
 | 
			
		||||
 *	   the new service.  You may have to change the arguments of these
 | 
			
		||||
 *	   routines; they basically just reflect what Kerberos v4 needs.
 | 
			
		||||
 *	4. Hack on src/{,bin}/Makefile.global and src/{backend,libpq}/Makefile
 | 
			
		||||
 *	   to add library and CFLAGS hooks -- basically, grep the Makefile
 | 
			
		||||
 *	   hierarchy for KRBVERS to see where you need to add things.
 | 
			
		||||
 *
 | 
			
		||||
 *	Send mail to post_hackers@postgres.Berkeley.EDU if you have to make 
 | 
			
		||||
 *	any changes to arguments, etc.  Context diffs would be nice, too.
 | 
			
		||||
 *
 | 
			
		||||
 *	Someday, this cruft will go away and magically be replaced by a
 | 
			
		||||
 *	nice interface based on the GSS API or something.  For now, though,
 | 
			
		||||
 *	there's no (stable) UNIX security API to work with...
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/param.h>	/* for MAX{HOSTNAME,PATH}LEN, NOFILE */
 | 
			
		||||
#include <pwd.h>
 | 
			
		||||
#include <ctype.h>		        /* isspace() declaration */
 | 
			
		||||
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include "libpq/auth.h"
 | 
			
		||||
#include "libpq/libpq.h"
 | 
			
		||||
#include "libpq/pqcomm.h"
 | 
			
		||||
#include "libpq/libpq-be.h"
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------
 | 
			
		||||
 * common definitions for generic fe/be routines
 | 
			
		||||
 *----------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct authsvc {
 | 
			
		||||
    char	name[16];	/* service nickname (for command line) */
 | 
			
		||||
    MsgType	msgtype;	/* startup packet header type */
 | 
			
		||||
    int		allowed;	/* initially allowed (before command line
 | 
			
		||||
				 * option parsing)?
 | 
			
		||||
				 */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Command-line parsing routines use this structure to map nicknames
 | 
			
		||||
 * onto service types (and the startup packets to use with them).
 | 
			
		||||
 *
 | 
			
		||||
 * Programs receiving an authentication request use this structure to
 | 
			
		||||
 * decide which authentication service types are currently permitted.
 | 
			
		||||
 * By default, all authentication systems compiled into the system are
 | 
			
		||||
 * allowed.  Unauthenticated connections are disallowed unless there
 | 
			
		||||
 * isn't any authentication system.
 | 
			
		||||
 */
 | 
			
		||||
static struct authsvc authsvcs[] = {
 | 
			
		||||
#ifdef KRB4
 | 
			
		||||
    { "krb4",     STARTUP_KRB4_MSG, 1 },
 | 
			
		||||
    { "kerberos", STARTUP_KRB4_MSG, 1 },
 | 
			
		||||
#endif /* KRB4 */
 | 
			
		||||
#ifdef KRB5
 | 
			
		||||
    { "krb5",     STARTUP_KRB5_MSG, 1 },
 | 
			
		||||
    { "kerberos", STARTUP_KRB5_MSG, 1 },
 | 
			
		||||
#endif /* KRB5 */
 | 
			
		||||
    { UNAUTHNAME, STARTUP_MSG,
 | 
			
		||||
#if defined(KRB4) || defined(KRB5)
 | 
			
		||||
	  0
 | 
			
		||||
#else /* !(KRB4 || KRB5) */
 | 
			
		||||
	  1
 | 
			
		||||
#endif /* !(KRB4 || KRB5) */
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
 | 
			
		||||
 | 
			
		||||
#ifdef KRB4
 | 
			
		||||
/*----------------------------------------------------------------
 | 
			
		||||
 * MIT Kerberos authentication system - protocol version 4
 | 
			
		||||
 *----------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "krb.h"
 | 
			
		||||
 | 
			
		||||
#ifdef FRONTEND
 | 
			
		||||
/* moves to src/libpq/fe-auth.c  */
 | 
			
		||||
#else /* !FRONTEND */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_krb4_recvauth -- server routine to receive authentication information
 | 
			
		||||
 *		       from the client
 | 
			
		||||
 *
 | 
			
		||||
 * Nothing unusual here, except that we compare the username obtained from
 | 
			
		||||
 * the client's setup packet to the authenticated name.  (We have to retain
 | 
			
		||||
 * the name in the setup packet since we have to retain the ability to handle
 | 
			
		||||
 * unauthenticated connections.)
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
pg_krb4_recvauth(int sock,
 | 
			
		||||
		 struct sockaddr_in *laddr,
 | 
			
		||||
		 struct sockaddr_in *raddr,
 | 
			
		||||
		 char *username)
 | 
			
		||||
{
 | 
			
		||||
    long		krbopts = 0;	/* one-way authentication */
 | 
			
		||||
    KTEXT_ST	clttkt;
 | 
			
		||||
    char		instance[INST_SZ];
 | 
			
		||||
    AUTH_DAT	auth_data;
 | 
			
		||||
    Key_schedule	key_sched;
 | 
			
		||||
    char		version[KRB_SENDAUTH_VLEN];
 | 
			
		||||
    int		status;
 | 
			
		||||
    
 | 
			
		||||
    strcpy(instance, "*");	/* don't care, but arg gets expanded anyway */
 | 
			
		||||
    status = krb_recvauth(krbopts,
 | 
			
		||||
			  sock,
 | 
			
		||||
			  &clttkt,
 | 
			
		||||
			  PG_KRB_SRVNAM,
 | 
			
		||||
			  instance,
 | 
			
		||||
			  raddr,
 | 
			
		||||
			  laddr,
 | 
			
		||||
			  &auth_data,
 | 
			
		||||
			  PG_KRB_SRVTAB,
 | 
			
		||||
			  key_sched,
 | 
			
		||||
			  version);
 | 
			
		||||
    if (status != KSUCCESS) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "pg_krb4_recvauth: kerberos error: %s\n",
 | 
			
		||||
		       krb_err_txt[status]);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    if (strncmp(version, PG_KRB4_VERSION, KRB_SENDAUTH_VLEN)) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "pg_krb4_recvauth: protocol version != \"%s\"\n",
 | 
			
		||||
		       PG_KRB4_VERSION);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    if (username && *username &&
 | 
			
		||||
	strncmp(username, auth_data.pname, NAMEDATALEN)) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "pg_krb4_recvauth: name \"%s\" != \"%s\"\n",
 | 
			
		||||
		       username,
 | 
			
		||||
		       auth_data.pname);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    return(STATUS_OK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* !FRONTEND */
 | 
			
		||||
 | 
			
		||||
#endif /* KRB4 */
 | 
			
		||||
 | 
			
		||||
#ifdef KRB5
 | 
			
		||||
/*----------------------------------------------------------------
 | 
			
		||||
 * MIT Kerberos authentication system - protocol version 5
 | 
			
		||||
 *----------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "krb5/krb5.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_an_to_ln -- return the local name corresponding to an authentication
 | 
			
		||||
 *		  name
 | 
			
		||||
 *
 | 
			
		||||
 * XXX Assumes that the first aname component is the user name.  This is NOT
 | 
			
		||||
 *     necessarily so, since an aname can actually be something out of your
 | 
			
		||||
 *     worst X.400 nightmare, like
 | 
			
		||||
 *	  ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU
 | 
			
		||||
 *     Note that the MIT an_to_ln code does the same thing if you don't
 | 
			
		||||
 *     provide an aname mapping database...it may be a better idea to use
 | 
			
		||||
 *     krb5_an_to_ln, except that it punts if multiple components are found,
 | 
			
		||||
 *     and we can't afford to punt.
 | 
			
		||||
 */
 | 
			
		||||
static char *
 | 
			
		||||
pg_an_to_ln(char *aname)
 | 
			
		||||
{
 | 
			
		||||
    char	*p;
 | 
			
		||||
    
 | 
			
		||||
    if ((p = strchr(aname, '/')) || (p = strchr(aname, '@')))
 | 
			
		||||
	*p = '\0';
 | 
			
		||||
    return(aname);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef FRONTEND
 | 
			
		||||
/* moves to src/libpq/fe-auth.c  */
 | 
			
		||||
#else /* !FRONTEND */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_krb4_recvauth -- server routine to receive authentication information
 | 
			
		||||
 *		       from the client
 | 
			
		||||
 *
 | 
			
		||||
 * We still need to compare the username obtained from the client's setup
 | 
			
		||||
 * packet to the authenticated name, as described in pg_krb4_recvauth.  This
 | 
			
		||||
 * is a bit more problematic in v5, as described above in pg_an_to_ln.
 | 
			
		||||
 *
 | 
			
		||||
 * In addition, as described above in pg_krb5_sendauth, we still need to
 | 
			
		||||
 * canonicalize the server name v4-style before constructing a principal
 | 
			
		||||
 * from it.  Again, this is kind of iffy.
 | 
			
		||||
 *
 | 
			
		||||
 * Finally, we need to tangle with the fact that v5 doesn't let you explicitly
 | 
			
		||||
 * set server keytab file names -- you have to feed lower-level routines a
 | 
			
		||||
 * function to retrieve the contents of a keytab, along with a single argument
 | 
			
		||||
 * that allows them to open the keytab.  We assume that a server keytab is
 | 
			
		||||
 * always a real file so we can allow people to specify their own filenames.
 | 
			
		||||
 * (This is important because the POSTGRES keytab needs to be readable by
 | 
			
		||||
 * non-root users/groups; the v4 tools used to force you do dump a whole
 | 
			
		||||
 * host's worth of keys into a file, effectively forcing you to use one file,
 | 
			
		||||
 * but kdb5_edit allows you to select which principals to dump.  Yay!)
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
pg_krb5_recvauth(int sock,
 | 
			
		||||
		 struct sockaddr_in *laddr,
 | 
			
		||||
		 struct sockaddr_in *raddr,
 | 
			
		||||
		 char *username)
 | 
			
		||||
{
 | 
			
		||||
    char			servbuf[MAXHOSTNAMELEN + 1 +
 | 
			
		||||
					sizeof(PG_KRB_SRVNAM)];
 | 
			
		||||
    char			*hostp, *kusername = (char *) NULL;
 | 
			
		||||
    krb5_error_code		code;
 | 
			
		||||
    krb5_principal		client, server;
 | 
			
		||||
    krb5_address		sender_addr;
 | 
			
		||||
    krb5_rdreq_key_proc	keyproc = (krb5_rdreq_key_proc) NULL;
 | 
			
		||||
    krb5_pointer		keyprocarg = (krb5_pointer) NULL;
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Set up server side -- since we have no ticket file to make this
 | 
			
		||||
     * easy, we construct our own name and parse it.  See note on
 | 
			
		||||
     * canonicalization above.
 | 
			
		||||
     */
 | 
			
		||||
    (void) strcpy(servbuf, PG_KRB_SRVNAM);
 | 
			
		||||
    *(hostp = servbuf + (sizeof(PG_KRB_SRVNAM) - 1)) = '/';
 | 
			
		||||
    if (gethostname(++hostp, MAXHOSTNAMELEN) < 0)
 | 
			
		||||
	(void) strcpy(hostp, "localhost");
 | 
			
		||||
    if (hostp = strchr(hostp, '.'))
 | 
			
		||||
	*hostp = '\0';
 | 
			
		||||
    if (code = krb5_parse_name(servbuf, &server)) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "pg_krb5_recvauth: Kerberos error %d in krb5_parse_name\n",
 | 
			
		||||
		       code);
 | 
			
		||||
	com_err("pg_krb5_recvauth", code, "in krb5_parse_name");
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * krb5_sendauth needs this to verify the address in the client
 | 
			
		||||
     * authenticator.
 | 
			
		||||
     */
 | 
			
		||||
    sender_addr.addrtype = raddr->sin_family;
 | 
			
		||||
    sender_addr.length = sizeof(raddr->sin_addr);
 | 
			
		||||
    sender_addr.contents = (krb5_octet *) &(raddr->sin_addr);
 | 
			
		||||
    
 | 
			
		||||
    if (strcmp(PG_KRB_SRVTAB, "")) {
 | 
			
		||||
	keyproc = krb5_kt_read_service_key;
 | 
			
		||||
	keyprocarg = PG_KRB_SRVTAB;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (code = krb5_recvauth((krb5_pointer) &sock,
 | 
			
		||||
			     PG_KRB5_VERSION,
 | 
			
		||||
			     server,
 | 
			
		||||
			     &sender_addr,
 | 
			
		||||
			     (krb5_pointer) NULL,
 | 
			
		||||
			     keyproc,
 | 
			
		||||
			     keyprocarg,
 | 
			
		||||
			     (char *) NULL,
 | 
			
		||||
			     (krb5_int32 *) NULL,
 | 
			
		||||
			     &client,
 | 
			
		||||
			     (krb5_ticket **) NULL,
 | 
			
		||||
			     (krb5_authenticator **) NULL)) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "pg_krb5_recvauth: Kerberos error %d in krb5_recvauth\n",
 | 
			
		||||
		       code);
 | 
			
		||||
	com_err("pg_krb5_recvauth", code, "in krb5_recvauth");
 | 
			
		||||
	krb5_free_principal(server);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    krb5_free_principal(server);
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * The "client" structure comes out of the ticket and is therefore
 | 
			
		||||
     * authenticated.  Use it to check the username obtained from the
 | 
			
		||||
     * postmaster startup packet.
 | 
			
		||||
     */
 | 
			
		||||
    if ((code = krb5_unparse_name(client, &kusername))) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "pg_krb5_recvauth: Kerberos error %d in krb5_unparse_name\n",
 | 
			
		||||
		       code);
 | 
			
		||||
	com_err("pg_krb5_recvauth", code, "in krb5_unparse_name");
 | 
			
		||||
	krb5_free_principal(client);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    krb5_free_principal(client);
 | 
			
		||||
    if (!kusername) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "pg_krb5_recvauth: could not decode username\n");
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    kusername = pg_an_to_ln(kusername);
 | 
			
		||||
    if (username && strncmp(username, kusername, NAMEDATALEN)) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "pg_krb5_recvauth: name \"%s\" != \"%s\"\n",
 | 
			
		||||
		       username, kusername);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	free(kusername);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    free(kusername);
 | 
			
		||||
    return(STATUS_OK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* !FRONTEND */
 | 
			
		||||
 | 
			
		||||
#endif /* KRB5 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------
 | 
			
		||||
 * host based authentication
 | 
			
		||||
 *----------------------------------------------------------------
 | 
			
		||||
 * based on the securelib package originally written by William
 | 
			
		||||
 * LeFebvre, EECS Department, Northwestern University
 | 
			
		||||
 * (phil@eecs.nwu.edu) - orginal configuration file code handling
 | 
			
		||||
 * by Sam Horrocks (sam@ics.uci.edu)
 | 
			
		||||
 *
 | 
			
		||||
 * modified and adapted for use with Postgres95 by Paul Fisher
 | 
			
		||||
 * (pnfisher@unity.ncsu.edu)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define CONF_FILE "pg_hba"              /* Name of the config file           */
 | 
			
		||||
 | 
			
		||||
#define MAX_LINES 255                    /* Maximum number of config lines    *
 | 
			
		||||
                                         * that can apply to one database    */
 | 
			
		||||
 | 
			
		||||
#define ALL_NAME "all"                  /* Name used in config file for      *
 | 
			
		||||
                                         * lines that apply to all databases */
 | 
			
		||||
 | 
			
		||||
#define MAX_TOKEN 80                    /* Maximum size of one token in the  *
 | 
			
		||||
                                         * configuration file                */
 | 
			
		||||
 
 | 
			
		||||
struct conf_line {                      /* Info about config file line */
 | 
			
		||||
  u_long adr, mask;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
static int next_token(FILE *, char *, int);
 | 
			
		||||
 | 
			
		||||
/* hba_recvauth */
 | 
			
		||||
/* check for host-based authentication */
 | 
			
		||||
/*
 | 
			
		||||
 * hba_recvauth - check the sockaddr_in "addr" to see if it corresponds
 | 
			
		||||
 *                to an acceptable host for the database that's being
 | 
			
		||||
 *                connected to.  Return STATUS_OK if acceptable,
 | 
			
		||||
 *                otherwise return STATUS_ERROR.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
hba_recvauth(struct sockaddr_in *addr, PacketBuf *pbuf, StartupInfo *sp)
 | 
			
		||||
{
 | 
			
		||||
    u_long ip_addr;
 | 
			
		||||
    static struct conf_line conf[MAX_LINES];
 | 
			
		||||
    static int nconf;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    char buf[MAX_TOKEN];
 | 
			
		||||
    FILE *file;
 | 
			
		||||
 | 
			
		||||
    char *conf_file;
 | 
			
		||||
 | 
			
		||||
    /* put together the full pathname to the config file */
 | 
			
		||||
    conf_file = (char *) malloc((strlen(GetPGData())+strlen(CONF_FILE)+2)*sizeof(char));
 | 
			
		||||
    strcpy(conf_file, GetPGData());
 | 
			
		||||
    strcat(conf_file, "/");
 | 
			
		||||
    strcat(conf_file, CONF_FILE);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /* Open the config file. */
 | 
			
		||||
    file = fopen(conf_file, "r");
 | 
			
		||||
    if (file)
 | 
			
		||||
    {
 | 
			
		||||
        free(conf_file);
 | 
			
		||||
	nconf = 0;
 | 
			
		||||
 | 
			
		||||
	/* Grab the "name" */
 | 
			
		||||
	while ((i = next_token(file, buf, sizeof(buf))) != EOF)
 | 
			
		||||
	{
 | 
			
		||||
	    /* If only token on the line, ignore */
 | 
			
		||||
	    if (i == '\n') continue;
 | 
			
		||||
	    
 | 
			
		||||
	    /* Comment -- read until end of line then next line */
 | 
			
		||||
	    if (buf[0] == '#')
 | 
			
		||||
	    {
 | 
			
		||||
	        while (next_token(file, buf, sizeof(buf)) == 0) ;
 | 
			
		||||
	        continue;
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    /*
 | 
			
		||||
	     * Check to make sure this says "all" or that it matches
 | 
			
		||||
	     * the database name.
 | 
			
		||||
	     */
 | 
			
		||||
	    
 | 
			
		||||
	    if (strcmp(buf, ALL_NAME) == 0 || (strcmp(buf, sp->database) == 0))
 | 
			
		||||
	    {
 | 
			
		||||
	        /* Get next token, if last on line, ignore */
 | 
			
		||||
	        if (next_token(file, buf, sizeof(buf)) != 0)
 | 
			
		||||
		    continue;
 | 
			
		||||
 | 
			
		||||
		/* Got address */
 | 
			
		||||
		conf[nconf].adr = inet_addr(buf);
 | 
			
		||||
		    
 | 
			
		||||
		/* Get next token (mask) */
 | 
			
		||||
		i = next_token(file, buf, sizeof(buf));
 | 
			
		||||
 | 
			
		||||
		/* Only ignore if we got no text at all */
 | 
			
		||||
		if (i != EOF)
 | 
			
		||||
		{
 | 
			
		||||
		    /* Add to list, quit if array is full */
 | 
			
		||||
		    conf[nconf++].mask = inet_addr(buf);
 | 
			
		||||
		    if (nconf == MAX_LINES) break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* If not at end-of-line, keep reading til we are */
 | 
			
		||||
		while (i == 0)
 | 
			
		||||
		    i = next_token(file, buf, sizeof(buf));
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
	fclose(file);
 | 
			
		||||
    }
 | 
			
		||||
    else 
 | 
			
		||||
    {  (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "hba_recvauth: config file does not exist or permissions are not setup correctly!\n");
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	free(conf_file);
 | 
			
		||||
        return(STATUS_ERROR); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /* Config lines now in memory so start checking address */
 | 
			
		||||
    /* grab just the address */
 | 
			
		||||
    ip_addr = addr->sin_addr.s_addr;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Go through the conf array, turn off the bits given by the mask
 | 
			
		||||
     * and then compare the result with the address.  A match means
 | 
			
		||||
     * that this address is ok.
 | 
			
		||||
     */
 | 
			
		||||
    for (i = 0; i < nconf; ++i)
 | 
			
		||||
        if ((ip_addr & ~conf[i].mask) == conf[i].adr) return(STATUS_OK);
 | 
			
		||||
    
 | 
			
		||||
    /* no match, so we can't approve the address */
 | 
			
		||||
    return(STATUS_ERROR);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Grab one token out of fp.  Defined as the next string of non-whitespace
 | 
			
		||||
 * in the file.  After we get the token, continue reading until EOF, end of
 | 
			
		||||
 * line or the next token.  If it's the last token on the line, return '\n'
 | 
			
		||||
 * for the value.  If we get EOF before reading a token, return EOF.  In all
 | 
			
		||||
 * other cases return 0.
 | 
			
		||||
 */
 | 
			
		||||
static int 
 | 
			
		||||
next_token(FILE *fp, char *buf, int bufsz)
 | 
			
		||||
{
 | 
			
		||||
    int c;
 | 
			
		||||
    char *eb = buf+(bufsz-1);
 | 
			
		||||
 | 
			
		||||
    /* Discard inital whitespace */
 | 
			
		||||
    while (isspace(c = getc(fp))) ;
 | 
			
		||||
 | 
			
		||||
    /* EOF seen before any token so return EOF */
 | 
			
		||||
    if (c == EOF) return -1;
 | 
			
		||||
 | 
			
		||||
    /* Form a token in buf */
 | 
			
		||||
    do {
 | 
			
		||||
	if (buf < eb) *buf++ = c;
 | 
			
		||||
	c = getc(fp);
 | 
			
		||||
    } while (!isspace(c) && c != EOF);
 | 
			
		||||
    *buf = '\0';
 | 
			
		||||
 | 
			
		||||
    /* Discard trailing tabs and spaces */
 | 
			
		||||
    while (c == ' ' || c == '\t') c = getc(fp);
 | 
			
		||||
 | 
			
		||||
    /* Put back the char that was non-whitespace (putting back EOF is ok) */
 | 
			
		||||
    (void) ungetc(c, fp);
 | 
			
		||||
 | 
			
		||||
    /* If we ended with a newline, return that, otherwise return 0 */
 | 
			
		||||
    return (c == '\n' ? '\n' : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * be_recvauth -- server demux routine for incoming authentication information
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
be_recvauth(MsgType msgtype, Port *port, char *username, StartupInfo* sp)
 | 
			
		||||
{
 | 
			
		||||
    if (!username) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "be_recvauth: no user name passed\n");
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    if (!port) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "be_recvauth: no port structure passed\n");
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    switch (msgtype) {
 | 
			
		||||
#ifdef KRB4
 | 
			
		||||
    case STARTUP_KRB4_MSG:
 | 
			
		||||
	if (!be_getauthsvc(msgtype)) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "be_recvauth: krb4 authentication disallowed\n");
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    return(STATUS_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
	if (pg_krb4_recvauth(port->sock, &port->laddr, &port->raddr,
 | 
			
		||||
			     username) != STATUS_OK) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "be_recvauth: krb4 authentication failed\n");
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    return(STATUS_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef KRB5
 | 
			
		||||
    case STARTUP_KRB5_MSG:
 | 
			
		||||
	if (!be_getauthsvc(msgtype)) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "be_recvauth: krb5 authentication disallowed\n");
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    return(STATUS_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
	if (pg_krb5_recvauth(port->sock, &port->laddr, &port->raddr,
 | 
			
		||||
			     username) != STATUS_OK) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "be_recvauth: krb5 authentication failed\n");
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    return(STATUS_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
#endif
 | 
			
		||||
    case STARTUP_MSG:
 | 
			
		||||
	if (!be_getauthsvc(msgtype)) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "be_recvauth: unauthenticated connections disallowed failed\n");
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    return(STATUS_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
    case STARTUP_HBA_MSG:
 | 
			
		||||
	if (hba_recvauth(&port->raddr, &port->buf, sp) != STATUS_OK) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "be_recvauth: host-based authentication failed\n");
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    return(STATUS_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
    default:
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "be_recvauth: unrecognized message type: %d\n",
 | 
			
		||||
		       msgtype);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    return(STATUS_OK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * be_setauthsvc -- enable/disable the authentication services currently
 | 
			
		||||
 *		    selected for use by the backend
 | 
			
		||||
 * be_getauthsvc -- returns whether a particular authentication system
 | 
			
		||||
 *		    (indicated by its message type) is permitted by the
 | 
			
		||||
 *		    current selections
 | 
			
		||||
 *
 | 
			
		||||
 * be_setauthsvc encodes the command-line syntax that
 | 
			
		||||
 *	-a "<service-name>"
 | 
			
		||||
 * enables a service, whereas
 | 
			
		||||
 *	-a "no<service-name>"
 | 
			
		||||
 * disables it.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
be_setauthsvc(char *name)
 | 
			
		||||
{
 | 
			
		||||
    int i, j;
 | 
			
		||||
    int turnon = 1;
 | 
			
		||||
    
 | 
			
		||||
    if (!name)
 | 
			
		||||
	return;
 | 
			
		||||
    if (!strncmp("no", name, 2)) {
 | 
			
		||||
	turnon = 0;
 | 
			
		||||
	name += 2;
 | 
			
		||||
    }
 | 
			
		||||
    if (name[0] == '\0')
 | 
			
		||||
	return;
 | 
			
		||||
    for (i = 0; i < n_authsvcs; ++i)
 | 
			
		||||
	if (!strcmp(name, authsvcs[i].name)) {
 | 
			
		||||
	    for (j = 0; j < n_authsvcs; ++j)
 | 
			
		||||
		if (authsvcs[j].msgtype == authsvcs[i].msgtype)
 | 
			
		||||
		    authsvcs[j].allowed = turnon;
 | 
			
		||||
	    break;
 | 
			
		||||
	}
 | 
			
		||||
    if (i == n_authsvcs) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "be_setauthsvc: invalid name %s, ignoring...\n",
 | 
			
		||||
		       name);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
be_getauthsvc(MsgType msgtype)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    
 | 
			
		||||
    for (i = 0; i < n_authsvcs; ++i)
 | 
			
		||||
	if (msgtype == authsvcs[i].msgtype)
 | 
			
		||||
	    return(authsvcs[i].allowed);
 | 
			
		||||
    return(0);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								src/backend/libpq/auth.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/backend/libpq/auth.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * auth.h--
 | 
			
		||||
 *    Definitions for network authentication routines
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: auth.h,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
#ifndef AUTH_H
 | 
			
		||||
#define	AUTH_H
 | 
			
		||||
 | 
			
		||||
#include "c.h"
 | 
			
		||||
#include "libpq/pqcomm.h"
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------
 | 
			
		||||
 * Common routines and definitions
 | 
			
		||||
 *----------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* what we call "no authentication system" */
 | 
			
		||||
#define	UNAUTHNAME		"unauth"
 | 
			
		||||
 | 
			
		||||
/* what a frontend uses by default */
 | 
			
		||||
#if !defined(KRB4) && !defined(KRB5)
 | 
			
		||||
#define	DEFAULT_CLIENT_AUTHSVC	UNAUTHNAME
 | 
			
		||||
#else /* KRB4 || KRB5 */
 | 
			
		||||
#define	DEFAULT_CLIENT_AUTHSVC	"kerberos"
 | 
			
		||||
#endif /* KRB4 || KRB5 */
 | 
			
		||||
 | 
			
		||||
extern int fe_sendauth(MsgType msgtype, Port *port, char *hostname);
 | 
			
		||||
extern void fe_setauthsvc(char *name);
 | 
			
		||||
extern MsgType fe_getauthsvc();
 | 
			
		||||
extern char *fe_getauthname(void);
 | 
			
		||||
extern int be_recvauth(MsgType msgtype, Port *port, char *username, StartupInfo* sp);
 | 
			
		||||
extern void be_setauthsvc(char *name);
 | 
			
		||||
extern int be_getauthsvc(MsgType msgtype);
 | 
			
		||||
 | 
			
		||||
/* the value that matches any dbName value when doing
 | 
			
		||||
   host based authentication*/
 | 
			
		||||
#define ALL_DBNAME      "*"
 | 
			
		||||
 | 
			
		||||
#define	PG_KRB4_VERSION	"PGVER4.1"	/* at most KRB_SENDAUTH_VLEN chars */
 | 
			
		||||
#define	PG_KRB5_VERSION	"PGVER5.1"
 | 
			
		||||
 | 
			
		||||
#endif /* AUTH_H */
 | 
			
		||||
							
								
								
									
										323
									
								
								src/backend/libpq/be-dumpdata.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										323
									
								
								src/backend/libpq/be-dumpdata.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,323 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * be-dumpdata.c--
 | 
			
		||||
 *    support for collection of returned tuples from an internal
 | 
			
		||||
 *    PQ call into a backend buffer.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *    $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
/*
 | 
			
		||||
 * INTERFACE ROUTINES
 | 
			
		||||
 *	be_portalinit    - initialize backend portal administration
 | 
			
		||||
 *	be_portalpush    - add a portal to the top of the portal stack
 | 
			
		||||
 *	be_portalpop     - remove portal on the top of the stack & return it
 | 
			
		||||
 *	be_currentportal - return the top portal on the portal stack
 | 
			
		||||
 *	be_newportal     - return a new portal.
 | 
			
		||||
 *	be_portalinit    - initialize backend portal expected to hold results.
 | 
			
		||||
 *	be_printtup      - add a tuple to a backend portal
 | 
			
		||||
 *
 | 
			
		||||
 * NOTES
 | 
			
		||||
 *	Since backend user-defined operators can call queries
 | 
			
		||||
 *	which in turn call user-defined operators can call queries...
 | 
			
		||||
 *	we have to keep track of portals on a stack.  BeginCommand()
 | 
			
		||||
 *	puts portals on the stack and the PQ functions remove them.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#include "postgres.h"
 | 
			
		||||
 | 
			
		||||
#include "lib/dllist.h"
 | 
			
		||||
#include "libpq/libpq-be.h"
 | 
			
		||||
 | 
			
		||||
#include "access/heapam.h"
 | 
			
		||||
#include "access/htup.h"
 | 
			
		||||
#include "storage/buf.h"
 | 
			
		||||
#include "utils/memutils.h"
 | 
			
		||||
#include "utils/palloc.h"
 | 
			
		||||
#include "fmgr.h"
 | 
			
		||||
#include "utils/mcxt.h"
 | 
			
		||||
#include "utils/elog.h"
 | 
			
		||||
#include "utils/exc.h"
 | 
			
		||||
 | 
			
		||||
#include "utils/syscache.h"
 | 
			
		||||
#include "catalog/pg_type.h"
 | 
			
		||||
#include "catalog/catalog.h"
 | 
			
		||||
#include "access/printtup.h"
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	backend portal stack for recursive PQexec calls
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
static Dllist *be_portalstack;
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	be_portalinit - initialize backend portal administration
 | 
			
		||||
 *
 | 
			
		||||
 *	This is called once from InitPostgres() to initialize
 | 
			
		||||
 *	the portal stack.
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
be_portalinit()
 | 
			
		||||
{
 | 
			
		||||
  be_portalstack = DLNewList();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	be_portalpush - add a portal to the top of the portal stack
 | 
			
		||||
 *
 | 
			
		||||
 *	used by BeginCommand()
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
be_portalpush(PortalEntry *entry)
 | 
			
		||||
{
 | 
			
		||||
  DLAddTail(be_portalstack, DLNewElem(entry));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	be_portalpop - remove the portal on the top of the stack & return it
 | 
			
		||||
 *
 | 
			
		||||
 *	used by PQexec()
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
PortalEntry *
 | 
			
		||||
be_portalpop()
 | 
			
		||||
{
 | 
			
		||||
  PortalEntry *p;
 | 
			
		||||
  Dlelem* elt;
 | 
			
		||||
  elt = DLRemTail(be_portalstack);
 | 
			
		||||
 | 
			
		||||
  p = (elt ? (PortalEntry*)DLE_VAL(elt) : NULL);
 | 
			
		||||
  DLFreeElem(elt);
 | 
			
		||||
  return p;
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	be_currentportal - return the top portal on the portal stack
 | 
			
		||||
 *
 | 
			
		||||
 *	used by be_printtup()
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
PortalEntry *
 | 
			
		||||
be_currentportal()
 | 
			
		||||
{
 | 
			
		||||
  Dlelem* elt;
 | 
			
		||||
  elt = DLGetTail(be_portalstack);
 | 
			
		||||
  return (elt ? (PortalEntry*)DLE_VAL(elt) : NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	be_newportal - return a new portal.
 | 
			
		||||
 *
 | 
			
		||||
 *	If the user-defined function does not specify a portal name,
 | 
			
		||||
 *	we generate a unique one.  Names are generated from a combination
 | 
			
		||||
 *	of a postgres oid and an integer counter which is incremented
 | 
			
		||||
 *	every time we ask for a local portal.
 | 
			
		||||
 *
 | 
			
		||||
 *	used by BeginCommand()
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static Oid	be_portaloid;
 | 
			
		||||
static u_int	be_portalcnt = 0;
 | 
			
		||||
 | 
			
		||||
PortalEntry *
 | 
			
		||||
be_newportal()   
 | 
			
		||||
{
 | 
			
		||||
    PortalEntry *entry;
 | 
			
		||||
    char 	buf[PortalNameLength];
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	generate a new name
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    if (be_portalcnt == 0)
 | 
			
		||||
	be_portaloid = newoid();
 | 
			
		||||
    be_portalcnt++;
 | 
			
		||||
    sprintf(buf, "be_%d_%d", be_portaloid, be_portalcnt);
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	initialize the new portal entry and keep track
 | 
			
		||||
     *  of the current memory context for be_printtup().
 | 
			
		||||
     *  This is important - otherwise whatever we allocate
 | 
			
		||||
     *  will go away and the contents of the portal after
 | 
			
		||||
     *  PQexec() returns will be meaningless.
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    entry = pbuf_setup(buf);
 | 
			
		||||
    entry->portalcxt = (Pointer) CurrentMemoryContext;
 | 
			
		||||
    
 | 
			
		||||
    return entry;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	be_typeinit - initialize backend portal expected to hold
 | 
			
		||||
 *			query results.
 | 
			
		||||
 *
 | 
			
		||||
 *	used by BeginCommand()
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
be_typeinit(PortalEntry *entry,
 | 
			
		||||
	    TupleDesc tupDesc,
 | 
			
		||||
	    int natts)
 | 
			
		||||
{
 | 
			
		||||
    PortalBuffer 	*portal;
 | 
			
		||||
    GroupBuffer 	*group;
 | 
			
		||||
    int 		i;
 | 
			
		||||
    AttributeTupleForm *attrs = tupDesc->attrs;
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	add a new portal group to the portal
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    portal = entry->portal;
 | 
			
		||||
    portal->no_groups++;
 | 
			
		||||
    portal->groups = group = pbuf_addGroup(portal);
 | 
			
		||||
    group->no_fields = natts;
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	initialize portal group type info
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    if (natts > 0) {
 | 
			
		||||
	group->types = pbuf_addTypes(natts);
 | 
			
		||||
	for (i = 0; i < natts; ++i) {
 | 
			
		||||
	    strncpy(group->types[i].name, attrs[i]->attname.data, NAMEDATALEN); 
 | 
			
		||||
	    group->types[i].adtid = attrs[i]->atttypid;
 | 
			
		||||
	    group->types[i].adtsize = attrs[i]->attlen;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	be_printtup - add a tuple to a backend portal
 | 
			
		||||
 *
 | 
			
		||||
 *	used indirectly by ExecRetrieve()
 | 
			
		||||
 *
 | 
			
		||||
 *	This code is pretty much copied from printtup(), dump_type()
 | 
			
		||||
 *	and dump_data().  -cim 2/12/91
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
be_printtup(HeapTuple tuple, TupleDesc typeinfo)
 | 
			
		||||
{
 | 
			
		||||
    int		i;
 | 
			
		||||
    char	*attr;
 | 
			
		||||
    bool	isnull;
 | 
			
		||||
    Oid	typoutput;
 | 
			
		||||
    
 | 
			
		||||
    PortalEntry  *entry = NULL;
 | 
			
		||||
    PortalBuffer *portal = NULL;
 | 
			
		||||
    GroupBuffer  *group = NULL ;
 | 
			
		||||
    TupleBlock 	 *tuples = NULL;
 | 
			
		||||
    char 	 **values;
 | 
			
		||||
    int          *lengths;
 | 
			
		||||
    
 | 
			
		||||
    MemoryContext savecxt;
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *  get the current portal and group
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    entry = be_currentportal();
 | 
			
		||||
    portal = entry->portal;
 | 
			
		||||
    group = portal->groups;
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	switch to the portal's memory context so that
 | 
			
		||||
     *  the tuples we allocate are returned to the user.
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    savecxt = MemoryContextSwitchTo((MemoryContext)entry->portalcxt);
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	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 {
 | 
			
		||||
	tuples = group->tuples;
 | 
			
		||||
	/* walk to the end of the linked list of TupleBlocks */
 | 
			
		||||
	while (tuples->next)
 | 
			
		||||
	    tuples = tuples->next;
 | 
			
		||||
	/* now, tuples is the last TupleBlock, check to see if it is full.  
 | 
			
		||||
	   If so, allocate a new TupleBlock and add it to the end of 
 | 
			
		||||
	   the chain */
 | 
			
		||||
	
 | 
			
		||||
	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(tuple->t_natts);
 | 
			
		||||
    tuples->lengths[tuples->tuple_index] = pbuf_addTupleValueLengths(tuple->t_natts);
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	copy printable representations of the tuple's attributes
 | 
			
		||||
     *  to the portal.
 | 
			
		||||
     *
 | 
			
		||||
     *  This seems silly, because the user's function which is calling
 | 
			
		||||
     *  PQexec() or PQfn() will probably just convert this back into the
 | 
			
		||||
     *  internal form anyways, but the point here is to provide a uniform
 | 
			
		||||
     *  libpq interface and this is how the fe libpq interface currently
 | 
			
		||||
     *  works.  Pretty soon we'll have to add code to let the fe or be
 | 
			
		||||
     *  select the desired data representation and then deal with that.
 | 
			
		||||
     *  This should not be too hard, as there already exist typrecieve()
 | 
			
		||||
     *  and typsend() procedures for user-defined types (see pg_type.h)
 | 
			
		||||
     *  -cim 2/11/91
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    values = tuples->values[tuples->tuple_index];
 | 
			
		||||
    lengths = tuples->lengths[tuples->tuple_index];
 | 
			
		||||
    
 | 
			
		||||
    for (i = 0; i < tuple->t_natts; i++) {
 | 
			
		||||
	attr = heap_getattr(tuple, InvalidBuffer, i+1, typeinfo, &isnull);
 | 
			
		||||
	typoutput = typtoout((Oid) typeinfo->attrs[i]->atttypid);
 | 
			
		||||
	
 | 
			
		||||
	lengths[i] = typeinfo->attrs[i]->attlen;
 | 
			
		||||
	
 | 
			
		||||
	if (lengths[i] == -1) /* variable length attribute */
 | 
			
		||||
	    if (!isnull)
 | 
			
		||||
		lengths[i] = VARSIZE(attr)-VARHDRSZ;
 | 
			
		||||
	    else
 | 
			
		||||
		lengths[i] = 0;
 | 
			
		||||
	
 | 
			
		||||
	if (!isnull && OidIsValid(typoutput)) {
 | 
			
		||||
	  values[i] = fmgr(typoutput, attr, gettypelem(typeinfo->attrs[i]->atttypid));
 | 
			
		||||
	} else 
 | 
			
		||||
	  values[i] = NULL;
 | 
			
		||||
	
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	increment tuple group counters
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    portal->no_tuples++;
 | 
			
		||||
    group->no_tuples++;
 | 
			
		||||
    tuples->tuple_index++;
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	return to the original memory context
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    MemoryContextSwitchTo(savecxt);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										351
									
								
								src/backend/libpq/be-fsstubs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										351
									
								
								src/backend/libpq/be-fsstubs.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,351 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * be-fsstubs.c--
 | 
			
		||||
 *    support for filesystem operations on large objects
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *    $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 * NOTES
 | 
			
		||||
 *    This should be moved to a more appropriate place.  It is here
 | 
			
		||||
 *    for lack of a better place.
 | 
			
		||||
 *
 | 
			
		||||
 *    Builtin functions for open/close/read/write operations on large objects.
 | 
			
		||||
 *
 | 
			
		||||
 *    These functions operate in the current portal variable context, which 
 | 
			
		||||
 *    means the large object descriptors hang around between transactions and 
 | 
			
		||||
 *    are not deallocated until explicitly closed, or until the portal is 
 | 
			
		||||
 *    closed.
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
#include "postgres.h"
 | 
			
		||||
#include "lib/dllist.h"
 | 
			
		||||
#include "libpq/libpq.h"
 | 
			
		||||
#include "libpq/libpq-fs.h"
 | 
			
		||||
#include "utils/mcxt.h"
 | 
			
		||||
#include "utils/palloc.h"
 | 
			
		||||
 | 
			
		||||
#include "storage/fd.h"		/* for O_ */
 | 
			
		||||
#include "storage/large_object.h"
 | 
			
		||||
 | 
			
		||||
#include "utils/elog.h"
 | 
			
		||||
#include "libpq/be-fsstubs.h"
 | 
			
		||||
 | 
			
		||||
/*#define FSDB 1*/
 | 
			
		||||
#define MAX_LOBJ_FDS 256
 | 
			
		||||
 | 
			
		||||
static LargeObjectDesc  *cookies[MAX_LOBJ_FDS];
 | 
			
		||||
 | 
			
		||||
static GlobalMemory fscxt = NULL;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int newLOfd(LargeObjectDesc *lobjCookie);
 | 
			
		||||
static void deleteLOfd(int fd);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 *  File Interfaces for Large Objects
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
lo_open(Oid lobjId, int mode)
 | 
			
		||||
{
 | 
			
		||||
    LargeObjectDesc *lobjDesc;
 | 
			
		||||
    int fd;
 | 
			
		||||
    MemoryContext currentContext;
 | 
			
		||||
    
 | 
			
		||||
#if FSDB
 | 
			
		||||
    elog(NOTICE,"LOopen(%d,%d)",lobjId,mode);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    if (fscxt == NULL) {
 | 
			
		||||
	fscxt = CreateGlobalMemory("Filesystem");
 | 
			
		||||
    }
 | 
			
		||||
    currentContext = MemoryContextSwitchTo((MemoryContext)fscxt);
 | 
			
		||||
 | 
			
		||||
    lobjDesc = inv_open(lobjId, mode);
 | 
			
		||||
    
 | 
			
		||||
    if (lobjDesc == NULL) { /* lookup failed */
 | 
			
		||||
	MemoryContextSwitchTo(currentContext);
 | 
			
		||||
#if FSDB	
 | 
			
		||||
	elog(NOTICE,"cannot open large object %d", lobjId);
 | 
			
		||||
#endif
 | 
			
		||||
	return -1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    fd = newLOfd(lobjDesc);
 | 
			
		||||
 | 
			
		||||
    /* switch context back to orig. */
 | 
			
		||||
    MemoryContextSwitchTo(currentContext);
 | 
			
		||||
 | 
			
		||||
    return fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
lo_close(int fd)
 | 
			
		||||
{
 | 
			
		||||
    MemoryContext currentContext;
 | 
			
		||||
 | 
			
		||||
    if (fd >= MAX_LOBJ_FDS) {
 | 
			
		||||
	elog(WARN,"lo_close: large obj descriptor (%d) out of range", fd);
 | 
			
		||||
	return -2;
 | 
			
		||||
    }
 | 
			
		||||
    if (cookies[fd] == NULL) {
 | 
			
		||||
	elog(WARN,"lo_close: invalid large obj descriptor (%d)", fd);
 | 
			
		||||
	return -3;
 | 
			
		||||
    }
 | 
			
		||||
#if FSDB
 | 
			
		||||
    elog(NOTICE,"LOclose(%d)",fd);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    Assert(fscxt != NULL);
 | 
			
		||||
    currentContext = MemoryContextSwitchTo((MemoryContext)fscxt);
 | 
			
		||||
 | 
			
		||||
    inv_close(cookies[fd]);
 | 
			
		||||
 | 
			
		||||
    MemoryContextSwitchTo(currentContext);
 | 
			
		||||
 | 
			
		||||
    deleteLOfd(fd);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  We assume the large object supports byte oriented reads and seeks so
 | 
			
		||||
 *  that our work is easier.
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
lo_read(int fd, char *buf, int len)
 | 
			
		||||
{
 | 
			
		||||
    Assert(cookies[fd]!=NULL);
 | 
			
		||||
    return inv_read(cookies[fd], buf, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
lo_write(int fd, char *buf, int len)
 | 
			
		||||
{
 | 
			
		||||
    Assert(cookies[fd]!=NULL);
 | 
			
		||||
    return inv_write(cookies[fd], buf, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
lo_lseek(int fd, int offset, int whence)
 | 
			
		||||
{
 | 
			
		||||
    if (fd >= MAX_LOBJ_FDS) {
 | 
			
		||||
	elog(WARN,"lo_seek: large obj descriptor (%d) out of range", fd);
 | 
			
		||||
	return -2;
 | 
			
		||||
    }
 | 
			
		||||
    return inv_seek(cookies[fd], offset, whence);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Oid
 | 
			
		||||
lo_creat(int mode)
 | 
			
		||||
{
 | 
			
		||||
    LargeObjectDesc *lobjDesc;
 | 
			
		||||
    MemoryContext currentContext;
 | 
			
		||||
    Oid lobjId;
 | 
			
		||||
    
 | 
			
		||||
    if (fscxt == NULL) {
 | 
			
		||||
	fscxt = CreateGlobalMemory("Filesystem");
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    currentContext = MemoryContextSwitchTo((MemoryContext)fscxt);
 | 
			
		||||
    
 | 
			
		||||
    lobjDesc = inv_create(mode);
 | 
			
		||||
    
 | 
			
		||||
    if (lobjDesc == NULL) {
 | 
			
		||||
	MemoryContextSwitchTo(currentContext);
 | 
			
		||||
	return InvalidOid;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    lobjId = lobjDesc->heap_r->rd_id;
 | 
			
		||||
    
 | 
			
		||||
    inv_close(lobjDesc);
 | 
			
		||||
    
 | 
			
		||||
    /* switch context back to original memory context */
 | 
			
		||||
    MemoryContextSwitchTo(currentContext);
 | 
			
		||||
    
 | 
			
		||||
    return lobjId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
lo_tell(int fd)
 | 
			
		||||
{
 | 
			
		||||
    if (fd >= MAX_LOBJ_FDS) {
 | 
			
		||||
	elog(WARN,"lo_tell: large object descriptor (%d) out of range",fd);
 | 
			
		||||
	return -2;
 | 
			
		||||
    }
 | 
			
		||||
    if (cookies[fd] == NULL) {
 | 
			
		||||
	elog(WARN,"lo_tell: invalid large object descriptor (%d)",fd);
 | 
			
		||||
	return -3;
 | 
			
		||||
    }
 | 
			
		||||
    return inv_tell(cookies[fd]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
lo_unlink(Oid lobjId)
 | 
			
		||||
{
 | 
			
		||||
    return (inv_destroy(lobjId));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 *  Read/Write using varlena 
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
struct varlena *
 | 
			
		||||
LOread(int fd, int len)
 | 
			
		||||
{
 | 
			
		||||
    struct varlena *retval;
 | 
			
		||||
    int totalread = 0;
 | 
			
		||||
    
 | 
			
		||||
    retval = (struct varlena *)palloc(sizeof(int32) + len);
 | 
			
		||||
    totalread = lo_read(fd, VARDATA(retval), len);
 | 
			
		||||
    VARSIZE(retval) = totalread + sizeof(int32);
 | 
			
		||||
    
 | 
			
		||||
    return retval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int LOwrite(int fd, struct varlena *wbuf)
 | 
			
		||||
{
 | 
			
		||||
    int totalwritten;
 | 
			
		||||
    int bytestowrite;
 | 
			
		||||
    
 | 
			
		||||
    bytestowrite = VARSIZE(wbuf) - sizeof(int32);
 | 
			
		||||
    totalwritten = lo_write(fd, VARDATA(wbuf), bytestowrite);
 | 
			
		||||
    return totalwritten;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 *   Import/Export of Large Object
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * lo_import -
 | 
			
		||||
 *    imports a file as an (inversion) large object.
 | 
			
		||||
 */
 | 
			
		||||
Oid
 | 
			
		||||
lo_import(text *filename)
 | 
			
		||||
{
 | 
			
		||||
    int fd;
 | 
			
		||||
    int nbytes, tmp;
 | 
			
		||||
#define BUFSIZE        1024
 | 
			
		||||
    char buf[BUFSIZE];
 | 
			
		||||
    LargeObjectDesc *lobj;
 | 
			
		||||
    Oid lobjOid;
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * open the file to be read in
 | 
			
		||||
     */
 | 
			
		||||
    fd = open(VARDATA(filename), O_RDONLY, 0666);
 | 
			
		||||
    if (fd < 0)  {   /* error */
 | 
			
		||||
	elog(WARN, "lo_import: can't open unix file\"%s\"\n", filename);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * create an inversion "object"
 | 
			
		||||
     */
 | 
			
		||||
    lobj = inv_create(INV_READ|INV_WRITE);
 | 
			
		||||
    if (lobj == NULL) {
 | 
			
		||||
	elog(WARN, "lo_import: can't create inv object for \"%s\"",
 | 
			
		||||
	     VARDATA(filename));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * the oid for the large object is just the oid of the relation
 | 
			
		||||
     * XInv??? which contains the data.
 | 
			
		||||
     */
 | 
			
		||||
    lobjOid = lobj->heap_r->rd_id;
 | 
			
		||||
	
 | 
			
		||||
    /*
 | 
			
		||||
     * read in from the Unix file and write to the inversion file
 | 
			
		||||
     */
 | 
			
		||||
    while ((nbytes = read(fd, buf, BUFSIZE)) > 0) {
 | 
			
		||||
	tmp = inv_write(lobj, buf, nbytes);
 | 
			
		||||
        if (tmp < nbytes) {
 | 
			
		||||
	    elog(WARN, "lo_import: error while reading \"%s\"",
 | 
			
		||||
		 VARDATA(filename));
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    (void) close(fd);
 | 
			
		||||
    (void) inv_close(lobj);
 | 
			
		||||
 | 
			
		||||
    return lobjOid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * lo_export -
 | 
			
		||||
 *    exports an (inversion) large object.
 | 
			
		||||
 */
 | 
			
		||||
int4
 | 
			
		||||
lo_export(Oid lobjId, text *filename)
 | 
			
		||||
{
 | 
			
		||||
    int fd;
 | 
			
		||||
    int nbytes, tmp;
 | 
			
		||||
#define BUFSIZE        1024
 | 
			
		||||
    char buf[BUFSIZE];
 | 
			
		||||
    LargeObjectDesc *lobj;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * create an inversion "object"
 | 
			
		||||
     */
 | 
			
		||||
    lobj = inv_open(lobjId, INV_READ);
 | 
			
		||||
    if (lobj == NULL) {
 | 
			
		||||
	elog(WARN, "lo_export: can't open inv object %d",
 | 
			
		||||
	     lobjId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * open the file to be written to
 | 
			
		||||
     */
 | 
			
		||||
    fd = open(VARDATA(filename), O_CREAT|O_WRONLY, 0666);
 | 
			
		||||
    if (fd < 0)  {   /* error */
 | 
			
		||||
	elog(WARN, "lo_export: can't open unix file\"%s\"",
 | 
			
		||||
	     VARDATA(filename));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * read in from the Unix file and write to the inversion file
 | 
			
		||||
     */
 | 
			
		||||
    while ((nbytes = inv_read(lobj, buf, BUFSIZE)) > 0) {
 | 
			
		||||
	tmp = write(fd, buf, nbytes);
 | 
			
		||||
        if (tmp < nbytes) {
 | 
			
		||||
	    elog(WARN, "lo_export: error while writing \"%s\"",
 | 
			
		||||
		 VARDATA(filename));
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    (void) inv_close(lobj);
 | 
			
		||||
    (void) close(fd);
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 *  Support routines for this file
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
newLOfd(LargeObjectDesc *lobjCookie)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    
 | 
			
		||||
    for (i = 0; i < MAX_LOBJ_FDS; i++) {
 | 
			
		||||
	
 | 
			
		||||
	if (cookies[i] == NULL) {
 | 
			
		||||
	    cookies[i] = lobjCookie;
 | 
			
		||||
	    return i;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void 
 | 
			
		||||
deleteLOfd(int fd)
 | 
			
		||||
{
 | 
			
		||||
    cookies[fd] = NULL;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								src/backend/libpq/be-fsstubs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/backend/libpq/be-fsstubs.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * be-fsstubs.h--
 | 
			
		||||
 *    
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: be-fsstubs.h,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
#ifndef	BE_FSSTUBS_H
 | 
			
		||||
#define	BE_FSSTUBS_H
 | 
			
		||||
 | 
			
		||||
extern Oid lo_import(text *filename);
 | 
			
		||||
extern int4 lo_export(Oid lobjId, text *filename);
 | 
			
		||||
 | 
			
		||||
extern Oid lo_creat(int mode);
 | 
			
		||||
 | 
			
		||||
extern int lo_open(Oid lobjId, int mode);
 | 
			
		||||
extern int lo_close(int fd);
 | 
			
		||||
extern int lo_read(int fd, char *buf, int len);
 | 
			
		||||
extern int lo_write(int fd, char *buf, int len);
 | 
			
		||||
extern int lo_lseek(int fd, int offset, int whence);
 | 
			
		||||
extern int lo_tell(int fd);
 | 
			
		||||
extern int lo_unlink(Oid lobjId);
 | 
			
		||||
 | 
			
		||||
extern struct varlena *LOread(int fd, int len);
 | 
			
		||||
extern int LOwrite(int fd, struct varlena *wbuf);
 | 
			
		||||
     
 | 
			
		||||
#endif	/* BE_FSSTUBS_H */
 | 
			
		||||
							
								
								
									
										382
									
								
								src/backend/libpq/be-pqexec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										382
									
								
								src/backend/libpq/be-pqexec.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,382 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * be-pqexec.c--
 | 
			
		||||
 *    support for executing POSTGRES commands and functions from a
 | 
			
		||||
 *    user-defined function in a backend.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *    $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
/*
 | 
			
		||||
 * INTERFACE ROUTINES
 | 
			
		||||
 * 	PQfn 		- call a POSTGRES function
 | 
			
		||||
 * 	PQexec 		- execute a POSTGRES query
 | 
			
		||||
 *	
 | 
			
		||||
 * NOTES
 | 
			
		||||
 *	These routines are compiled into the postgres backend.
 | 
			
		||||
 */
 | 
			
		||||
#include "postgres.h"
 | 
			
		||||
 | 
			
		||||
#include "nodes/pg_list.h"
 | 
			
		||||
#include "tcop/dest.h"
 | 
			
		||||
#include "tcop/fastpath.h"
 | 
			
		||||
#include "tcop/tcopprot.h"
 | 
			
		||||
#include "lib/dllist.h"
 | 
			
		||||
#include "libpq/libpq-be.h"
 | 
			
		||||
#include "fmgr.h"
 | 
			
		||||
#include "utils/exc.h"
 | 
			
		||||
#include "utils/builtins.h"
 | 
			
		||||
#include "utils/elog.h"
 | 
			
		||||
#include "utils/palloc.h"
 | 
			
		||||
 | 
			
		||||
/* ----------------------------------------------------------------
 | 
			
		||||
 *			PQ interface routines
 | 
			
		||||
 * ----------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	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.
 | 
			
		||||
 * 	result_is_int	: If the result is an integer, this must be non-zero
 | 
			
		||||
 * 	args		: pointer to a NULL terminated arg array.
 | 
			
		||||
 *			  (length, if integer, and result-pointer)
 | 
			
		||||
 * 	nargs		: # of arguments in args array.
 | 
			
		||||
 *
 | 
			
		||||
 *	This code scavanged from HandleFunctionRequest() in tcop/fastpath.h
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
char *
 | 
			
		||||
PQfn(int fnid,
 | 
			
		||||
     int *result_buf,		/* can't use void, dec compiler barfs */
 | 
			
		||||
     int result_len,
 | 
			
		||||
     int result_is_int,
 | 
			
		||||
     PQArgBlock *args,
 | 
			
		||||
     int nargs)
 | 
			
		||||
{
 | 
			
		||||
    char *retval;		/* XXX - should be datum, maybe ? */
 | 
			
		||||
    char *arg[8];
 | 
			
		||||
    int  i;
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	fill args[] array
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    for (i = 0; i < nargs; i++) {
 | 
			
		||||
	if (args[i].len == VAR_LENGTH_ARG) {
 | 
			
		||||
	    arg[i] = (char*) args[i].u.ptr;
 | 
			
		||||
	} else if (args[i].len > 4)  {
 | 
			
		||||
	    elog(WARN,"arg_length of argument %d too long",i);
 | 
			
		||||
	} else {
 | 
			
		||||
	    arg[i] = (char*)args[i].u.integer;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	call the postgres function manager
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    retval = (char *)
 | 
			
		||||
	fmgr(fnid, arg[0], arg[1], arg[2], arg[3],
 | 
			
		||||
	     arg[4], arg[5], arg[6], arg[7]);
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	put the result in the buffer the user specified and
 | 
			
		||||
     *  return the proper code.
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    if (retval == (char *) NULL)	/* void retval */
 | 
			
		||||
	return "0";
 | 
			
		||||
    
 | 
			
		||||
    if (result_is_int) {
 | 
			
		||||
	*result_buf = (int) retval;
 | 
			
		||||
    } else {
 | 
			
		||||
	memmove(result_buf, retval, result_len); 
 | 
			
		||||
    }
 | 
			
		||||
    return "G";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	PQexec -  Send a query to the POSTGRES backend
 | 
			
		||||
 *
 | 
			
		||||
 * 	The return value is a string.  
 | 
			
		||||
 * 	If 0 or more tuples fetched from the backend, return "P portal-name".
 | 
			
		||||
 * 	If a query is does not return tuples, return "C query-command".
 | 
			
		||||
 * 	If there is an error: return "E error-message".
 | 
			
		||||
 *
 | 
			
		||||
 *	Note: if we get a serious error or an elog(WARN), then PQexec never
 | 
			
		||||
 *	returns because the system longjmp's back to the main loop.
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
char *
 | 
			
		||||
PQexec(char *query)
 | 
			
		||||
{
 | 
			
		||||
    PortalEntry *entry = NULL;
 | 
			
		||||
    char *result = NULL;
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	create a new portal and put it on top of the portal stack.
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    entry = (PortalEntry *) be_newportal();
 | 
			
		||||
    be_portalpush(entry);
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	pg_eval_dest will put the query results in a portal which will
 | 
			
		||||
     *  end up on the top of the portal stack.
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    pg_eval_dest(query, (char **) NULL, (Oid *) NULL, 0, Local);
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	pop the portal off the portal stack and return the
 | 
			
		||||
     *  result.  Note if result is null, we return C.
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    entry = (PortalEntry *) be_portalpop();
 | 
			
		||||
    result = entry->result;
 | 
			
		||||
    if (result == NULL) {
 | 
			
		||||
	char *PQE = "Cnull PQexec result";
 | 
			
		||||
	result = pstrdup(PQE);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (result[0] != 'P')
 | 
			
		||||
	{
 | 
			
		||||
	    /* some successful command was executed,
 | 
			
		||||
	       but it's not one where we return the portal name so
 | 
			
		||||
	       here we should be sure to clear out the portal 
 | 
			
		||||
	       (since the caller has no handle on it)
 | 
			
		||||
	       */
 | 
			
		||||
	    pbuf_close(entry->name); 
 | 
			
		||||
	    
 | 
			
		||||
	}
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------------------------------------------------------
 | 
			
		||||
 *			pqtest support
 | 
			
		||||
 * ----------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	pqtest_PQexec takes a text query and returns the number of
 | 
			
		||||
 *	tuples it returns.  Note: there is no need to PQclear()
 | 
			
		||||
 *	here - the memory will go away at end transaction.
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
pqtest_PQexec(char *q)
 | 
			
		||||
{
 | 
			
		||||
    PortalBuffer *a;
 | 
			
		||||
    char 	 *res;
 | 
			
		||||
    int 	 t;
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	execute the postgres query
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    res = PQexec(q);
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	return number of tuples in portal or 0 if command returns no tuples.
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    t = 0;
 | 
			
		||||
    switch(res[0]) {
 | 
			
		||||
    case 'P':
 | 
			
		||||
	a = PQparray(&res[1]);
 | 
			
		||||
	if (a == NULL)
 | 
			
		||||
	    elog(WARN, "pqtest_PQexec: PQparray could not find portal %s",
 | 
			
		||||
		 res);
 | 
			
		||||
	
 | 
			
		||||
	t = PQntuples(a);
 | 
			
		||||
	break;
 | 
			
		||||
    case 'C':
 | 
			
		||||
	break;
 | 
			
		||||
    default:
 | 
			
		||||
	elog(NOTICE, "pqtest_PQexec: PQexec(%s) returns %s", q, res);
 | 
			
		||||
	break;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return t;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	utilities for pqtest_PQfn()
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
char *
 | 
			
		||||
strmake(char *str, int len)
 | 
			
		||||
{
 | 
			
		||||
    char *newstr;
 | 
			
		||||
    if (str == NULL) return NULL;
 | 
			
		||||
    if (len <= 0) len = strlen(str);
 | 
			
		||||
    
 | 
			
		||||
    newstr = (char *) palloc((unsigned) len+1);
 | 
			
		||||
    (void) strncpy(newstr, str, len);
 | 
			
		||||
    newstr[len] = (char) 0;
 | 
			
		||||
    return newstr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define SKIP 0
 | 
			
		||||
#define SCAN 1
 | 
			
		||||
 | 
			
		||||
static char spacestr[] = " ";
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
strparse(char *s, char **fields, int *offsets, int maxfields)
 | 
			
		||||
{
 | 
			
		||||
    int len = strlen(s);
 | 
			
		||||
    char *cp = s, *end = cp + len, *ep;
 | 
			
		||||
    int parsed = 0;
 | 
			
		||||
    int mode = SKIP, i = 0;
 | 
			
		||||
    
 | 
			
		||||
    if (*(end - 1) == '\n') end--;
 | 
			
		||||
    
 | 
			
		||||
    for (i=0; i<maxfields; i++)
 | 
			
		||||
	fields[i] = spacestr;
 | 
			
		||||
    
 | 
			
		||||
    i = 0;
 | 
			
		||||
    while (!parsed) {
 | 
			
		||||
	if (mode == SKIP) {
 | 
			
		||||
	    
 | 
			
		||||
	    while ((cp < end) &&
 | 
			
		||||
		   (*cp == ' ' || *cp == '\t'))
 | 
			
		||||
		cp++;
 | 
			
		||||
	    if (cp < end) mode = SCAN;
 | 
			
		||||
	    else parsed = 1;
 | 
			
		||||
	    
 | 
			
		||||
	} else {
 | 
			
		||||
	    
 | 
			
		||||
	    ep = cp;
 | 
			
		||||
	    while ((ep < end) && (*ep != ' ' && *ep != '\t'))
 | 
			
		||||
		ep++;
 | 
			
		||||
	    
 | 
			
		||||
	    if (ep < end) mode = SKIP;
 | 
			
		||||
	    else parsed = 1;
 | 
			
		||||
	    
 | 
			
		||||
	    fields[i] = strmake(cp, ep - cp);
 | 
			
		||||
	    if (offsets != NULL)
 | 
			
		||||
		offsets[i] = cp - s;
 | 
			
		||||
	    
 | 
			
		||||
	    i++;
 | 
			
		||||
	    cp = ep;
 | 
			
		||||
	    if (i > maxfields)
 | 
			
		||||
		parsed = 1;
 | 
			
		||||
	    
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	pqtest_PQfn converts it's string into a PQArgBlock and
 | 
			
		||||
 *	calls the specified function, which is assumed to return
 | 
			
		||||
 *	an integer value.
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
pqtest_PQfn(char *q)
 | 
			
		||||
{
 | 
			
		||||
    int k, j, i, v, f, offsets;
 | 
			
		||||
    char *fields[8];
 | 
			
		||||
    PQArgBlock pqargs[7];
 | 
			
		||||
    int res;
 | 
			
		||||
    char *pqres;
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	parse q into fields
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    i = strparse(q, fields, &offsets, 8);
 | 
			
		||||
    printf("pqtest_PQfn: strparse returns %d fields\n", i); /* debug */
 | 
			
		||||
    if (i == 0)
 | 
			
		||||
	return -1;
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	get the function id
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    f = atoi(fields[0]);
 | 
			
		||||
    printf("pqtest_PQfn: func is %d\n", f); /* debug */
 | 
			
		||||
    if (f == 0)
 | 
			
		||||
	return -1;
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	build a PQArgBlock
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    for (j=1; j<i && j<8; j++) {
 | 
			
		||||
	k = j-1;
 | 
			
		||||
	v = atoi(fields[j]);
 | 
			
		||||
	if (v != 0 || (v == 0 && fields[j][0] == '0')) {
 | 
			
		||||
	    pqargs[k].len = 4;
 | 
			
		||||
	    pqargs[k].u.integer = v;
 | 
			
		||||
	    printf("pqtest_PQfn: arg %d is int %d\n", k, v); /* debug */
 | 
			
		||||
	} else {
 | 
			
		||||
	    pqargs[k].len = VAR_LENGTH_ARG;
 | 
			
		||||
	    pqargs[k].u.ptr = (int *) textin(fields[j]);
 | 
			
		||||
	    printf("pqtest_PQfn: arg %d is text %s\n", k, fields[j]); /*debug*/
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	call PQfn
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    pqres = PQfn(f, &res, 4, 1, pqargs, i-1);
 | 
			
		||||
    printf("pqtest_PQfn: pqres is %s\n", pqres); /* debug */
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	free memory used
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    for (j=0; j<i; j++) {
 | 
			
		||||
	pfree(fields[j]);
 | 
			
		||||
	if (pqargs[j].len == VAR_LENGTH_ARG)
 | 
			
		||||
	    pfree(pqargs[j].u.ptr);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	return result
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    printf("pqtest_PQfn: res is %d\n", res); /* debugg */
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	pqtest looks at the first character of it's test argument
 | 
			
		||||
 *	and decides which of pqtest_PQexec or pqtest_PQfn to call.
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
int32
 | 
			
		||||
pqtest(struct varlena *vlena)
 | 
			
		||||
{
 | 
			
		||||
    char 	 *q;
 | 
			
		||||
    
 | 
			
		||||
    /* ----------------
 | 
			
		||||
     *	get the query
 | 
			
		||||
     * ----------------
 | 
			
		||||
     */
 | 
			
		||||
    q = textout(vlena);
 | 
			
		||||
    if (q == NULL)
 | 
			
		||||
	return -1;
 | 
			
		||||
    
 | 
			
		||||
    switch(q[0]) {
 | 
			
		||||
    case '%':
 | 
			
		||||
	return pqtest_PQfn(&q[1]);
 | 
			
		||||
	break;
 | 
			
		||||
    default:
 | 
			
		||||
	return pqtest_PQexec(q);
 | 
			
		||||
	break;
 | 
			
		||||
    }
 | 
			
		||||
    return(0);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								src/backend/libpq/libpq-be.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/backend/libpq/libpq-be.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * libpq-be.h--
 | 
			
		||||
 *    This file contains definitions for structures and
 | 
			
		||||
 *    externs for functions used by the POSTGRES backend.
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: libpq-be.h,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
#ifndef LIBPQ_BE_H
 | 
			
		||||
#define LIBPQ_BE_H
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	include stuff common to fe and be
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
#include "libpq/libpq.h"
 | 
			
		||||
#include "access/htup.h"
 | 
			
		||||
 | 
			
		||||
#include "access/tupdesc.h"
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	declarations for backend libpq support routines
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* in be-dumpdata.c */
 | 
			
		||||
extern void be_portalinit(void);
 | 
			
		||||
extern void be_portalpush(PortalEntry *entry);
 | 
			
		||||
extern PortalEntry *be_portalpop(void);
 | 
			
		||||
extern PortalEntry *be_currentportal();
 | 
			
		||||
extern PortalEntry *be_newportal(void);
 | 
			
		||||
extern void be_typeinit(PortalEntry *entry, TupleDesc attrs,
 | 
			
		||||
			int natts);
 | 
			
		||||
extern void be_printtup(HeapTuple tuple, TupleDesc typeinfo);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* in be-pqexec.c */
 | 
			
		||||
extern char *PQfn(int fnid, int *result_buf, int result_len, int result_is_int, 
 | 
			
		||||
		  PQArgBlock *args, int nargs);
 | 
			
		||||
extern char *PQexec(char *query);
 | 
			
		||||
extern int pqtest_PQexec(char *q);
 | 
			
		||||
extern char *strmake(char *str, int len);
 | 
			
		||||
extern int pqtest_PQfn(char *q);
 | 
			
		||||
extern int32 pqtest(struct varlena *vlena);
 | 
			
		||||
 | 
			
		||||
#endif /* LIBPQ_BE_H */
 | 
			
		||||
							
								
								
									
										119
									
								
								src/backend/libpq/libpq-fs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								src/backend/libpq/libpq-fs.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * libpq-fs.h--
 | 
			
		||||
 *    definitions for using Inversion file system routines
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: libpq-fs.h,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
#ifndef LIBPQ_FS_H
 | 
			
		||||
#define LIBPQ_FS_H
 | 
			
		||||
 | 
			
		||||
#include "lib/dllist.h"
 | 
			
		||||
#include <sys/file.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
 | 
			
		||||
#include <fcntl.h>		/* for O_ on some */
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>		/* for SEEK_ on most */
 | 
			
		||||
#endif /* WIN32 */
 | 
			
		||||
#ifndef SEEK_SET
 | 
			
		||||
#include <stdio.h>		/* for SEEK_ on others */
 | 
			
		||||
#endif /* SEEK_SET */
 | 
			
		||||
 | 
			
		||||
/* UNIX compatibility junk.  This should be in all systems' include files,
 | 
			
		||||
   but this is not always the case. */
 | 
			
		||||
 | 
			
		||||
#ifndef MAXNAMLEN
 | 
			
		||||
#define MAXNAMLEN 255
 | 
			
		||||
#endif /* MAXNAMLEN */
 | 
			
		||||
 | 
			
		||||
struct pgdirent {
 | 
			
		||||
	unsigned long d_ino;
 | 
			
		||||
	unsigned short d_namlen;
 | 
			
		||||
	char d_name[MAXNAMLEN+1];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * SysV struct dirent doesn't have d_namlen.
 | 
			
		||||
 * This counts on d_name being last, which is moderately safe (ha) since 
 | 
			
		||||
 * it's the variable-length part of the structure.
 | 
			
		||||
 */
 | 
			
		||||
#ifdef SYSV_DIRENT
 | 
			
		||||
#define	D_NAMLEN(dp) \
 | 
			
		||||
	((dp)->d_reclen - offsetof(struct dirent, d_name[0]))
 | 
			
		||||
#else /* SYSV_DIRENT */
 | 
			
		||||
#define	D_NAMLEN(dp) \
 | 
			
		||||
	((dp)->d_namlen)
 | 
			
		||||
#endif /* SYSV_DIRENT */
 | 
			
		||||
 | 
			
		||||
/* for stat(2) */
 | 
			
		||||
#ifndef S_IRUSR
 | 
			
		||||
/* file modes */
 | 
			
		||||
 | 
			
		||||
#define S_IRWXU 00700           /* read, write, execute: owner */
 | 
			
		||||
#define S_IRUSR 00400           /*  read permission: owner */
 | 
			
		||||
#define S_IWUSR 00200           /*  write permission: owner */
 | 
			
		||||
#define S_IXUSR 00100           /*  execute permission: owner */
 | 
			
		||||
 | 
			
		||||
#define S_IRWXG 00070           /* read, write, execute: group */
 | 
			
		||||
#define S_IRGRP 00040           /*  read permission: group */
 | 
			
		||||
#define S_IWGRP 00020           /*  write permission: group */
 | 
			
		||||
#define S_IXGRP 00010           /*  execute permission: group */
 | 
			
		||||
 | 
			
		||||
#define S_IRWXO 00007           /* read, write, execute: other */
 | 
			
		||||
#define S_IROTH 00004           /*  read permission: other */
 | 
			
		||||
#define S_IWOTH 00002           /*  write permission: other */
 | 
			
		||||
#define S_IXOTH 00001           /*  execute permission: other */
 | 
			
		||||
 | 
			
		||||
#define _S_IFMT  0170000        /* type of file; sync with S_IFMT */
 | 
			
		||||
#define _S_IFBLK 0060000        /* block special; sync with S_IFBLK */
 | 
			
		||||
#define _S_IFCHR 0020000        /* character special sync with S_IFCHR */
 | 
			
		||||
#define _S_IFDIR 0040000        /* directory; sync with S_IFDIR */
 | 
			
		||||
#define _S_IFIFO 0010000        /* FIFO - named pipe; sync with S_IFIFO */
 | 
			
		||||
#define _S_IFREG 0100000        /* regular; sync with S_IFREG */
 | 
			
		||||
 | 
			
		||||
#define S_IFDIR _S_IFDIR
 | 
			
		||||
#define S_IFREG _S_IFREG
 | 
			
		||||
 | 
			
		||||
#define S_ISDIR( mode )         (((mode) & _S_IFMT) == _S_IFDIR)
 | 
			
		||||
 | 
			
		||||
#endif /* S_IRUSR */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Inversion doesn't have links.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef S_ISLNK
 | 
			
		||||
#define S_ISLNK(x) 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  Flags for inversion file system large objects.  Normally, creat()
 | 
			
		||||
 *  takes mode arguments, but we don't use them in inversion, since
 | 
			
		||||
 *  you get postgres protections.  Instead, we use the low sixteen bits
 | 
			
		||||
 *  of the integer mode argument to store the number of the storage
 | 
			
		||||
 *  manager to be used, and the high sixteen bits for flags.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define INV_SMGRMASK	0x0000ffff
 | 
			
		||||
#define	INV_ARCHIVE	0x00010000
 | 
			
		||||
#define	INV_WRITE	0x00020000
 | 
			
		||||
#define	INV_READ	0x00040000
 | 
			
		||||
 | 
			
		||||
/* Error values for p_errno */
 | 
			
		||||
#define PEPERM           1               /* Not owner */
 | 
			
		||||
#define PENOENT          2               /* No such file or directory */
 | 
			
		||||
#define PEACCES          13              /* Permission denied */
 | 
			
		||||
#define PEEXIST          17              /* File exists */
 | 
			
		||||
#define PENOTDIR         20              /* Not a directory*/
 | 
			
		||||
#define PEISDIR          21              /* Is a directory */
 | 
			
		||||
#define PEINVAL          22              /* Invalid argument */
 | 
			
		||||
#define PENAMETOOLONG    63              /* File name too long */
 | 
			
		||||
#define PENOTEMPTY       66              /* Directory not empty */
 | 
			
		||||
#define PEPGIO           99              /* postgres backend had problems */
 | 
			
		||||
 | 
			
		||||
#endif	/* LIBPQ_FS_H */
 | 
			
		||||
							
								
								
									
										261
									
								
								src/backend/libpq/libpq.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								src/backend/libpq/libpq.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,261 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * libpq.h--
 | 
			
		||||
 *    POSTGRES LIBPQ buffer structure definitions.
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: libpq.h,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 * NOTES
 | 
			
		||||
 *    This file contains definitions for structures and
 | 
			
		||||
 *    externs for functions used by both frontend applications
 | 
			
		||||
 *    and the POSTGRES backend.  See the files libpq-fe.h and
 | 
			
		||||
 *    libpq-be.h for frontend/backend specific information
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
#ifndef LIBPQ_H
 | 
			
		||||
#define LIBPQ_H
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <winsock.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#endif /* WIN32 */
 | 
			
		||||
 | 
			
		||||
#include "lib/dllist.h"
 | 
			
		||||
#include "utils/exc.h"
 | 
			
		||||
#include "postgres.h"
 | 
			
		||||
 | 
			
		||||
#include "libpq/pqcomm.h"
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 * PQArgBlock --
 | 
			
		||||
 *	Information (pointer to array of this structure) required
 | 
			
		||||
 *	for the PQfn() call.
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int len;
 | 
			
		||||
    int isint;
 | 
			
		||||
    union {
 | 
			
		||||
        int *ptr;	/* can't use void (dec compiler barfs)	*/
 | 
			
		||||
	int integer;
 | 
			
		||||
    } u;
 | 
			
		||||
} PQArgBlock;
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 * TypeBlock --
 | 
			
		||||
 * 	Information about an attribute.
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
#define NameLength 16
 | 
			
		||||
 | 
			
		||||
typedef struct TypeBlock {
 | 
			
		||||
    char name[NAMEDATALEN];	/* name of the attribute */
 | 
			
		||||
    int adtid;			/* adtid of the type */
 | 
			
		||||
    int adtsize;		/* adtsize of the type */
 | 
			
		||||
} TypeBlock;
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 * TupleBlock --
 | 
			
		||||
 *	Data of a tuple.
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
#define TupleBlockSize 100
 | 
			
		||||
 | 
			
		||||
typedef struct TupleBlock {
 | 
			
		||||
    char **values[TupleBlockSize];	/* an array of tuples */
 | 
			
		||||
    int *lengths[TupleBlockSize];       /* an array of length vec. foreach
 | 
			
		||||
					   tuple */
 | 
			
		||||
    struct TupleBlock *next;		/* next tuple block */
 | 
			
		||||
    int    tuple_index;			/* current tuple index */
 | 
			
		||||
} TupleBlock;
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 * GroupBuffer --
 | 
			
		||||
 * 	A group of tuples with the same attributes.
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
typedef struct GroupBuffer {
 | 
			
		||||
    int no_tuples;		/* number of tuples in this group */
 | 
			
		||||
    int no_fields;		/* number of attributes */
 | 
			
		||||
    TypeBlock *types;  		/* types of the attributes */
 | 
			
		||||
    TupleBlock *tuples;		/* tuples in this group */
 | 
			
		||||
    struct GroupBuffer *next;	/* next group */
 | 
			
		||||
} GroupBuffer;
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 * PortalBuffer --
 | 
			
		||||
 *	Data structure of a portal buffer.  
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
typedef struct PortalBuffer {
 | 
			
		||||
    int rule_p;			/* 1 if this is an asynchronized portal. */
 | 
			
		||||
    int no_tuples;		/* number of tuples in this portal buffer */
 | 
			
		||||
    int no_groups;		/* number of tuple groups */
 | 
			
		||||
    GroupBuffer *groups;	/* linked list of tuple groups */
 | 
			
		||||
} PortalBuffer;
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 * PortalEntry --
 | 
			
		||||
 *	an entry in the global portal table
 | 
			
		||||
 *
 | 
			
		||||
 * Note: the portalcxt is only meaningful for PQcalls made from
 | 
			
		||||
 *       within a postgres backend.  frontend apps should ignore it.
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
#define PortalNameLength 32
 | 
			
		||||
 | 
			
		||||
typedef struct PortalEntry {
 | 
			
		||||
    char 	  name[PortalNameLength]; /* name of this portal */
 | 
			
		||||
    PortalBuffer  *portal;	          /* tuples contained in this portal */
 | 
			
		||||
    Pointer	  portalcxt;	          /* memory context (for backend) */
 | 
			
		||||
    Pointer	  result;	          /* result for PQexec */
 | 
			
		||||
} PortalEntry;
 | 
			
		||||
 | 
			
		||||
#define PORTALS_INITIAL_SIZE 32
 | 
			
		||||
#define PORTALS_GROW_BY      32
 | 
			
		||||
 | 
			
		||||
/* in portalbuf.c */
 | 
			
		||||
extern PortalEntry** portals;		
 | 
			
		||||
extern size_t portals_array_size;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  Asynchronous notification
 | 
			
		||||
 */
 | 
			
		||||
typedef struct PQNotifyList {
 | 
			
		||||
    char relname[NAMEDATALEN];	/* name of relation containing data */
 | 
			
		||||
    int be_pid;			/* process id of backend */
 | 
			
		||||
    int valid;			/* has this already been handled by user. */
 | 
			
		||||
/*    SLNode Node; */
 | 
			
		||||
} PQNotifyList;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Exceptions.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define libpq_raise(X, Y) ExcRaise((Exception *)(X), (ExcDetail) (Y),\
 | 
			
		||||
				   (ExcData)0, (ExcMessage) 0)
 | 
			
		||||
 | 
			
		||||
/* in portal.c */
 | 
			
		||||
extern Exception MemoryError, PortalError, PostquelError, ProtocolError;
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * POSTGRES backend dependent Constants. 
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* ERROR_MSG_LENGTH should really be the same as ELOG_MAXLEN in utils/elog.h*/
 | 
			
		||||
#define ERROR_MSG_LENGTH 4096
 | 
			
		||||
#define COMMAND_LENGTH 20
 | 
			
		||||
#define REMARK_LENGTH 80
 | 
			
		||||
 | 
			
		||||
extern char PQerrormsg[ERROR_MSG_LENGTH];	/* in portal.c */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * External functions.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * prototypes for functions in portal.c 
 | 
			
		||||
 */
 | 
			
		||||
extern void pqdebug(char *target, char *msg);
 | 
			
		||||
extern void pqdebug2(char *target, char *msg1, char *msg2);
 | 
			
		||||
extern void PQtrace(void);
 | 
			
		||||
extern void PQuntrace(void);
 | 
			
		||||
extern int PQnportals(int rule_p);
 | 
			
		||||
extern void PQpnames(char **pnames, int rule_p);
 | 
			
		||||
extern PortalBuffer *PQparray(char *pname);
 | 
			
		||||
extern int PQrulep(PortalBuffer *portal);
 | 
			
		||||
extern int PQntuples(PortalBuffer *portal); 
 | 
			
		||||
extern int PQninstances(PortalBuffer *portal);
 | 
			
		||||
extern int PQngroups(PortalBuffer *portal);
 | 
			
		||||
extern int PQntuplesGroup(PortalBuffer *portal, int group_index);
 | 
			
		||||
extern int PQninstancesGroup(PortalBuffer *portal, int group_index);
 | 
			
		||||
extern int PQnfieldsGroup(PortalBuffer *portal, int group_index);
 | 
			
		||||
extern int PQfnumberGroup(PortalBuffer *portal, int group_index, char *field_name);
 | 
			
		||||
extern char *PQfnameGroup(PortalBuffer *portal, int group_index, int field_number);
 | 
			
		||||
extern int PQftypeGroup(PortalBuffer *portal, int group_index,
 | 
			
		||||
			int field_number);
 | 
			
		||||
extern int PQfsizeGroup(PortalBuffer *portal, int group_index,
 | 
			
		||||
			int field_number);
 | 
			
		||||
extern GroupBuffer *PQgroup(PortalBuffer *portal, int tuple_index);
 | 
			
		||||
extern int PQgetgroup(PortalBuffer *portal, int tuple_index);
 | 
			
		||||
extern int PQnfields(PortalBuffer *portal, int tuple_index);
 | 
			
		||||
extern int PQfnumber(PortalBuffer *portal, int tuple_index, char *field_name);
 | 
			
		||||
 extern char *PQfname(PortalBuffer *portal, int tuple_index, int field_number); 
 | 
			
		||||
extern int PQftype(PortalBuffer *portal, int tuple_index, int field_number);
 | 
			
		||||
extern int PQfsize(PortalBuffer *portal, int tuple_index, int field_number);
 | 
			
		||||
extern int PQsametype(PortalBuffer *portal, int tuple_index1, int tuple_index2);
 | 
			
		||||
extern char *PQgetvalue(PortalBuffer *portal, int tuple_index, int field_number);
 | 
			
		||||
extern char *PQgetAttr(PortalBuffer *portal, int tuple_index, int field_number);
 | 
			
		||||
extern int PQgetlength(PortalBuffer *portal, int tuple_index, int field_number);
 | 
			
		||||
extern void PQclear(char *pname);
 | 
			
		||||
extern void PQcleanNotify(void);
 | 
			
		||||
extern void PQnotifies_init(void);
 | 
			
		||||
extern PQNotifyList *PQnotifies(void);
 | 
			
		||||
extern void PQremoveNotify(PQNotifyList *nPtr);
 | 
			
		||||
extern void PQappendNotify(char *relname, int pid);
 | 
			
		||||
/* 
 | 
			
		||||
 * prototypes for functions in portalbuf.c 
 | 
			
		||||
 */
 | 
			
		||||
extern caddr_t pbuf_alloc(size_t size);
 | 
			
		||||
extern void pbuf_free(caddr_t pointer);
 | 
			
		||||
extern PortalBuffer *pbuf_addPortal(void);
 | 
			
		||||
extern GroupBuffer *pbuf_addGroup(PortalBuffer *portal);
 | 
			
		||||
extern TypeBlock *pbuf_addTypes(int n);
 | 
			
		||||
extern TupleBlock *pbuf_addTuples(void);
 | 
			
		||||
extern char **pbuf_addTuple(int n);
 | 
			
		||||
extern int *pbuf_addTupleValueLengths(int n);
 | 
			
		||||
extern char *pbuf_addValues(int n);
 | 
			
		||||
extern PortalEntry *pbuf_addEntry(void);
 | 
			
		||||
extern void pbuf_freeEntry(int i);
 | 
			
		||||
extern void pbuf_freeTypes(TypeBlock *types);
 | 
			
		||||
extern void pbuf_freeTuples(TupleBlock *tuples, int no_tuples, int no_fields);
 | 
			
		||||
extern void pbuf_freeGroup(GroupBuffer *group);
 | 
			
		||||
extern void pbuf_freePortal(PortalBuffer *portal);
 | 
			
		||||
extern int pbuf_getIndex(char *pname);
 | 
			
		||||
extern void pbuf_setportalinfo(PortalEntry *entry, char *pname);
 | 
			
		||||
extern PortalEntry *pbuf_setup(char *pname);
 | 
			
		||||
extern void pbuf_close(char *pname);
 | 
			
		||||
extern GroupBuffer *pbuf_findGroup(PortalBuffer *portal, int group_index);
 | 
			
		||||
extern int pbuf_findFnumber(GroupBuffer *group, char *field_name);
 | 
			
		||||
extern void pbuf_checkFnumber(GroupBuffer *group, int field_number);
 | 
			
		||||
extern char *pbuf_findFname(GroupBuffer *group, int field_number);
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * prototypes for functions in pqcomm.c 
 | 
			
		||||
 */
 | 
			
		||||
extern void pq_init(int fd);
 | 
			
		||||
extern void pq_gettty(char *tp);
 | 
			
		||||
extern int pq_getport(void);
 | 
			
		||||
extern void pq_close(void);
 | 
			
		||||
extern void pq_flush(void);
 | 
			
		||||
extern int pq_getstr(char *s, int maxlen);
 | 
			
		||||
extern int PQgetline(char *s, int maxlen); 
 | 
			
		||||
extern int PQputline(char *s); 
 | 
			
		||||
extern int pq_getnchar(char *s, int off, int maxlen);
 | 
			
		||||
extern int pq_getint(int b);
 | 
			
		||||
extern void pq_putstr(char *s);
 | 
			
		||||
extern void pq_putnchar(char *s, int n);
 | 
			
		||||
extern void pq_putint(int i, int b);
 | 
			
		||||
extern int pq_sendoob(char *msg, int len);
 | 
			
		||||
extern int pq_recvoob(char *msgPtr, int *lenPtr);
 | 
			
		||||
extern int pq_getinaddr(struct sockaddr_in *sin, char *host, int port);
 | 
			
		||||
extern int pq_getinserv(struct sockaddr_in *sin, char *host, char *serv);
 | 
			
		||||
extern int pq_connect(char *dbname, char *user, char *args, char *hostName, 
 | 
			
		||||
		      char *debugTty, char *execFile, short portName);
 | 
			
		||||
extern int StreamOpen(char *hostName, short portName, Port *port);
 | 
			
		||||
extern void pq_regoob(void (*fptr)());
 | 
			
		||||
extern void pq_unregoob(void);
 | 
			
		||||
extern void pq_async_notify(void);
 | 
			
		||||
extern int StreamServerPort(char *hostName, short portName, int *fdP);
 | 
			
		||||
extern int StreamConnection(int server_fd, Port *port);
 | 
			
		||||
extern void StreamClose(int sock);
 | 
			
		||||
 | 
			
		||||
#endif	/* LIBPQ_H */
 | 
			
		||||
							
								
								
									
										783
									
								
								src/backend/libpq/portal.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										783
									
								
								src/backend/libpq/portal.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,783 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * portal.c--
 | 
			
		||||
 *    generalized portal support routines
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *    $Header: /cvsroot/pgsql/src/backend/libpq/Attic/portal.c,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
/*
 | 
			
		||||
 *   UTILITY ROUTINES
 | 
			
		||||
 *	pqdebug		- send a string to the debugging output port
 | 
			
		||||
 *	pqdebug2	- send two strings to stdout
 | 
			
		||||
 *	PQtrace		- turn on pqdebug() tracing
 | 
			
		||||
 *	PQuntrace	- turn off pqdebug() tracing
 | 
			
		||||
 *
 | 
			
		||||
 *   INTERFACE ROUTINES
 | 
			
		||||
 *	PQnportals 	- Return the number of open portals. 
 | 
			
		||||
 *	PQpnames 	- Return all the portal names
 | 
			
		||||
 *	PQparray 	- Return the portal buffer given a portal name
 | 
			
		||||
 *	PQrulep 	- Return 1 if an asynchronous portal
 | 
			
		||||
 *	PQntuples 	- Return the number of tuples in a portal buffer
 | 
			
		||||
 *	PQninstances	-   same as PQntuples using object terminology
 | 
			
		||||
 *	PQngroups 	- Return the number of tuple groups in a portal buffer
 | 
			
		||||
 *	PQntuplesGroup 	- Return the number of tuples in a tuple group
 | 
			
		||||
 *	PQninstancesGroup  - same as PQntuplesGroup using object terminology
 | 
			
		||||
 *	PQnfieldsGroup 	- Return the number of fields in a tuple group
 | 
			
		||||
 *	PQfnumberGroup 	- Return field number given (group index, field name)
 | 
			
		||||
 *	PQftypeGroup    - Return field type given (group index, field index)
 | 
			
		||||
 *	PQfsizeGroup    - Return field size given (group index, field index)
 | 
			
		||||
 *	PQfnameGroup 	- Return field name given (group index, field index)
 | 
			
		||||
 *	PQgroup 	- Return the tuple group that a particular tuple is in
 | 
			
		||||
 *	PQgetgroup 	- Return the index of the group that a tuple is in
 | 
			
		||||
 *	PQnfields 	- Return the number of fields in a tuple
 | 
			
		||||
 *	PQfnumber 	- Return the field index of a field name in a tuple
 | 
			
		||||
 *	PQfname 	- Return the name of a field
 | 
			
		||||
 *	PQftype         - Return the type of a field
 | 
			
		||||
 *	PQfsize         - Return the size of a field
 | 
			
		||||
 *	PQftype 	- Return the type of a field
 | 
			
		||||
 *	PQsametype 	- Return 1 if the two tuples have the same type
 | 
			
		||||
 *	PQgetvalue 	- Return an attribute (field) value
 | 
			
		||||
 *	PQgetlength 	- Return an attribute (field) length
 | 
			
		||||
 *	PQclear		- free storage claimed by named portal
 | 
			
		||||
 *      PQnotifies      - Return a list of relations on which notification 
 | 
			
		||||
 *                        has occurred.
 | 
			
		||||
 *      PQremoveNotify  - Remove this notification from the list.
 | 
			
		||||
 *
 | 
			
		||||
 *   NOTES
 | 
			
		||||
 *	These functions may be used by both frontend routines which
 | 
			
		||||
 *	communicate with a backend or by user-defined functions which
 | 
			
		||||
 *	are compiled or dynamically loaded into a backend.
 | 
			
		||||
 *
 | 
			
		||||
 *	the portals[] array should be organized as a hash table for
 | 
			
		||||
 *	quick portal-by-name lookup.
 | 
			
		||||
 *
 | 
			
		||||
 *	Do not confuse "PortalEntry" (or "PortalBuffer") with "Portal"
 | 
			
		||||
 *	see utils/mmgr/portalmem.c for why. -cim 2/22/91
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#include <stdio.h>	/* for sprintf() */
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "c.h"
 | 
			
		||||
#include "lib/dllist.h"
 | 
			
		||||
#include "libpq/libpq.h"	/* where the declarations go */
 | 
			
		||||
#include "utils/exc.h"
 | 
			
		||||
#include "utils/palloc.h"
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	exceptions
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
Exception MemoryError = {"Memory Allocation Error"};
 | 
			
		||||
Exception PortalError = {"Invalid arguments to portal functions"};
 | 
			
		||||
Exception PostquelError = {"Sql Error"};
 | 
			
		||||
Exception ProtocolError = {"Protocol Error"};
 | 
			
		||||
char PQerrormsg[ERROR_MSG_LENGTH];
 | 
			
		||||
 | 
			
		||||
int PQtracep = 0;		/* 1 to print out debugging messages */
 | 
			
		||||
FILE *debug_port = (FILE *) NULL;
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
in_range(char *msg, int value, int min, int max)
 | 
			
		||||
{
 | 
			
		||||
    if (value < min || value >= max) {
 | 
			
		||||
	(void) sprintf(PQerrormsg, "FATAL: %s, %d is not in range [%d,%d)\n",
 | 
			
		||||
		       msg, value, min, max);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	return(0);
 | 
			
		||||
    }
 | 
			
		||||
    return(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
valid_pointer(char *msg, void *ptr)
 | 
			
		||||
{
 | 
			
		||||
    if (!ptr) {
 | 
			
		||||
	(void) sprintf(PQerrormsg, "FATAL: %s\n", msg);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	return(0);
 | 
			
		||||
    }
 | 
			
		||||
    return(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------------------------------------------------------
 | 
			
		||||
 *			PQ utility routines
 | 
			
		||||
 * ----------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pqdebug(char *target, char *msg)
 | 
			
		||||
{
 | 
			
		||||
    if (!target)
 | 
			
		||||
	return;
 | 
			
		||||
    
 | 
			
		||||
    if (PQtracep) {
 | 
			
		||||
	/*
 | 
			
		||||
	 * if nothing else was suggested default to stdout
 | 
			
		||||
	 */
 | 
			
		||||
	if (!debug_port)
 | 
			
		||||
	    debug_port = stdout;
 | 
			
		||||
	fprintf(debug_port, target, msg);
 | 
			
		||||
	fprintf(debug_port, "\n");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
pqdebug2(char *target, char *msg1, char *msg2)
 | 
			
		||||
{
 | 
			
		||||
    if (!target)
 | 
			
		||||
	return;
 | 
			
		||||
    
 | 
			
		||||
    if (PQtracep) {
 | 
			
		||||
	/*
 | 
			
		||||
	 * if nothing else was suggested default to stdout
 | 
			
		||||
	 */
 | 
			
		||||
	if (!debug_port)
 | 
			
		||||
	    debug_port = stdout;
 | 
			
		||||
	fprintf(debug_port, target, msg1, msg2);
 | 
			
		||||
	fprintf(debug_port, "\n");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQtrace() / PQuntrace()
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
PQtrace()
 | 
			
		||||
{
 | 
			
		||||
    PQtracep = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
PQuntrace()
 | 
			
		||||
{
 | 
			
		||||
    PQtracep = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------------------------------------------------------
 | 
			
		||||
 *		    PQ portal interface routines
 | 
			
		||||
 * ----------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQnportals - Return the number of open portals. 
 | 
			
		||||
 * 	If rule_p, only return asynchronous portals. 
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQnportals(int rule_p)
 | 
			
		||||
{
 | 
			
		||||
    int i, n = 0;
 | 
			
		||||
    
 | 
			
		||||
    for (i = 0; i < portals_array_size; ++i) {
 | 
			
		||||
	if (portals[i] && portals[i]->portal) {
 | 
			
		||||
	    if (!rule_p || portals[i]->portal->rule_p) {
 | 
			
		||||
		++n;
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    return(n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQpnames - Return all the portal names
 | 
			
		||||
 * 	If rule_p, only return asynchronous portals. 
 | 
			
		||||
 *
 | 
			
		||||
 *         the caller must have allocated sufficient memory for char** pnames
 | 
			
		||||
 *	   (an array of PQnportals strings of length PortalNameLength).
 | 
			
		||||
 *
 | 
			
		||||
 *	   notice that this assumes that the user is calling PQnportals and
 | 
			
		||||
 *	   PQpnames with the same rule_p argument, and with no intervening
 | 
			
		||||
 *	   portal closures.  if not, you can get in heap big trouble..
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
PQpnames(char **pnames, int rule_p)
 | 
			
		||||
{
 | 
			
		||||
    int i, cur_pname = 0;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQpnames: invalid name buffer", pnames))
 | 
			
		||||
	return;
 | 
			
		||||
    
 | 
			
		||||
    for (i = 0; i < portals_array_size; ++i) {
 | 
			
		||||
	if (portals[i] && portals[i]->portal) {
 | 
			
		||||
	    if (!rule_p || portals[i]->portal->rule_p) {
 | 
			
		||||
		(void) strncpy(pnames[cur_pname], portals[i]->name, PortalNameLength);
 | 
			
		||||
		++cur_pname;
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQparray - Return the portal buffer given a portal name
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
PortalBuffer *
 | 
			
		||||
PQparray(char *pname)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQparray: invalid name buffer", pname))
 | 
			
		||||
	return NULL;
 | 
			
		||||
    
 | 
			
		||||
    if ((i = pbuf_getIndex(pname)) < 0)
 | 
			
		||||
	return((PortalBuffer *) NULL);
 | 
			
		||||
    return(portals[i]->portal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQrulep - Return 1 if an asynchronous portal
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQrulep(PortalBuffer *portal)
 | 
			
		||||
{
 | 
			
		||||
    if (!valid_pointer("PQrulep: invalid portal pointer", portal))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    
 | 
			
		||||
    return(portal->rule_p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQntuples - Return the number of tuples in a portal buffer
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQntuples(PortalBuffer *portal)
 | 
			
		||||
{
 | 
			
		||||
    if (!valid_pointer("PQntuples: invalid portal pointer", portal))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    
 | 
			
		||||
    return(portal->no_tuples);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
PQninstances(PortalBuffer *portal)
 | 
			
		||||
{
 | 
			
		||||
    return(PQntuples(portal));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQngroups - Return the number of tuple groups in a portal buffer
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQngroups(PortalBuffer *portal)
 | 
			
		||||
{
 | 
			
		||||
    if (!valid_pointer("PQngroups: invalid portal pointer", portal))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    
 | 
			
		||||
    return(portal->no_groups);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQntuplesGroup - Return the number of tuples in a tuple group
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQntuplesGroup(PortalBuffer *portal, int group_index)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQntuplesGroup: invalid portal pointer", portal) ||
 | 
			
		||||
	!in_range("PQntuplesGroup: group index",
 | 
			
		||||
		  group_index, 0, portal->no_groups))
 | 
			
		||||
	return(-1);
 | 
			
		||||
 | 
			
		||||
    gbp = pbuf_findGroup(portal, group_index);
 | 
			
		||||
    if (gbp)
 | 
			
		||||
	return(gbp->no_tuples);
 | 
			
		||||
    return(-1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
PQninstancesGroup(PortalBuffer *portal, int group_index)
 | 
			
		||||
{
 | 
			
		||||
    return(PQntuplesGroup(portal, group_index));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQnfieldsGroup - Return the number of fields in a tuple group
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQnfieldsGroup(PortalBuffer *portal, int group_index)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQnfieldsGroup: invalid portal pointer", portal) ||
 | 
			
		||||
	!in_range("PQnfieldsGroup: group index",
 | 
			
		||||
		  group_index, 0, portal->no_groups))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    gbp = pbuf_findGroup(portal, group_index);
 | 
			
		||||
    if (gbp)
 | 
			
		||||
	return(gbp->no_fields);
 | 
			
		||||
    return(-1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQfnumberGroup - Return the field number (index) given
 | 
			
		||||
 *			 the group index and the field name
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQfnumberGroup(PortalBuffer *portal, int group_index, char *field_name)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQfnumberGroup: invalid portal pointer", portal) ||
 | 
			
		||||
	!valid_pointer("PQfnumberGroup: invalid field name pointer",
 | 
			
		||||
		       field_name) ||
 | 
			
		||||
	!in_range("PQfnumberGroup: group index",
 | 
			
		||||
		  group_index, 0, portal->no_groups))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    gbp = pbuf_findGroup(portal, group_index);
 | 
			
		||||
    if (gbp)
 | 
			
		||||
	return(pbuf_findFnumber(gbp, field_name));
 | 
			
		||||
    return(-1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQfnameGroup - Return the field (attribute) name given
 | 
			
		||||
 *			the group index and field index. 
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
char *
 | 
			
		||||
PQfnameGroup(PortalBuffer *portal, int group_index, int field_number)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQfnameGroup: invalid portal pointer", portal) ||
 | 
			
		||||
	!in_range("PQfnameGroup: group index",
 | 
			
		||||
		  group_index, 0, portal->no_groups))
 | 
			
		||||
	return((char *) NULL);
 | 
			
		||||
    
 | 
			
		||||
    if ((gbp = pbuf_findGroup(portal, group_index)) &&
 | 
			
		||||
	in_range("PQfnameGroup: field number",
 | 
			
		||||
		 field_number, 0, gbp->no_fields))
 | 
			
		||||
	return(pbuf_findFname(gbp, field_number));
 | 
			
		||||
    return((char *) NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQftypeGroup - Return the type of a field given
 | 
			
		||||
 *                      the group index and field index
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQftypeGroup(PortalBuffer *portal, int group_index, int field_number)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQftypeGroup: invalid portal pointer", portal) ||
 | 
			
		||||
	!in_range("PQftypeGroup: group index",
 | 
			
		||||
		  group_index, 0, portal->no_groups))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    
 | 
			
		||||
    if ((gbp = pbuf_findGroup(portal, group_index)) &&
 | 
			
		||||
	in_range("PQftypeGroup: field number", field_number, 0, gbp->no_fields))
 | 
			
		||||
	return(gbp->types[field_number].adtid);
 | 
			
		||||
    return(-1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQfsizeGroup - Return the size of a field given
 | 
			
		||||
 *                     the group index and field index
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQfsizeGroup(PortalBuffer *portal, int group_index, int field_number)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQfsizeGroup: invalid portal pointer", portal) ||
 | 
			
		||||
	!in_range("PQfsizeGroup: tuple index",
 | 
			
		||||
		  group_index, 0, portal->no_groups))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    
 | 
			
		||||
    if ((gbp = pbuf_findGroup(portal, group_index)) &&
 | 
			
		||||
	in_range("PQfsizeGroup: field number", field_number, 0, gbp->no_fields))
 | 
			
		||||
	return(gbp->types[field_number].adtsize);
 | 
			
		||||
    return(-1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQgroup - Return the tuple group that a particular tuple is in
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
GroupBuffer *
 | 
			
		||||
PQgroup(PortalBuffer *portal, int tuple_index)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    int tuple_count = 0;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQgroup: invalid portal pointer", portal) ||
 | 
			
		||||
	!in_range("PQgroup: tuple index",
 | 
			
		||||
		  tuple_index, 0, portal->no_tuples))
 | 
			
		||||
	return((GroupBuffer *) NULL);
 | 
			
		||||
    
 | 
			
		||||
    for (gbp = portal->groups;
 | 
			
		||||
	 gbp && tuple_index >= (tuple_count += gbp->no_tuples);
 | 
			
		||||
	 gbp = gbp->next)
 | 
			
		||||
	;
 | 
			
		||||
    if (!in_range("PQgroup: tuple not found: tuple index",
 | 
			
		||||
		  tuple_index, 0, tuple_count))
 | 
			
		||||
	return((GroupBuffer *) NULL);
 | 
			
		||||
    return(gbp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQgetgroup - Return the index of the group that a
 | 
			
		||||
 *		     particular tuple is in
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQgetgroup(PortalBuffer *portal, int tuple_index)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    int tuple_count = 0, group_count = 0;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQgetgroup: invalid portal pointer", portal) ||
 | 
			
		||||
	!in_range("PQgetgroup: tuple index",
 | 
			
		||||
		  tuple_index, 0, portal->no_tuples))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    
 | 
			
		||||
    for (gbp = portal->groups;
 | 
			
		||||
	 gbp && tuple_index >= (tuple_count += gbp->no_tuples);
 | 
			
		||||
	 gbp = gbp->next)
 | 
			
		||||
	++group_count;
 | 
			
		||||
    if (!gbp || !in_range("PQgetgroup: tuple not found: tuple index",
 | 
			
		||||
			  tuple_index, 0, tuple_count))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    return(group_count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQnfields - Return the number of fields in a tuple
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQnfields(PortalBuffer *portal, int	tuple_index)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQnfields: invalid portal pointer", portal) ||
 | 
			
		||||
	!in_range("PQnfields: tuple index",
 | 
			
		||||
		  tuple_index, 0, portal->no_tuples))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    gbp = PQgroup(portal, tuple_index);
 | 
			
		||||
    if (gbp)
 | 
			
		||||
	return(gbp->no_fields);
 | 
			
		||||
    return(-1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQfnumber - Return the field index of a given
 | 
			
		||||
 *		    field name within a tuple. 
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQfnumber(PortalBuffer *portal, int tuple_index, char *field_name)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQfnumber: invalid portal pointer", portal) ||
 | 
			
		||||
	!valid_pointer("PQfnumber: invalid field name pointer", field_name) ||
 | 
			
		||||
	!in_range("PQfnumber: tuple index",
 | 
			
		||||
		  tuple_index, 0, portal->no_tuples))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    gbp = PQgroup(portal, tuple_index);
 | 
			
		||||
    if (gbp)
 | 
			
		||||
	return(pbuf_findFnumber(gbp, field_name));
 | 
			
		||||
    return(-1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQfname - Return the name of a field
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
char *
 | 
			
		||||
PQfname(PortalBuffer *portal, int	tuple_index, int field_number)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQfname: invalid portal pointer", portal) ||
 | 
			
		||||
	!in_range("PQfname: tuple index",
 | 
			
		||||
		  tuple_index, 0, portal->no_tuples))
 | 
			
		||||
	return((char *) NULL);
 | 
			
		||||
    
 | 
			
		||||
    if ((gbp = PQgroup(portal, tuple_index)) &&
 | 
			
		||||
	in_range("PQfname: field number",
 | 
			
		||||
		 field_number, 0, gbp->no_fields))
 | 
			
		||||
	return(pbuf_findFname(gbp, field_number));
 | 
			
		||||
    return((char *) NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQftype - Return the type of a field
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQftype(PortalBuffer *portal, int tuple_index, int field_number)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQftype: invalid portal pointer", portal) ||
 | 
			
		||||
	!in_range("PQfname: tuple index",
 | 
			
		||||
		  tuple_index, 0, portal->no_tuples))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    
 | 
			
		||||
    if ((gbp = PQgroup(portal, tuple_index)) &&
 | 
			
		||||
	in_range("PQftype: field number", field_number, 0, gbp->no_fields))
 | 
			
		||||
	return(gbp->types[field_number].adtid);
 | 
			
		||||
    return(-1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQfsize - Return the size of a field
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQfsize(PortalBuffer *portal, int tuple_index, int field_number)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQfsize: invalid portal pointer", portal) ||
 | 
			
		||||
	!in_range("PQfsize: tuple index",
 | 
			
		||||
		  tuple_index, 0, portal->no_tuples))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    
 | 
			
		||||
    if ((gbp = PQgroup(portal, tuple_index)) &&
 | 
			
		||||
	in_range("PQfsize: field number", field_number, 0, gbp->no_fields))
 | 
			
		||||
	return(gbp->types[field_number].adtsize);
 | 
			
		||||
    return(-1);
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQsametype - Return 1 if the two tuples have the same type
 | 
			
		||||
 *			(in the same group)
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQsametype(PortalBuffer *portal, int tuple_index1, int tuple_index2)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp1, *gbp2;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQsametype: invalid portal pointer", portal) ||
 | 
			
		||||
	!in_range("PQsametype: tuple index 1",
 | 
			
		||||
		  tuple_index1, 0, portal->no_tuples) ||
 | 
			
		||||
	!in_range("PQsametype: tuple index 2",
 | 
			
		||||
		  tuple_index2, 0, portal->no_tuples))
 | 
			
		||||
	return(-1);
 | 
			
		||||
    
 | 
			
		||||
    gbp1 = PQgroup(portal, tuple_index1);
 | 
			
		||||
    gbp2 = PQgroup(portal, tuple_index2);
 | 
			
		||||
    if (gbp1 && gbp2)
 | 
			
		||||
	return(gbp1 == gbp2);
 | 
			
		||||
    return(-1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static TupleBlock *
 | 
			
		||||
PQGetTupleBlock(PortalBuffer *portal,
 | 
			
		||||
		int tuple_index,
 | 
			
		||||
		int *tuple_offset)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *gbp;
 | 
			
		||||
    TupleBlock  *tbp;
 | 
			
		||||
    int tuple_count = 0;
 | 
			
		||||
    
 | 
			
		||||
    if (!valid_pointer("PQGetTupleBlock: invalid portal pointer", portal) ||
 | 
			
		||||
	!valid_pointer("PQGetTupleBlock: invalid offset pointer",
 | 
			
		||||
		       tuple_offset) ||
 | 
			
		||||
	!in_range("PQGetTupleBlock: tuple index",
 | 
			
		||||
		  tuple_index, 0, portal->no_tuples))
 | 
			
		||||
	return((TupleBlock *) NULL);
 | 
			
		||||
    
 | 
			
		||||
    for (gbp = portal->groups;
 | 
			
		||||
	 gbp && tuple_index >= (tuple_count += gbp->no_tuples);
 | 
			
		||||
	 gbp = gbp->next)
 | 
			
		||||
	;
 | 
			
		||||
    if (!gbp ||
 | 
			
		||||
	!in_range("PQGetTupleBlock: tuple not found: tuple index",
 | 
			
		||||
		  tuple_index, 0, tuple_count))
 | 
			
		||||
	return((TupleBlock *) NULL);
 | 
			
		||||
    tuple_count -= gbp->no_tuples;
 | 
			
		||||
    for (tbp = gbp->tuples;
 | 
			
		||||
	 tbp && tuple_index >= (tuple_count += TupleBlockSize);
 | 
			
		||||
	 tbp = tbp->next)
 | 
			
		||||
	;
 | 
			
		||||
    if (!tbp ||
 | 
			
		||||
	!in_range("PQGetTupleBlock: tuple not found: tuple index",
 | 
			
		||||
		  tuple_index, 0, tuple_count))
 | 
			
		||||
	return((TupleBlock *) NULL);
 | 
			
		||||
    tuple_count -= TupleBlockSize;
 | 
			
		||||
    
 | 
			
		||||
    *tuple_offset = tuple_index - tuple_count;
 | 
			
		||||
    return(tbp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQgetvalue - Return an attribute (field) value
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
char *
 | 
			
		||||
PQgetvalue(PortalBuffer *portal,
 | 
			
		||||
	   int tuple_index,
 | 
			
		||||
	   int field_number)
 | 
			
		||||
{
 | 
			
		||||
    TupleBlock *tbp;
 | 
			
		||||
    int tuple_offset;
 | 
			
		||||
 | 
			
		||||
    tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
 | 
			
		||||
    if (tbp)
 | 
			
		||||
	return(tbp->values[tuple_offset][field_number]);
 | 
			
		||||
    return((char *) NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQgetAttr - Return an attribute (field) value
 | 
			
		||||
 *      this differs from PQgetvalue in that the value returned is
 | 
			
		||||
 *      a copy.  The CALLER is responsible for free'ing the data returned.
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
char *
 | 
			
		||||
PQgetAttr(PortalBuffer *portal,
 | 
			
		||||
	  int tuple_index,
 | 
			
		||||
	  int field_number)
 | 
			
		||||
{
 | 
			
		||||
    TupleBlock *tbp;
 | 
			
		||||
    int tuple_offset;
 | 
			
		||||
    int len;
 | 
			
		||||
    char* result = NULL;
 | 
			
		||||
 | 
			
		||||
    tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
 | 
			
		||||
    if (tbp) {
 | 
			
		||||
      len = tbp->lengths[tuple_offset][field_number];
 | 
			
		||||
      result = malloc(len + 1);
 | 
			
		||||
      memcpy(result, 
 | 
			
		||||
	     tbp->values[tuple_offset][field_number],
 | 
			
		||||
	     len);
 | 
			
		||||
      result[len] = '\0';
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	PQgetlength - Return an attribute (field) length
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQgetlength(PortalBuffer *portal,
 | 
			
		||||
	    int tuple_index,
 | 
			
		||||
	    int field_number)
 | 
			
		||||
{
 | 
			
		||||
    TupleBlock *tbp;
 | 
			
		||||
    int tuple_offset;
 | 
			
		||||
 | 
			
		||||
    tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
 | 
			
		||||
    if (tbp)
 | 
			
		||||
	return(tbp->lengths[tuple_offset][field_number]);
 | 
			
		||||
    return(-1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	PQclear		- free storage claimed by named portal
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
PQclear(char *pname)
 | 
			
		||||
{    
 | 
			
		||||
    if (!valid_pointer("PQclear: invalid portal name pointer", pname))
 | 
			
		||||
	return;
 | 
			
		||||
    pbuf_close(pname);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * async notification.
 | 
			
		||||
 * This is going away with pending rewrite of comm. code...
 | 
			
		||||
 */
 | 
			
		||||
/* static SLList pqNotifyList;*/
 | 
			
		||||
static Dllist *pqNotifyList = NULL;
 | 
			
		||||
 | 
			
		||||
/* remove invalid notifies before returning */
 | 
			
		||||
void
 | 
			
		||||
PQcleanNotify()
 | 
			
		||||
{
 | 
			
		||||
  Dlelem *e, *next;
 | 
			
		||||
  PQNotifyList *p;
 | 
			
		||||
 | 
			
		||||
  e = DLGetHead(pqNotifyList);
 | 
			
		||||
 | 
			
		||||
  while (e) {
 | 
			
		||||
    next = DLGetSucc(e);
 | 
			
		||||
    p = (PQNotifyList*)DLE_VAL(e);
 | 
			
		||||
    if (p->valid == 0)  {
 | 
			
		||||
      DLRemove(e);
 | 
			
		||||
      DLFreeElem(e);
 | 
			
		||||
      pfree(p);
 | 
			
		||||
    }
 | 
			
		||||
    e = next;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
PQnotifies_init()
 | 
			
		||||
{
 | 
			
		||||
    Dlelem *e;
 | 
			
		||||
    PQNotifyList *p;
 | 
			
		||||
    
 | 
			
		||||
    if (pqNotifyList == NULL) {
 | 
			
		||||
	pqNotifyList = DLNewList();
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	/* clean all notifies */
 | 
			
		||||
	for (e = DLGetHead(pqNotifyList); e != NULL; e = DLGetSucc(e)) {
 | 
			
		||||
	    p = (PQNotifyList*)DLE_VAL(e);
 | 
			
		||||
	    p->valid = 0;
 | 
			
		||||
	}
 | 
			
		||||
	PQcleanNotify();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PQNotifyList *
 | 
			
		||||
PQnotifies()
 | 
			
		||||
{
 | 
			
		||||
    Dlelem *e;
 | 
			
		||||
    PQcleanNotify();
 | 
			
		||||
    e = DLGetHead(pqNotifyList);
 | 
			
		||||
    return (e ? (PQNotifyList*)DLE_VAL(e) : NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
PQremoveNotify(PQNotifyList *nPtr)
 | 
			
		||||
{
 | 
			
		||||
    nPtr->valid = 0;		/* remove later */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
PQappendNotify(char *relname, int pid)
 | 
			
		||||
{
 | 
			
		||||
    PQNotifyList *p;
 | 
			
		||||
    
 | 
			
		||||
    if (pqNotifyList == NULL) 
 | 
			
		||||
	pqNotifyList = DLNewList();
 | 
			
		||||
    
 | 
			
		||||
    p = (PQNotifyList*)pbuf_alloc(sizeof(PQNotifyList));
 | 
			
		||||
    strncpy(p->relname, relname, NAMEDATALEN);
 | 
			
		||||
    p->be_pid = pid;
 | 
			
		||||
    p->valid = 1;
 | 
			
		||||
    DLAddTail(pqNotifyList, DLNewElem(p));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										511
									
								
								src/backend/libpq/portalbuf.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										511
									
								
								src/backend/libpq/portalbuf.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,511 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * portalbuf.c--
 | 
			
		||||
 *    portal buffer support routines for src/libpq/portal.c
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *    $Header: /cvsroot/pgsql/src/backend/libpq/Attic/portalbuf.c,v 1.1.1.1 1996/07/09 06:21:30 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
/*
 | 
			
		||||
 * INTERFACE ROUTINES
 | 
			
		||||
 *	pbuf_alloc 	  - allocate memory for libpq routines
 | 
			
		||||
 *	pbuf_free 	  - free memory for libpq routines
 | 
			
		||||
 *	pbuf_addPortal 	  - Allocate a new portal buffer
 | 
			
		||||
 *	pbuf_addGroup 	  - Add a new tuple group to the portal
 | 
			
		||||
 *	pbuf_addTypes 	  - Allocate n type blocks
 | 
			
		||||
 *	pbuf_addTuples 	  - Allocate a tuple block
 | 
			
		||||
 *	pbuf_addTuple 	  - Allocate a tuple of n fields (attributes)
 | 
			
		||||
 *	pbuf_addValues 	  - Allocate n bytes for a value
 | 
			
		||||
 *	pbuf_addEntry 	  - Allocate a portal entry
 | 
			
		||||
 *	pbuf_freeEntry    - Free a portal entry in the portal table
 | 
			
		||||
 *	pbuf_freeTypes 	  - Free up the space used by a portal 
 | 
			
		||||
 *	pbuf_freeTuples   - free space used by tuple block
 | 
			
		||||
 *	pbuf_freeGroup 	  - free space used by group, types and tuples
 | 
			
		||||
 *	pbuf_freePortal   - free space used by portal and portal's group
 | 
			
		||||
 *	pbuf_getIndex 	  - Return the index of the portal entry
 | 
			
		||||
 *	pbuf_setup 	  - Set up a portal for dumping data
 | 
			
		||||
 *	pbuf_close 	  - Close a portal, remove it from the portal table
 | 
			
		||||
 *	pbuf_findGroup 	  - Return group given the group_index
 | 
			
		||||
 *	pbuf_findFnumber  - Return field index of a given field within a group
 | 
			
		||||
 *	pbuf_findFname 	  - Find the field name given the field index
 | 
			
		||||
 *	pbuf_checkFnumber - signal an error if field number is out of bounds
 | 
			
		||||
 *
 | 
			
		||||
 * NOTES
 | 
			
		||||
 *	These functions may be used by both frontend routines which
 | 
			
		||||
 *	communicate with a backend or by user-defined functions which
 | 
			
		||||
 *	are compiled or dynamically loaded into a backend.
 | 
			
		||||
 *
 | 
			
		||||
 *	the portals[] array should be organized as a hash table for
 | 
			
		||||
 *	quick portal-by-name lookup.
 | 
			
		||||
 *
 | 
			
		||||
 *	Do not confuse "PortalEntry" (or "PortalBuffer") with "Portal"
 | 
			
		||||
 *	see utils/mmgr/portalmem.c for why. -cim 2/22/91
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include "c.h"
 | 
			
		||||
 | 
			
		||||
#include "libpq/libpq.h"		/* where the declarations go */
 | 
			
		||||
#include "utils/exc.h"
 | 
			
		||||
#include "utils/palloc.h"
 | 
			
		||||
 | 
			
		||||
PortalEntry** portals = (PortalEntry**) NULL;
 | 
			
		||||
size_t portals_array_size = 0;
 | 
			
		||||
 | 
			
		||||
/* portals array memory is malloc'd instead of using MemoryContexts */
 | 
			
		||||
/* since it will be used by both front and backend programs*/
 | 
			
		||||
/*  GlobalMemory portals_mmcxt = (GlobalMemory) NULL;  */
 | 
			
		||||
 | 
			
		||||
/* ------------------------------- 
 | 
			
		||||
 * portals_realloc --
 | 
			
		||||
 *    grow the size of the portals array by size
 | 
			
		||||
 *
 | 
			
		||||
 *    also ensures that elements are initially NULL 
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
portals_realloc(size_t size)
 | 
			
		||||
{
 | 
			
		||||
    size_t oldsize;
 | 
			
		||||
    int i;
 | 
			
		||||
    PortalEntry** newp;
 | 
			
		||||
    
 | 
			
		||||
    oldsize = portals_array_size;
 | 
			
		||||
    
 | 
			
		||||
    portals_array_size += size;
 | 
			
		||||
    if (portals)
 | 
			
		||||
	newp= (PortalEntry**)realloc(portals,
 | 
			
		||||
				     portals_array_size*sizeof(PortalEntry*));
 | 
			
		||||
    else
 | 
			
		||||
	newp= (PortalEntry**)malloc(portals_array_size*sizeof(PortalEntry*));
 | 
			
		||||
    
 | 
			
		||||
    if (newp)
 | 
			
		||||
	portals = newp;
 | 
			
		||||
    else
 | 
			
		||||
	libpq_raise(&PortalError,
 | 
			
		||||
		    form("Cannot alloc more memory in portals_realloc"));
 | 
			
		||||
    
 | 
			
		||||
    for (i=oldsize;i<portals_array_size;i++)
 | 
			
		||||
	portals[i]=(PortalEntry*)NULL;
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_alloc - allocate memory for portal buffers
 | 
			
		||||
 *
 | 
			
		||||
 *	remember: palloc() in the backend uses the postgres MemoryContext
 | 
			
		||||
 *	library and palloc() in the frontend (fe-pqstubs.c) calls malloc().
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
caddr_t
 | 
			
		||||
pbuf_alloc(size_t size)
 | 
			
		||||
{
 | 
			
		||||
    caddr_t 	addr;
 | 
			
		||||
    
 | 
			
		||||
    if (size <= 0)
 | 
			
		||||
	libpq_raise(&MemoryError, form("Invalid argument to pbuf_alloc()."));
 | 
			
		||||
    
 | 
			
		||||
    addr = (caddr_t) palloc(size);
 | 
			
		||||
    if (addr == (caddr_t) NULL)
 | 
			
		||||
	libpq_raise(&MemoryError, form("Cannot Allocate space."));
 | 
			
		||||
    
 | 
			
		||||
    return (addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_free - free memory for portal buffers
 | 
			
		||||
 *
 | 
			
		||||
 *	remember: pfree() in the backend uses the postgres MemoryContext
 | 
			
		||||
 *	library and pfree() in the frontend (fe-pqstubs.c) calls free().
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pbuf_free(caddr_t pointer)
 | 
			
		||||
{
 | 
			
		||||
    if (pointer)
 | 
			
		||||
	pfree(pointer);
 | 
			
		||||
    else
 | 
			
		||||
	libpq_raise(&MemoryError, form("Tried to free NULL memory pointer"));
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_addPortal - Allocate a new portal buffer
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
PortalBuffer *
 | 
			
		||||
pbuf_addPortal()
 | 
			
		||||
{
 | 
			
		||||
    PortalBuffer *portal;
 | 
			
		||||
    
 | 
			
		||||
    portal = (PortalBuffer *)
 | 
			
		||||
	pbuf_alloc(sizeof (PortalBuffer));
 | 
			
		||||
    
 | 
			
		||||
    portal->rule_p = 0;
 | 
			
		||||
    portal->no_tuples = 0;
 | 
			
		||||
    portal->no_groups = 0;
 | 
			
		||||
    portal->groups = NULL;
 | 
			
		||||
    
 | 
			
		||||
    return (portal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_addGroup - Add a new tuple group to the portal
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
GroupBuffer *
 | 
			
		||||
pbuf_addGroup(PortalBuffer *portal)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *group, *group1;
 | 
			
		||||
    
 | 
			
		||||
    group = (GroupBuffer *)
 | 
			
		||||
	pbuf_alloc(sizeof (GroupBuffer));
 | 
			
		||||
    
 | 
			
		||||
    /* Initialize the new group buffer. */
 | 
			
		||||
    group->no_tuples  = 0;
 | 
			
		||||
    group->no_fields = 0;
 | 
			
		||||
    group->types = NULL;
 | 
			
		||||
    group->tuples = NULL;
 | 
			
		||||
    group->next = NULL;
 | 
			
		||||
    
 | 
			
		||||
    if ((group1 = portal->groups) == NULL)
 | 
			
		||||
	portal->groups = group;
 | 
			
		||||
    else {
 | 
			
		||||
	while (group1->next != NULL) 
 | 
			
		||||
	    group1 = group1->next;
 | 
			
		||||
	group1->next = group;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return (group);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_addTypes - Allocate n type blocks
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
TypeBlock *
 | 
			
		||||
pbuf_addTypes(int n)
 | 
			
		||||
{
 | 
			
		||||
    TypeBlock *types;
 | 
			
		||||
    
 | 
			
		||||
    types = (TypeBlock *)
 | 
			
		||||
	pbuf_alloc(n * sizeof (TypeBlock));
 | 
			
		||||
    
 | 
			
		||||
    return (types);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_addTuples - Allocate a tuple block
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
TupleBlock *
 | 
			
		||||
pbuf_addTuples()
 | 
			
		||||
{
 | 
			
		||||
    TupleBlock *tuples;
 | 
			
		||||
    
 | 
			
		||||
    tuples = (TupleBlock *)
 | 
			
		||||
	pbuf_alloc(sizeof (TupleBlock));
 | 
			
		||||
    
 | 
			
		||||
    tuples->next = NULL;
 | 
			
		||||
    tuples->tuple_index = 0;
 | 
			
		||||
    
 | 
			
		||||
    return (tuples);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_addTuple - Allocate a tuple of n fields (attributes)
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
char **
 | 
			
		||||
pbuf_addTuple(int n)
 | 
			
		||||
{
 | 
			
		||||
    return (char **)
 | 
			
		||||
	pbuf_alloc(n * sizeof (char *));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_addTupleValueLengths - Allocate a tuple of n lengths (attributes)
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int *
 | 
			
		||||
pbuf_addTupleValueLengths(int n)
 | 
			
		||||
{
 | 
			
		||||
    return (int *)
 | 
			
		||||
	pbuf_alloc(n * sizeof(int));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_addValues - Allocate n bytes for a value
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
char *
 | 
			
		||||
pbuf_addValues(int n)
 | 
			
		||||
{
 | 
			
		||||
    return
 | 
			
		||||
	pbuf_alloc(n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_addEntry - Allocate a portal entry
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
PortalEntry *pbuf_addEntry()
 | 
			
		||||
{
 | 
			
		||||
    return (PortalEntry *)
 | 
			
		||||
	pbuf_alloc (sizeof (PortalEntry));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_freeEntry - Free a portal entry in the portal table
 | 
			
		||||
 *	the portal is freed separately.
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pbuf_freeEntry(int i)
 | 
			
		||||
{
 | 
			
		||||
    if (portals)
 | 
			
		||||
	{
 | 
			
		||||
	    pbuf_free ((caddr_t)portals[i]);
 | 
			
		||||
	    portals[i] = NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_freeTypes - Free up the space used by a portal 
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pbuf_freeTypes(TypeBlock *types)
 | 
			
		||||
{
 | 
			
		||||
    pbuf_free((caddr_t)types);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_freeTuples - free space used by tuple block
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pbuf_freeTuples(TupleBlock *tuples,
 | 
			
		||||
		int no_tuples,
 | 
			
		||||
		int no_fields)
 | 
			
		||||
{
 | 
			
		||||
    int i, j;
 | 
			
		||||
    
 | 
			
		||||
    if (no_tuples > TupleBlockSize) {
 | 
			
		||||
	pbuf_freeTuples (tuples->next, no_tuples - TupleBlockSize, no_fields);
 | 
			
		||||
	no_tuples = TupleBlockSize;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /* For each tuple, free all its attribute values. */
 | 
			
		||||
    for (i = 0; i < no_tuples; i++) {
 | 
			
		||||
	for (j = 0; j < no_fields; j++)
 | 
			
		||||
	    if (tuples->values[i][j] != NULL)
 | 
			
		||||
		pbuf_free((caddr_t)tuples->values[i][j]);
 | 
			
		||||
	if (tuples->lengths[i])
 | 
			
		||||
	    pbuf_free((caddr_t)tuples->lengths[i]);
 | 
			
		||||
	if (tuples->values[i])
 | 
			
		||||
	    pbuf_free((caddr_t)tuples->values[i]);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    pbuf_free((caddr_t)tuples);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_freeGroup - free space used by group, types and tuples
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pbuf_freeGroup(GroupBuffer *group)
 | 
			
		||||
{
 | 
			
		||||
    if (group->next != NULL)
 | 
			
		||||
	pbuf_freeGroup(group->next);
 | 
			
		||||
    
 | 
			
		||||
    if (group->types != NULL)
 | 
			
		||||
	pbuf_freeTypes(group->types);
 | 
			
		||||
    
 | 
			
		||||
    if (group->tuples != NULL)
 | 
			
		||||
	pbuf_freeTuples(group->tuples, group->no_tuples,group->no_fields);
 | 
			
		||||
    
 | 
			
		||||
    pbuf_free((caddr_t)group);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_freePortal - free space used by portal and portal's group
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pbuf_freePortal(PortalBuffer *portal)
 | 
			
		||||
{
 | 
			
		||||
    if (portal->groups != NULL)
 | 
			
		||||
	pbuf_freeGroup(portal->groups);
 | 
			
		||||
    
 | 
			
		||||
    pbuf_free((caddr_t)portal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_getIndex - Return the index of the portal entry
 | 
			
		||||
 * 	note: portals[] maps portal names to portal buffers.
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
pbuf_getIndex(char *pname)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    
 | 
			
		||||
    if (portals) {
 | 
			
		||||
	for (i = 0; i < portals_array_size; i++) 
 | 
			
		||||
	    if (portals[i] != NULL &&
 | 
			
		||||
		strncmp(portals[i]->name, pname, PortalNameLength) == 0)
 | 
			
		||||
		return i;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return (-1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_setportalname - assign a user given name to a portal
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pbuf_setportalinfo(PortalEntry *entry, char *pname)
 | 
			
		||||
{
 | 
			
		||||
    if (entry)
 | 
			
		||||
	strncpy(entry->name, pname, PortalNameLength-1);
 | 
			
		||||
    entry->name[PortalNameLength-1] = '\0';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_setup - Set up a portal for dumping data
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
PortalEntry *
 | 
			
		||||
pbuf_setup(char *pname)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    
 | 
			
		||||
    if (!portals) /* the portals array has not been allocated yet */
 | 
			
		||||
	{
 | 
			
		||||
	    /* allocate portals[] array here */
 | 
			
		||||
	    portals_realloc(PORTALS_INITIAL_SIZE);
 | 
			
		||||
	}
 | 
			
		||||
    
 | 
			
		||||
    /* If a portal with the same name already exists, close it. */
 | 
			
		||||
    /* else look for an empty entry in the portal table. */
 | 
			
		||||
    if ((i = pbuf_getIndex(pname)) != -1) 
 | 
			
		||||
	pbuf_freePortal(portals[i]->portal);
 | 
			
		||||
    else {
 | 
			
		||||
	for (i = 0; i < portals_array_size; i++)
 | 
			
		||||
	    if (portals[i] == NULL)
 | 
			
		||||
		break;
 | 
			
		||||
	
 | 
			
		||||
	/* If the portal table is full, enlarge it */
 | 
			
		||||
	if (i >= portals_array_size) 
 | 
			
		||||
	    portals_realloc(PORTALS_GROW_BY);
 | 
			
		||||
	
 | 
			
		||||
	portals[i] = pbuf_addEntry();
 | 
			
		||||
	strncpy(portals[i]->name, pname, PortalNameLength);
 | 
			
		||||
    }
 | 
			
		||||
    portals[i]->portal = pbuf_addPortal();
 | 
			
		||||
    portals[i]->portalcxt = NULL;
 | 
			
		||||
    portals[i]->result = NULL;
 | 
			
		||||
    
 | 
			
		||||
    return portals[i];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_close - Close a portal, remove it from the portal table
 | 
			
		||||
 *			and free up the space
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pbuf_close(char *pname)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    
 | 
			
		||||
    if ((i = pbuf_getIndex(pname)) == -1) 
 | 
			
		||||
	libpq_raise(&PortalError, form("Portal %s does not exist.", pname));
 | 
			
		||||
    
 | 
			
		||||
    pbuf_freePortal(portals[i]->portal);
 | 
			
		||||
    pbuf_freeEntry(i);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_findGroup - Return the group given the group_index
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
GroupBuffer *
 | 
			
		||||
pbuf_findGroup(PortalBuffer *portal,
 | 
			
		||||
	       int group_index)
 | 
			
		||||
{
 | 
			
		||||
    GroupBuffer *group;
 | 
			
		||||
    
 | 
			
		||||
    group = portal->groups;
 | 
			
		||||
    while (group_index > 0 && group != NULL) {
 | 
			
		||||
	group = group->next;
 | 
			
		||||
	group_index--;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (group == NULL)
 | 
			
		||||
	libpq_raise(&PortalError, 
 | 
			
		||||
		    form("Group index %d out of bound.", group_index));
 | 
			
		||||
    
 | 
			
		||||
    return (group);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 * pbuf_findFnumber - Return the field index of a given field within a group
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
pbuf_findFnumber(GroupBuffer *group,
 | 
			
		||||
		 char *field_name)
 | 
			
		||||
{	
 | 
			
		||||
    TypeBlock *types;
 | 
			
		||||
    int i;
 | 
			
		||||
    
 | 
			
		||||
    types = group->types;
 | 
			
		||||
    
 | 
			
		||||
    for (i = 0; i < group->no_fields; i++) 
 | 
			
		||||
	if (strncmp(types[i].name, field_name, NAMEDATALEN) == 0)
 | 
			
		||||
	    return (i);
 | 
			
		||||
    
 | 
			
		||||
    libpq_raise(&PortalError, 
 | 
			
		||||
		form("Field-name %s does not exist.", field_name));
 | 
			
		||||
 
 | 
			
		||||
     /* not reached, here to make compiler happy */
 | 
			
		||||
     return 0;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_checkFnumber - signal an error if field number is out of bounds
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pbuf_checkFnumber(GroupBuffer *group,
 | 
			
		||||
		  int field_number)
 | 
			
		||||
{
 | 
			
		||||
    if (field_number < 0 || field_number >= group->no_fields)
 | 
			
		||||
	libpq_raise(&PortalError, 
 | 
			
		||||
		    form("Field number %d out of bound.", field_number));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pbuf_findFname - Find the field name given the field index
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
char *
 | 
			
		||||
pbuf_findFname(GroupBuffer *group,
 | 
			
		||||
	       int field_number)
 | 
			
		||||
{
 | 
			
		||||
    pbuf_checkFnumber(group, field_number);
 | 
			
		||||
    return
 | 
			
		||||
	(group->types[field_number]).name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										724
									
								
								src/backend/libpq/pqcomm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										724
									
								
								src/backend/libpq/pqcomm.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,724 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * pqcomm.c--
 | 
			
		||||
 *    Communication functions between the Frontend and the Backend
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *    $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.1.1.1 1996/07/09 06:21:31 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
/*
 | 
			
		||||
 * INTERFACE ROUTINES
 | 
			
		||||
 *	pq_gettty 	- return the name of the tty in the given buffer
 | 
			
		||||
 *	pq_getport 	- return the PGPORT setting
 | 
			
		||||
 *	pq_close 	- close input / output connections
 | 
			
		||||
 *	pq_flush 	- flush pending output
 | 
			
		||||
 *	pq_getstr 	- get a null terminated string from connection
 | 
			
		||||
 *	pq_getnchar 	- get n characters from connection
 | 
			
		||||
 *	pq_getint 	- get an integer from connection
 | 
			
		||||
 *	pq_putstr 	- send a null terminated string to connection
 | 
			
		||||
 *	pq_putnchar 	- send n characters to connection
 | 
			
		||||
 *	pq_putint 	- send an integer to connection
 | 
			
		||||
 *	pq_getinaddr 	- initialize address from host and port number
 | 
			
		||||
 *	pq_getinserv 	- initialize address from host and service name
 | 
			
		||||
 *	pq_connect 	- create remote input / output connection
 | 
			
		||||
 *	pq_accept 	- accept remote input / output connection
 | 
			
		||||
 *      pq_async_notify - receive notification from backend.
 | 
			
		||||
 *
 | 
			
		||||
 * NOTES
 | 
			
		||||
 * 	These functions are used by both frontend applications and
 | 
			
		||||
 *	the postgres backend.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#include "libpq/pqsignal.h"	/* substitute for <signal.h> */
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>		/* for ttyname() */
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <netdb.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <winsock.h>
 | 
			
		||||
#endif /* WIN32 */
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
#ifdef PORTNAME_linux
 | 
			
		||||
#ifndef SOMAXCONN
 | 
			
		||||
#define SOMAXCONN 5		/* from Linux listen(2) man page */
 | 
			
		||||
#endif /* SOMAXCONN */
 | 
			
		||||
#endif /* PORTNAME_linux */
 | 
			
		||||
 | 
			
		||||
#include "c.h"
 | 
			
		||||
#include "libpq/auth.h"
 | 
			
		||||
#include "libpq/libpq.h"	/* where the declarations go */
 | 
			
		||||
#include "libpq/pqcomm.h"
 | 
			
		||||
#include "utils/elog.h"
 | 
			
		||||
 | 
			
		||||
/* ----------------
 | 
			
		||||
 *	declarations
 | 
			
		||||
 * ----------------
 | 
			
		||||
 */
 | 
			
		||||
FILE *Pfout, *Pfin;
 | 
			
		||||
FILE *Pfdebug;	  /* debugging libpq */
 | 
			
		||||
int PQAsyncNotifyWaiting;	/* for async. notification */
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pq_init - open portal file descriptors
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pq_init(int fd)
 | 
			
		||||
{
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
    int in, out;
 | 
			
		||||
 | 
			
		||||
    in = _open_osfhandle(fd, _O_RDONLY);
 | 
			
		||||
    out = _open_osfhandle(fd, _O_APPEND);
 | 
			
		||||
    Pfin = fdopen(in, "rb");
 | 
			
		||||
    Pfout = fdopen(out, "wb");
 | 
			
		||||
#else
 | 
			
		||||
    Pfin = fdopen(fd, "r");
 | 
			
		||||
    Pfout = fdopen(dup(fd), "w");
 | 
			
		||||
#endif /* WIN32 */
 | 
			
		||||
    if (!Pfin || !Pfout)
 | 
			
		||||
	elog(FATAL, "pq_init: Couldn't initialize socket connection");
 | 
			
		||||
    PQnotifies_init();
 | 
			
		||||
    if (getenv("LIBPQ_DEBUG")) {
 | 
			
		||||
	Pfdebug = stderr;
 | 
			
		||||
    }else {
 | 
			
		||||
	Pfdebug = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* -------------------------
 | 
			
		||||
 *   pq_getc(File* fin)
 | 
			
		||||
 *  
 | 
			
		||||
 *   get a character from the input file,
 | 
			
		||||
 *
 | 
			
		||||
 *   if Pfdebug is set, also echo the character fetched into Pfdebug
 | 
			
		||||
 *
 | 
			
		||||
 *   used for debugging libpq
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
pq_getc(FILE* fin)
 | 
			
		||||
{
 | 
			
		||||
  int c;
 | 
			
		||||
 | 
			
		||||
  c = getc(fin);
 | 
			
		||||
  if (Pfdebug && c != EOF)
 | 
			
		||||
    putc(c,Pfdebug);
 | 
			
		||||
  return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pq_gettty - return the name of the tty in the given buffer
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pq_gettty(char *tp)
 | 
			
		||||
{	
 | 
			
		||||
    (void) strncpy(tp, ttyname(0), 19);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pq_getport - return the PGPORT setting
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
pq_getport()
 | 
			
		||||
{
 | 
			
		||||
    char *envport = getenv("PGPORT");
 | 
			
		||||
    
 | 
			
		||||
    if (envport)
 | 
			
		||||
	return(atoi(envport));
 | 
			
		||||
    return(atoi(POSTPORT));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pq_close - close input / output connections
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pq_close()
 | 
			
		||||
{
 | 
			
		||||
    if (Pfin) {
 | 
			
		||||
	fclose(Pfin);
 | 
			
		||||
	Pfin = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (Pfout) {
 | 
			
		||||
	fclose(Pfout);
 | 
			
		||||
	Pfout = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    PQAsyncNotifyWaiting = 0;
 | 
			
		||||
    PQnotifies_init();
 | 
			
		||||
    pq_unregoob();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pq_flush - flush pending output
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pq_flush()
 | 
			
		||||
{
 | 
			
		||||
    if (Pfout)
 | 
			
		||||
	fflush(Pfout);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pq_getstr - get a null terminated string from connection
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
pq_getstr(char *s, int maxlen)
 | 
			
		||||
{
 | 
			
		||||
    int	c;
 | 
			
		||||
    
 | 
			
		||||
    if (Pfin == (FILE *) NULL) {
 | 
			
		||||
/*	elog(DEBUG, "Input descriptor is null"); */
 | 
			
		||||
	return(EOF);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    while (maxlen-- && (c = pq_getc(Pfin)) != EOF && c)
 | 
			
		||||
	*s++ = c;
 | 
			
		||||
    *s = '\0';
 | 
			
		||||
    
 | 
			
		||||
    /* -----------------
 | 
			
		||||
     *     If EOF reached let caller know.
 | 
			
		||||
     *     (This will only happen if we hit EOF before the string
 | 
			
		||||
     *     delimiter is reached.)
 | 
			
		||||
     * -----------------
 | 
			
		||||
     */
 | 
			
		||||
    if (c == EOF)
 | 
			
		||||
	return(EOF);
 | 
			
		||||
    return(!EOF);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * USER FUNCTION - gets a newline-terminated string from the backend.
 | 
			
		||||
 * 
 | 
			
		||||
 * Chiefly here so that applications can use "COPY <rel> to stdout"
 | 
			
		||||
 * and read the output string.  Returns a null-terminated string in s.
 | 
			
		||||
 *
 | 
			
		||||
 * PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
 | 
			
		||||
 * the terminating \n (like gets(3)).
 | 
			
		||||
 *
 | 
			
		||||
 * RETURNS:
 | 
			
		||||
 *	EOF if it is detected or invalid arguments are given
 | 
			
		||||
 *	0 if EOL is reached (i.e., \n has been read)
 | 
			
		||||
 *		(this is required for backward-compatibility -- this
 | 
			
		||||
 *		 routine used to always return EOF or 0, assuming that
 | 
			
		||||
 *		 the line ended within maxlen bytes.)
 | 
			
		||||
 *	1 in other cases
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQgetline(char *s, int maxlen)
 | 
			
		||||
{
 | 
			
		||||
    int c = '\0';
 | 
			
		||||
    
 | 
			
		||||
    if (!Pfin || !s || maxlen <= 1)
 | 
			
		||||
	return(EOF);
 | 
			
		||||
    
 | 
			
		||||
    for (; maxlen > 1 && (c = pq_getc(Pfin)) != '\n' && c != EOF; --maxlen) {
 | 
			
		||||
	*s++ = c;
 | 
			
		||||
    }
 | 
			
		||||
    *s = '\0';
 | 
			
		||||
    
 | 
			
		||||
    if (c == EOF) {
 | 
			
		||||
	return(EOF);		/* error -- reached EOF before \n */
 | 
			
		||||
    } else if (c == '\n') {
 | 
			
		||||
	return(0);		/* done with this line */
 | 
			
		||||
    }
 | 
			
		||||
    return(1);			/* returning a full buffer */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * USER FUNCTION - sends a string to the backend.
 | 
			
		||||
 * 
 | 
			
		||||
 * Chiefly here so that applications can use "COPY <rel> from stdin".
 | 
			
		||||
 *
 | 
			
		||||
 * RETURNS:
 | 
			
		||||
 *	0 in all cases.
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PQputline(char *s)
 | 
			
		||||
{
 | 
			
		||||
    if (Pfout) {
 | 
			
		||||
	(void) fputs(s, Pfout);
 | 
			
		||||
	fflush(Pfout);
 | 
			
		||||
    }
 | 
			
		||||
    return(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pq_getnchar - get n characters from connection
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
pq_getnchar(char *s, int off, int maxlen)
 | 
			
		||||
{
 | 
			
		||||
    int	c;
 | 
			
		||||
    
 | 
			
		||||
    if (Pfin == (FILE *) NULL) {
 | 
			
		||||
/*	elog(DEBUG, "Input descriptor is null"); */
 | 
			
		||||
	return(EOF);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    s += off;
 | 
			
		||||
    while (maxlen-- && (c = pq_getc(Pfin)) != EOF)
 | 
			
		||||
	*s++ = c;
 | 
			
		||||
    
 | 
			
		||||
    /* -----------------
 | 
			
		||||
     *     If EOF reached let caller know
 | 
			
		||||
     * -----------------
 | 
			
		||||
     */
 | 
			
		||||
    if (c == EOF)
 | 
			
		||||
	return(EOF);
 | 
			
		||||
    return(!EOF);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pq_getint - get an integer from connection
 | 
			
		||||
 *   we receive an integer a byte at a type and reconstruct it so that
 | 
			
		||||
 *   machines with different ENDIAN representations can talk to each
 | 
			
		||||
 *   other
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
pq_getint(int b)
 | 
			
		||||
{
 | 
			
		||||
    int	n, c, p;
 | 
			
		||||
    
 | 
			
		||||
    if (Pfin == (FILE *) NULL) {
 | 
			
		||||
/*	elog(DEBUG, "pq_getint: Input descriptor is null"); */
 | 
			
		||||
	return(EOF);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    n = p = 0;
 | 
			
		||||
    while (b-- && (c = pq_getc(Pfin)) != EOF && p < 32) {
 | 
			
		||||
	n |= (c & 0xff) << p;
 | 
			
		||||
	p += 8;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return(n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pq_putstr - send a null terminated string to connection
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pq_putstr(char *s)
 | 
			
		||||
{
 | 
			
		||||
    int status;
 | 
			
		||||
    
 | 
			
		||||
    if (Pfout) {
 | 
			
		||||
	status = fputs(s, Pfout);
 | 
			
		||||
	if (status == EOF) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "FATAL: pq_putstr: fputs() failed: errno=%d\n",
 | 
			
		||||
			   errno);
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	}
 | 
			
		||||
	status = fputc('\0', Pfout);
 | 
			
		||||
	if (status == EOF) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "FATAL: pq_putstr: fputc() failed: errno=%d\n",
 | 
			
		||||
			   errno);
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pq_putnchar - send n characters to connection
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pq_putnchar(char *s, int n)
 | 
			
		||||
{
 | 
			
		||||
    int status;
 | 
			
		||||
    
 | 
			
		||||
    if (Pfout) {
 | 
			
		||||
	while (n--) {
 | 
			
		||||
	    status = fputc(*s++, Pfout);
 | 
			
		||||
	    if (status == EOF) {
 | 
			
		||||
		(void) sprintf(PQerrormsg,
 | 
			
		||||
			       "FATAL: pq_putnchar: fputc() failed: errno=%d\n",
 | 
			
		||||
			       errno);
 | 
			
		||||
		fputs(PQerrormsg, stderr);
 | 
			
		||||
		pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pq_putint - send an integer to connection
 | 
			
		||||
 *   we chop an integer into bytes and send individual bytes
 | 
			
		||||
 *   machines with different ENDIAN representations can still talk to each
 | 
			
		||||
 *   other
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pq_putint(int i, int b)
 | 
			
		||||
{
 | 
			
		||||
    int status;
 | 
			
		||||
    
 | 
			
		||||
    if (b > 4)
 | 
			
		||||
	b = 4;
 | 
			
		||||
    
 | 
			
		||||
    if (Pfout) {
 | 
			
		||||
	while (b--) {
 | 
			
		||||
	    status = fputc(i & 0xff, Pfout);
 | 
			
		||||
	    i >>= 8;
 | 
			
		||||
	    if (status == EOF) {
 | 
			
		||||
		(void) sprintf(PQerrormsg,
 | 
			
		||||
			       "FATAL: pq_putint: fputc() failed: errno=%d\n",
 | 
			
		||||
			       errno);
 | 
			
		||||
		fputs(PQerrormsg, stderr);
 | 
			
		||||
		pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ---
 | 
			
		||||
 *     pq_sendoob - send a string over the out-of-band channel
 | 
			
		||||
 *     pq_recvoob - receive a string over the oob channel
 | 
			
		||||
 *  NB: Fortunately, the out-of-band channel doesn't conflict with
 | 
			
		||||
 *      buffered I/O because it is separate from regular com. channel.
 | 
			
		||||
 * ---
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
pq_sendoob(char *msg, int len)
 | 
			
		||||
{
 | 
			
		||||
    int fd = fileno(Pfout);
 | 
			
		||||
    
 | 
			
		||||
    return(send(fd,msg,len,MSG_OOB));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
pq_recvoob(char *msgPtr, int *lenPtr)
 | 
			
		||||
{
 | 
			
		||||
    int fd = fileno(Pfout);
 | 
			
		||||
    int len = 0;
 | 
			
		||||
    
 | 
			
		||||
    len = recv(fd,msgPtr+len,*lenPtr,MSG_OOB);
 | 
			
		||||
    *lenPtr = len;
 | 
			
		||||
    return(len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pq_getinaddr - initialize address from host and port number
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
pq_getinaddr(struct sockaddr_in *sin,
 | 
			
		||||
	     char *host,
 | 
			
		||||
	     int port)
 | 
			
		||||
{
 | 
			
		||||
    struct hostent	*hs;
 | 
			
		||||
    
 | 
			
		||||
    memset((char *) sin, 0, sizeof(*sin));
 | 
			
		||||
    
 | 
			
		||||
    if (host) {
 | 
			
		||||
	if (*host >= '0' && *host <= '9')
 | 
			
		||||
	    sin->sin_addr.s_addr = inet_addr(host);
 | 
			
		||||
	else {
 | 
			
		||||
	    if (!(hs = gethostbyname(host))) {
 | 
			
		||||
		perror(host);
 | 
			
		||||
		return(1);
 | 
			
		||||
	    }
 | 
			
		||||
	    if (hs->h_addrtype != AF_INET) {
 | 
			
		||||
		(void) sprintf(PQerrormsg,
 | 
			
		||||
			       "FATAL: pq_getinaddr: %s not on Internet\n",
 | 
			
		||||
			       host);
 | 
			
		||||
		fputs(PQerrormsg, stderr);
 | 
			
		||||
		pqdebug("%s", PQerrormsg);
 | 
			
		||||
		return(1);
 | 
			
		||||
	    }
 | 
			
		||||
	    memmove((char *) &sin->sin_addr,
 | 
			
		||||
		    hs->h_addr,
 | 
			
		||||
		    hs->h_length);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    sin->sin_family = AF_INET;
 | 
			
		||||
    sin->sin_port = htons(port);
 | 
			
		||||
    return(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* --------------------------------
 | 
			
		||||
 *	pq_getinserv - initialize address from host and servive name
 | 
			
		||||
 * --------------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
pq_getinserv(struct sockaddr_in *sin, char *host, char *serv)
 | 
			
		||||
{
 | 
			
		||||
    struct servent *ss;
 | 
			
		||||
    
 | 
			
		||||
    if (*serv >= '0' && *serv <= '9')
 | 
			
		||||
	return(pq_getinaddr(sin, host, atoi(serv)));
 | 
			
		||||
    if (!(ss = getservbyname(serv, NULL))) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "FATAL: pq_getinserv: unknown service: %s\n",
 | 
			
		||||
		       serv);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(1);
 | 
			
		||||
    }
 | 
			
		||||
    return(pq_getinaddr(sin, host, ntohs(ss->s_port)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * register an out-of-band listener proc--at most one allowed.
 | 
			
		||||
 * This is used for receiving async. notification from the backend.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
pq_regoob(void (*fptr)())
 | 
			
		||||
{
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
    /* Who knows what to do here? */
 | 
			
		||||
    return;
 | 
			
		||||
#else
 | 
			
		||||
    int fd = fileno(Pfout);
 | 
			
		||||
#ifdef PORTNAME_hpux
 | 
			
		||||
    ioctl(fd, FIOSSAIOOWN, getpid());
 | 
			
		||||
#else /* PORTNAME_hpux */
 | 
			
		||||
    fcntl(fd, F_SETOWN, getpid());
 | 
			
		||||
#endif /* PORTNAME_hpux */
 | 
			
		||||
    (void) signal(SIGURG,fptr);
 | 
			
		||||
#endif /* WIN32 */    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
pq_unregoob()
 | 
			
		||||
{
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
    signal(SIGURG,SIG_DFL);
 | 
			
		||||
#endif /* WIN32 */    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
pq_async_notify()
 | 
			
		||||
{
 | 
			
		||||
    char msg[20];
 | 
			
		||||
    /*    int len = sizeof(msg);*/
 | 
			
		||||
    int len = 20;
 | 
			
		||||
    
 | 
			
		||||
    if (pq_recvoob(msg,&len) >= 0) {
 | 
			
		||||
	/* debugging */
 | 
			
		||||
	printf("received notification: %s\n",msg);
 | 
			
		||||
	PQAsyncNotifyWaiting = 1;
 | 
			
		||||
	/*	PQappendNotify(msg+1);*/
 | 
			
		||||
    } else {
 | 
			
		||||
	extern int errno;
 | 
			
		||||
	printf("SIGURG but no data: len = %d, err=%d\n",len,errno);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Streams -- wrapper around Unix socket system calls
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 *	Stream functions are used for vanilla TCP connection protocol.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * StreamServerPort -- open a sock stream "listening" port.
 | 
			
		||||
 *
 | 
			
		||||
 * This initializes the Postmaster's connection
 | 
			
		||||
 *	accepting port.  
 | 
			
		||||
 *
 | 
			
		||||
 * ASSUME: that this doesn't need to be non-blocking because
 | 
			
		||||
 *	the Postmaster uses select() to tell when the socket
 | 
			
		||||
 *	is ready.
 | 
			
		||||
 *
 | 
			
		||||
 * RETURNS: STATUS_OK or STATUS_ERROR
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
StreamServerPort(char *hostName, short portName, int *fdP)
 | 
			
		||||
{
 | 
			
		||||
    struct sockaddr_in	sin;
 | 
			
		||||
    int			fd;
 | 
			
		||||
    
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
    /* This is necessary to make it possible for a backend to use
 | 
			
		||||
    ** stdio to read from the socket.
 | 
			
		||||
    */
 | 
			
		||||
    int optionvalue = SO_SYNCHRONOUS_NONALERT;
 | 
			
		||||
 | 
			
		||||
    setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionvalue,
 | 
			
		||||
	       sizeof(optionvalue));
 | 
			
		||||
#endif /* WIN32 */
 | 
			
		||||
 | 
			
		||||
    if (! hostName)
 | 
			
		||||
	hostName = "localhost";
 | 
			
		||||
    
 | 
			
		||||
    memset((char *)&sin, 0, sizeof sin);
 | 
			
		||||
    
 | 
			
		||||
    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "FATAL: StreamServerPort: socket() failed: errno=%d\n",
 | 
			
		||||
		       errno);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    sin.sin_family = AF_INET;
 | 
			
		||||
    sin.sin_port = htons(portName);
 | 
			
		||||
    
 | 
			
		||||
    if (bind(fd, (struct sockaddr *)&sin, sizeof sin) < 0) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "FATAL: StreamServerPort: bind() failed: errno=%d\n",
 | 
			
		||||
		       errno);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	(void) strcat(PQerrormsg, "\tIs another postmaster already running on that port?\n");
 | 
			
		||||
	(void) strcat(PQerrormsg, "\tIf not, wait a few seconds and retry.\n");
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    listen(fd, SOMAXCONN);
 | 
			
		||||
    
 | 
			
		||||
    /* MS: I took this code from Dillon's version.  It makes the 
 | 
			
		||||
     * listening port non-blocking.  That is not necessary (and
 | 
			
		||||
     * may tickle kernel bugs).
 | 
			
		||||
     
 | 
			
		||||
     (void) fcntl(fd, F_SETFD, 1);
 | 
			
		||||
     (void) fcntl(fd, F_SETFL, FNDELAY);
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    *fdP = fd;
 | 
			
		||||
    return(STATUS_OK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * StreamConnection -- create a new connection with client using
 | 
			
		||||
 *	server port.
 | 
			
		||||
 *
 | 
			
		||||
 * This one should be non-blocking.
 | 
			
		||||
 * 
 | 
			
		||||
 * RETURNS: STATUS_OK or STATUS_ERROR
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
StreamConnection(int server_fd, Port *port)
 | 
			
		||||
{
 | 
			
		||||
    int	addrlen;
 | 
			
		||||
    
 | 
			
		||||
    /* accept connection (and fill in the client (remote) address) */
 | 
			
		||||
    addrlen = sizeof(struct sockaddr_in);
 | 
			
		||||
    if ((port->sock = accept(server_fd,
 | 
			
		||||
			     (struct sockaddr *) &port->raddr,
 | 
			
		||||
			     &addrlen)) < 0) {
 | 
			
		||||
	elog(WARN, "postmaster: StreamConnection: accept: %m");
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /* fill in the server (local) address */
 | 
			
		||||
    addrlen = sizeof(struct sockaddr_in);
 | 
			
		||||
    if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
 | 
			
		||||
		    &addrlen) < 0) {
 | 
			
		||||
	elog(WARN, "postmaster: StreamConnection: getsockname: %m");
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    port->mask = 1 << port->sock;
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32    
 | 
			
		||||
    /* reset to non-blocking */
 | 
			
		||||
    fcntl(port->sock, F_SETFL, 1);
 | 
			
		||||
#endif /* WIN32 */    
 | 
			
		||||
    
 | 
			
		||||
    return(STATUS_OK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * StreamClose -- close a client/backend connection
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
StreamClose(int sock)
 | 
			
		||||
{
 | 
			
		||||
    (void) close(sock); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ---------------------------
 | 
			
		||||
 * StreamOpen -- From client, initiate a connection with the 
 | 
			
		||||
 *	server (Postmaster).
 | 
			
		||||
 *
 | 
			
		||||
 * RETURNS: STATUS_OK or STATUS_ERROR
 | 
			
		||||
 *
 | 
			
		||||
 * NOTE: connection is NOT established just because this
 | 
			
		||||
 *	routine exits.  Local state is ok, but we haven't
 | 
			
		||||
 *	spoken to the postmaster yet.
 | 
			
		||||
 * ---------------------------
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
StreamOpen(char *hostName, short portName, Port *port)
 | 
			
		||||
{
 | 
			
		||||
    struct hostent	*hp;
 | 
			
		||||
    int			laddrlen = sizeof(struct sockaddr_in);
 | 
			
		||||
    extern int		errno;
 | 
			
		||||
    
 | 
			
		||||
    if (!hostName)
 | 
			
		||||
	hostName = "localhost";
 | 
			
		||||
    
 | 
			
		||||
    /* set up the server (remote) address */
 | 
			
		||||
    if (!(hp = gethostbyname(hostName)) || hp->h_addrtype != AF_INET) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "FATAL: StreamOpen: unknown hostname: %s\n",
 | 
			
		||||
		       hostName);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    memset((char *) &port->raddr, 0, sizeof(port->raddr));
 | 
			
		||||
    memmove((char *) &(port->raddr.sin_addr),
 | 
			
		||||
	    (char *) hp->h_addr, 
 | 
			
		||||
	    hp->h_length);
 | 
			
		||||
    port->raddr.sin_family = AF_INET;
 | 
			
		||||
    port->raddr.sin_port = htons(portName);
 | 
			
		||||
    
 | 
			
		||||
    /* connect to the server */
 | 
			
		||||
    if ((port->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "FATAL: StreamOpen: socket() failed: errno=%d\n",
 | 
			
		||||
		       errno);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    if (connect(port->sock, (struct sockaddr *)&port->raddr,
 | 
			
		||||
		sizeof(port->raddr)) < 0) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "FATAL: StreamOpen: connect() failed: errno=%d\n",
 | 
			
		||||
		       errno);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /* fill in the client address */
 | 
			
		||||
    if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
 | 
			
		||||
		    &laddrlen) < 0) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "FATAL: StreamOpen: getsockname() failed: errno=%d\n",
 | 
			
		||||
		       errno);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return(STATUS_OK);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										124
									
								
								src/backend/libpq/pqcomm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								src/backend/libpq/pqcomm.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,124 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * pqcomm.h--
 | 
			
		||||
 *    Parameters for the communication module
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: pqcomm.h,v 1.1.1.1 1996/07/09 06:21:31 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 * NOTES
 | 
			
		||||
 *    Some of this should move to libpq.h
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
#ifndef PQCOMM_H
 | 
			
		||||
#define	PQCOMM_H
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <winsock.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#endif /* WIN32 */
 | 
			
		||||
 | 
			
		||||
#include "postgres.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * startup msg parameters: path length, argument string length
 | 
			
		||||
 */
 | 
			
		||||
#define PATH_SIZE	64
 | 
			
		||||
#define ARGV_SIZE	64
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef enum _MsgType {
 | 
			
		||||
    ACK_MSG = 0,		/* acknowledge a message */
 | 
			
		||||
    ERROR_MSG=1,		/* error response to client from server */
 | 
			
		||||
    RESET_MSG=2,		/* client must reset connection */
 | 
			
		||||
    PRINT_MSG=3,		/* tuples for client from server */
 | 
			
		||||
    NET_ERROR=4,		/* error in net system call */
 | 
			
		||||
    FUNCTION_MSG=5,		/* fastpath call (unused) */
 | 
			
		||||
    QUERY_MSG=6,		/* client query to server */
 | 
			
		||||
    STARTUP_MSG=7,		/* initialize a connection with a backend */
 | 
			
		||||
    DUPLICATE_MSG=8,		/* duplicate msg arrived (errors msg only) */
 | 
			
		||||
    INVALID_MSG=9,		/* for some control functions */
 | 
			
		||||
    STARTUP_KRB4_MSG=10,	/* krb4 session follows startup packet */
 | 
			
		||||
    STARTUP_KRB5_MSG=11,      	/* krb5 session follows startup packet */
 | 
			
		||||
    STARTUP_HBA_MSG=12         /* use host-based authentication */
 | 
			
		||||
    /* insert new values here -- DO NOT REORDER OR DELETE ENTRIES */
 | 
			
		||||
} MsgType;
 | 
			
		||||
 | 
			
		||||
typedef char *Addr;
 | 
			
		||||
typedef int PacketLen;	/* packet length */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct StartupInfo {
 | 
			
		||||
/*     PacketHdr	hdr; */
 | 
			
		||||
    char		database[PATH_SIZE]; /* database name */
 | 
			
		||||
    char		user[NAMEDATALEN];   /* user name */
 | 
			
		||||
    char		options[ARGV_SIZE];  /* possible additional args */
 | 
			
		||||
    char		execFile[ARGV_SIZE]; /* possible backend to use */
 | 
			
		||||
    char		tty[PATH_SIZE];	     /* possible tty for debug output*/
 | 
			
		||||
} StartupInfo;
 | 
			
		||||
 | 
			
		||||
/* amount of available data in a packet buffer */
 | 
			
		||||
#define MESSAGE_SIZE	sizeof(StartupInfo) + 5
 | 
			
		||||
 | 
			
		||||
/* I/O can be blocking or non-blocking */
 | 
			
		||||
#define BLOCKING 	(FALSE)
 | 
			
		||||
#define NON_BLOCKING	(TRUE)
 | 
			
		||||
 | 
			
		||||
/* a PacketBuf gets shipped from client to server so be careful
 | 
			
		||||
   of differences in representation.  
 | 
			
		||||
   Be sure to use htonl() and ntohl() on the len and msgtype fields! */
 | 
			
		||||
typedef struct PacketBuf {
 | 
			
		||||
    int len;
 | 
			
		||||
    MsgType msgtype;
 | 
			
		||||
    char data[MESSAGE_SIZE];
 | 
			
		||||
} PacketBuf;
 | 
			
		||||
 | 
			
		||||
/* update the conversion routines 
 | 
			
		||||
  StartupInfo2PacketBuf() and PacketBuf2StartupInfo() (decl. below)
 | 
			
		||||
  if StartupInfo or PacketBuf structs ever change */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * socket descriptor port 
 | 
			
		||||
 *	we need addresses of both sides to do authentication calls
 | 
			
		||||
 */
 | 
			
		||||
typedef struct Port {
 | 
			
		||||
    int			sock;	/* file descriptor */
 | 
			
		||||
    int			mask;	/* select mask */
 | 
			
		||||
    int   		nBytes;	/* nBytes read in so far */
 | 
			
		||||
    struct sockaddr_in	laddr;	/* local addr (us) */
 | 
			
		||||
    struct sockaddr_in	raddr;	/* remote addr (them) */
 | 
			
		||||
/*     PacketBufId		id;*/	/* id of packet buf currently in use */ 
 | 
			
		||||
    PacketBuf		buf;	/* stream implementation (curr pack buf) */
 | 
			
		||||
} Port;
 | 
			
		||||
 | 
			
		||||
/* invalid socket descriptor */
 | 
			
		||||
#define INVALID_SOCK	(-1)
 | 
			
		||||
 | 
			
		||||
#define INVALID_ID (-1)
 | 
			
		||||
#define MAX_CONNECTIONS	10
 | 
			
		||||
#define N_PACK_BUFS	20
 | 
			
		||||
 | 
			
		||||
/* no multi-packet messages yet */
 | 
			
		||||
#define MAX_PACKET_BACKLOG	1
 | 
			
		||||
 | 
			
		||||
#define	DEFAULT_STRING		""
 | 
			
		||||
 | 
			
		||||
extern FILE *Pfout, *Pfin;
 | 
			
		||||
extern int PQAsyncNotifyWaiting;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * prototypes for functions in pqpacket.c
 | 
			
		||||
 */
 | 
			
		||||
extern int PacketReceive(Port *port, PacketBuf *buf, bool nonBlocking);
 | 
			
		||||
extern int PacketSend(Port *port, PacketBuf *buf,
 | 
			
		||||
		      PacketLen len, bool nonBlocking);
 | 
			
		||||
/* extern PacketBuf* StartupInfo2PacketBuf(StartupInfo*); */
 | 
			
		||||
/* extern StartupInfo* PacketBuf2StartupInfo(PacketBuf*); */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif	/* PQCOMM_H */
 | 
			
		||||
							
								
								
									
										283
									
								
								src/backend/libpq/pqpacket.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								src/backend/libpq/pqpacket.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,283 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * pqpacket.c--
 | 
			
		||||
 *    routines for reading and writing data packets sent/received by
 | 
			
		||||
 *    POSTGRES clients and servers
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *    $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.1.1.1 1996/07/09 06:21:31 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
/* NOTES
 | 
			
		||||
 *    This is the module that understands the lowest-level part
 | 
			
		||||
 *    of the communication protocol.  All of the trickiness in
 | 
			
		||||
 *    this module is for making sure that non-blocking I/O in
 | 
			
		||||
 *    the Postmaster works correctly.   Check the notes in PacketRecv
 | 
			
		||||
 *    on non-blocking I/O.
 | 
			
		||||
 *
 | 
			
		||||
 * Data Structures:
 | 
			
		||||
 *	Port has two important functions. (1) It records the 
 | 
			
		||||
 *	sock/addr used in communication. (2) It holds partially
 | 
			
		||||
 *	read in messages.  This is especially important when
 | 
			
		||||
 *	we haven't seen enough to construct a complete packet 
 | 
			
		||||
 *	header.
 | 
			
		||||
 *
 | 
			
		||||
 * PacketBuf -- None of the clients of this module should know
 | 
			
		||||
 *	what goes into a packet hdr (although they know how big
 | 
			
		||||
 *	it is).  This routine is in charge of host to net order
 | 
			
		||||
 *	conversion for headers.  Data conversion is someone elses
 | 
			
		||||
 *	responsibility.
 | 
			
		||||
 *
 | 
			
		||||
 * IMPORTANT: these routines are called by backends, clients, and
 | 
			
		||||
 *	the Postmaster.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <netdb.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <winsock.h>
 | 
			
		||||
#endif /*WIN32 */
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include "postgres.h"
 | 
			
		||||
#include "miscadmin.h" 
 | 
			
		||||
#include "utils/elog.h"
 | 
			
		||||
#include "storage/ipc.h"
 | 
			
		||||
#include "libpq/pqcomm.h"	/* where the declarations go */
 | 
			
		||||
#include "libpq/libpq.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * PacketReceive -- receive a packet on a port.
 | 
			
		||||
 *
 | 
			
		||||
 * RETURNS: connection id of the packet sender, if one
 | 
			
		||||
 * is available.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PacketReceive(Port *port,	/* receive port */
 | 
			
		||||
	      PacketBuf *buf,   /* MAX_PACKET_SIZE-worth of buffer space */
 | 
			
		||||
	      bool nonBlocking) /* NON_BLOCKING or BLOCKING i/o */
 | 
			
		||||
{
 | 
			
		||||
    PacketLen   max_size = sizeof(PacketBuf);
 | 
			
		||||
    PacketLen	cc;	    	/* character count -- bytes recvd */
 | 
			
		||||
    PacketLen	packetLen; 	/* remaining packet chars to read */
 | 
			
		||||
    Addr	tmp;	   	/* curr recv buf pointer */
 | 
			
		||||
    int		addrLen = sizeof(struct sockaddr_in);
 | 
			
		||||
    int         hdrLen;
 | 
			
		||||
    int		flag;
 | 
			
		||||
    int		decr;
 | 
			
		||||
    
 | 
			
		||||
    hdrLen = sizeof(buf->len);
 | 
			
		||||
 | 
			
		||||
    if (nonBlocking == NON_BLOCKING) {
 | 
			
		||||
	flag = MSG_PEEK;
 | 
			
		||||
	decr = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
	flag = 0;
 | 
			
		||||
	decr = hdrLen;
 | 
			
		||||
    }
 | 
			
		||||
    /*
 | 
			
		||||
     * Assume port->nBytes is zero unless we were interrupted during
 | 
			
		||||
     * non-blocking I/O.  This first recvfrom() is to get the hdr
 | 
			
		||||
     * information so we know how many bytes to read.  Life would
 | 
			
		||||
     * be very complicated if we read too much data (buffering).
 | 
			
		||||
     */
 | 
			
		||||
    tmp = ((Addr)buf) + port->nBytes;
 | 
			
		||||
 | 
			
		||||
    if (port->nBytes >= hdrLen)  {
 | 
			
		||||
	packetLen = ntohl(buf->len) - port->nBytes;
 | 
			
		||||
    }
 | 
			
		||||
     else {
 | 
			
		||||
      /* peeking into the incoming message */
 | 
			
		||||
       cc = recvfrom(port->sock, (char *)&(buf->len), hdrLen, flag, 
 | 
			
		||||
                      (struct sockaddr*) &(port->raddr), &addrLen);
 | 
			
		||||
	if (cc < hdrLen) {
 | 
			
		||||
	    /* if cc is negative, the system call failed */
 | 
			
		||||
	    if (cc < 0) {
 | 
			
		||||
		return(STATUS_ERROR);
 | 
			
		||||
	    }
 | 
			
		||||
	    /* 
 | 
			
		||||
	     * cc == 0 means the connection was broken at the 
 | 
			
		||||
	     * other end.
 | 
			
		||||
	     */
 | 
			
		||||
	    else if (! cc) {
 | 
			
		||||
		return(STATUS_INVALID);
 | 
			
		||||
		
 | 
			
		||||
	    } else {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Worst case.  We didn't even read in enough data to
 | 
			
		||||
		 * get the header length.
 | 
			
		||||
		 * since we are using a data stream, 
 | 
			
		||||
		 * this happens only if the client is mallicious.
 | 
			
		||||
		 *
 | 
			
		||||
		 * Don't save the number of bytes we've read so far.
 | 
			
		||||
		 * Since we only peeked at the incoming message, the
 | 
			
		||||
		 * kernel is going to keep it for us.
 | 
			
		||||
		 */
 | 
			
		||||
		return(STATUS_NOT_DONE);
 | 
			
		||||
	    }
 | 
			
		||||
	} else {
 | 
			
		||||
	    /*
 | 
			
		||||
	     * great. got the header. now get the true length (including
 | 
			
		||||
	     * header size).
 | 
			
		||||
	     */
 | 
			
		||||
	    packetLen = ntohl(buf->len);
 | 
			
		||||
           /*
 | 
			
		||||
            * if someone is sending us junk, close the connection
 | 
			
		||||
            */
 | 
			
		||||
           if (packetLen > max_size) {
 | 
			
		||||
               port->nBytes = packetLen;
 | 
			
		||||
               return(STATUS_BAD_PACKET);
 | 
			
		||||
           }
 | 
			
		||||
	    packetLen -= decr;
 | 
			
		||||
	    tmp += decr - port->nBytes;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Now that we know how big it is, read the packet.  We read
 | 
			
		||||
     * the entire packet, since the last call was just a peek.
 | 
			
		||||
     */
 | 
			
		||||
    while (packetLen) { 
 | 
			
		||||
	cc = recvfrom(port->sock, tmp, packetLen, 0,
 | 
			
		||||
		      (struct sockaddr*) &(port->raddr), &addrLen);
 | 
			
		||||
	if (cc < 0)
 | 
			
		||||
	    return(STATUS_ERROR);
 | 
			
		||||
	/* 
 | 
			
		||||
	 * cc == 0 means the connection was broken at the 
 | 
			
		||||
	 * other end.
 | 
			
		||||
	 */
 | 
			
		||||
	else if (! cc) 
 | 
			
		||||
	    return(STATUS_INVALID);
 | 
			
		||||
	
 | 
			
		||||
/*
 | 
			
		||||
   fprintf(stderr,"expected packet of %d bytes, got %d bytes\n",
 | 
			
		||||
           packetLen, cc);
 | 
			
		||||
*/
 | 
			
		||||
	tmp += cc;
 | 
			
		||||
	packetLen -= cc;
 | 
			
		||||
	
 | 
			
		||||
	/* if non-blocking, we're done. */
 | 
			
		||||
	if (nonBlocking && packetLen) {
 | 
			
		||||
	    port->nBytes += cc;
 | 
			
		||||
	    return(STATUS_NOT_DONE);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    port->nBytes = 0;
 | 
			
		||||
    return(STATUS_OK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * PacketSend -- send a single-packet message.
 | 
			
		||||
 *
 | 
			
		||||
 * RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
 | 
			
		||||
 * SIDE_EFFECTS: may block.
 | 
			
		||||
 * NOTES: Non-blocking writes would significantly complicate 
 | 
			
		||||
 *	buffer management.  For now, we're not going to do it.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
PacketSend(Port *port,
 | 
			
		||||
	   PacketBuf *buf,
 | 
			
		||||
	   PacketLen len,
 | 
			
		||||
	   bool nonBlocking)
 | 
			
		||||
{
 | 
			
		||||
    PacketLen	totalLen;
 | 
			
		||||
    int		addrLen = sizeof(struct sockaddr_in);
 | 
			
		||||
    
 | 
			
		||||
    Assert(!nonBlocking);
 | 
			
		||||
    Assert(buf);
 | 
			
		||||
    
 | 
			
		||||
    totalLen = len;
 | 
			
		||||
    
 | 
			
		||||
    len = sendto(port->sock, (Addr) buf, totalLen, /* flags */ 0,
 | 
			
		||||
		 (struct sockaddr *)&(port->raddr), addrLen);
 | 
			
		||||
    
 | 
			
		||||
    if (len < totalLen) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "FATAL: PacketSend: couldn't send complete packet: errno=%d\n",
 | 
			
		||||
		       errno);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return(STATUS_OK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * StartupInfo2PacketBuf -
 | 
			
		||||
 *   convert the fields of the StartupInfo to a PacketBuf
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
/* moved to src/libpq/fe-connect.c */
 | 
			
		||||
/*
 | 
			
		||||
PacketBuf* 
 | 
			
		||||
StartupInfo2PacketBuf(StartupInfo* s)
 | 
			
		||||
{
 | 
			
		||||
  PacketBuf* res;
 | 
			
		||||
  char* tmp;
 | 
			
		||||
 | 
			
		||||
  res = (PacketBuf*)malloc(sizeof(PacketBuf));
 | 
			
		||||
  res->len = htonl(sizeof(PacketBuf));
 | 
			
		||||
  res->data[0] = '\0';
 | 
			
		||||
 | 
			
		||||
  tmp= res->data;
 | 
			
		||||
 | 
			
		||||
  strncpy(tmp, s->database, sizeof(s->database));
 | 
			
		||||
  tmp += sizeof(s->database);
 | 
			
		||||
  strncpy(tmp, s->user, sizeof(s->user));
 | 
			
		||||
  tmp += sizeof(s->user);
 | 
			
		||||
  strncpy(tmp, s->options, sizeof(s->options));
 | 
			
		||||
  tmp += sizeof(s->options);
 | 
			
		||||
  strncpy(tmp, s->execFile, sizeof(s->execFile));
 | 
			
		||||
  tmp += sizeof(s->execFile);
 | 
			
		||||
  strncpy(tmp, s->tty, sizeof(s->execFile));
 | 
			
		||||
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * PacketBuf2StartupInfo -
 | 
			
		||||
 *   convert the fields of the StartupInfo to a PacketBuf
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
/* moved to postmaster.c 
 | 
			
		||||
StartupInfo*
 | 
			
		||||
PacketBuf2StartupInfo(PacketBuf* p)
 | 
			
		||||
{
 | 
			
		||||
  StartupInfo* res;
 | 
			
		||||
  char* tmp;
 | 
			
		||||
 | 
			
		||||
  res = (StartupInfo*)malloc(sizeof(StartupInfo));
 | 
			
		||||
 | 
			
		||||
  res->database[0]='\0';
 | 
			
		||||
  res->user[0]='\0';
 | 
			
		||||
  res->options[0]='\0';
 | 
			
		||||
  res->execFile[0]='\0';
 | 
			
		||||
  res->tty[0]='\0';
 | 
			
		||||
 | 
			
		||||
  tmp= p->data;
 | 
			
		||||
  strncpy(res->database,tmp,sizeof(res->database));
 | 
			
		||||
  tmp += sizeof(res->database);
 | 
			
		||||
  strncpy(res->user,tmp, sizeof(res->user));
 | 
			
		||||
  tmp += sizeof(res->user);
 | 
			
		||||
  strncpy(res->options,tmp, sizeof(res->options));
 | 
			
		||||
  tmp += sizeof(res->options);
 | 
			
		||||
  strncpy(res->execFile,tmp, sizeof(res->execFile));
 | 
			
		||||
  tmp += sizeof(res->execFile);
 | 
			
		||||
  strncpy(res->tty,tmp, sizeof(res->tty));
 | 
			
		||||
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
							
								
								
									
										40
									
								
								src/backend/libpq/pqsignal.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/backend/libpq/pqsignal.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * pqsignal.c--
 | 
			
		||||
 *    reliable BSD-style signal(2) routine stolen from RWW who stole it
 | 
			
		||||
 *    from Stevens...
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *    $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.1.1.1 1996/07/09 06:21:31 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 * NOTES
 | 
			
		||||
 *	This shouldn't be in libpq, but the monitor and some other
 | 
			
		||||
 *	things need it...
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
#include "libpq/pqsignal.h"
 | 
			
		||||
 | 
			
		||||
pqsigfunc
 | 
			
		||||
pqsignal(int signo, pqsigfunc func)
 | 
			
		||||
{
 | 
			
		||||
#if defined(USE_POSIX_SIGNALS)
 | 
			
		||||
    struct sigaction act, oact;
 | 
			
		||||
    
 | 
			
		||||
    act.sa_handler = func;
 | 
			
		||||
    sigemptyset(&act.sa_mask);
 | 
			
		||||
    act.sa_flags = 0;
 | 
			
		||||
    if (signo != SIGALRM) {
 | 
			
		||||
	act.sa_flags |= SA_RESTART;
 | 
			
		||||
    }
 | 
			
		||||
    if (sigaction(signo, &act, &oact) < 0)
 | 
			
		||||
	return(SIG_ERR);
 | 
			
		||||
    return(oact.sa_handler);
 | 
			
		||||
#else /* !USE_POSIX_SIGNALS */
 | 
			
		||||
    Assert(0);
 | 
			
		||||
    return 0;
 | 
			
		||||
#endif /* !USE_POSIX_SIGNALS */
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								src/backend/libpq/pqsignal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/backend/libpq/pqsignal.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * pqsignal.h--
 | 
			
		||||
 *    prototypes for the reliable BSD-style signal(2) routine.
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: pqsignal.h,v 1.1.1.1 1996/07/09 06:21:31 scrappy Exp $
 | 
			
		||||
 *
 | 
			
		||||
 * NOTES
 | 
			
		||||
 *    This shouldn't be in libpq, but the monitor and some other
 | 
			
		||||
 *    things need it...
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
#ifndef PQSIGNAL_H
 | 
			
		||||
#define PQSIGNAL_H
 | 
			
		||||
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
 | 
			
		||||
#include "c.h"
 | 
			
		||||
 | 
			
		||||
typedef void (*pqsigfunc)(int);
 | 
			
		||||
 | 
			
		||||
extern pqsigfunc pqsignal(int signo, pqsigfunc func);
 | 
			
		||||
 | 
			
		||||
#if defined(USE_POSIX_SIGNALS)
 | 
			
		||||
#define	signal(signo, handler)	pqsignal(signo, (pqsigfunc)(handler))
 | 
			
		||||
#endif /* USE_POSIX_SIGNALS */
 | 
			
		||||
 | 
			
		||||
#endif	/* PQSIGNAL_H */
 | 
			
		||||
		Reference in New Issue
	
	Block a user