Here is a patch to add a few functions to libpq:

PQmakeResult: creates a new result with attributes but no rows
PQsetValue: set a field inside a result, creating a row if necessary
(but only one at a time)
PQresultAlloc (basically public wrapper to existing internal function).

also, the attribute structure (but not the result) is moved to the
public header.

We thought these functions, particularly PQsetValue, are something
positive that came out of the libpqtypes dicussions.

merlin
Index: interfaces/libpq/exports.txt
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/exports.txt,v
retrieving revision 1.19
diff -C6 -r1.19 exports.txt
*** interfaces/libpq/exports.txt	19 Mar 2008 00:39:33 -0000	1.19
--- interfaces/libpq/exports.txt	15 Apr 2008 14:22:00 -0000
***************
*** 138,143 ****
--- 138,146 ----
  PQsendDescribePortal      136
  lo_truncate               137
  PQconnectionUsedPassword  138
  pg_valid_server_encoding_id 139
  PQconnectionNeedsPassword 140
  lo_import_with_oid		  141
+ PQmakeResult              142
+ PQsetvalue                143
+ PQresultAlloc             144
Index: interfaces/libpq/fe-exec.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v
retrieving revision 1.194
diff -C6 -r1.194 fe-exec.c
*** interfaces/libpq/fe-exec.c	1 Jan 2008 19:46:00 -0000	1.194
--- interfaces/libpq/fe-exec.c	15 Apr 2008 14:22:00 -0000
***************
*** 60,72 ****
  				int resultFormat);
  static void parseInput(PGconn *conn);
  static bool PQexecStart(PGconn *conn);
  static PGresult *PQexecFinish(PGconn *conn);
  static int PQsendDescribe(PGconn *conn, char desc_type,
  			   const char *desc_target);
! 
  
  /* ----------------
   * Space management for PGresult.
   *
   * Formerly, libpq did a separate malloc() for each field of each tuple
   * returned by a query.  This was remarkably expensive --- malloc/free
--- 60,73 ----
  				int resultFormat);
  static void parseInput(PGconn *conn);
  static bool PQexecStart(PGconn *conn);
  static PGresult *PQexecFinish(PGconn *conn);
  static int PQsendDescribe(PGconn *conn, char desc_type,
  			   const char *desc_target);
! static int check_field_number(const PGresult *res,
! 				int field_num);
  
  /* ----------------
   * Space management for PGresult.
   *
   * Formerly, libpq did a separate malloc() for each field of each tuple
   * returned by a query.  This was remarkably expensive --- malloc/free
***************
*** 192,203 ****
--- 193,338 ----
  		result->client_encoding = PG_SQL_ASCII;
  	}
  
  	return result;
  }
  
+ PGresult *
+ PQmakeResult(const PGconn *conn, int numAttributes,
+   PGresAttDesc *attDescs)
+ {
+ 	int i;
+ 	PGresult *res;
+ 
+ 	if(numAttributes <= 0 || !attDescs)
+ 		return NULL;
+ 
+ 	res = PQmakeEmptyPGresult((PGconn *)conn, PGRES_TUPLES_OK);
+ 	if(!res)
+ 		return NULL;
+ 
+ 	res->attDescs = (PGresAttDesc *)
+ 		pqResultAlloc(res, numAttributes * sizeof(PGresAttDesc), TRUE);
+ 
+ 	if(!res->attDescs)
+ 	{
+ 		PQclear(res);
+ 		return NULL;
+ 	}
+ 
+ 	res->numAttributes = numAttributes;
+ 	memcpy(res->attDescs, attDescs, numAttributes * sizeof(PGresAttDesc));
+ 
+ 	/* resultalloc the attribute names. */
+ 	res->binary = 1;
+ 	for(i=0; i < numAttributes; i++)
+ 	{
+ 		if(attDescs[i].name)
+ 			res->attDescs[i].name = pqResultStrdup(res, attDescs[i].name);
+ 		else
+ 			res->attDescs[i].name = res->null_field;
+ 
+ 		if(!res->attDescs[i].name)
+ 		{
+ 			PQclear(res);
+ 			return NULL;
+ 		}
+ 
+ 		/* Although deprecated, because results can have text+binary columns,
+ 		 * its easy enough to deduce so set it for completeness.
+ 		 */
+ 		if(res->attDescs[i].format == 0)
+ 			res->binary = 0;
+ 	}
+ 
+ 	return res;
+ }
+ 
+ int
+ PQsetvalue(PGresult *res, int tup_num, int field_num,
+ 	char *value, int len)
+ {
+ 	PGresAttValue *attval;
+ 
+ 	if(!check_field_number(res, field_num))
+ 		return FALSE;
+ 
+ 	/* Invalid tup_num, must be <= ntups */
+ 	if(tup_num > res->ntups)
+ 		return FALSE;
+ 
+ 	/* need to grow the tuple table */
+ 	if(res->ntups >= res->tupArrSize)
+ 	{
+ 		int n = res->tupArrSize ? (res->tupArrSize*3)/2 : 64;
+ 		PGresAttValue **tups = (PGresAttValue **)
+ 			(res->tuples ? realloc(res->tuples, n*sizeof(PGresAttValue *)) :
+ 			 malloc(n*sizeof(PGresAttValue *)));
+ 
+ 		if(!tups)
+ 			return FALSE;
+ 
+ 		res->tuples = tups;
+ 		res->tupArrSize = n;
+ 	}
+ 
+ 	/* new to allocate a new tuple */
+ 	if(tup_num == res->ntups && !res->tuples[tup_num])
+ 	{
+ 		int i;
+ 		PGresAttValue *tup = (PGresAttValue *)pqResultAlloc(
+ 			res, res->numAttributes * sizeof(PGresAttValue), TRUE);
+ 
+ 		if(!tup)
+ 			return FALSE;
+ 
+ 		/* initialize each column to NULL */
+ 		for(i=0; i < res->numAttributes; i++)
+ 		{
+ 			tup[i].len = NULL_LEN;
+ 			tup[i].value = res->null_field;
+ 		}
+ 
+ 		res->tuples[tup_num] = tup;
+ 		res->ntups++;
+ 	}
+ 
+ 	attval = &res->tuples[tup_num][field_num];
+ 
+ 	/* On top of NULL_LEN, treat a NULL value as a NULL field */
+ 	if(len == NULL_LEN || value == NULL)
+ 	{
+ 		attval->len = NULL_LEN;
+ 		attval->value = res->null_field;
+ 	}
+ 	else
+ 	{
+ 		if(len < 0)
+ 			len = 0;
+ 
+ 		attval->value = (char *)pqResultAlloc(res, len + 1, TRUE);
+ 		if(!attval->value)
+ 			return FALSE;
+ 
+ 		attval->len = len;
+ 		memcpy(attval->value, value, len);
+ 		attval->value[len] = '\0';
+ 	}
+ 
+ 	return TRUE;
+ }
+ 
+ /* wrapper for pqResultAlloc, avoids refactoring pqResultAlloc
+  * to PQresultAlloc everywhere.  Always sets isBinary to TRUE.
+  */
+ void *
+ PQresultAlloc(PGresult *res, size_t nBytes)
+ {
+ 	return pqResultAlloc(res, nBytes, TRUE);
+ }
+ 
  /*
   * pqResultAlloc -
   *		Allocate subsidiary storage for a PGresult.
   *
   * nBytes is the amount of space needed for the object.
   * If isBinary is true, we assume that we need to align the object on
Index: interfaces/libpq/libpq-fe.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/libpq-fe.h,v
retrieving revision 1.142
diff -C6 -r1.142 libpq-fe.h
*** interfaces/libpq/libpq-fe.h	19 Mar 2008 00:39:33 -0000	1.142
--- interfaces/libpq/libpq-fe.h	15 Apr 2008 14:22:01 -0000
***************
*** 189,200 ****
--- 189,212 ----
  	{
  		int		   *ptr;		/* can't use void (dec compiler barfs)	 */
  		int			integer;
  	}			u;
  } PQArgBlock;
  
+ /* Data about a single attribute (column) of a query result */
+ typedef struct pgresAttDesc
+ {
+ 	char	   *name;			/* column name */
+ 	Oid			tableid;		/* source table, if known */
+ 	int			columnid;		/* source column, if known */
+ 	int			format;			/* format code for value (text/binary) */
+ 	Oid			typid;			/* type id */
+ 	int			typlen;			/* type size */
+ 	int			atttypmod;		/* type-specific modifier info */
+ } PGresAttDesc;
+ 
  /* ----------------
   * Exported functions of libpq
   * ----------------
   */
  
  /* ===	in fe-connect.c === */
***************
*** 414,425 ****
--- 426,463 ----
  /* Describe prepared statements and portals */
  extern PGresult *PQdescribePrepared(PGconn *conn, const char *stmt);
  extern PGresult *PQdescribePortal(PGconn *conn, const char *portal);
  extern int	PQsendDescribePrepared(PGconn *conn, const char *stmt);
  extern int	PQsendDescribePortal(PGconn *conn, const char *portal);
  
+ /*
+  * Makes a new result using the provided field descriptors.
+  * If conn is not NULL, some information will be copied to the
+  * new result. The returned result has zero tuples and a
+  * resultStatus of  PGRES_TUPLES_OK. To add tuples and set field
+  * values, see PQsetvalue.
+  */
+ extern PGresult *
+ PQmakeResult(const PGconn *conn, int numAttributes,
+   PGresAttDesc *attDescs);
+ 
+ /* Allocate subsidiary storage for a PGresult. */
+ extern void *
+ PQresultAlloc(PGresult *res, size_t nBytes);
+ 
+ /*
+  * Sets the value for a tuple field.  The tup_num must be less than or
+  * equal to PQntuples(res).  This function will generate tuples as needed.
+  * A new tuple is generated when tup_num equals PQntuples(res) and there
+  * are no fields defined for that tuple.
+  * Returns a non-zero value for success and zero for failure.
+  */
+ extern int
+ PQsetvalue(PGresult *res, int tup_num, int field_num,
+ 	char *value, int len);
+ 
  /* Delete a PGresult */
  extern void PQclear(PGresult *res);
  
  /* For freeing other alloc'd results, such as PGnotify structs */
  extern void PQfreemem(void *ptr);
  
Index: interfaces/libpq/libpq-int.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/libpq-int.h,v
retrieving revision 1.129
diff -C6 -r1.129 libpq-int.h
*** interfaces/libpq/libpq-int.h	1 Jan 2008 19:46:00 -0000	1.129
--- interfaces/libpq/libpq-int.h	15 Apr 2008 14:22:01 -0000
***************
*** 97,121 ****
  union pgresult_data
  {
  	PGresult_data *next;		/* link to next block, or NULL */
  	char		space[1];		/* dummy for accessing block as bytes */
  };
  
- /* Data about a single attribute (column) of a query result */
- 
- typedef struct pgresAttDesc
- {
- 	char	   *name;			/* column name */
- 	Oid			tableid;		/* source table, if known */
- 	int			columnid;		/* source column, if known */
- 	int			format;			/* format code for value (text/binary) */
- 	Oid			typid;			/* type id */
- 	int			typlen;			/* type size */
- 	int			atttypmod;		/* type-specific modifier info */
- } PGresAttDesc;
- 
  /* Data about a single parameter of a prepared statement */
  typedef struct pgresParamDesc
  {
  	Oid			typid;			/* type id */
  } PGresParamDesc;
  
--- 97,108 ----
-- 
Sent via pgsql-patches mailing list (pgsql-patches@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-patches

Reply via email to