summaryrefslogtreecommitdiff
path: root/src/backend/libpq
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
committerMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
commitd31084e9d1118b25fd16580d9d8c2924b5740dff (patch)
tree3179e66307d54df9c7b966543550e601eb55e668 /src/backend/libpq
downloadpostgresql-d31084e9d1118b25fd16580d9d8c2924b5740dff.tar.gz
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/libpq')
-rw-r--r--src/backend/libpq/Makefile.inc26
-rw-r--r--src/backend/libpq/auth.c668
-rw-r--r--src/backend/libpq/auth.h49
-rw-r--r--src/backend/libpq/be-dumpdata.c323
-rw-r--r--src/backend/libpq/be-fsstubs.c351
-rw-r--r--src/backend/libpq/be-fsstubs.h32
-rw-r--r--src/backend/libpq/be-pqexec.c382
-rw-r--r--src/backend/libpq/libpq-be.h51
-rw-r--r--src/backend/libpq/libpq-fs.h119
-rw-r--r--src/backend/libpq/libpq.h261
-rw-r--r--src/backend/libpq/portal.c783
-rw-r--r--src/backend/libpq/portalbuf.c511
-rw-r--r--src/backend/libpq/pqcomm.c724
-rw-r--r--src/backend/libpq/pqcomm.h124
-rw-r--r--src/backend/libpq/pqpacket.c283
-rw-r--r--src/backend/libpq/pqsignal.c40
-rw-r--r--src/backend/libpq/pqsignal.h32
17 files changed, 4759 insertions, 0 deletions
diff --git a/src/backend/libpq/Makefile.inc b/src/backend/libpq/Makefile.inc
new file mode 100644
index 0000000000..67052518d3
--- /dev/null
+++ b/src/backend/libpq/Makefile.inc
@@ -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
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
new file mode 100644
index 0000000000..7b4437736f
--- /dev/null
+++ b/src/backend/libpq/auth.c
@@ -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);
+}
diff --git a/src/backend/libpq/auth.h b/src/backend/libpq/auth.h
new file mode 100644
index 0000000000..adda8dc13c
--- /dev/null
+++ b/src/backend/libpq/auth.h
@@ -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 */
diff --git a/src/backend/libpq/be-dumpdata.c b/src/backend/libpq/be-dumpdata.c
new file mode 100644
index 0000000000..fb6b90c149
--- /dev/null
+++ b/src/backend/libpq/be-dumpdata.c
@@ -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);
+}
diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c
new file mode 100644
index 0000000000..e32cd3b474
--- /dev/null
+++ b/src/backend/libpq/be-fsstubs.c
@@ -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;
+}
diff --git a/src/backend/libpq/be-fsstubs.h b/src/backend/libpq/be-fsstubs.h
new file mode 100644
index 0000000000..3929f42a69
--- /dev/null
+++ b/src/backend/libpq/be-fsstubs.h
@@ -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 */
diff --git a/src/backend/libpq/be-pqexec.c b/src/backend/libpq/be-pqexec.c
new file mode 100644
index 0000000000..1b1738d4fc
--- /dev/null
+++ b/src/backend/libpq/be-pqexec.c
@@ -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);
+}
diff --git a/src/backend/libpq/libpq-be.h b/src/backend/libpq/libpq-be.h
new file mode 100644
index 0000000000..b73ca59455
--- /dev/null
+++ b/src/backend/libpq/libpq-be.h
@@ -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 */
diff --git a/src/backend/libpq/libpq-fs.h b/src/backend/libpq/libpq-fs.h
new file mode 100644
index 0000000000..76f1f84c30
--- /dev/null
+++ b/src/backend/libpq/libpq-fs.h
@@ -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 */
diff --git a/src/backend/libpq/libpq.h b/src/backend/libpq/libpq.h
new file mode 100644
index 0000000000..5fafbb148d
--- /dev/null
+++ b/src/backend/libpq/libpq.h
@@ -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 */
diff --git a/src/backend/libpq/portal.c b/src/backend/libpq/portal.c
new file mode 100644
index 0000000000..ca27fd8308
--- /dev/null
+++ b/src/backend/libpq/portal.c
@@ -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));
+}
diff --git a/src/backend/libpq/portalbuf.c b/src/backend/libpq/portalbuf.c
new file mode 100644
index 0000000000..f927e268ed
--- /dev/null
+++ b/src/backend/libpq/portalbuf.c
@@ -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;
+}
+
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
new file mode 100644
index 0000000000..7fc4a85f20
--- /dev/null
+++ b/src/backend/libpq/pqcomm.c
@@ -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);
+}
diff --git a/src/backend/libpq/pqcomm.h b/src/backend/libpq/pqcomm.h
new file mode 100644
index 0000000000..a7870871ea
--- /dev/null
+++ b/src/backend/libpq/pqcomm.h
@@ -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 */
diff --git a/src/backend/libpq/pqpacket.c b/src/backend/libpq/pqpacket.c
new file mode 100644
index 0000000000..edf373d1af
--- /dev/null
+++ b/src/backend/libpq/pqpacket.c
@@ -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;
+}
+*/
diff --git a/src/backend/libpq/pqsignal.c b/src/backend/libpq/pqsignal.c
new file mode 100644
index 0000000000..b60a5659cc
--- /dev/null
+++ b/src/backend/libpq/pqsignal.c
@@ -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 */
+}
diff --git a/src/backend/libpq/pqsignal.h b/src/backend/libpq/pqsignal.h
new file mode 100644
index 0000000000..44f10882f2
--- /dev/null
+++ b/src/backend/libpq/pqsignal.h
@@ -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 */