*** src/backend/utils/adt/varbit.c.old Sun Oct 29 11:05:11 2000 --- src/backend/utils/adt/varbit.c Mon Oct 30 04:58:35 2000 *************** *** 1053,1060 **** /* Negative shift is a shift to the left */ if (shft < 0) PG_RETURN_DATUM(DirectFunctionCall2(bitshiftleft, ! VarBitPGetDatum(arg), ! Int32GetDatum(-shft))); result = (VarBit *) palloc(VARSIZE(arg)); VARATT_SIZEP(result) = VARSIZE(arg); --- 1053,1060 ---- /* Negative shift is a shift to the left */ if (shft < 0) PG_RETURN_DATUM(DirectFunctionCall2(bitshiftleft, ! VarBitPGetDatum(arg), ! Int32GetDatum(-shft))); result = (VarBit *) palloc(VARSIZE(arg)); VARATT_SIZEP(result) = VARSIZE(arg); *************** *** 1145,1148 **** --- 1145,1242 ---- result >>= VARBITPAD(arg); PG_RETURN_INT32(result); + } + + /* Determines the position of S1 in the bitstring S2 (1-based string). + * If S1 does not appear in S2 this function returns 0. + * If S1 is of length 0 this function returns 1. + */ + Datum + bitposition(PG_FUNCTION_ARGS) + { + VarBit *substr = PG_GETARG_VARBIT_P(0); + VarBit *arg = PG_GETARG_VARBIT_P(1); + 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); }