From 79d78bb26a61989e52b5a39b5a094d73e9c97d94 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Thu, 12 Jul 2001 14:05:31 +0000 Subject: [PATCH] Add missing encode file. --- src/backend/utils/adt/encode.c | 346 ++++++++++++++++++ .../postgresql/jdbc1/PreparedStatement.java | 29 +- .../postgresql/jdbc2/PreparedStatement.java | 44 ++- 3 files changed, 393 insertions(+), 26 deletions(-) create mode 100644 src/backend/utils/adt/encode.c diff --git a/src/backend/utils/adt/encode.c b/src/backend/utils/adt/encode.c new file mode 100644 index 0000000000..89ba357aa5 --- /dev/null +++ b/src/backend/utils/adt/encode.c @@ -0,0 +1,346 @@ +/*------------------------------------------------------------------------- + * + * encode.c + * Various data encoding/decoding things. + * + * Copyright (c) 2001 PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/adt/encode.c,v 1.1 2001/07/12 14:05:31 momjian Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include +#include "utils/builtins.h" + + +struct pg_encoding +{ + unsigned (*encode_len) (unsigned dlen); + unsigned (*decode_len) (unsigned dlen); + unsigned (*encode) (const uint8 *data, unsigned dlen, uint8 *res); + unsigned (*decode) (const uint8 *data, unsigned dlen, uint8 *res); +}; + +static struct pg_encoding * pg_find_encoding(const char *name); + +/* + * SQL functions. + */ + +Datum +binary_encode(PG_FUNCTION_ARGS) +{ + bytea *data = PG_GETARG_BYTEA_P(0); + Datum name = PG_GETARG_DATUM(1); + text *result; + char *namebuf; + int namelen, datalen, resultlen, res; + struct pg_encoding *enc; + + datalen = VARSIZE(data) - VARHDRSZ; + namelen = VARSIZE(name) - VARHDRSZ; + + namebuf = (char *)DirectFunctionCall1(textout, name); + + enc = pg_find_encoding(namebuf); + if (enc == NULL) + elog(ERROR, "No such encoding"); + + resultlen = enc->encode_len(datalen); + result = palloc(VARHDRSZ + resultlen); + + res = enc->encode(VARDATA(data), datalen, VARDATA(result)); + if (res > resultlen) + elog(ERROR, "Overflow - encode estimate too small"); + + VARATT_SIZEP(result) = VARHDRSZ + res; + + PG_RETURN_TEXT_P(result); +} + +Datum +binary_decode(PG_FUNCTION_ARGS) +{ + text *data = PG_GETARG_TEXT_P(0); + Datum name = PG_GETARG_DATUM(1); + bytea *result; + char *namebuf; + int namelen, datalen, resultlen, res; + struct pg_encoding *enc; + + datalen = VARSIZE(data) - VARHDRSZ; + namelen = VARSIZE(name) - VARHDRSZ; + + namebuf = (char *)DirectFunctionCall1(textout, name); + + enc = pg_find_encoding(namebuf); + if (enc == NULL) + elog(ERROR, "No such encoding"); + + resultlen = enc->decode_len(datalen); + result = palloc(VARHDRSZ + resultlen); + + res = enc->decode(VARDATA(data), datalen, VARDATA(result)); + if (res > resultlen) + elog(ERROR, "Overflow - decode estimate too small"); + + VARATT_SIZEP(result) = VARHDRSZ + res; + + PG_RETURN_BYTEA_P(result); +} + + +/* + * HEX + */ + +static const char *hextbl = "0123456789abcdef"; + +static const int8 hexlookup[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static unsigned +hex_encode(const uint8 * src, unsigned len, uint8 * dst) +{ + const uint8 *end = src + len; + + while (src < end) + { + *dst++ = hextbl[(*src >> 4) & 0xF]; + *dst++ = hextbl[*src & 0xF]; + src++; + } + return len * 2; +} + +static uint8 +get_hex(unsigned c) +{ + int res = -1; + + if (c > 0 && c < 127) + res = hexlookup[c]; + + if (res < 0) + elog(ERROR, "Bad hex code: '%c'", c); + + return (uint8)res; +} + +static unsigned +hex_decode(const uint8 * src, unsigned len, uint8 * dst) +{ + const uint8 *s, + *srcend; + uint8 v1, + v2, + *p = dst; + + srcend = src + len; + s = src; + p = dst; + while (s < srcend) + { + if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') + { + s++; + continue; + } + v1 = get_hex(*s++) << 4; + if (s >= srcend) + elog(ERROR, "hex_decode: invalid data"); + v2 = get_hex(*s++); + *p++ = v1 | v2; + } + + return p - dst; +} + +static unsigned +hex_enc_len(unsigned srclen) +{ + return srclen << 1; +} + +static unsigned +hex_dec_len(unsigned srclen) +{ + return srclen >> 1; +} + +/* + * BASE64 + */ + +static const unsigned char _base64[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const int8 b64lookup[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, +}; + +static unsigned +b64_encode(const uint8 * src, unsigned len, uint8 * dst) +{ + uint8 *p, + *lend = dst + 76; + const uint8 *s, + *end = src + len; + int pos = 2; + uint32 buf = 0; + + s = src; + p = dst; + + while (s < end) + { + buf |= *s << (pos << 3); + pos--; + s++; + + /* write it out */ + if (pos < 0) + { + *p++ = _base64[(buf >> 18) & 0x3f]; + *p++ = _base64[(buf >> 12) & 0x3f]; + *p++ = _base64[(buf >> 6) & 0x3f]; + *p++ = _base64[buf & 0x3f]; + + pos = 2; + buf = 0; + } + if (p >= lend) + { + *p++ = '\n'; + lend = p + 76; + } + } + if (pos != 2) + { + *p++ = _base64[(buf >> 18) & 0x3f]; + *p++ = _base64[(buf >> 12) & 0x3f]; + *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '='; + *p++ = '='; + } + + return p - dst; +} + +static unsigned +b64_decode(const uint8 * src, unsigned len, uint8 * dst) +{ + const char *srcend = src + len, + *s = src; + uint8 *p = dst; + unsigned c; + int b = 0; + uint32 buf = 0; + int pos = 0, + end = 0; + + while (s < srcend) + { + c = *s++; + + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') + continue; + + if (c == '=') + { + /* end sequence */ + if (!end) + { + if (pos == 2) + end = 1; + else if (pos == 3) + end = 2; + else + elog(ERROR, "base64: unexpected '='"); + } + b = 0; + } + else { + b = -1; + if (c > 0 && c < 127) + b = b64lookup[c]; + if (b < 0) + elog(ERROR, "base64: Invalid symbol"); + } + /* add it to buffer */ + buf = (buf << 6) + b; + pos++; + if (pos == 4) + { + *p++ = (buf >> 16) & 255; + if (end == 0 || end > 1) + *p++ = (buf >> 8) & 255; + if (end == 0 || end > 2) + *p++ = buf & 255; + buf = 0; + pos = 0; + } + } + + if (pos != 0) + elog(ERROR, "base64: invalid end sequence"); + + return p - dst; +} + + +static unsigned +b64_enc_len(unsigned srclen) +{ + /* 3 bytes will be converted to 4, linefeed after 76 chars */ + return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4); +} + +static unsigned +b64_dec_len(unsigned srclen) +{ + return (srclen * 3) >> 2; +} + +/* + * Common + */ + +static struct { + const char *name; + struct pg_encoding enc; +} enclist[] = { + {"hex", { hex_enc_len, hex_dec_len, hex_encode, hex_decode }}, + {"base64", { b64_enc_len, b64_dec_len, b64_encode, b64_decode }}, + {NULL, { NULL, NULL, NULL, NULL } } +}; + +static struct pg_encoding * +pg_find_encoding(const char *name) +{ + int i; + + for (i = 0; enclist[i].name; i++) + if (!strcasecmp(enclist[i].name, name)) + return &enclist[i].enc; + + return NULL; +} diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java index e4c50f13af..b2b68d50a5 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java @@ -260,7 +260,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta { // if the passed string is null, then set this column to null if(x==null) - set(parameterIndex,"null"); + setNull(parameterIndex,Types.OTHER); else { StringBuffer b = new StringBuffer(); int i; @@ -312,9 +312,12 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta */ public void setDate(int parameterIndex, java.sql.Date x) throws SQLException { - SimpleDateFormat df = new SimpleDateFormat("''yyyy-MM-dd''"); - set(parameterIndex, df.format(x)); - + if (null == x){ + setNull(parameterIndex,Types.OTHER); + }else{ + SimpleDateFormat df = new SimpleDateFormat("''yyyy-MM-dd''"); + set(parameterIndex, df.format(x)); + } // The above is how the date should be handled. // // However, in JDK's prior to 1.1.6 (confirmed with the @@ -337,7 +340,11 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta */ public void setTime(int parameterIndex, Time x) throws SQLException { + if (null == x){ + setNull(parameterIndex,Types.OTHER); + }else{ set(parameterIndex, "'" + x.toString() + "'"); + } } /** @@ -350,11 +357,15 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta */ public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { - SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - df.setTimeZone(TimeZone.getTimeZone("GMT")); - StringBuffer strBuf = new StringBuffer("'"); - strBuf.append(df.format(x)).append('.').append(x.getNanos()/10000000).append("+00'"); - set(parameterIndex, strBuf.toString()); + if (null == x){ + setNull(parameterIndex,Types.OTHER); + }else{ + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("GMT")); + StringBuffer strBuf = new StringBuffer("'"); + strBuf.append(df.format(x)).append('.').append(x.getNanos()/10000000).append("+00'"); + set(parameterIndex, strBuf.toString()); + } } /** diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java index 1936845a92..ab5601b026 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java @@ -267,7 +267,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta { // if the passed string is null, then set this column to null if(x==null) - set(parameterIndex,"null"); + setNull(parameterIndex,Types.OTHER); else { // use the shared buffer object. Should never clash but this makes // us thread safe! @@ -323,14 +323,16 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta */ public void setDate(int parameterIndex, java.sql.Date x) throws SQLException { - SimpleDateFormat df = (SimpleDateFormat) tl_df.get(); - if(df==null) { - df = new SimpleDateFormat("''yyyy-MM-dd''"); - tl_df.set(df); - } - - set(parameterIndex, df.format(x)); - + if(null == x){ + setNull(parameterIndex,Types.OTHER); + } else { + SimpleDateFormat df = (SimpleDateFormat) tl_df.get(); + if(df==null) { + df = new SimpleDateFormat("''yyyy-MM-dd''"); + tl_df.set(df); + } + set(parameterIndex, df.format(x)); + } // The above is how the date should be handled. // // However, in JDK's prior to 1.1.6 (confirmed with the @@ -353,7 +355,11 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta */ public void setTime(int parameterIndex, Time x) throws SQLException { - set(parameterIndex, "'" + x.toString() + "'"); + if (null == x){ + setNull(parameterIndex,Types.OTHER); + } else { + set(parameterIndex, "'" + x.toString() + "'"); + } } /** @@ -365,13 +371,16 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta * @exception SQLException if a database access error occurs */ public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException - { - SimpleDateFormat df = (SimpleDateFormat) tl_tsdf.get(); - if(df==null) { - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - df.setTimeZone(TimeZone.getTimeZone("GMT")); - tl_tsdf.set(df); - } + { + if (null == x){ + setNull(parameterIndex,Types.OTHER); + } else { + SimpleDateFormat df = (SimpleDateFormat) tl_tsdf.get(); + if(df==null) { + df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("GMT")); + tl_tsdf.set(df); + } // Use the shared StringBuffer synchronized(sbuf) { @@ -383,6 +392,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta // The above works, but so does the following. I'm leaving the above in, but this seems // to be identical. Pays to read the docs ;-) //set(parameterIndex,"'"+x.toString()+"'"); + } } /**