diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index e78de345d9c..9435a396f07 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.127 2000/10/26 21:35:47 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.128 2000/10/31 10:22:10 petere Exp $ * *------------------------------------------------------------------------- */ @@ -2511,6 +2511,7 @@ _copyValue(Value *from) break; case T_Float: case T_String: + case T_BitString: newnode->val.str = pstrdup(from->val.str); break; default: @@ -2703,6 +2704,7 @@ copyObject(void *from) case T_Integer: case T_Float: case T_String: + case T_BitString: retval = _copyValue(from); break; case T_List: diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 372f22499d5..8519fd6115e 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -20,7 +20,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.77 2000/10/18 16:16:04 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.78 2000/10/31 10:22:10 petere Exp $ * *------------------------------------------------------------------------- */ @@ -1719,6 +1719,7 @@ _equalValue(Value *a, Value *b) return a->val.ival == b->val.ival; case T_Float: case T_String: + case T_BitString: return strcmp(a->val.str, b->val.str) == 0; default: break; @@ -1874,6 +1875,7 @@ equal(void *a, void *b) case T_Integer: case T_Float: case T_String: + case T_BitString: retval = _equalValue(a, b); break; diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c index 66674b5c364..c106a131120 100644 --- a/src/backend/nodes/list.c +++ b/src/backend/nodes/list.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.35 2000/10/05 19:11:27 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.36 2000/10/31 10:22:10 petere Exp $ * * NOTES * XXX a few of the following functions are duplicated to handle @@ -70,6 +70,23 @@ makeString(char *str) return v; } + +/* + * makeBitString + * + * Caller is responsible for passing a palloc'd string. + */ +Value * +makeBitString(char *str) +{ + Value *v = makeNode(Value); + + v->type = T_BitString; + v->val.str = str; + return v; +} + + /* * lcons * diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 16b64851097..2e8ecaca652 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.129 2000/10/26 21:35:48 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.130 2000/10/31 10:22:10 petere Exp $ * * NOTES * Every (plan) node in POSTGRES has an associated "out" routine which @@ -20,10 +20,10 @@ * representation plus some other information (string length, etc.) * */ -#include - #include "postgres.h" +#include + #include "access/heapam.h" #include "access/htup.h" #include "catalog/pg_type.h" @@ -1352,6 +1352,9 @@ _outValue(StringInfo str, Value *value) _outToken(str, value->val.str); appendStringInfo(str, "\" "); break; + case T_BitString: + appendStringInfo(str, " B%s ", value->val.str); + break; default: elog(NOTICE, "_outValue: don't know how to print type %d ", value->type); diff --git a/src/backend/nodes/read.c b/src/backend/nodes/read.c index dbfc0926f5e..a6401a238fa 100644 --- a/src/backend/nodes/read.c +++ b/src/backend/nodes/read.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/read.c,v 1.23 2000/06/14 18:17:32 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/read.c,v 1.24 2000/10/31 10:22:10 petere Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -17,11 +17,11 @@ * *------------------------------------------------------------------------- */ +#include "postgres.h" + #include #include -#include "postgres.h" - #include "nodes/pg_list.h" #include "nodes/readfuncs.h" @@ -184,7 +184,7 @@ debackslash(char *token, int length) * nodeTokenType - * returns the type of the node token contained in token. * It returns one of the following valid NodeTags: - * T_Integer, T_Float, T_String + * T_Integer, T_Float, T_String, T_BitString * and some of its own: * RIGHT_PAREN, LEFT_PAREN, PLAN_SYM, AT_SYMBOL, ATOM_TOKEN * @@ -236,6 +236,8 @@ nodeTokenType(char *token, int length) retval = AT_SYMBOL; else if (*token == '\"' && length > 1 && token[length - 1] == '\"') retval = T_String; + else if (*token == 'B') + retval = T_BitString; else retval = ATOM_TOKEN; return retval; @@ -346,6 +348,15 @@ nodeRead(bool read_car_only) this_value = (Node *) makeString(debackslash(token + 1, tok_len - 2)); make_dotted_pair_cell = true; break; + case T_BitString: + { + char * val = palloc(tok_len); + /* skip leading 'B'*/ + strncpy(val, token + 1, tok_len - 1); + val[tok_len - 1] = '\0'; + this_value = (Node *) makeBitString(val); + break; + } default: elog(ERROR, "nodeRead: Bad type %d", type); this_value = NULL; /* keep compiler happy */ diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 5c2a2ab5d60..ece0493acf9 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.201 2000/10/29 16:11:33 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.202 2000/10/31 10:22:10 petere Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -353,7 +353,7 @@ static void doNegateFloat(Value *v); %token UNIONJOIN /* Special keywords, not in the query language - see the "lex" file */ -%token IDENT, FCONST, SCONST, Op +%token IDENT, FCONST, SCONST, BITCONST, Op %token ICONST, PARAM /* these are not real. they are here so that they get generated as #define's*/ @@ -1798,6 +1798,10 @@ TriggerFuncArg: ICONST { $$ = makeString($1); } + | BITCONST + { + $$ = makeString($1); + } | ColId { $$ = makeString($1); @@ -4786,8 +4790,9 @@ c_expr: attr } | POSITION '(' position_list ')' { + /* position(A in B) is converted to position(B, A) */ FuncCall *n = makeNode(FuncCall); - n->funcname = "strpos"; + n->funcname = "position"; n->args = $3; n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -4795,8 +4800,10 @@ c_expr: attr } | SUBSTRING '(' substr_list ')' { + /* substring(A from B for C) is converted to + * substring(A, B, C) */ FuncCall *n = makeNode(FuncCall); - n->funcname = "substr"; + n->funcname = "substring"; n->args = $3; n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -5201,6 +5208,13 @@ AexprConst: Iconst n->val.val.str = $1; $$ = (Node *)n; } + | BITCONST + { + A_Const *n = makeNode(A_Const); + n->val.type = T_BitString; + n->val.val.str = $1; + $$ = (Node *)n; + } /* This rule formerly used Typename, * but that causes reduce conflicts with subscripted column names. * Now, separate into ConstTypename and ConstInterval, diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 2ff4d9c990b..d23c5c1e7c7 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.47 2000/09/29 18:21:36 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.48 2000/10/31 10:22:11 petere Exp $ * *------------------------------------------------------------------------- */ @@ -31,6 +31,7 @@ #include "parser/parse_target.h" #include "parser/parse_type.h" #include "utils/builtins.h" +#include "utils/varbit.h" #include "utils/lsyscache.h" #include "utils/syscache.h" @@ -473,6 +474,16 @@ make_const(Value *value) typebyval = false; break; + case T_BitString: + val = DirectFunctionCall3(zpbit_in, + CStringGetDatum(strVal(value)), + ObjectIdGetDatum(InvalidOid), + Int32GetDatum(-1)); + typeid = ZPBITOID; + typelen = -1; + typebyval = false; + break; + default: elog(NOTICE, "make_const: unknown type %d", nodeTag(value)); /* FALLTHROUGH */ diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l index 8a782f72aa6..083bd70b026 100644 --- a/src/backend/parser/scan.l +++ b/src/backend/parser/scan.l @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/scan.l,v 1.79 2000/10/30 17:54:16 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/scan.l,v 1.80 2000/10/31 10:22:11 petere Exp $ * *------------------------------------------------------------------------- */ @@ -93,25 +93,25 @@ static void addlit(char *ytext, int yleng); * We use exclusive states for quoted strings, extended comments, * and to eliminate parsing troubles for numeric strings. * Exclusive states: - * binary numeric string - thomas 1997-11-16 + * bit string literal * extended C-style comments - thomas 1997-07-12 * delimited identifiers (double-quoted identifiers) - thomas 1997-10-27 * hexadecimal numeric string - thomas 1997-11-16 * quoted strings - thomas 1997-07-30 */ -%x xb +%x xbit %x xc %x xd %x xh %x xq -/* Binary number +/* Bit string */ -xbstart [bB]{quote} -xbstop {quote} -xbinside [^']+ -xbcat {quote}{whitespace_with_newline}{quote} +xbitstart [bB]{quote} +xbitstop {quote} +xbitinside [^']* +xbitcat {quote}{whitespace_with_newline}{quote} /* Hexadecimal number */ @@ -279,30 +279,27 @@ other . <> { elog(ERROR, "Unterminated /* comment"); } -{xbstart} { - BEGIN(xb); +{xbitstart} { + BEGIN(xbit); startlit(); } -{xbstop} { - char* endptr; - +{xbitstop} { BEGIN(INITIAL); - errno = 0; - yylval.ival = strtol(literalbuf, &endptr, 2); - if (*endptr != '\0' || errno == ERANGE) - elog(ERROR, "Bad binary integer input '%s'", + if (literalbuf[strspn(literalbuf, "01")] != '\0') + elog(ERROR, "invalid bit string input: '%s'", literalbuf); - return ICONST; + yylval.str = literalbuf; + return BITCONST; } {xhinside} | -{xbinside} { +{xbitinside} { addlit(yytext, yyleng); } {xhcat} | -{xbcat} { +{xbitcat} { /* ignore */ } -<> { elog(ERROR, "Unterminated binary integer"); } +<> { elog(ERROR, "unterminated bit string literal"); } {xhstart} { BEGIN(xh); diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index 04717dbf17e..741ef3f924b 100644 --- a/src/backend/utils/adt/varbit.c +++ b/src/backend/utils/adt/varbit.c @@ -9,7 +9,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.9 2000/08/26 21:53:41 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.10 2000/10/31 10:22:11 petere Exp $ * *------------------------------------------------------------------------- */ @@ -1053,8 +1053,8 @@ bitshiftright(PG_FUNCTION_ARGS) /* Negative shift is a shift to the left */ if (shft < 0) PG_RETURN_DATUM(DirectFunctionCall2(bitshiftleft, - VarBitPGetDatum(arg), - Int32GetDatum(-shft))); + VarBitPGetDatum(arg), + Int32GetDatum(-shft))); result = (VarBit *) palloc(VARSIZE(arg)); VARATT_SIZEP(result) = VARSIZE(arg); @@ -1146,3 +1146,99 @@ bittoint4(PG_FUNCTION_ARGS) PG_RETURN_INT32(result); } + + + +/* Determines the position of S2 in the bitstring S1 (1-based string). + * If S2 does not appear in S1 this function returns 0. + * If S2 is of length 0 this function returns 1. + */ +Datum +bitposition(PG_FUNCTION_ARGS) +{ + VarBit *substr = PG_GETARG_VARBIT_P(1); + VarBit *arg = PG_GETARG_VARBIT_P(0); + int substr_length, + arg_length, + i, + is; + bits8 *s, /* pointer into substring */ + *p; /* pointer into arg */ + bits8 cmp, /* shifted substring byte to compare */ + mask1, /* mask for substring byte shifted right */ + mask2, /* mask for substring byte shifted left */ + end_mask, /* pad mask for last substring byte */ + arg_mask; /* pad mask for last argument byte */ + bool is_match; + + /* Get the substring length */ + substr_length = VARBITLEN(substr); + arg_length = VARBITLEN(arg); + + /* Argument has 0 length or substring longer than argument, return 0 */ + if (arg_length == 0 || substr_length > arg_length) + PG_RETURN_INT32(0); + + /* 0-length means return 1 */ + if (substr_length == 0) + PG_RETURN_INT32(1); + + /* Initialise the padding masks */ + end_mask = BITMASK << VARBITPAD(substr); + arg_mask = BITMASK << VARBITPAD(arg); + for (i = 0; i < VARBITBYTES(arg) - VARBITBYTES(substr) + 1; i++) + { + for (is = 0; is < BITS_PER_BYTE; is++) { + is_match = true; + p = VARBITS(arg) + i; + mask1 = BITMASK >> is; + mask2 = ~mask1; + for (s = VARBITS(substr); + is_match && s < VARBITEND(substr); s++) + { + cmp = *s >> is; + if (s == VARBITEND(substr) - 1) + { + mask1 &= end_mask >> is; + if (p == VARBITEND(arg) - 1) { + /* Check that there is enough of arg left */ + if (mask1 & ~arg_mask) { + is_match = false; + break; + } + mask1 &= arg_mask; + } + } + is_match = ((cmp ^ *p) & mask1) == 0; + if (!is_match) + break; + // Move on to the next byte + p++; + if (p == VARBITEND(arg)) { + mask2 = end_mask << (BITS_PER_BYTE - is); + is_match = mask2 == 0; + elog(NOTICE,"S. %d %d em=%2x sm=%2x r=%d", + i,is,end_mask,mask2,is_match); + break; + } + cmp = *s << (BITS_PER_BYTE - is); + if (s == VARBITEND(substr) - 1) + { + mask2 &= end_mask << (BITS_PER_BYTE - is); + if (p == VARBITEND(arg) - 1) { + if (mask2 & ~arg_mask) { + is_match = false; + break; + } + mask2 &= arg_mask; + } + } + is_match = ((cmp ^ *p) & mask2) == 0; + } + /* Have we found a match */ + if (is_match) + PG_RETURN_INT32(i*BITS_PER_BYTE + is + 1); + } + } + PG_RETURN_INT32(0); +} diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 56f515b662a..983e95da347 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: catversion.h,v 1.53 2000/10/24 03:34:15 tgl Exp $ + * $Id: catversion.h,v 1.54 2000/10/31 10:22:12 petere Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200010233 +#define CATALOG_VERSION_NO 200010310 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 1748e1ea947..53ecc5f68ec 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_proc.h,v 1.170 2000/10/24 20:15:45 petere Exp $ + * $Id: pg_proc.h,v 1.171 2000/10/31 10:22:12 petere Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -2097,6 +2097,11 @@ DESCR("trim both ends of string"); DATA(insert OID = 885 ( btrim PGUID 14 f t t t 1 f 25 "25" 100 0 0 100 "select btrim($1, \' \')" - )); DESCR("trim both ends of string"); +DATA(insert OID = 936 ( substring PGUID 12 f t t t 3 f 25 "25 23 23" 100 0 0 100 text_substr - )); +DESCR("return portion of string"); +DATA(insert OID = 937 ( substring PGUID 14 f t t t 2 f 25 "25 23" 100 0 0 100 "select \042substring\042($1, $2, -1)" - )); +DESCR("return portion of string"); + /* for multi-byte support */ DATA(insert OID = 1039 ( getdatabaseencoding PGUID 12 f t f t 0 f 19 "0" 100 0 0 100 getdatabaseencoding - )); DESCR("encoding name of current database"); @@ -2172,8 +2177,8 @@ DATA(insert OID = 1678 ( bitshiftright PGUID 12 f t t t 2 f 1560 "1560 23" 100 DESCR("bitwise right shift"); DATA(insert OID = 1679 ( bitcat PGUID 12 f t t t 2 f 1560 "1560 1560" 100 0 0 100 bitcat - )); DESCR("bitwise concatenation"); -DATA(insert OID = 1680 ( bitsubstr PGUID 12 f t t t 3 f 1560 "1560 23 23" 100 0 0 100 bitsubstr - )); -DESCR("bitwise field"); +DATA(insert OID = 1680 ( substring PGUID 12 f t t t 3 f 1560 "1560 23 23" 100 0 0 100 bitsubstr - )); +DESCR("return portion of bitstring"); DATA(insert OID = 1681 ( length PGUID 12 f t t t 1 f 23 "1560" 100 0 0 100 bitlength - )); DESCR("bitstring length"); DATA(insert OID = 1682 ( octet_length PGUID 12 f t t t 1 f 23 "1560" 100 0 0 100 bitoctetlength - )); @@ -2192,6 +2197,12 @@ DESCR("adjust varbit() to typmod length"); DATA(insert OID = 1688 ( _varbit PGUID 12 f t t t 2 f 1563 "1563 23" 100 0 0 100 _varbit - )); DESCR("adjust varbit()[] to typmod length"); +DATA(insert OID = 1698 ( position PGUID 12 f t t t 2 f 23 "1560 1560" 100 0 0 100 bitposition - )); +DESCR("return position of sub-bitstring"); +DATA(insert OID = 1699 ( substring PGUID 14 f t t t 2 f 1560 "1560 23" 100 0 0 100 "select \042substring\042($1, $2, -1)" - )); +DESCR("return portion of bitstring"); + + /* for mac type support */ DATA(insert OID = 436 ( macaddr_in PGUID 12 f t t t 1 f 829 "0" 100 0 0 100 macaddr_in - )); DESCR("(internal)"); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index b06335290f4..9a939a73345 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: nodes.h,v 1.80 2000/10/26 21:38:12 tgl Exp $ + * $Id: nodes.h,v 1.81 2000/10/31 10:22:12 petere Exp $ * *------------------------------------------------------------------------- */ @@ -140,6 +140,7 @@ typedef enum NodeTag T_Integer, T_Float, T_String, + T_BitString, T_Null, /*--------------------- diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h index 07c58348e07..1e11e4504f2 100644 --- a/src/include/nodes/pg_list.h +++ b/src/include/nodes/pg_list.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_list.h,v 1.21 2000/10/05 19:11:36 tgl Exp $ + * $Id: pg_list.h,v 1.22 2000/10/31 10:22:12 petere Exp $ * *------------------------------------------------------------------------- */ @@ -118,6 +118,7 @@ extern bool intMember(int datum, List *list); extern Value *makeInteger(long i); extern Value *makeFloat(char *numericStr); extern Value *makeString(char *str); +extern Value *makeBitString(char *str); extern List *lappend(List *list, void *datum); extern List *lappendi(List *list, int datum); extern List *lremove(void *elem, List *list); diff --git a/src/include/utils/varbit.h b/src/include/utils/varbit.h index ed3710ddf70..50ab4556ad7 100644 --- a/src/include/utils/varbit.h +++ b/src/include/utils/varbit.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: varbit.h,v 1.7 2000/08/26 21:53:40 tgl Exp $ + * $Id: varbit.h,v 1.8 2000/10/31 10:22:13 petere Exp $ * *------------------------------------------------------------------------- */ @@ -87,5 +87,6 @@ extern Datum bitlength(PG_FUNCTION_ARGS); extern Datum bitoctetlength(PG_FUNCTION_ARGS); extern Datum bitfromint4(PG_FUNCTION_ARGS); extern Datum bittoint4(PG_FUNCTION_ARGS); +extern Datum bitposition(PG_FUNCTION_ARGS); #endif