From 812a6c2b546850e9f9721b580698d5a161e5d76e Mon Sep 17 00:00:00 2001
From: "Marc G. Fournier" <scrappy@hub.org>
Date: Tue, 18 Mar 1997 20:15:39 +0000
Subject: [PATCH]   - Move most of the I/O in both libpq and the backend to a
 set     of common routines in pqcomprim.c (pq communication primitives).    
 Not all adapted to it yet, but it's a start.

  - Rewritten some of those routines, to write/read bigger chunks of
    data, precomputing stuff in buffers instead of sending out byte
    by byte.

  - As a consequence, I need to know the endianness of the machine.
    Currently I rely on getting it from machine/endian.h, but this
    may not be available everywhere? (Who the hell thought it was
    a good idea to pass integers to the backend the other way around
    than the normal network byte order? *argl*)

  - Libpq looks in the environment for magic variables, and upon
    establishing a connection to the backend, sends it queries
    of the form "SET var_name TO 'var_value'". This needs a change
    in the backend parser (Mr. Parser, are you there? :)

  - Currently it looks for two Env-Vars, namely PG_DATEFORMAT
    and PG_FLOATFORMAT. What else makes sense? PG_TIMEFORMAT?
    PG_TIMEZONE?

From: "Martin J. Laubach" <mjl@wwx.vip.at>
---
 src/backend/libpq/Makefile        |   4 +-
 src/backend/libpq/pqcomm.c        | 141 ++++++++++++++------------
 src/backend/libpq/pqcomprim.c     | 158 ++++++++++++++++++++++++++++++
 src/backend/utils/init/globals.c  |   5 +-
 src/include/miscadmin.h           |   5 +-
 src/interfaces/libpq/fe-connect.c |  30 +++++-
 6 files changed, 275 insertions(+), 68 deletions(-)

diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile
index a7c7f13704e..84b2b9a3a38 100644
--- a/src/backend/libpq/Makefile
+++ b/src/backend/libpq/Makefile
@@ -4,7 +4,7 @@
 #    Makefile for libpq subsystem (backend half of libpq interface)
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.5 1997/03/12 21:17:45 scrappy Exp $
+#    $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.6 1997/03/18 20:14:32 scrappy Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -23,7 +23,7 @@ CFLAGS+= $(KRBFLAGS)
 LDADD+= $(KRBLIBS)
 endif
 
-OBJS = be-dumpdata.o be-fsstubs.o be-pqexec.o \
+OBJS = be-dumpdata.o be-fsstubs.o be-pqexec.o pqcomprim.o\
        auth.o hba.o pqcomm.o portal.o util.o portalbuf.o pqpacket.o pqsignal.o \
        password.o
 
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 6b8ecdac28b..10fa738c0fd 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -1,4 +1,4 @@
-/*-------------------------------------------------------------------------
+ /*-------------------------------------------------------------------------
  *
  * pqcomm.c--
  *    Communication functions between the Frontend and the Backend
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.12 1997/03/12 21:17:58 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.13 1997/03/18 20:14:33 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -206,26 +206,29 @@ pq_getstr(char *s, int maxlen)
  *		 the line ended within maxlen bytes.)
  *	1 in other cases
  */
-int
-PQgetline(char *s, int maxlen)
-{
-    int c = '\0';
-    
+int PQgetline(char *s, int maxlen)
+	{
     if (!Pfin || !s || maxlen <= 1)
 	return(EOF);
     
-    for (; maxlen > 1 && (c = pq_getc(Pfin)) != '\n' && c != EOF; --maxlen) {
-	*s++ = c;
-    }
+   if(fgets(s, maxlen - 1, Pfin) == NULL)
+   	{
+   	return feof(Pfin) ? EOF : 1;
+   	}
+   else
+   	{
+   	for( ; *s; *s++)
+   		{
+   		if(*s == '\n')
+   			{
     *s = '\0';
+   			break;
+   			}
+   		}
+   	}
     
-    if (c == EOF) {
-	return(EOF);		/* error -- reached EOF before \n */
-    } else if (c == '\n') {
-	return(0);		/* done with this line */
+   return 0;
     }
-    return(1);			/* returning a full buffer */
-}
 
 /*
  * USER FUNCTION - sends a string to the backend.
@@ -252,6 +255,9 @@ PQputline(char *s)
 int
 pq_getnchar(char *s, int off, int maxlen)
 {
+	return pqGetNBytes(s + off, maxlen, Pfin);
+
+#if 0
     int	c = '\0';
     
     if (Pfin == (FILE *) NULL) {
@@ -270,6 +276,7 @@ pq_getnchar(char *s, int off, int maxlen)
     if (c == EOF)
 	return(EOF);
     return(!EOF);
+#endif
 }
 
 /* --------------------------------
@@ -282,20 +289,38 @@ pq_getnchar(char *s, int off, int maxlen)
 int
 pq_getint(int b)
 {
-    int	n, c, p;
-    
-    if (Pfin == (FILE *) NULL) {
-/*	elog(DEBUG, "pq_getint: Input descriptor is null"); */
-	return(EOF);
+    int n, status = 1;
+    
+    if(!Pfin)
+    	return EOF;    
+    /* mjl: Seems inconsisten w/ return value of pq_putint (void). Also,
+    	EOF is a valid return value for an int! XXX */
+    	    
+    switch(b)
+    	{
+    	case 1:
+    	    status = ((n = fgetc(Pfin)) == EOF);
+    	    break;
+    	case 2:
+    	    pqGetShort(&n, Pfin);
+    	    break;
+    	case 4:
+    	    pqGetLong(&n, Pfin);
+    	    break;
+    	default:
+    	    fprintf(stderr, "** Unsupported size %d\n", b);
     }
     
-    n = p = 0;
-    while (b-- && (c = pq_getc(Pfin)) != EOF && p < 32) {
-	n |= (c & 0xff) << p;
-	p += 8;
+    if(status)
+    	{
+	(void) sprintf(PQerrormsg,
+    	    "FATAL: pq_getint failed: errno=%d\n", errno);
+    	fputs(PQerrormsg, stderr);
+    	pqdebug("%s", PQerrormsg);
+    	n = 0;
     }
     
-    return(n);
+    return n;
 }
 
 /* --------------------------------
@@ -305,26 +330,13 @@ pq_getint(int b)
 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) {
+	if(pqPutString(s, Pfout))
+		{
 	    (void) sprintf(PQerrormsg,
-			   "FATAL: pq_putstr: fputc() failed: errno=%d\n",
-			   errno);
+			"FATAL: pq_putstr: fputs() failed: errno=%d\n", errno);
 	    fputs(PQerrormsg, stderr);
 	    pqdebug("%s", PQerrormsg);
 	}
-    }
 }
 
 /* --------------------------------
@@ -333,13 +345,9 @@ pq_putstr(char *s)
  */
 void
 pq_putnchar(char *s, int n)
-{
-    int status;
-    
-    if (Pfout) {
-	while (n--) {
-	    status = fputc(*s++, Pfout);
-	    if (status == EOF) {
+	{
+	if(pqPutNBytes(s, n, Pfout))
+		{	
 		(void) sprintf(PQerrormsg,
 			       "FATAL: pq_putnchar: fputc() failed: errno=%d\n",
 			       errno);
@@ -347,8 +355,6 @@ pq_putnchar(char *s, int n)
 		pqdebug("%s", PQerrormsg);
 	    }
 	}
-    }
-}
 
 /* --------------------------------
  *	pq_putint - send an integer to connection
@@ -362,22 +368,31 @@ 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) {
+    if(!Pfout)	return;
+    
+    status = 1;
+    switch(b)
+    	{
+    	case 1:
+    	    status = (fputc(i, Pfout) == EOF);
+    	    break;
+       	case 2:
+    	    status = pqPutShort(i, Pfout);
+    	    break;
+    	case 4:
+    	    status = pqPutLong(i, Pfout);
+    	    break;
+    	default:
+    	    fprintf(stderr, "** Unsupported size %d\n", b);
+    	}
+
+    if(status)
+    	{
 		(void) sprintf(PQerrormsg,
-			       "FATAL: pq_putint: fputc() failed: errno=%d\n",
-			       errno);
+    	    "FATAL: pq_putint failed: errno=%d\n", errno);
 		fputs(PQerrormsg, stderr);
 		pqdebug("%s", PQerrormsg);
 	    }
-	}
-    }
 }
 
 /* ---
diff --git a/src/backend/libpq/pqcomprim.c b/src/backend/libpq/pqcomprim.c
index fa1fc866b88..abb634b536f 100644
--- a/src/backend/libpq/pqcomprim.c
+++ b/src/backend/libpq/pqcomprim.c
@@ -27,6 +27,164 @@
 #error Please write byte order macros
 #endif
 
+/* --------------------------------------------------------------------- */
+int pqPutShort(const int integer, FILE *f)
+    {
+    int retval = 0;
+    u_short n;
+		
+    n = hton_s(integer);
+    if(fwrite(&n, sizeof(u_short), 1, f) != 1)
+    	retval = EOF;
+    
+    return retval;
+    }
+
+/* --------------------------------------------------------------------- */
+int pqPutLong(const int integer, FILE *f)
+    {
+    int retval = 0;
+    u_long n;
+		
+    n = hton_l(integer);
+    if(fwrite(&n, sizeof(u_long), 1, f) != 1)
+    	retval = EOF;
+    
+    return retval;
+    }
+    
+/* --------------------------------------------------------------------- */
+int pqGetShort(int *result, FILE *f)
+    {
+    int retval = 0;
+    u_short n;
+
+    if(fread(&n, sizeof(u_short), 1, f) != 1)
+    	retval = EOF;
+			
+    *result = ntoh_s(n);
+    return retval;
+    }
+
+/* --------------------------------------------------------------------- */
+int pqGetLong(int *result, FILE *f)
+    {
+    int retval = 0;
+    u_long n;
+		
+    if(fread(&n, sizeof(u_long), 1, f) != 1)
+    	retval = EOF;
+			
+    *result = ntoh_l(n);
+    return retval;
+    }
+
+/* --------------------------------------------------------------------- */
+/* pqGetNBytes: Read a chunk of exactly len bytes in buffer s.
+	Return 0 if ok.
+*/
+int pqGetNBytes(char* s, const int len, FILE *f)
+	{
+	int cnt;
+
+	if (f == NULL)
+		return EOF;
+  
+	cnt = fread(s, 1, len, f);
+	s[cnt] = '\0';
+   /* mjl: actually needs up to len+1 bytes, is this okay? XXX */
+
+	return (cnt == len) ? 0 : EOF;
+	}
+
+/* --------------------------------------------------------------------- */
+int pqPutNBytes(const char *s, const int len, FILE *f)
+	{    
+	if (f == NULL)
+		return 0;
+
+   if(fwrite(s, 1, len, f) != len)
+	    return EOF;
+
+	return 0;
+	}
+	
+/* --------------------------------------------------------------------- */
+int pqGetString(char *s, int len, FILE *f)
+	{
+	int c;
+
+	if (f == NULL)
+	return EOF;
+  
+	while (len-- && (c = getc(f)) != EOF && c)
+		*s++ = c;
+	*s = '\0';
+   /* mjl: actually needs up to len+1 bytes, is this okay? XXX */
+
+	return 0;
+	}
+
+/* --------------------------------------------------------------------- */
+int pqPutString(const char *s, FILE *f)
+	{
+	if (f == NULL)
+		return 0;
+  
+	if (fputs(s, f) == EOF)
+		return EOF;
+
+	fputc('\0', f); /* important to send an ending \0 since backend expects it */
+	fflush(f);
+
+	return 0;
+	}
+
+/* --------------------------------------------------------------------- */
+int pqGetByte(FILE *f)
+	{
+	return getc(f);
+	}
+	
+/* --------------------------------------------------------------------- */
+int pqPutByte(const int c, FILE *f)
+	{
+	if(!f)	return 0;
+	
+	return (putc(c, f) == c) ? 0 : EOF;
+	}
+	
+/* --------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "postgres.h"
+#include "libpq/pqcomm.h"
+
+/* --------------------------------------------------------------------- */
+/* Is the other way around than system ntoh/hton, so we roll our own
+	here */
+	
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define ntoh_s(n) n
+#define ntoh_l(n) n
+#define hton_s(n) n
+#define hton_l(n) n
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+#define ntoh_s(n) (u_short)(((u_char *) &n)[0] << 8 | ((u_char *) &n)[1]);
+#define ntoh_l(n) (u_long)(((u_char *)&n)[0] << 24 | ((u_char *)&n)[1] << 16 |\
+      	             	   ((u_char *)&n)[2] << 8 | ((u_char *)&n)[3]);
+#define hton_s(n) (ntoh_s(n))
+#define hton_l(n) (ntoh_l(n))
+#endif
+#if BYTE_ORDER == PDP_ENDIAN
+#endif
+#ifndef ntoh_s
+#error Please write byte order macros
+#endif
+
 /* --------------------------------------------------------------------- */
 int pqPutShort(const int integer, FILE *f)
     {
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 65ea4b10dd4..d5fa06071f3 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.6 1997/03/18 16:35:46 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.7 1997/03/18 20:14:46 scrappy Exp $
  *
  * NOTES
  *    Globals used all over the place should be declared here and not
@@ -71,6 +71,9 @@ bool		CDayLight = false;
 int		CTimeZone = 0;
 char		CTZName[8] = "";
 
+char DateFormat[20] 	= "%d-%m-%Y";	/* mjl: sizes! or better malloc? XXX */
+char FloatFormat[20] = "%f";
+
 char *IndexedCatalogNames[] = {
     AttributeRelationName,
     ProcedureRelationName,
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 81fcece3463..a7648feb99a 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -11,7 +11,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: miscadmin.h,v 1.6 1997/03/18 16:36:23 scrappy Exp $
+ * $Id: miscadmin.h,v 1.7 1997/03/18 20:15:19 scrappy Exp $
  *
  * NOTES
  *    some of the information in this file will be moved to
@@ -70,6 +70,9 @@ extern bool	    CDayLight;
 extern int	    CTimeZone;
 extern char	    CTZName[];
 
+extern char FloatFormat[];
+extern char DateFormat[];
+
 extern Oid	    LastOidProcessed;	/* for query rewrite */
 
 #define MAX_PARSE_BUFFER 8192
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 60f55ae5993..4b3a8630a51 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.24 1997/03/12 21:23:09 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.25 1997/03/18 20:15:39 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -100,6 +100,16 @@ static PQconninfoOption PQconninfoOptions[] = {
     			NULL,				NULL, 0	}
 };
 
+struct EnvironmentOptions
+	{
+	const char *envName, *pgName;
+	} EnvironmentOptions[] =
+	{
+		{ "PG_DATEFORMAT",	"pg_dateformat" },
+		{ "PG_FLOATFORMAT",	"pg_floatformat" },
+		{ NULL }
+	};
+	
 /* ----------------
  *	PQconnectdb
  * 
@@ -514,6 +524,24 @@ connectDB(PGconn *conn)
     
     conn->port = port;
 
+		{	
+		struct EnvironmentOptions *eo;
+		char setQuery[80]; /* mjl: size okay? XXX */
+		
+		for(eo = EnvironmentOptions; eo->envName; eo++)
+			{
+			const char *val;
+			
+			if(val = getenv(eo->envName))
+				{
+				PGresult *res;
+				
+				sprintf(setQuery, "SET %s TO \".60%s\"", eo->pgName, val);
+				res = PQexec(conn, setQuery);
+				PQclear(res);	/* Don't care? */
+				}
+			}
+		}
     return CONNECTION_OK;
 
 connect_errReturn:
-- 
GitLab