From 73874a06f02691b32c07318e543d83e7947efa51 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Tue, 31 Oct 2000 10:22:13 +0000 Subject: [PATCH] Change the parser to convert SQL "position" and "substring" syntax to position() and substring() functions, so that it works transparently for bit types as well. Alias the text functions appropriately. Add position() for bit types. Add new constant node T_BitString that represents literals of the form B'1001 and pass those to zpbit type. --- src/backend/nodes/copyfuncs.c | 4 +- src/backend/nodes/equalfuncs.c | 4 +- src/backend/nodes/list.c | 19 +++++- src/backend/nodes/outfuncs.c | 9 ++- src/backend/nodes/read.c | 19 ++++-- src/backend/parser/gram.y | 22 +++++-- src/backend/parser/parse_node.c | 13 +++- src/backend/parser/scan.l | 39 ++++++------ src/backend/utils/adt/varbit.c | 102 ++++++++++++++++++++++++++++++- src/include/catalog/catversion.h | 4 +- src/include/catalog/pg_proc.h | 17 +++++- src/include/nodes/nodes.h | 3 +- src/include/nodes/pg_list.h | 3 +- src/include/utils/varbit.h | 3 +- 14 files changed, 214 insertions(+), 47 deletions(-) diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index e78de345d9..9435a396f0 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 372f22499d..8519fd6115 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 66674b5c36..c106a13112 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 16b6485109..2e8ecaca65 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 dbfc0926f5..a6401a238f 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 5c2a2ab5d6..ece0493acf 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 2ff4d9c990..d23c5c1e7c 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 8a782f72aa..083bd70b02 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 04717dbf17..741ef3f924 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 56f515b662..983e95da34 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 1748e1ea94..53ecc5f68e 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 b06335290f..9a939a7334 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 07c58348e0..1e11e4504f 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 ed3710ddf7..50ab4556ad 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 -- 2.40.0