From 294f0d4bd66af9b74beba1efaeb318045a5a060b Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Mon, 4 Mar 2002 23:59:14 +0000 Subject: [PATCH] Add PQunescapeBytea libpq function. Everyone using libpq and bytea is probably having to invent this wheel.. Patrick Welche --- doc/src/sgml/libpq.sgml | 21 +++++++- src/include/utils/elog.h | 45 ++++++++-------- src/interfaces/libpq/fe-exec.c | 91 ++++++++++++++++++++++++++++++++- src/interfaces/libpq/libpq-fe.h | 5 +- 4 files changed, 137 insertions(+), 25 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index d487cce5cc..34ab2bb59f 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1,5 +1,5 @@ @@ -955,6 +955,25 @@ strings overlap. byte is also added. The single quotes that must surround PostgreSQL string literals are not part of the result string. + + + PQunescapeBytea + Converts an escaped string representation of binary data into binary + data - the reverse of PQescapeBytea. + + unsigned char *PQunescapeBytea(unsigned char *from, size_t *to_length); + + + The from parameter points to an escaped string + such as might be returned by PQgetvalue of a + BYTEA column. PQunescapeBytea converts + this NUL terminated string representation into binary, filling a buffer. + It returns a pointer to the buffer which is NULL on error, and the size + of the buffer in to_length. The pointer may + subsequently be used as an argument to the function + free(3). + + diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index 0b72865e39..2d8dc4ea5c 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: elog.h,v 1.32 2002/03/04 01:46:04 tgl Exp $ + * $Id: elog.h,v 1.33 2002/03/04 23:59:14 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -15,27 +15,28 @@ #define ELOG_H /* Error level codes */ -#define DEBUG5 10 /* Debugging messages, in categories - * of decreasing detail. */ -#define DEBUG4 11 -#define DEBUG3 12 -#define DEBUG2 13 -#define DEBUG1 14 -#define LOG 15 /* Server operational history messages; - * sent only to server log by default. */ -#define COMMERROR 16 /* Client communication problems; same as - * LOG for server reporting, but never ever - * try to send to client. */ -#define INFO 17 /* Informative messages that are part of - * normal query operation; sent only to - * client by default. */ -#define NOTICE 18 /* Important messages, for unusual cases that - * should be reported but are not serious - * enough to abort the query. Sent to client - * and server log by default. */ -#define ERROR 19 /* user error - return to known state */ -#define FATAL 20 /* fatal error - abort process */ -#define PANIC 21 /* take down the other backends with me */ +#define DEBUG5 10 /* Debugging messages, in categories + * of decreasing detail. */ +#define DEBUG4 11 +#define DEBUG3 12 +#define DEBUG2 13 +#define DEBUG1 14 +#define LOG 15 /* Server operational history messages; + * sent only to server log by default. */ +#define COMMERROR 16 /* Client communication problems; same as + * LOG for server reporting, but never ever + * try to send to client. */ +#define INFO 17 /* Informative messages that are part of + * normal query operation; sent only to + * client by default. */ +#define INFOALWAYS 18 /* Like INFO, but always prints to client */ +#define NOTICE 19 /* Important messages, for unusual cases that + * should be reported but are not serious + * enough to abort the query. Sent to client + * and server log by default. */ +#define ERROR 20 /* user error - return to known state */ +#define FATAL 21 /* fatal error - abort process */ +#define PANIC 22 /* take down the other backends with me */ /*#define DEBUG DEBUG1*/ /* Backward compatibility with pre-7.3 */ diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 123d7abd12..7eeaefbb55 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.113 2001/10/25 05:50:13 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.114 2002/03/04 23:59:14 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -180,6 +180,95 @@ PQescapeBytea(unsigned char *bintext, size_t binlen, size_t *bytealen) return result; } +/* + * PQunescapeBytea - converts the null terminated string representation + * of a bytea, strtext, into binary, filling a buffer. It returns a + * pointer to the buffer which is NULL on error, and the size of the + * buffer in retbuflen. The pointer may subsequently be used as an + * argument to the function free(3). It is the reverse of PQescapeBytea. + * + * The following transformations are reversed: + * '\0' == ASCII 0 == \000 + * '\'' == ASCII 39 == \' + * '\\' == ASCII 92 == \\ + * + * States: + * 0 normal 0->1->2->3->4 + * 1 \ 1->5 + * 2 \0 1->6 + * 3 \00 + * 4 \000 + * 5 \' + * 6 \\ + */ +unsigned char * +PQunescapeBytea(unsigned char *strtext, size_t *retbuflen) +{ + size_t buflen; + unsigned char *buffer, *sp, *bp; + unsigned int state=0; + + if(strtext == NULL)return NULL; + buflen = strlen(strtext); /* will shrink, also we discover if strtext */ + buffer = (unsigned char *) malloc(buflen); /* isn't NULL terminated */ + if(buffer == NULL)return NULL; + for(bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++) + { + switch(state) + { + case 0: + if(*sp == '\\')state=1; + *bp = *sp; + break; + case 1: + if(*sp == '\'') /* state=5 */ + { /* replace \' with 39 */ + bp--; + *bp = 39; + buflen--; + state=0; + } + else if(*sp == '\\') /* state=6 */ + { /* replace \\ with 92 */ + bp--; + *bp = 92; + buflen--; + state=0; + } + else + { + if(*sp == '0')state=2; + else state=0; + *bp = *sp; + } + break; + case 2: + if(*sp == '0')state=3; + else state=0; + *bp = *sp; + break; + case 3: + if(*sp == '0') /* state=4 */ + { + bp -= 3; + *bp = 0; + buflen -= 3; + state=0; + } + else + { + *bp = *sp; + state=0; + } + break; + } + } + realloc(buffer,buflen); + + *retbuflen=buflen; + return buffer; +} + /* ---------------- * Space management for PGresult. * diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 02dbe104d0..b94b5aae0a 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: libpq-fe.h,v 1.80 2001/11/08 20:37:52 momjian Exp $ + * $Id: libpq-fe.h,v 1.81 2002/03/04 23:59:14 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -252,6 +252,9 @@ extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn, extern size_t PQescapeString(char *to, const char *from, size_t length); extern unsigned char *PQescapeBytea(unsigned char *bintext, size_t binlen, size_t *bytealen); +extern unsigned char *PQunescapeBytea(unsigned char *strtext, + size_t *retbuflen); + /* Simple synchronous query */ extern PGresult *PQexec(PGconn *conn, const char *query);