libpq_desc_msg.patch.1

text/plain

Filename: libpq_desc_msg.patch.1
Type: text/plain
Part: 0
Message: libpq Describe Extension [WAS: Bytea and perl]
? src/interfaces/libpq/.deps
? src/interfaces/libpq/cscope.out
? src/interfaces/libpq/libpq.so.4.2
Index: doc/src/sgml/libpq.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/libpq.sgml,v
retrieving revision 1.206
diff -c -r1.206 libpq.sgml
*** doc/src/sgml/libpq.sgml	10 Mar 2006 19:10:48 -0000	1.206
--- doc/src/sgml/libpq.sgml	1 Apr 2006 18:27:41 -0000
***************
*** 2045,2053 ****
  </varlistentry>
  
  <varlistentry>
! <term><function>PQprint</function><indexterm><primary>PQprint</></></term>
  <listitem>
  <para>
            Prints out all the rows and,  optionally,  the
            column names  to  the specified output stream.
  <synopsis>
--- 2045,2081 ----
  </varlistentry>
  
  <varlistentry>
! <term><function>PQdescPrepared</function><indexterm><primary>PQdescPrepared</></></term>
! <term><function>PQdescPortal</function><indexterm><primary>PQdescPortal</></></term>
  <listitem>
  <para>
+ 	Describe a prepared statement or portal.
+ 	<synopsis>int PQdescPrepared(PGconn *conn, const char *stmt);</synopsis>
+ 	<synopsis>int PQdescPortal(PGconn *conn, const char *portal);</synopsis>
+ </para>
+ <para>
+ 	These two functions are used to describe a prepared statement or portal.
+ 	Functions return 1 on success and 0 on failure. (An appropriate error
+ 	message will be placed in an error situation.) <symbol>NULL</> values in
+ 	the <parameter>stmt</> and <parameter>portal</> parameters will be treated
+ 	as an empty string.
+ </para>
+ <para>
+ 	After a <function>PQdescPrepared</> or <function>PQdescPortal</> function
+ 	call, issuing a <function>PQgetResult</> will place backend's response
+ 	into a <structname>PGresult</structname> structure - that'll be
+ 	extractable via <function>PQftype</>.
+ </para>
+ <para>
+ 	These functions are available within extended query protocol which is
+ 	available in version 3.0 and above.
+ </para>
+ </listitem>
+ </varlistentry>
+ 
+ <varlistentry>
+ <term><function>PQprint</function><indexterm><primary>PQprint</></></term>
+ <para>
            Prints out all the rows and,  optionally,  the
            column names  to  the specified output stream.
  <synopsis>
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/postgres.c,v
retrieving revision 1.482
diff -c -r1.482 postgres.c
*** src/backend/tcop/postgres.c	14 Mar 2006 22:48:21 -0000	1.482
--- src/backend/tcop/postgres.c	1 Apr 2006 18:28:08 -0000
***************
*** 3391,3396 ****
--- 3391,3398 ----
  									   describe_type)));
  							break;
  					}
+ 				
+ 					send_ready_for_query = true;
  				}
  				break;
  
Index: src/interfaces/libpq/fe-exec.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v
retrieving revision 1.182
diff -c -r1.182 fe-exec.c
*** src/interfaces/libpq/fe-exec.c	14 Mar 2006 22:48:23 -0000	1.182
--- src/interfaces/libpq/fe-exec.c	1 Apr 2006 18:28:15 -0000
***************
*** 55,60 ****
--- 55,62 ----
  static void parseInput(PGconn *conn);
  static bool PQexecStart(PGconn *conn);
  static PGresult *PQexecFinish(PGconn *conn);
+ static int pqDescribe(PGconn *conn, const char desc_type,
+ 					  const char *desc_target);
  
  
  /* ----------------
***************
*** 2281,2286 ****
--- 2283,2400 ----
  		return 0;
  }
  
+ 
+ /*
+  * pqDescribe - Describe given prepared statement or portal.
+  *
+  * Available options for target_type are
+  *   's' to describe a prepared statement; or
+  *   'p' to describe a portal.
+  * Returns 1 on success and 0 on failure.
+  *
+  * By issuing a PQgetResult(), response from the server will be placed
+  * in an empty PGresult that will be extractable via PQftype().
+  */
+ static int
+ pqDescribe(PGconn *conn, const char desc_type, const char *desc_target)
+ {
+ 	int	ret;
+ 
+ 	/* This isn't gonna work on a 2.0 server. */
+ 	if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
+ 	{
+ 		printfPQExpBuffer(&conn->errorMessage,
+ 						  libpq_gettext("function requires at least protocol version 3.0\n"));
+ 		return 0;
+ 	}
+ 	
+ 	if (!conn)
+ 		return 0;
+ 	
+ 	/* Clear the connection error message. */
+ 	resetPQExpBuffer(&conn->errorMessage);
+ 
+ 	/* Don't try to send if we know there's no live connection. */
+ 	if (conn->status != CONNECTION_OK)
+ 	{
+ 		printfPQExpBuffer(&conn->errorMessage,
+ 						  libpq_gettext("no connection to the server\n"));
+ 		return false;
+ 	}
+ 	
+ 	/* Can't send while already busy, either. */
+ 	if (conn->asyncStatus != PGASYNC_IDLE)
+ 	{
+ 		printfPQExpBuffer(&conn->errorMessage,
+ 						  libpq_gettext("another command is already in progress\n"));
+ 		return false;
+ 	}
+ 
+ 	/* Initialize async result-accumulation state. */
+ 	conn->result = NULL;
+ 	conn->curTuple = NULL;
+ 	
+ 	if (desc_target)
+ 	{
+ 		int		len = strlen(desc_target) + 2;
+ 		char	buf[len];
+ 
+ 		snprintf(buf, len, "%c%s", desc_type, desc_target);
+ 
+ 		/*
+ 		 * Flushing stuff will be handled by pqPacketSend(). (Although
+ 		 * this theoretically could block, it really shouldn't for
+ 		 * these kind of small messages.)
+ 		 */
+ 		ret = pqPacketSend(conn, 'D', buf, len);
+ 	}
+ 	
+ 	/* NULL desc_target values will be treated as an empty string. */
+ 	else
+ 	{
+ 		int		len = 2;
+ 		char	buf[len];
+ 
+ 		buf[0] = desc_type;
+ 		buf[1] = '\0';
+ 		ret = pqPacketSend(conn, 'D', buf, len);
+ 	}
+ 
+ 	/* In case of a pqPacketSend() failure... */
+ 	if (ret != STATUS_OK)
+ 	{
+ 		pqHandleSendFailure(conn);
+ 		return 0;
+ 	}
+ 
+ 	/* Remember we are using extended query protocol. */
+ 	conn->queryclass = PGQUERY_EXTENDED;
+ 
+ 	/* Free last query string. */
+ 	if (conn->last_query)
+ 	{
+ 		free(conn->last_query);
+ 		conn->last_query = NULL;
+ 	}
+ 
+ 	/* Describe request is sent. */
+ 	conn->asyncStatus = PGASYNC_BUSY;
+ 	return 1;
+ }
+ 
+ int
+ PQdescPrepared(PGconn *conn, const char *stmt)
+ {
+ 	return pqDescribe(conn, 'S', stmt);
+ }
+ 
+ int
+ PQdescPortal(PGconn *conn, const char *portal)
+ {
+ 	return pqDescribe(conn, 'P', portal);
+ }
+ 
+ 
  /* PQsetnonblocking:
   *	sets the PGconn's database connection non-blocking if the arg is TRUE
   *	or makes it non-blocking if the arg is FALSE, this will not protect
***************
*** 2346,2351 ****
--- 2460,2466 ----
  	free(ptr);
  }
  
+ 
  /*
   * PQfreeNotify - free's the memory associated with a PGnotify
   *
Index: src/interfaces/libpq/fe-protocol3.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/fe-protocol3.c,v
retrieving revision 1.26
diff -c -r1.26 fe-protocol3.c
*** src/interfaces/libpq/fe-protocol3.c	14 Mar 2006 22:48:23 -0000	1.26
--- src/interfaces/libpq/fe-protocol3.c	1 Apr 2006 18:28:22 -0000
***************
*** 50,55 ****
--- 50,56 ----
  static int	getNotify(PGconn *conn);
  static int	getCopyStart(PGconn *conn, ExecStatusType copytype);
  static int	getReadyForQuery(PGconn *conn);
+ static int	getParamDescriptions(PGconn *conn);
  static void reportErrorPosition(PQExpBuffer msg, const char *query,
  								int loc, int encoding);
  static int build_startup_packet(const PGconn *conn, char *packet,
***************
*** 350,355 ****
--- 351,375 ----
  					 * the COPY command.
  					 */
  					break;
+ 				case 't':		/* Parameter Description */
+ 					if (!conn->result)
+ 					{
+ 						if (!getParamDescriptions(conn))	/* Success. */
+ 							break;
+ 						else								/* Not enough data or an error. */
+ 							return;
+ 					}
+ 					else
+ 					{
+ 						/*
+ 						 * We'll use a new PGresult to place 't' input. Thus,
+ 						 * we stop parsing until the application accepts the
+ 						 * current result.
+ 						 */
+ 						conn->asyncStatus = PGASYNC_READY;
+ 						return;
+ 					}
+ 					break;
  				default:
  					printfPQExpBuffer(&conn->errorMessage,
  									  libpq_gettext(
***************
*** 1154,1159 ****
--- 1174,1249 ----
  }
  
  /*
+  * getParamDescriptions - process ParameterDescription message.
+  *
+  * We'll place parsed message information into a new PGresult. (Only
+  * parameter description attributes are going to be reliable.)
+  * Returns 0 if parsing is completed, 1 if there isn't enough data yet
+  * and -1 if there occurs an error.
+  */
+ static int
+ getParamDescriptions(PGconn *conn)
+ {
+ 	PGresult	*res;
+ 	int			 nattr;
+ 	int			 i;
+ 	Oid			 typid;
+ 
+ 	res = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK);
+ 	if (!res)
+ 	{
+ 		printfPQExpBuffer(&conn->errorMessage,
+ 						  libpq_gettext("out of memory\n"));
+ 		goto Error;
+ 	}
+ 	
+ 	/*
+ 	 * parseInput() already read the 't' label and message length.
+ 	 * The next byte is the number of parameters used by the
+ 	 * statement (may be zero).
+ 	 */
+ 	if (pqGetInt(&nattr, 2, conn) < 0)
+ 		goto NotEnoughData;
+ 	res->numAttributes = nattr;
+ 
+ 	/* Allocate space for the attribute descriptors. */		
+ 	if (nattr > 0)
+ 	{
+ 		int sz = nattr * sizeof(PGresAttDesc);
+ 		
+ 		res->attDescs = (PGresAttDesc *) pqResultAlloc(res, sz, TRUE);
+ 		if (!res->attDescs)
+ 		{
+ 			printfPQExpBuffer(&conn->errorMessage,
+ 							  libpq_gettext("out of memory\n"));
+ 			goto Error;
+ 		}
+ 		
+ 		MemSet(res->attDescs, 0, sz);
+ 	}
+ 
+ 	/* Loop through attribute's type OIDs. */
+ 	for (i = 0; i < nattr; i++)
+ 	{
+ 		if (pqGetInt(&typid, 4, conn) < 0)
+ 			goto NotEnoughData;
+ 		res->attDescs[i].typid = typid;
+ 	}
+ 
+ 	/* Success. */
+ 	conn->result = res;
+ 	return 0;
+ 
+ NotEnoughData:
+ 	PQclear(res);
+ 	return 1;
+ 
+ Error:
+ 	PQclear(res);
+ 	return -1;
+ }
+ 
+ /*
   * PQgetCopyData - read a row of data from the backend during COPY OUT
   *
   * If successful, sets *buffer to point to a malloc'd row of data, and
Index: src/interfaces/libpq/libpq-fe.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/libpq-fe.h,v
retrieving revision 1.126
diff -c -r1.126 libpq-fe.h
*** src/interfaces/libpq/libpq-fe.h	20 Mar 2006 15:07:05 -0000	1.126
--- src/interfaces/libpq/libpq-fe.h	1 Apr 2006 18:28:25 -0000
***************
*** 414,419 ****
--- 414,423 ----
  extern int	PQgetlength(const PGresult *res, int tup_num, int field_num);
  extern int	PQgetisnull(const PGresult *res, int tup_num, int field_num);
  
+ /* Describe prepared statements or portals. */
+ extern int	PQdescPrepared(PGconn *conn, const char *stmt);
+ extern int	PQdescPortal(PGconn *conn, const char *portal);
+ 
  /* Delete a PGresult */
  extern void PQclear(PGresult *res);