From 1047d59c49059a88ae4c99b7f02c9105b81bf48f Mon Sep 17 00:00:00 2001 From: vmgolovin Date: Mon, 3 Feb 2020 18:22:50 +0400 Subject: [PATCH] BIT data type support added BIT data type support has been added and a minor fix in a test of geometric types has been made. --- source/src/handler.c | 6 +++- source/src/libpqtypes-int.h | 4 ++- source/src/libpqtypes.h | 8 +++++ source/src/regression-test.c | 34 ++++++++++++++----- source/src/varlena.c | 66 +++++++++++++++++++++++++++++++++++- 5 files changed, 106 insertions(+), 12 deletions(-) diff --git a/source/src/handler.c b/source/src/handler.c index 8d908ad..861b775 100644 --- a/source/src/handler.c +++ b/source/src/handler.c @@ -111,7 +111,11 @@ static PGtypeHandler pg_handlers[] = { /* more character types */ {33, "pg_catalog", "name", -1, NAMEOID, 1003, pqt_put_text, - pqt_get_text, __HANDLER_DEFAULTS__} /* supports ptr */ + pqt_get_text, __HANDLER_DEFAULTS__}, /* supports ptr */ + + /* bit string types */ + {34, "pg_catalog", "bit", -1, ZPBITOID, 1561, pqt_put_bit, + pqt_get_bit, __HANDLER_DEFAULTS__} }; static int diff --git a/source/src/libpqtypes-int.h b/source/src/libpqtypes-int.h index 00faf93..adb4b68 100644 --- a/source/src/libpqtypes-int.h +++ b/source/src/libpqtypes-int.h @@ -254,7 +254,7 @@ extern "C" { #define VARCHAROID 1043 #define NAMEOID 19 #define TEXTOID 25 -#define ZPBITOID 1560 /* not supported yet */ +#define ZPBITOID 1560 #define VARBITOID 1562 /* not supported yet */ #define BYTEAOID 17 /* date and time types */ @@ -524,6 +524,8 @@ int pqt_put_text(PGtypeArgs *args); /* handles varchar, bpchar and name */ int pqt_get_text(PGtypeArgs *args); /* handles varchar, bpchar and name */ int pqt_put_bytea(PGtypeArgs *args); int pqt_get_bytea(PGtypeArgs *args); +int pqt_put_bit(PGtypeArgs *args); +int pqt_get_bit(PGtypeArgs *args); #ifdef __cplusplus } diff --git a/source/src/libpqtypes.h b/source/src/libpqtypes.h index 6e25a7d..ee8051c 100644 --- a/source/src/libpqtypes.h +++ b/source/src/libpqtypes.h @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -140,6 +141,13 @@ typedef struct char *data; } PGbytea; +typedef struct +{ + int len_bytes; + int32_t len_bits; + char *data; +} PGbit; + /* ---------------- * Numeric types * ---------------- diff --git a/source/src/regression-test.c b/source/src/regression-test.c index e8845bb..25d4838 100644 --- a/source/src/regression-test.c +++ b/source/src/regression-test.c @@ -806,8 +806,8 @@ static void test_geometrics(int format) } testcnt++; - if (polygon.npts == polygon.npts && - memcmp(polygon.pts, polygon.pts, polygon.npts * sizeof(PGpoint))==0) + if (polygon.npts == polygonval.npts && + memcmp(polygon.pts, polygonval.pts, polygon.npts * sizeof(PGpoint))==0) printf(" %%polygon - passed\n"); else { @@ -840,14 +840,17 @@ static void test_varlen(int format) PGnumeric num; PGnumeric numin = "-62731893541288039212143296120112.12431212671229121291821928918211"; + static char bitdata[] = {7, 6, 5, 4, 3, 2, 1, 0}; + PGbit bit; + PGbit bitin = {8, 59, bitdata}; PQparamReset(param); printf("\nVariable-length types: (%s)\n", format ? "binary" : "text"); r = PQputf(param, "%bpchar %bpchar* %varchar %varchar* " - "%text %text* %bytea %bytea* %uuid %numeric", + "%text %text* %bytea %bytea* %uuid %numeric %bit", bpcharin, bpcharin, varcharin, varcharin, textin, textin, - &byteain, &byteain, uuidin, numin); + &byteain, &byteain, uuidin, numin, &bitin); PUTOKAY(param, r, "PQputf(varlen)"); DROP_TABLE("libpq_varlen"); @@ -855,27 +858,28 @@ static void test_varlen(int format) result = PQexec(conn, "CREATE TABLE libpq_varlen (" "bp_a bpchar(32), bp_b bpchar(32), vc_a varchar(32), vc_b varchar(32), " "text_a text, text_b text, bytea_a bytea, bytea_b bytea, " - "uid uuid, n numeric)"); + "uid uuid, n numeric, bit_a bit(59))"); CMDOKAY("creating libpq_varlen table"); PQclear(result); result = PQparamExec(conn, param, "INSERT INTO libpq_varlen VALUES" - "($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)", format); + "($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)", format); CMDOKAY("PQparamExec(INSERT:varlen)"); PQclear(result); result = PQparamExec(conn, NULL, - "SELECT bp_a,vc_a,text_a,bytea_a,uid,n FROM libpq_varlen", format); + "SELECT bp_a,vc_a,text_a,bytea_a,uid,n,bit_a FROM libpq_varlen", format); TUPSOKAY("PQparamExec(SELECT:varlen)"); r = PQgetf(result, 0, - "%bpchar %varchar %text %bytea %uuid %numeric", + "%bpchar %varchar %text %bytea %uuid %numeric %bit", 0, &bpcharp, /* field_num, PGbpchar* */ 1, &varcharp, /* field_num, PGvarchar* */ 2, &textp, /* field_num, PGtext* */ 3, &byteap, /* field_num, PGbytea* */ 4, &uuid, /* field_num, PGuuid* */ - 5, &num); /* field_num, PGnumeric* */ + 5, &num, /* field_num, PGnumeric* */ + 6, &bit); /* field num, PGbit* */ GETOKAY(r, "PQgetf(varlen)"); /* Because we are using the '*' specifier flag, we clear the results at @@ -914,6 +918,18 @@ static void test_varlen(int format) printf(" %%uuid - passed\n"); CHKVLEN("numeric", num, numin); + + testcnt++; + if (bitin.len_bytes != bit.len_bytes || + bitin.len_bits != bit.len_bits || + memcmp(bitin.data, bit.data, (size_t)bit.len_bytes)) + { + failcnt++; + fprintf(stderr, " %%bit - FAILED'n"); + } + else + printf(" %%bit - passed\n"); + PQclear(result); } diff --git a/source/src/varlena.c b/source/src/varlena.c index a20727c..0490bae 100644 --- a/source/src/varlena.c +++ b/source/src/varlena.c @@ -84,5 +84,69 @@ pqt_get_bytea(PGtypeArgs *args) return 0; } +int +pqt_put_bit(PGtypeArgs *args) +{ + int len_bytes; + int total_bytes; + char *out; + PGbit *bit = va_arg(args->ap, PGbit *); + PUTNULLCHK(args, bit); + len_bytes = bit->len_bytes; + total_bytes = len_bytes + (int)sizeof(int32_t); + if (args->put.expandBuffer(args, total_bytes) == -1) + RERR_MEM(args); + out = args->put.out; + pqt_buf_putint4(out, bit->len_bits); + memcpy(out + sizeof(int32_t), bit->data, (size_t)len_bytes); + return total_bytes; +} - +int +pqt_get_bit(PGtypeArgs *args) +{ + DECLVALUE(args); + DECLLENGTH(args); + PGbit *bit = va_arg(args->ap, PGbit *); + CHKGETVALS(args, bit); + if (args->format == TEXTFMT) + { + unsigned char *cur_byte; + char *cur_char; + unsigned char mask_byte; + uint32_t len_bits = (uint32_t)strlen(value); + int len_bytes = (len_bits >> 3) + !!(len_bits & 07); + char *data = (char *)PQresultAlloc(args->get.result, (size_t)len_bytes); + if (!data) + RERR_MEM(args); + cur_byte = (unsigned char *)data; + *cur_byte = 0; + mask_byte = 0x80; + for (cur_char = value; *cur_char; ++cur_char) + { + if (*cur_char == '1') + *cur_byte |= mask_byte; + else if (*cur_char != '0') + { + PQfreemem(data); + RERR(args, "String to bit string conversion failed"); + } + mask_byte >>= 1; + if (mask_byte == 0) + { + ++cur_byte; + *cur_byte = 0; + mask_byte = 0x80; + } + } + bit->len_bytes = len_bytes; + bit->len_bits = (int32_t)len_bits; + bit->data = data; + return 0; + } + /* binary format */ + bit->len_bytes = valuel - (int)sizeof(int32_t); + bit->len_bits = pqt_buf_getint4(value); + bit->data = value + sizeof(int32_t); + return 0; +}