Index: mod_nsd/postgres.c
===================================================================
RCS file: /usr/local/cvsroot/mod_nsd/postgres.c,v
diff -u -r1.2 -r1.4
--- mod_nsd/postgres.c	14 Apr 2001 07:17:26 -0000	1.2
+++ mod_nsd/postgres.c	17 Apr 2001 04:20:12 -0000	1.4
@@ -136,6 +136,17 @@
 /* 2000-12-30: Added bind variable emulation to support acs 4.0 porting.
    dcwickstrom@earthlink.net*/
 
+/* 2001-03-??: Added automatic quoting of emulated bind variables in order
+   to make it compatible with the analogous routine in the Oracle driver.
+   dhogaza@pacifier.com*/
+
+/* 2001-04-14: Added Henry Minsky's patch which echoes changes in the
+   Oracle driver to stream blob data directly to the connection 
+   rather than first spool to a temp file.  Since the call to return
+   the file to the user doesn't return until after the operation is
+   complete, spooling was a waste of time and resource.
+   dhogaza@pacifier.com*/
+
 /* Contributors to this file include:
 
 	Don Baccus		<dhogaza@pacifier.com>
@@ -272,7 +283,9 @@
     int             in_transaction;
 }               NsPgConn;
 
+#ifdef notdef
 DllExport int   Ns_ModuleVersion = 1;
+#endif
 
 static char datestyle[STRING_BUF_LEN];
 
@@ -1077,121 +1090,38 @@
 }
 
 
+/** 
+ * Write the contents of BUFP to a file descriptor or to
+ * the network connection directly.
+ *
+ * Lifted from Oracle driver.
+ */
 static int
-blob_write(Tcl_Interp *interp, Ns_DbHandle *handle, char* lob_id)
+stream_actually_write (int fd, Ns_Conn *conn, void *bufp, int length, int to_conn_p)
 {
-    NsPgConn	*nsConn = (NsPgConn *) handle->connection;
-	char		*filename;
-	int			result;
-	Ns_Conn		*conn;
-	int			segment;
-	char		query[100];
-	int			fd;
-	char		*segment_pos;
-	int			nbytes = 0;
+  int bytes_written = 0;
 
-	/* spool to a tmp file, then return that out the conn
-	 * note that tmpnam returns malloc'd memory.
-	 */
-
-	filename = tempnam (NULL, "tadgp");
-
-	if (filename == NULL) 
-	{
-		Tcl_AppendResult (interp, "could not create temporary file to spool "
-							"BLOB/CLOB result", NULL);
-		return TCL_ERROR;
-	}
-
-
-	fd = open (filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
-
-	if (fd < 0) 
-	{
-		Ns_Log (Error, "Can't open %s for writing. error %d(%s)",
-				filename, errno, strerror(errno));
-		Tcl_AppendResult (interp, "can't open file ", filename,
-				 " for writing. ",
-			"received error ", strerror(errno), NULL);
-		return TCL_ERROR;
-	}
-
-	segment = 1;
-
-	strcpy(query, "SELECT BYTE_LEN, DATA FROM LOB_DATA WHERE LOB_ID = ");
-	strcat(query, lob_id);
-	strcat(query, " AND SEGMENT = ");
-
-	segment_pos = query + strlen(query);
-
-	for (;;) {
-		char	*data_column;
-		char	*byte_len_column;
-		int		i, j, n, byte_len;
-		char	buf[6000];
-
-		sprintf(segment_pos, "%d", segment);
-		if (Ns_PgExec(handle, query) != NS_ROWS) {
-			Tcl_AppendResult(interp, "Error selecting data from BLOB", NULL);
-			return TCL_ERROR;
-		}
-
-		if (PQntuples(nsConn->res) == 0) break;
-
-		byte_len_column = PQgetvalue(nsConn->res, 0, 0);
-		data_column = PQgetvalue(nsConn->res, 0, 1);
-		sscanf(byte_len_column, "%d", &byte_len);
-		nbytes += byte_len;
-		n = byte_len;
-		for (i=0, j=0; n > 0; i += 4, j += 3, n -= 3) {
-			decode3(&data_column[i], &buf[j], n);
-		}
-		write(fd, buf, byte_len);
-		segment++;
+  if (to_conn_p)
+    {
+      if (Ns_WriteConn (conn, bufp, length) == NS_OK) 
+        {
+	  bytes_written = length;
+        } 
+      else 
+        {
+	  bytes_written = 0;
+        }
     }
+  else
+    {
+      bytes_written = write (fd, bufp, length);
+    }
 
-	close(fd);
+  return bytes_written;
+  
+} /* stream_actually_write */
 
-	PQclear(nsConn->res);
-	nsConn->res = NULL;
 
-	conn = Ns_TclGetConn (interp);
-
-	if (conn == NULL) 
-	{
-		Tcl_AppendResult (interp, "no connection", NULL);
-		free (filename);
-		return TCL_ERROR;
-	}
-
-	fd = open (filename, O_RDONLY);
-
-	if (fd == -1) 
-	{
-		Ns_Log (Error, "Error opening file %s: %d(%s)",
-				filename, errno, strerror(errno));
-		Tcl_AppendResult (interp, "can't open file ", filename,	
-				 " for reading. ", "received error ", strerror(errno), NULL);
-		return TCL_ERROR;
-	}
-	  
-	result = Ns_ConnSendFd (conn, fd, nbytes);
-
-	close (fd);
-
-	if (result != NS_OK) 
-	{
-		Tcl_AppendResult (interp, "could not return file ", filename, NULL);
-		free (filename);
-		return TCL_ERROR;
-	}
-
-	unlink (filename);
-	free (filename);
-
-	return TCL_OK;
-}
-
 /* ns_pg blob_put blob_id value
  * Stuff the contents of value into the pseudo-blob blob_id
  */
@@ -1285,83 +1215,103 @@
  * DanW - This is just blob_write, except it doesn't send anything out the
  *        connection.
  * .
+ * Combined blob_select_file and blob_write:
+ * If you want to write to the network connection, set TO_CONN_P to TRUE
+ * and pass a null filename.
+ *
+ * If you want to write the blob to a file, set TO_CONN_P = FALSE, and
+ * pass the filename in.
  */
 
 static int
-blob_select_file(Tcl_Interp *interp, Ns_DbHandle *handle, char* lob_id, 
-                                                          char* filename)
+blob_send_to_stream(Tcl_Interp *interp, Ns_DbHandle *handle, char* lob_id, 
+		    int to_conn_p, char* filename)
 {
-    NsPgConn	*nsConn = (NsPgConn *) handle->connection;
-	int			segment;
-	char		query[100];
-	int			fd;
-	char		*segment_pos;
-	int			nbytes = 0;
+  NsPgConn	*nsConn = (NsPgConn *) handle->connection;
+  int		segment;
+  char		query[100];
+  int		fd;
+  char		*segment_pos;
+  Ns_Conn       *conn;
 
-	/* spool to a tmp file, then return that out the conn
-	 * note that tmpnam returns malloc'd memory.
-	 */
+  if (to_conn_p) 
+    {  
+      conn = Ns_TclGetConn(interp);
+      
+      /* this Shouldn't Happen, but spew an error just in case */
+      if (conn == NULL) 
+        {
+	  Ns_Log (Error, "blob_send_to_stream: No AOLserver conn available");
 
-	if (filename == NULL) 
+	  Tcl_AppendResult (interp, "No AOLserver conn available", NULL);
+	  goto bailout;
+        }
+    } else {
+      if (filename == NULL) 
 	{
-		Tcl_AppendResult (interp, "could not create temporary file to spool "
-							"BLOB/CLOB result", NULL);
-		return TCL_ERROR;
+	  Tcl_AppendResult (interp, "could not create temporary file to spool "
+			    "BLOB/CLOB result", NULL);
+	  return TCL_ERROR;
 	}
 
 
-	fd = open (filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+      fd = open (filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
 
-	if (fd < 0) 
+      if (fd < 0) 
 	{
-		Ns_Log (Error, "Can't open %s for writing. error %d(%s)",
-				filename, errno, strerror(errno));
-		Tcl_AppendResult (interp, "can't open file ", filename,
-				 " for writing. ",
-			"received error ", strerror(errno), NULL);
-		return TCL_ERROR;
+	  Ns_Log (Error, "Can't open %s for writing. error %d(%s)",
+		  filename, errno, strerror(errno));
+	  Tcl_AppendResult (interp, "can't open file ", filename,
+			    " for writing. ",
+			    "received error ", strerror(errno), NULL);
+	  return TCL_ERROR;
 	}
+    }
 
-	segment = 1;
+  segment = 1;
 
-	strcpy(query, "SELECT BYTE_LEN, DATA FROM LOB_DATA WHERE LOB_ID = ");
-	strcat(query, lob_id);
-	strcat(query, " AND SEGMENT = ");
+  strcpy(query, "SELECT BYTE_LEN, DATA FROM LOB_DATA WHERE LOB_ID = ");
+  strcat(query, lob_id);
+  strcat(query, " AND SEGMENT = ");
 
-	segment_pos = query + strlen(query);
+  segment_pos = query + strlen(query);
 
-	for (;;) {
-		char	*data_column;
-		char	*byte_len_column;
-		int		i, j, n, byte_len;
-		char	buf[6000];
+  for (;;) {
+    char	*data_column;
+    char	*byte_len_column;
+    int		i, j, n, byte_len;
+    char	buf[6000];
 
-		sprintf(segment_pos, "%d", segment);
-		if (Ns_PgExec(handle, query) != NS_ROWS) {
-			Tcl_AppendResult(interp, "Error selecting data from BLOB", NULL);
-			return TCL_ERROR;
-		}
+    sprintf(segment_pos, "%d", segment);
+    if (Ns_PgExec(handle, query) != NS_ROWS) {
+      Tcl_AppendResult(interp, "Error selecting data from BLOB", NULL);
+      return TCL_ERROR;
+    }
 
-		if (PQntuples(nsConn->res) == 0) break;
+    if (PQntuples(nsConn->res) == 0) break;
 
-		byte_len_column = PQgetvalue(nsConn->res, 0, 0);
-		data_column = PQgetvalue(nsConn->res, 0, 1);
-		sscanf(byte_len_column, "%d", &byte_len);
-		nbytes += byte_len;
-		n = byte_len;
-		for (i=0, j=0; n > 0; i += 4, j += 3, n -= 3) {
-			decode3(&data_column[i], &buf[j], n);
-		}
-		write(fd, buf, byte_len);
-		segment++;
-        }
+    byte_len_column = PQgetvalue(nsConn->res, 0, 0);
+    data_column = PQgetvalue(nsConn->res, 0, 1);
+    sscanf(byte_len_column, "%d", &byte_len);
+    n = byte_len;
+    for (i=0, j=0; n > 0; i += 4, j += 3, n -= 3) {
+      decode3(&data_column[i], &buf[j], n);
+    }
 
-	close(fd);
+    stream_actually_write (fd, conn, buf, byte_len, to_conn_p);
+    segment++;
+  }
 
-	PQclear(nsConn->res);
-	nsConn->res = NULL;
+ bailout:
+  if (!to_conn_p)
+    {
+      close (fd);
+    }
 
-	return TCL_OK;
+  PQclear(nsConn->res);
+  nsConn->res = NULL;
+
+  return TCL_OK;
 }
 
 
@@ -1836,7 +1786,7 @@
                          	argv[0], " command dbId blobId\"", NULL);
         	return TCL_ERROR;
 		}
-		return blob_write(interp, handle, argv[3]);
+		return blob_send_to_stream(interp, handle, argv[3], TRUE, NULL);
 	} else if (!strcmp(argv[1], "blob_get")) {
     	if (argc != 4) {
         	Tcl_AppendResult(interp, "wrong # args: should be \"",
@@ -1879,7 +1829,7 @@
                          	argv[0], " command dbId blobId filename\"", NULL);          
         	return TCL_ERROR;
         }
-                return blob_select_file(interp, handle, argv[3], argv[4]);
+                return blob_send_to_stream(interp, handle, argv[3], FALSE, argv[4]);
     }
 
 #endif /* FOR_ACS_USE */