head	1.1;
access;
symbols;
locks; strict;
comment	@ * @;


1.1
date	94.10.17.20.52.31;	author jolly;	state Exp;
branches;
next	;


desc
@@


1.1
log
@Initial revision
@
text
@/* pqutils:  a bunch of routines to make dealing with libpq a little easier */

/* these are the exported routines:

   char* text2str(text* textarg)
   text* str2text(char* str)
   char* pq_exec(char* querybuf, char* where)
   PortalBuffer* do_query(char* querybuf, char* where)
   char* get_attr(PortalBuffer* portalbuf, int tupno, int attno)
   long get_attr_long(PortalBuffer* portalbuf, int tupno, int attno)
   void* bin_get_attr(PortalBuffer* portalbuf, int tupno, int attno)
   char* bin_get_attr_char16(PortalBuffer* portalbuf, int tupno, int attno)
   char* bin_get_attr_text(PortalBuffer* portalbuf, int tupno, int attno)
   char* bin_get_attr_long(PortalBuffer* portalbuf, int tupno, int attno)
*/


#include <stdio.h>
#include <string.h>
#include <varargs.h>

/* #define malloc post_malloc */                                             
/* #define free post_free */

#include "libpq-fe.h"
/*
#include "postgres.h"
#include "c.h"
*/

/* #undef malloc */
/* #undef free */

extern char PQerrormsg[];

#include "pqutils.h"

int g_pqutil_debug = 0;

#define PQUTILS_ERRLOG_MAXLEN 512

/*********************************************
text2str:
     takes a text varlena and returns a char* 
    the CALLER is responsible for freeing the memory of the char* returned
******************************************* **/

char* text2str(text* textarg)
{
  int len;
  char* result;

  if (textarg == NULL)		/* NULL text* */
    return "";
  len = VARSIZE(textarg) - VARHDRSZ;
  result = (char*)palloc(len+1); 
  strncpy(result, VARDATA(textarg), len);
  result[len] = '\0';
  return result;
}
/*********************************************
str2text:
    takes a null-terminated characters string and convert it to a text varlena
******************************************* **/
text* str2text(char* str)
{
  int size;
  text* result;

  if (str == NULL)
    {
      size = VARHDRSZ + 1;
      str = "";
    }
  else
    size = strlen(str) + 1 + VARHDRSZ;
  
  result = (text*)palloc(size);
  VARSIZE(result) = size;
  strcpy(VARDATA(result), str);
  return result;
}


/****************************************
pq_exec: 
     like PQexec
     send a query to the postgres backend 
     checks the libpq result, reporting an error if there is one 

     returns the result string

     the first argument is the query string,  the second is the name of the
     procedure sending the query (used for more meaningful error messages)
*****************************************/
char* pq_exec(char* querybuf, char* where)
{
  char* res;

if (g_pqutil_debug & PQUTIL_DEBUG_EXEC)
  fprintf(stderr,"sending query: %s: %s\n", where, querybuf);

  res = PQexec(querybuf);
  if ( (*res == 'E') || (*res == 'R') )
    {
/*
    pqutils_err(PQUTILS_ERROR, "%s: error while executing query: \n\t %s\n", where, querybuf);
    pqutils_err(PQUTILS_ERROR, "result = %s, error is %s\n", res, PQerrormsg);
*/
      /* an error message will be given higher up in the libtdb layer */
      return "E";
    }

if (g_pqutil_debug & PQUTIL_DEBUG_EXEC)
  fprintf(stderr,"query completed, res = %s\n",res);
}

/****************************************
  do_query:
           like pq_exec
	   returns a PortalBuffer if the query result is a portal,
	       otherwise, return NULL.
*****************************************/
PortalBuffer* do_query(char* querybuf, char* where)
{
  char* res;
  res = pq_exec(querybuf,where);
  if (*res != 'P')
    {
    pqutils_err(PQUTILS_ERROR, "error: no portal from \n%s\n",querybuf);
    return (PortalBuffer*)NULL;
  }
  else
    return PQparray(++res);
}     

/****************************************
  get_attr:
     get an attribute from the buffer, by tuple number and attribute number
     The attribute value must be a null terminated string.  
        (in other words, use this only for ascii portals, not binary portals)
     the CALLER is responsible for freeing the string returned
     NULL attributes are converted to the NULLATTR_STRING
*****************************************/
char* get_attr(portalbuf, tupno, attno)
    PortalBuffer* portalbuf;
    int tupno;
    int attno;
{
    char *attval;
    char *result;

if (g_pqutil_debug & PQUTIL_DEBUG_GETATTR)
  fprintf(stderr,"calling get_attr() with portalbuf = %X, tupno = %d, attno = %d\n",
	  portalbuf, tupno, attno);

    attval = PQgetvalue(portalbuf, tupno, attno);
    if (attval)
      {
      result = (char *) palloc(strlen(attval) + 1);
      strcpy(result, attval);
    }
    else
      {
      result = (char *) palloc(strlen(NULLATTR_STRING) + 1);
      strcpy(result, NULLATTR_STRING);
    }
if (g_pqutil_debug & PQUTIL_DEBUG_GETATTR)
  fprintf(stderr,"exiting get_attr()\n");
    return (result);
}

/****************************************
get_attr_long:
    use this only if the attribute is a long
    this saves the effort of allocating and freeing space for the string 
    if the attribute is null, 0 is returned.
*****************************************/
long get_attr_long(portalbuf, tupno, attno)
    PortalBuffer* portalbuf;
    int tupno;
    int attno;
{
  
  char *attval;
  long result = 0;

  attval = PQgetvalue(portalbuf, tupno, attno);
  if (attval)
      result = strtol(attval,NULL,10);
  return result;
}

/****************************************
bin_get_attr:
    get an attribute from a binary portal.  the result is a void*
    the CALLER is responsible for freeing the space allocated
*****************************************/
void* bin_get_attr(portalbuf, tupno, attno)
    PortalBuffer* portalbuf;
    int tupno;
    int attno;
{
    struct varlena *attval;
    void *result;
    int size;
    
    attval = (struct varlena*)((char*)PQgetvalue(portalbuf, tupno, attno) - VARHDRSZ);

    if (attval)
      {
	size = PQgetlength(portalbuf, tupno, attno);
	attval->vl_len = size + VARHDRSZ;
	result = (void *) palloc(size);
	memmove(result,attval,size);
    }
    else
      {
      result = (void *) palloc(strlen(NULLATTR_STRING) + 1);
      strcpy(result, NULLATTR_STRING);
    }

    return (result);
}

/****************************************
bin_get_attr_char16:
   use this for getting char16 attributes from binary portals.
   returns a null-terminated string.
   CALLER is responsible for freeing the space allocated.
*****************************************/

char* bin_get_attr_char16(portalbuf, tupno, attno)
    PortalBuffer* portalbuf;
    int tupno;
    int attno;
{
    char* attval;
    char* result;
    int size;
    
    attval = (char*)PQgetvalue(portalbuf, tupno, attno);

    if (attval)
      {
	size = PQgetlength(portalbuf, tupno, attno);
	/* size-4 because the size field is included, +1 for the '\0' */
	size -= VARHDRSZ;
	result = (char *) palloc(size+1);
	bcopy(attval, result, size);
	result[size] = '\0';
    }
    else
      {
      result = (char *) palloc(strlen(NULLATTR_STRING) + 1);
      strcpy(result, NULLATTR_STRING);
    }
    return (result);
}

/****************************************
bin_get_attr_text:
   use this for getting text attributes from binary portals.
   returns a null-terminated string.
   CALLER is responsible for freeing the space allocated.
*****************************************/
char* bin_get_attr_text(portalbuf, tupno, attno)
    PortalBuffer* portalbuf;
    int tupno;
    int attno;
{
    text* attval;
    char* result;
    int size;
    
    attval = (struct varlena*)((char*)PQgetvalue(portalbuf, tupno, attno) - VARHDRSZ);
    attval->vl_len  = PQgetlength(portalbuf, tupno, attno) + VARHDRSZ;

    if (attval)
	result = text2str(attval);
    else
      {
      result = (char *) palloc(strlen(NULLATTR_STRING) + 1);
      strcpy(result, NULLATTR_STRING);
    }
    return (result);
}

/****************************************
bin_get_attr_long:
   use this for getting attributes of type long from binary portals.
   returns a long
   if the attribute is null, 0 is returned
*****************************************/
long bin_get_attr_long(PortalBuffer* portalbuf, int tupno, int attno) 
{
  long *attval;
  long result = 0;

  attval = (long*)PQgetvalue(portalbuf, tupno, attno);
  if (attval)
      result = *attval;
  return result;
}


/****************************************
parseTextArray:

   parse an text[]:
   given a string and an integer length, parse into an array of char*,
   input strings are of the form   {"A","B","C","D"} 

   the CALLER is responsible for allocating sufficient number of char*'s
   in the string array,

   parseTextArray will allocate space for each individual char*
*****************************************/
void parseTextArray(char* str, int num, char** strArray)
{
  int i;
  char* beginQuote;
  char* endQuote;
  int nextlen;

  if (*str != '{')
    {
    pqutils_err(PQUTILS_WARN,"parseTextArray(): badly formed string, must have { as first character\n");
    return;
  }
  str++; /* skip the first { */
  for (i=0;i<num;i++)
    {
      if (*str == '\0')
	{ pqutils_err(PQUTILS_WARN,"parseTextArray(): text string ended prematurely\n");
	  return;
	}
      if  ( (beginQuote = index(str,'"')) == NULL)
	{
	pqutils_err(PQUTILS_WARN,"parseTextArray():  missing a begin quote\n");
	return;
      }
      if  ( (endQuote = index(beginQuote+1,'"')) == NULL)
	{
	pqutils_err(PQUTILS_WARN,"parseTextArray():  missing a begin quote\n");
	return;
      }
      nextlen = endQuote - beginQuote; /* don't subtract one here because we need the extra character for \0 anyway */
      strArray[i] =(char*) malloc(nextlen);
      strncpy(strArray[i], beginQuote+1, nextlen-1);
      strArray[i][nextlen-1] ='\0';
      str = endQuote + 1;
    }
}

/****************************************
   a varargs interface to print out pqutils errors,  similar to elog
*****************************************/
void pqutils_err(va_alist)
va_dcl
{
        va_list ap;
        register int    lev;
        char            *fmt;
        char            buf[PQUTILS_ERRLOG_MAXLEN], line[PQUTILS_ERRLOG_MAXLEN];
        register char   *bp, *cp;
        extern  int     errno, sys_nerr;
        extern  char    *sys_errlist[], *ctime();
        time_t          tim, time();
        int             i = 0;

        va_start(ap);
        lev = va_arg(ap, int);
        fmt = va_arg(ap, char *);
        switch (lev) {
        case PQUTILS_DEBUG:
                cp = "DEBUG:";
                break;
        case PQUTILS_WARN:
                cp = "WARN:";
                break;
        case PQUTILS_ERROR:
                cp = "ERROR:";
                break;
        default:
                sprintf(line, "FATAL %d:", lev);
                cp = line;
        }
        time(&tim);
        strcat(strcpy(buf, cp), ctime(&tim)+4);
        bp = buf+strlen(buf)-6;
        *bp++ = ':';
        while (i-- >0) *bp++ = ' ';
        for (cp = fmt; *cp; cp++)
                if (*cp == '%' && *(cp+1) == 'm') {
                        if (errno < sys_nerr && errno >= 0)
                                strcpy(bp, sys_errlist[errno]);
                        else
                                sprintf(bp, "error %d", errno);
                        bp += strlen(bp);
                        cp++;
                } else
                        *bp++ = *cp;
        *bp = '\0';
        vsprintf(line, buf, ap);
        va_end(ap);
        strcat(line, "\n");
	fputs(line, stderr);
}

/* this is a stub for the real GetAttributeByName.  This helps us in
   being to compile and link certain modules both statically and dynamically */
char* GetAttributeByName(tuple, attname, isnull)
     TUPLE tuple;
     char* attname;
     bool* isnull;
{
  pqutils_err(PQUTILS_ERROR, "GetAttributeByName should never be called by statically linked procedure!");
  exit(1);
  return NULL;
}
@
