📄 varbit.c
字号:
/*------------------------------------------------------------------------- * * varbit.c * Functions for the SQL datatypes BIT() and BIT VARYING(). * * Code originally contributed by Adriaan Joubert. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.47 2005/10/15 02:49:30 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/pg_type.h"#include "libpq/pqformat.h"#include "utils/array.h"#include "utils/fmgroids.h"#include "utils/memutils.h"#include "utils/varbit.h"#define HEXDIG(z) ((z)<10 ? ((z)+'0') : ((z)-10+'A'))/*---------- * attypmod -- contains the length of the bit string in bits, or for * varying bits the maximum length. * * The data structure contains the following elements: * header -- length of the whole data structure (incl header) * in bytes. (as with all varying length datatypes) * data section -- private data section for the bits data structures * bitlength -- length of the bit string in bits * bitdata -- bit string, most significant byte first * * The length of the bitdata vector should always be exactly as many * bytes as are needed for the given bitlength. If the bitlength is * not a multiple of 8, the extra low-order padding bits of the last * byte must be zeroes. *---------- *//* * bit_in - * converts a char string to the internal representation of a bitstring. * The length is determined by the number of bits required plus * VARHDRSZ bytes or from atttypmod. */Datumbit_in(PG_FUNCTION_ARGS){ char *input_string = PG_GETARG_CSTRING(0);#ifdef NOT_USED Oid typelem = PG_GETARG_OID(1);#endif int32 atttypmod = PG_GETARG_INT32(2); VarBit *result; /* The resulting bit string */ char *sp; /* pointer into the character string */ bits8 *r; /* pointer into the result */ int len, /* Length of the whole data structure */ bitlen, /* Number of bits in the bit string */ slen; /* Length of the input string */ bool bit_not_hex; /* false = hex string true = bit string */ int bc; bits8 x = 0; /* Check that the first character is a b or an x */ if (input_string[0] == 'b' || input_string[0] == 'B') { bit_not_hex = true; sp = input_string + 1; } else if (input_string[0] == 'x' || input_string[0] == 'X') { bit_not_hex = false; sp = input_string + 1; } else { /* * Otherwise it's binary. This allows things like cast('1001' as bit) * to work transparently. */ bit_not_hex = true; sp = input_string; } slen = strlen(sp); /* Determine bitlength from input string */ if (bit_not_hex) bitlen = slen; else bitlen = slen * 4; /* * Sometimes atttypmod is not supplied. If it is supplied we need to make * sure that the bitstring fits. */ if (atttypmod <= 0) atttypmod = bitlen; else if (bitlen != atttypmod) ereport(ERROR, (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH), errmsg("bit string length %d does not match type bit(%d)", bitlen, atttypmod))); len = VARBITTOTALLEN(atttypmod); /* set to 0 so that *r is always initialised and string is zero-padded */ result = (VarBit *) palloc0(len); VARATT_SIZEP(result) = len; VARBITLEN(result) = atttypmod; r = VARBITS(result); if (bit_not_hex) { /* Parse the bit representation of the string */ /* We know it fits, as bitlen was compared to atttypmod */ x = BITHIGH; for (; *sp; sp++) { if (*sp == '1') *r |= x; else if (*sp != '0') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("\"%c\" is not a valid binary digit", *sp))); x >>= 1; if (x == 0) { x = BITHIGH; r++; } } } else { /* Parse the hex representation of the string */ for (bc = 0; *sp; sp++) { if (*sp >= '0' && *sp <= '9') x = (bits8) (*sp - '0'); else if (*sp >= 'A' && *sp <= 'F') x = (bits8) (*sp - 'A') + 10; else if (*sp >= 'a' && *sp <= 'f') x = (bits8) (*sp - 'a') + 10; else ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("\"%c\" is not a valid hexadecimal digit", *sp))); if (bc) { *r++ |= x; bc = 0; } else { *r = x << 4; bc = 1; } } } PG_RETURN_VARBIT_P(result);}Datumbit_out(PG_FUNCTION_ARGS){#if 1 /* same as varbit output */ return varbit_out(fcinfo);#else/* This is how one would print a hex string, in case someone wants to write a formatting function. */ VarBit *s = PG_GETARG_VARBIT_P(0); char *result, *r; bits8 *sp; int i, len, bitlen; bitlen = VARBITLEN(s); len = (bitlen + 3) / 4; result = (char *) palloc(len + 2); sp = VARBITS(s); r = result; *r++ = 'X'; /* we cheat by knowing that we store full bytes zero padded */ for (i = 0; i < len; i += 2, sp++) { *r++ = HEXDIG((*sp) >> 4); *r++ = HEXDIG((*sp) & 0xF); } /* * Go back one step if we printed a hex number that was not part of the * bitstring anymore */ if (i > len) r--; *r = '\0'; PG_RETURN_CSTRING(result);#endif}/* * bit_recv - converts external binary format to bit */Datumbit_recv(PG_FUNCTION_ARGS){ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);#ifdef NOT_USED Oid typelem = PG_GETARG_OID(1);#endif int32 atttypmod = PG_GETARG_INT32(2); VarBit *result; int len, bitlen; int ipad; bits8 mask; bitlen = pq_getmsgint(buf, sizeof(int32)); if (bitlen < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid length in external bit string"))); /* * Sometimes atttypmod is not supplied. If it is supplied we need to make * sure that the bitstring fits. */ if (atttypmod > 0 && bitlen != atttypmod) ereport(ERROR, (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH), errmsg("bit string length %d does not match type bit(%d)", bitlen, atttypmod))); len = VARBITTOTALLEN(bitlen); result = (VarBit *) palloc(len); VARATT_SIZEP(result) = len; VARBITLEN(result) = bitlen; pq_copymsgbytes(buf, (char *) VARBITS(result), VARBITBYTES(result)); /* Make sure last byte is zero-padded if needed */ ipad = VARBITPAD(result); if (ipad > 0) { mask = BITMASK << ipad; *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask; } PG_RETURN_VARBIT_P(result);}/* * bit_send - converts bit to binary format */Datumbit_send(PG_FUNCTION_ARGS){ /* Exactly the same as varbit_send, so share code */ return varbit_send(fcinfo);}/* bit() * Converts a bit() type to a specific internal length. * len is the bitlength specified in the column definition. * * If doing implicit cast, raise error when source data is wrong length. * If doing explicit cast, silently truncate or zero-pad to specified length. */Datumbit(PG_FUNCTION_ARGS){ VarBit *arg = PG_GETARG_VARBIT_P(0); int32 len = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); VarBit *result; int rlen; int ipad; bits8 mask; /* No work if typmod is invalid or supplied data matches it already */ if (len <= 0 || len == VARBITLEN(arg)) PG_RETURN_VARBIT_P(arg); if (!isExplicit) ereport(ERROR, (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH), errmsg("bit string length %d does not match type bit(%d)", VARBITLEN(arg), len))); rlen = VARBITTOTALLEN(len); /* set to 0 so that string is zero-padded */ result = (VarBit *) palloc0(rlen); VARATT_SIZEP(result) = rlen; VARBITLEN(result) = len; memcpy(VARBITS(result), VARBITS(arg), Min(VARBITBYTES(result), VARBITBYTES(arg))); /* * Make sure last byte is zero-padded if needed. This is useless but safe * if source data was shorter than target length (we assume the last byte * of the source data was itself correctly zero-padded). */ ipad = VARBITPAD(result); if (ipad > 0) { mask = BITMASK << ipad; *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask; } PG_RETURN_VARBIT_P(result);}/* * varbit_in - * converts a string to the internal representation of a bitstring. * This is the same as bit_in except that atttypmod is taken as * the maximum length, not the exact length to force the bitstring to. */Datumvarbit_in(PG_FUNCTION_ARGS){ char *input_string = PG_GETARG_CSTRING(0);#ifdef NOT_USED Oid typelem = PG_GETARG_OID(1);#endif int32 atttypmod = PG_GETARG_INT32(2); VarBit *result; /* The resulting bit string */ char *sp; /* pointer into the character string */ bits8 *r; /* pointer into the result */ int len, /* Length of the whole data structure */ bitlen, /* Number of bits in the bit string */ slen; /* Length of the input string */ bool bit_not_hex; /* false = hex string true = bit string */ int bc; bits8 x = 0; /* Check that the first character is a b or an x */ if (input_string[0] == 'b' || input_string[0] == 'B') { bit_not_hex = true; sp = input_string + 1; } else if (input_string[0] == 'x' || input_string[0] == 'X') { bit_not_hex = false; sp = input_string + 1; } else { bit_not_hex = true; sp = input_string; } slen = strlen(sp); /* Determine bitlength from input string */ if (bit_not_hex) bitlen = slen; else bitlen = slen * 4; /* * Sometimes atttypmod is not supplied. If it is supplied we need to make * sure that the bitstring fits. */ if (atttypmod <= 0) atttypmod = bitlen; else if (bitlen > atttypmod) ereport(ERROR, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), errmsg("bit string too long for type bit varying(%d)", atttypmod))); len = VARBITTOTALLEN(bitlen); /* set to 0 so that *r is always initialised and string is zero-padded */ result = (VarBit *) palloc0(len); VARATT_SIZEP(result) = len; VARBITLEN(result) = Min(bitlen, atttypmod); r = VARBITS(result); if (bit_not_hex) { /* Parse the bit representation of the string */ /* We know it fits, as bitlen was compared to atttypmod */ x = BITHIGH; for (; *sp; sp++) { if (*sp == '1') *r |= x; else if (*sp != '0') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("\"%c\" is not a valid binary digit", *sp))); x >>= 1; if (x == 0) { x = BITHIGH; r++; } } } else { /* Parse the hex representation of the string */ for (bc = 0; *sp; sp++) { if (*sp >= '0' && *sp <= '9') x = (bits8) (*sp - '0'); else if (*sp >= 'A' && *sp <= 'F') x = (bits8) (*sp - 'A') + 10; else if (*sp >= 'a' && *sp <= 'f') x = (bits8) (*sp - 'a') + 10; else ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("\"%c\" is not a valid hexadecimal digit", *sp))); if (bc) { *r++ |= x; bc = 0; } else { *r = x << 4; bc = 1; } } } PG_RETURN_VARBIT_P(result);}/* varbit_out - * Prints the string as bits to preserve length accurately */Datumvarbit_out(PG_FUNCTION_ARGS){ VarBit *s = PG_GETARG_VARBIT_P(0); char *result, *r; bits8 *sp; bits8 x; int i, k, len; len = VARBITLEN(s); result = (char *) palloc(len + 1); sp = VARBITS(s); r = result; for (i = 0; i < len - BITS_PER_BYTE; i += BITS_PER_BYTE, sp++) { x = *sp; for (k = 0; k < BITS_PER_BYTE; k++) { *r++ = (x & BITHIGH) ? '1' : '0'; x <<= 1; } } x = *sp; for (k = i; k < len; k++) { *r++ = (x & BITHIGH) ? '1' : '0'; x <<= 1; } *r = '\0'; PG_RETURN_CSTRING(result);}/* * varbit_recv - converts external binary format to varbit
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -