* Copyright (c) 2022 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* ---------------------------------------------------------------------------------------
*
* set.cpp
* I/O functions, operators, aggregates etc for set types
*
*
*
* IDENTIFICATION
* src/backend/utils/adt/set.cpp
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/hash.h"
#include "catalog/indexing.h"
#include "catalog/pg_set.h"
#include "catalog/pg_type.h"
#include "libpq/pqformat.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
#include "utils/varbit.h"
#include "utils/int8.h"
#include "utils/sortsupport.h"
#include "fmgr.h"
#include "catalog/gs_collation.h"
#define KEY_NUM (2)
static VarBit* get_set_in_result(Oid settypoid, char *setlabels, Oid collation);
Datum set_in(PG_FUNCTION_ARGS)
{
char *setlabels = PG_GETARG_CSTRING(0);
Oid settypoid = PG_GETARG_OID(1);
PG_RETURN_VARBIT_P(get_set_in_result(settypoid, setlabels, PG_GET_COLLATION()));
}
Datum set_out(PG_FUNCTION_ARGS)
{
bool needdelimt = false;
Oid settypid = InvalidOid;
VarBit *data = PG_GETARG_VARBIT_P(0);
char *result = pstrdup("");
Relation pg_set = NULL;
ScanKeyData key[2];
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
bool isnull = true;
int typmod = VARBITLEN(data);
if (typmod <= int(sizeof(Oid) * BITS_PER_BYTE)) {
PG_RETURN_CSTRING(result);
}
StringInfoData buf;
initStringInfo(&buf);
settypid = *(Oid *)VARBITS(data);
bits8 *base = (bits8*)VARBITS(data) + sizeof(Oid);
pg_set = heap_open(SetRelationId, AccessShareLock);
ScanKeyInit(&key[0], Anum_pg_set_settypid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(settypid));
int1 bitlen = typmod - sizeof(Oid) * BITS_PER_BYTE;
for (int1 order = 0; order < bitlen; order++) {
bits8 *r = base + order / BITS_PER_BYTE;
bool bitset = (*r) & (1 << (order % BITS_PER_BYTE));
if (bitset) {
ScanKeyInit(&key[1], Anum_pg_set_setsortorder, BTEqualStrategyNumber, F_INT1EQ, UInt8GetDatum(order));
scan = systable_beginscan(pg_set, SetTypIdOrderIndexId, true, NULL, KEY_NUM, key);
tup = systable_getnext(scan);
if (!HeapTupleIsValid(tup)) {
systable_endscan(scan);
heap_close(pg_set, AccessShareLock);
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid internal value for set order: %d", order)));
}
text* setlabel = (text*)heap_getattr(tup, Anum_pg_set_setlabel, pg_set->rd_att, &isnull);
char* label = text_to_cstring(setlabel);
if (needdelimt) {
appendStringInfoString(&buf, SETLABELDELIMIT);
}
appendStringInfoString(&buf, label);
needdelimt = true;
pfree(label);
systable_endscan(scan);
}
}
heap_close(pg_set, AccessShareLock);
if (buf.len > 0) {
result = (char *)palloc(buf.len + 1);
errno_t rc = memcpy_s(result, buf.len + 1, buf.data, buf.len);
securec_check(rc, "\0", "\0");
result[buf.len] = '\0';
}
FreeStringInfo(&buf);
PG_RETURN_CSTRING(result);
}
Datum set_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo)PG_GETARG_POINTER(0);
Oid settypoid = PG_GETARG_OID(1);
if (get_fn_expr_argtype(fcinfo->flinfo, 0) == CSTRINGOID)
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid argument for set_recv")));
int nbytes;
char* setlabels = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
PG_RETURN_VARBIT_P(get_set_in_result(settypoid, setlabels, PG_GET_COLLATION()));
}
Datum set_send(PG_FUNCTION_ARGS)
{
Oid settypid = InvalidOid;
VarBit *data = PG_GETARG_VARBIT_P(0);
StringInfoData buf;
bool needdelimt = false;
Relation pg_set = NULL;
ScanKeyData key[2];
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
bool isnull = true;
pq_begintypsend(&buf);
int typmod = VARBITLEN(data);
if (typmod <= int(sizeof(Oid) * BITS_PER_BYTE)) {
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
settypid = *(Oid *)VARBITS(data);
bits8 *base = (bits8*)VARBITS(data) + sizeof(Oid);
pg_set = heap_open(SetRelationId, AccessShareLock);
ScanKeyInit(&key[0], Anum_pg_set_settypid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(settypid));
int1 bitlen = typmod - sizeof(Oid) * BITS_PER_BYTE;
for (int1 order = 0; order < bitlen; order++) {
bits8 *r = base + order / BITS_PER_BYTE;
bool bitset = (*r) & (1 << (order % BITS_PER_BYTE));
if (bitset) {
ScanKeyInit(&key[1], Anum_pg_set_setsortorder, BTEqualStrategyNumber, F_INT1EQ, UInt8GetDatum(order));
scan = systable_beginscan(pg_set, SetTypIdOrderIndexId, true, NULL, KEY_NUM, key);
tup = systable_getnext(scan);
if (!HeapTupleIsValid(tup)) {
systable_endscan(scan);
heap_close(pg_set, AccessShareLock);
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid internal value for set order: %d", order)));
}
text* setlabel = (text*)heap_getattr(tup, Anum_pg_set_setlabel, pg_set->rd_att, &isnull);
char* label = text_to_cstring(setlabel);
if (needdelimt) {
pq_sendtext(&buf, SETLABELDELIMIT, 1);
}
needdelimt = true;
pq_sendtext(&buf, label, strlen(label));
pfree(label);
systable_endscan(scan);
}
}
heap_close(pg_set, AccessShareLock);
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
static int64 settoint64(VarBit *bitmap)
{
int64 result = 0;
int typmod = VARBITLEN(bitmap);
bits8 *base = (bits8*)VARBITS(bitmap) + sizeof(Oid);
int1 bitlen = typmod - sizeof(Oid) * BITS_PER_BYTE;
for (int1 order = 0; order < bitlen; order++) {
bits8 *r = base + order / BITS_PER_BYTE;
bool bitset = (*r) & (1 << (order % BITS_PER_BYTE));
if (bitset) {
result |= (1UL << order);
}
}
return result;
}
static Datum int64toset(int64 val, Oid typid)
{
int bitlen = 0;
Relation pg_set = NULL;
ScanKeyData key[2];
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
if (val != 0) {
pg_set = heap_open(SetRelationId, AccessShareLock);
ScanKeyInit(&key[0], Anum_pg_set_settypid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(typid));
ScanKeyInit(&key[1], Anum_pg_set_setsortorder, BTEqualStrategyNumber, F_INT1EQ, UInt8GetDatum(0));
scan = systable_beginscan(pg_set, SetTypIdOrderIndexId, true, NULL, KEY_NUM, key);
tup = systable_getnext(scan);
if (!HeapTupleIsValid(tup)) {
systable_endscan(scan);
heap_close(pg_set, AccessShareLock);
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid input value for set %s: %ld", format_type_be(typid), val)));
}
Form_pg_set settup = (Form_pg_set)GETSTRUCT(tup);
bitlen = settup->setnum;
systable_endscan(scan);
heap_close(pg_set, AccessShareLock);
uint64 mask = (bitlen < SETLABELNUM) ? ((1UL << bitlen) - 1) : PG_UINT64_MAX;
if (val & (~mask)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid input value for set %s: %ld", format_type_be(typid), val)));
}
}
int typmod = sizeof(Oid) * BITS_PER_BYTE + bitlen;
int len = VARBITTOTALLEN(typmod);
VarBit *result = (VarBit*)palloc0(len);
*(Oid *)VARBITS(result) = typid;
bits8 *base = (bits8*)VARBITS(result) + sizeof(Oid);
for (int1 order = 0; order < bitlen; order++) {
bits8 *r = base + order / BITS_PER_BYTE;
if (val & (1UL << order)) {
(*r) |= (1 << (order % BITS_PER_BYTE));
}
}
SET_VARSIZE(result, len);
VARBITLEN(result) = typmod;
PG_RETURN_VARBIT_P(result);
}
Datum hashsetint(PG_FUNCTION_ARGS)
{
int64 val = settoint64(PG_GETARG_VARBIT_P(0));
return DirectFunctionCall1(hashint8, Int64GetDatum(val));
}
Datum hashsettext(PG_FUNCTION_ARGS)
{
char *setlabels = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
if (is_b_format_collation(PG_GET_COLLATION())) {
Datum result = hash_text_by_builtin_collations((GS_UCHAR*)setlabels, strlen(setlabels), PG_GET_COLLATION());
pfree_ext(setlabels);
return result;
}
return DirectFunctionCall1(hashtext, PointerGetDatum(cstring_to_text(setlabels)));
}
Datum btsetcmp(PG_FUNCTION_ARGS)
{
VarBit *d1 = PG_GETARG_VARBIT_P(0);
Oid settypid1 = *(Oid *)VARBITS(d1);
VarBit *d2 = PG_GETARG_VARBIT_P(1);
Oid settypid2 = *(Oid *)VARBITS(d2);
if (settypid1 == settypid2) {
int64 a = settoint64(d1);
int64 b = settoint64(d2);
return DirectFunctionCall2(btint8cmp, Int64GetDatum(a), Int64GetDatum(b));
} else {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(1)));
int result = strcmp(a, b);
PG_RETURN_INT32(result);
}
}
Datum btint4setcmp(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT32(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
return DirectFunctionCall2(btint8cmp, Int64GetDatum(a), Int64GetDatum(b));
}
Datum btsetint4cmp(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT32(1);
return DirectFunctionCall2(btint8cmp, Int64GetDatum(a), Int64GetDatum(b));
}
Datum btint2setcmp(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT16(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
return DirectFunctionCall2(btint8cmp, Int64GetDatum(a), Int64GetDatum(b));
}
Datum btsetint2cmp(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT16(1);
return DirectFunctionCall2(btint8cmp, Int64GetDatum(a), Int64GetDatum(b));
}
Datum btint8setcmp(PG_FUNCTION_ARGS)
{
int64 a = PG_GETARG_INT64(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
return DirectFunctionCall2(btint8cmp, Int64GetDatum(a), Int64GetDatum(b));
}
Datum btsetint8cmp(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = PG_GETARG_INT64(1);
return DirectFunctionCall2(btint8cmp, Int64GetDatum(a), Int64GetDatum(b));
}
Datum seteq(PG_FUNCTION_ARGS)
{
if (is_b_format_collation(PG_GET_COLLATION())) {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(1)));
bool result = (varstr_cmp_by_builtin_collations(a, strlen(a), b, strlen(b), PG_GET_COLLATION()) == 0);
PG_RETURN_BOOL(result);
}
VarBit *d1 = PG_GETARG_VARBIT_P(0);
Oid settypid1 = *(Oid *)VARBITS(d1);
VarBit *d2 = PG_GETARG_VARBIT_P(1);
Oid settypid2 = *(Oid *)VARBITS(d2);
if (settypid1 == settypid2) {
int64 a = settoint64(d1);
int64 b = settoint64(d2);
PG_RETURN_BOOL(a == b);
} else {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(1)));
int result = strcmp(a, b);
if (result == 0)
PG_RETURN_BOOL(true);
else
PG_RETURN_BOOL(false);
}
}
Datum setne(PG_FUNCTION_ARGS)
{
if (is_b_format_collation(PG_GET_COLLATION())) {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(1)));
bool result = (varstr_cmp_by_builtin_collations(a, strlen(a), b, strlen(b), PG_GET_COLLATION()) != 0);
PG_RETURN_BOOL(result);
}
VarBit *d1 = PG_GETARG_VARBIT_P(0);
Oid settypid1 = *(Oid *)VARBITS(d1);
VarBit *d2 = PG_GETARG_VARBIT_P(1);
Oid settypid2 = *(Oid *)VARBITS(d2);
if (settypid1 == settypid2) {
int64 a = settoint64(d1);
int64 b = settoint64(d2);
PG_RETURN_BOOL(a != b);
} else {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(1)));
int result = strcmp(a, b);
if (result != 0)
PG_RETURN_BOOL(true);
else
PG_RETURN_BOOL(false);
}
}
Datum setge(PG_FUNCTION_ARGS)
{
if (is_b_format_collation(PG_GET_COLLATION())) {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(1)));
bool result = (varstr_cmp_by_builtin_collations(a, strlen(a), b, strlen(b), PG_GET_COLLATION()) >= 0);
PG_RETURN_BOOL(result);
}
VarBit *d1 = PG_GETARG_VARBIT_P(0);
Oid settypid1 = *(Oid *)VARBITS(d1);
VarBit *d2 = PG_GETARG_VARBIT_P(1);
Oid settypid2 = *(Oid *)VARBITS(d2);
if (settypid1 == settypid2) {
int64 a = settoint64(d1);
int64 b = settoint64(d2);
PG_RETURN_BOOL(a >= b);
} else {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(1)));
int result = strcmp(a, b);
if (result >= 0)
PG_RETURN_BOOL(true);
else
PG_RETURN_BOOL(false);
}
}
Datum setgt(PG_FUNCTION_ARGS)
{
if (is_b_format_collation(PG_GET_COLLATION())) {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(1)));
bool result = (varstr_cmp_by_builtin_collations(a, strlen(a), b, strlen(b), PG_GET_COLLATION()) > 0);
PG_RETURN_BOOL(result);
}
VarBit *d1 = PG_GETARG_VARBIT_P(0);
Oid settypid1 = *(Oid *)VARBITS(d1);
VarBit *d2 = PG_GETARG_VARBIT_P(1);
Oid settypid2 = *(Oid *)VARBITS(d2);
if (settypid1 == settypid2) {
int64 a = settoint64(d1);
int64 b = settoint64(d2);
PG_RETURN_BOOL(a > b);
} else {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(1)));
int result = strcmp(a, b);
if (result > 0)
PG_RETURN_BOOL(true);
else
PG_RETURN_BOOL(false);
}
}
Datum setlt(PG_FUNCTION_ARGS)
{
if (is_b_format_collation(PG_GET_COLLATION())) {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(1)));
bool result = (varstr_cmp_by_builtin_collations(a, strlen(a), b, strlen(b), PG_GET_COLLATION()) < 0);
PG_RETURN_BOOL(result);
}
VarBit *d1 = PG_GETARG_VARBIT_P(0);
Oid settypid1 = *(Oid *)VARBITS(d1);
VarBit *d2 = PG_GETARG_VARBIT_P(1);
Oid settypid2 = *(Oid *)VARBITS(d2);
if (settypid1 == settypid2) {
int64 a = settoint64(d1);
int64 b = settoint64(d2);
PG_RETURN_BOOL(a < b);
} else {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(1)));
int result = strcmp(a, b);
if (result < 0)
PG_RETURN_BOOL(true);
else
PG_RETURN_BOOL(false);
}
}
Datum setle(PG_FUNCTION_ARGS)
{
if (is_b_format_collation(PG_GET_COLLATION())) {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(1)));
bool result = (varstr_cmp_by_builtin_collations(a, strlen(a), b, strlen(b), PG_GET_COLLATION()) <= 0);
PG_RETURN_BOOL(result);
}
VarBit *d1 = PG_GETARG_VARBIT_P(0);
Oid settypid1 = *(Oid *)VARBITS(d1);
VarBit *d2 = PG_GETARG_VARBIT_P(1);
Oid settypid2 = *(Oid *)VARBITS(d2);
if (settypid1 == settypid2) {
int64 a = settoint64(d1);
int64 b = settoint64(d2);
PG_RETURN_BOOL(a <= b);
} else {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(0)));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, PG_GETARG_DATUM(1)));
int result = strcmp(a, b);
if (result <= 0)
PG_RETURN_BOOL(true);
else
PG_RETURN_BOOL(false);
}
}
Datum int4seteq(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT32(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a == b);
}
Datum int4setne(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT32(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a != b);
}
Datum int4setge(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT32(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a >= b);
}
Datum int4setgt(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT32(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a > b);
}
Datum int4setlt(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT32(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a < b);
}
Datum int4setle(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT32(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a <= b);
}
Datum setint4eq(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT32(1);
PG_RETURN_BOOL(a == b);
}
Datum setint4ne(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT32(1);
PG_RETURN_BOOL(a != b);
}
Datum setint4ge(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT32(1);
PG_RETURN_BOOL(a >= b);
}
Datum setint4gt(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT32(1);
PG_RETURN_BOOL(a > b);
}
Datum setint4lt(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT32(1);
PG_RETURN_BOOL(a < b);
}
Datum setint4le(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT32(1);
PG_RETURN_BOOL(a <= b);
}
Datum int2seteq(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT16(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a == b);
}
Datum int2setne(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT16(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a != b);
}
Datum int2setge(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT16(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a >= b);
}
Datum int2setgt(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT16(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a > b);
}
Datum int2setlt(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT16(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a < b);
}
Datum int2setle(PG_FUNCTION_ARGS)
{
int64 a = (int64)PG_GETARG_INT16(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a <= b);
}
Datum setint2eq(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT16(1);
PG_RETURN_BOOL(a == b);
}
Datum setint2ne(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT16(1);
PG_RETURN_BOOL(a != b);
}
Datum setint2ge(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT16(1);
PG_RETURN_BOOL(a >= b);
}
Datum setint2gt(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT16(1);
PG_RETURN_BOOL(a > b);
}
Datum setint2lt(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT16(1);
PG_RETURN_BOOL(a < b);
}
Datum setint2le(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = (int64)PG_GETARG_INT16(1);
PG_RETURN_BOOL(a <= b);
}
Datum int8seteq(PG_FUNCTION_ARGS)
{
int64 a = PG_GETARG_INT64(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a == b);
}
Datum int8setne(PG_FUNCTION_ARGS)
{
int64 a = PG_GETARG_INT64(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a != b);
}
Datum int8setge(PG_FUNCTION_ARGS)
{
int64 a = PG_GETARG_INT64(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a >= b);
}
Datum int8setgt(PG_FUNCTION_ARGS)
{
int64 a = PG_GETARG_INT64(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a > b);
}
Datum int8setlt(PG_FUNCTION_ARGS)
{
int64 a = PG_GETARG_INT64(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a < b);
}
Datum int8setle(PG_FUNCTION_ARGS)
{
int64 a = PG_GETARG_INT64(0);
int64 b = settoint64(PG_GETARG_VARBIT_P(1));
PG_RETURN_BOOL(a <= b);
}
Datum setint8eq(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = PG_GETARG_INT64(1);
PG_RETURN_BOOL(a == b);
}
Datum setint8ne(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = PG_GETARG_INT64(1);
PG_RETURN_BOOL(a != b);
}
Datum setint8ge(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = PG_GETARG_INT64(1);
PG_RETURN_BOOL(a >= b);
}
Datum setint8gt(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = PG_GETARG_INT64(1);
PG_RETURN_BOOL(a > b);
}
Datum setint8lt(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = PG_GETARG_INT64(1);
PG_RETURN_BOOL(a < b);
}
Datum setint8le(PG_FUNCTION_ARGS)
{
int64 a = settoint64(PG_GETARG_VARBIT_P(0));
int64 b = PG_GETARG_INT64(1);
PG_RETURN_BOOL(a <= b);
}
Datum settexteq(PG_FUNCTION_ARGS)
{
Datum set = DirectFunctionCall1(settotext, PG_GETARG_DATUM(0));
return DirectFunctionCall2Coll(texteq, PG_GET_COLLATION(), PointerGetDatum(set), PG_GETARG_DATUM(1));
}
Datum settextne(PG_FUNCTION_ARGS)
{
Datum set = DirectFunctionCall1(settotext, PG_GETARG_DATUM(0));
return DirectFunctionCall2Coll(textne, PG_GET_COLLATION(), PointerGetDatum(set), PG_GETARG_DATUM(1));
}
Datum settextgt(PG_FUNCTION_ARGS)
{
Datum set = DirectFunctionCall1(settotext, PG_GETARG_DATUM(0));
return DirectFunctionCall2Coll(text_gt, PG_GET_COLLATION(), PointerGetDatum(set), PG_GETARG_DATUM(1));
}
Datum settextge(PG_FUNCTION_ARGS)
{
Datum set = DirectFunctionCall1(settotext, PG_GETARG_DATUM(0));
return DirectFunctionCall2Coll(text_ge, PG_GET_COLLATION(), PointerGetDatum(set), PG_GETARG_DATUM(1));
}
Datum settextlt(PG_FUNCTION_ARGS)
{
Datum set = DirectFunctionCall1(settotext, PG_GETARG_DATUM(0));\
return DirectFunctionCall2Coll(text_lt, PG_GET_COLLATION(), PointerGetDatum(set), PG_GETARG_DATUM(1));
}
Datum settextle(PG_FUNCTION_ARGS)
{
Datum set = DirectFunctionCall1(settotext, PG_GETARG_DATUM(0));
return DirectFunctionCall2Coll(text_le, PG_GET_COLLATION(), PointerGetDatum(set), PG_GETARG_DATUM(1));
}
Datum textseteq(PG_FUNCTION_ARGS)
{
Datum set = DirectFunctionCall1(settotext, PG_GETARG_DATUM(1));
return DirectFunctionCall2Coll(texteq, PG_GET_COLLATION(), PG_GETARG_DATUM(0), PointerGetDatum(set));
}
Datum textsetne(PG_FUNCTION_ARGS)
{
Datum set = DirectFunctionCall1(settotext, PG_GETARG_DATUM(1));
return DirectFunctionCall2Coll(textne, PG_GET_COLLATION(), PG_GETARG_DATUM(0), PointerGetDatum(set));
}
Datum textsetgt(PG_FUNCTION_ARGS)
{
Datum set = DirectFunctionCall1(settotext, PG_GETARG_DATUM(1));
return DirectFunctionCall2Coll(text_gt, PG_GET_COLLATION(), PG_GETARG_DATUM(0), PointerGetDatum(set));
}
Datum textsetge(PG_FUNCTION_ARGS)
{
Datum set = DirectFunctionCall1(settotext, PG_GETARG_DATUM(1));
return DirectFunctionCall2Coll(text_ge, PG_GET_COLLATION(), PG_GETARG_DATUM(0), PointerGetDatum(set));
}
Datum textsetlt(PG_FUNCTION_ARGS)
{
Datum set = DirectFunctionCall1(settotext, PG_GETARG_DATUM(1));
return DirectFunctionCall2Coll(text_lt, PG_GET_COLLATION(), PG_GETARG_DATUM(0), PointerGetDatum(set));
}
Datum textsetle(PG_FUNCTION_ARGS)
{
Datum set = DirectFunctionCall1(settotext, PG_GETARG_DATUM(1));
return DirectFunctionCall2Coll(text_le, PG_GET_COLLATION(), PG_GETARG_DATUM(0), PointerGetDatum(set));
}
Datum setint2(PG_FUNCTION_ARGS)
{
int64 val = settoint64(PG_GETARG_VARBIT_P(0));
return DirectFunctionCall1(int82, Int64GetDatum(val));
}
Datum setint4(PG_FUNCTION_ARGS)
{
int64 val = settoint64(PG_GETARG_VARBIT_P(0));
return DirectFunctionCall1(int84, Int64GetDatum(val));
}
Datum setint8(PG_FUNCTION_ARGS)
{
PG_RETURN_INT64(settoint64(PG_GETARG_VARBIT_P(0)));
}
Datum settof(PG_FUNCTION_ARGS)
{
int64 val = settoint64(PG_GETARG_VARBIT_P(0));
return DirectFunctionCall1(i8tof, Int64GetDatum(val));
}
Datum settod(PG_FUNCTION_ARGS)
{
int64 val = settoint64(PG_GETARG_VARBIT_P(0));
return DirectFunctionCall1(i8tod, Int64GetDatum(val));
}
Datum settonumber(PG_FUNCTION_ARGS)
{
int64 val = settoint64(PG_GETARG_VARBIT_P(0));
return DirectFunctionCall1(int8_numeric, Int64GetDatum(val));
}
Datum settobpchar(PG_FUNCTION_ARGS)
{
Datum setlabels = DirectFunctionCall1(set_out, PG_GETARG_DATUM(0));
int32 atttypmod = PG_GETARG_INT32(1);
return DirectFunctionCall3(bpcharin, PointerGetDatum(setlabels),
ObjectIdGetDatum(BPCHAROID), Int32GetDatum(atttypmod));
}
Datum settovarchar(PG_FUNCTION_ARGS)
{
Datum setlabels = DirectFunctionCall1(set_out, PG_GETARG_DATUM(0));
int32 atttypmod = PG_GETARG_INT32(1);
return DirectFunctionCall3(varcharin, PointerGetDatum(setlabels),
ObjectIdGetDatum(VARCHAROID), Int32GetDatum(atttypmod));
}
Datum settotext(PG_FUNCTION_ARGS)
{
Datum setlabels = DirectFunctionCall1(set_out, PG_GETARG_DATUM(0));
return DirectFunctionCall1(textin, PointerGetDatum(setlabels));
}
Datum settonvarchar2(PG_FUNCTION_ARGS)
{
Datum setlabels = DirectFunctionCall1(set_out, PG_GETARG_DATUM(0));
int32 atttypmod = PG_GETARG_INT32(1);
return DirectFunctionCall3(nvarchar2in, PointerGetDatum(setlabels),
ObjectIdGetDatum(NVARCHAR2OID), Int32GetDatum(atttypmod));
}
Datum i8toset(PG_FUNCTION_ARGS)
{
return int64toset(PG_GETARG_INT64(0), PG_GETARG_OID(1));
}
Datum i4toset(PG_FUNCTION_ARGS)
{
return int64toset(PG_GETARG_INT32(0), PG_GETARG_OID(1));
}
Datum i2toset(PG_FUNCTION_ARGS)
{
return int64toset(PG_GETARG_INT16(0), PG_GETARG_OID(1));
}
Datum ftoset(PG_FUNCTION_ARGS)
{
float4 val = PG_GETARG_FLOAT4(0);
return int64toset(DirectFunctionCall1(ftoi8, Float4GetDatum(val)), PG_GETARG_OID(1));
}
Datum dtoset(PG_FUNCTION_ARGS)
{
float8 val = PG_GETARG_FLOAT8(0);
return int64toset(DirectFunctionCall1(dtoi8, Float8GetDatum(val)), PG_GETARG_OID(1));
}
Datum numbertoset(PG_FUNCTION_ARGS)
{
Numeric val = PG_GETARG_NUMERIC(0);
return int64toset(DirectFunctionCall1(numeric_int8, NumericGetDatum(val)), PG_GETARG_OID(1));
}
Datum bpchartoset(PG_FUNCTION_ARGS)
{
Datum txt = PG_GETARG_DATUM(0);
text* trimtxt = (text*)DirectFunctionCall1(rtrim1, txt);
char* setlabels = TextDatumGetCString(trimtxt);
Datum result = (Datum)get_set_in_result(PG_GETARG_OID(1), setlabels, PG_GET_COLLATION());
pfree_ext(trimtxt);
pfree_ext(setlabels);
PG_RETURN_VARBIT_P(result);
}
Datum varchartoset(PG_FUNCTION_ARGS)
{
Datum txt = PG_GETARG_DATUM(0);
char* setlabels = DatumGetCString(DirectFunctionCall1(varcharout, txt));
Datum result = (Datum)get_set_in_result(PG_GETARG_OID(1), setlabels, PG_GET_COLLATION());
pfree_ext(setlabels);
PG_RETURN_VARBIT_P(result);
}
Datum texttoset(PG_FUNCTION_ARGS)
{
Datum txt = PG_GETARG_DATUM(0);
char *setlabels = DatumGetCString(DirectFunctionCall1(textout, txt));
Datum result = (Datum)get_set_in_result(PG_GETARG_OID(1), setlabels, PG_GET_COLLATION());
pfree_ext(setlabels);
PG_RETURN_VARBIT_P(result);
}
Datum nvarchar2toset(PG_FUNCTION_ARGS)
{
Datum txt = PG_GETARG_DATUM(0);
char *setlabels = DatumGetCString(DirectFunctionCall1(nvarchar2out, txt));
Datum result = (Datum)get_set_in_result(PG_GETARG_OID(1), setlabels, PG_GET_COLLATION());
pfree_ext(setlabels);
PG_RETURN_VARBIT_P(result);
}
static int btsetfastcmp(Datum x, Datum y, SortSupport ssup)
{
VarBit *d1 = DatumGetVarBitP(x);
Oid settypid1 = *(Oid *)VARBITS(d1);
VarBit *d2 = DatumGetVarBitP(y);
Oid settypid2 = *(Oid *)VARBITS(d2);
if (is_b_format_collation(ssup->ssup_collation)) {
int result;
const char *a = DatumGetCString(DirectFunctionCall1(set_out, x));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, y));
result = varstr_cmp_by_builtin_collations((char*)a, strlen(a), (char*)b, strlen(b), ssup->ssup_collation);
return result;
}
if (settypid1 == settypid2) {
int64 a = settoint64(d1);
int64 b = settoint64(d2);
if (a > b)
return 1;
else if (a == b)
return 0;
else
return -1;
} else {
const char *a = DatumGetCString(DirectFunctionCall1(set_out, x));
const char *b = DatumGetCString(DirectFunctionCall1(set_out, y));
return strcmp(a, b);
}
}
Datum btsetsortsupport(PG_FUNCTION_ARGS)
{
SortSupport ssup = (SortSupport)PG_GETARG_POINTER(0);
ssup->comparator = btsetfastcmp;
PG_RETURN_VOID();
}
Datum findinset(PG_FUNCTION_ARGS)
{
int count = 0;
bool isnull = true;
text *txt = PG_GETARG_TEXT_PP(0);
FUNC_CHECK_HUGE_POINTER(PG_ARGISNULL(0), txt, "findinset()");
char *label = text_to_cstring(txt);
if (strstr(label, ",")) {
PG_RETURN_INT32(0);
}
VarBit *data = PG_GETARG_VARBIT_P(1);
int typmod = VARBITLEN(data);
if (typmod <= int(sizeof(Oid) * BITS_PER_BYTE)) {
PG_RETURN_INT32(0);
}
Oid settypid = *(Oid *)VARBITS(data);
if (settypid == InvalidOid) {
PG_RETURN_INT32(0);
}
Relation pg_set = NULL;
ScanKeyData key[2];
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
pg_set = heap_open(SetRelationId, AccessShareLock);
ScanKeyInit(&key[0], Anum_pg_set_settypid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(settypid));
bits8 *base = (bits8*)VARBITS(data) + sizeof(Oid);
int1 bitlen = typmod - sizeof(Oid) * BITS_PER_BYTE;
for (int1 order = 0; order < bitlen; order++) {
bits8 *r = base + order / BITS_PER_BYTE;
bool bitset = (*r) & (1 << (order % BITS_PER_BYTE));
if (bitset) {
ScanKeyInit(&key[1], Anum_pg_set_setsortorder, BTEqualStrategyNumber, F_INT1EQ, UInt8GetDatum(order));
scan = systable_beginscan(pg_set, SetTypIdOrderIndexId, true, NULL, KEY_NUM, key);
tup = systable_getnext(scan);
if (!HeapTupleIsValid(tup)) {
systable_endscan(scan);
heap_close(pg_set, AccessShareLock);
PG_RETURN_INT32(0);
}
count++;
text* set = (text*)heap_getattr(tup, Anum_pg_set_setlabel, pg_set->rd_att, &isnull);
char* setlabel = text_to_cstring(set);
if (strcmp(label, setlabel) == 0) {
pfree(setlabel);
systable_endscan(scan);
heap_close(pg_set, AccessShareLock);
PG_RETURN_INT32(count);
}
pfree(setlabel);
systable_endscan(scan);
}
}
heap_close(pg_set, AccessShareLock);
PG_RETURN_INT32(0);
}
static void get_set_result(Oid settypoid, VarBit **result, Form_pg_set settup)
{
Oid *oid = NULL;
if (*result == NULL) {
int typmod = settup->setnum + sizeof(Oid) * BITS_PER_BYTE;
int len = VARBITTOTALLEN(typmod);
*result = (VarBit*)palloc0(len);
SET_VARSIZE(*result, len);
VARBITLEN(*result) = typmod;
}
oid = (Oid *)VARBITS(*result);
*oid = settypoid;
bits8 *bitmap = (bits8 *)((char*)oid + sizeof(Oid) + (settup->setsortorder / BITS_PER_BYTE));
(*bitmap) |= (1 << (settup->setsortorder % BITS_PER_BYTE));
}
static void process_set_label_by_collation(char *label, Oid settypoid, VarBit **result, Oid collation)
{
Relation pg_set = NULL;
HeapTuple tup = NULL;
ScanKeyData key[1];
SysScanDesc scan = NULL;
int res = 0;
bool find = false;
bool isnull = true;
pg_set = heap_open(SetRelationId, AccessShareLock);
ScanKeyInit(&key[0], Anum_pg_set_settypid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(settypoid));
scan = systable_beginscan(pg_set, SetTypIdLabelIndexId, true, NULL, 1, key);
while (HeapTupleIsValid(tup = systable_getnext(scan))) {
Form_pg_set settup = (Form_pg_set)GETSTRUCT(tup);
text* setlabel = (text*)heap_getattr(tup, Anum_pg_set_setlabel, pg_set->rd_att, &isnull);
res = varstr_cmp_by_builtin_collations((char*)VARDATA_ANY(setlabel), VARSIZE_ANY_EXHDR(setlabel),
label, strlen(label), collation);
if (res == 0) {
get_set_result(settypoid, result, settup);
find = true;
break;
}
}
systable_endscan(scan);
heap_close(pg_set, AccessShareLock);
if (!find) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input value for set %s: '%s'", format_type_be(settypoid), label)));
}
}
static void process_set_label(char *label, Oid settypoid, VarBit **result, Oid collation)
{
Relation pg_set = NULL;
HeapTuple tup = NULL;
text *s = cstring_to_text(label);
if (is_b_format_collation(collation)) {
process_set_label_by_collation(label, settypoid, result, collation);
} else {
if (text_length(PointerGetDatum(s)) > SETNAMELEN) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input value for set %s: \"%s\"", format_type_be(settypoid), label)));
}
ScanKeyData key[2];
SysScanDesc scan = NULL;
pg_set = heap_open(SetRelationId, AccessShareLock);
ScanKeyInit(&key[0], Anum_pg_set_settypid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(settypoid));
ScanKeyInit(&key[1], Anum_pg_set_setlabel, BTEqualStrategyNumber, F_TEXTEQ, PointerGetDatum(s));
scan = systable_beginscan(pg_set, SetTypIdLabelIndexId, true, NULL, KEY_NUM, key);
tup = systable_getnext(scan);
pfree_ext(s);
if (!HeapTupleIsValid(tup)) {
systable_endscan(scan);
heap_close(pg_set, AccessShareLock);
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input value for set %s: '%s'", format_type_be(settypoid), label)));
}
Form_pg_set settup = (Form_pg_set)GETSTRUCT(tup);
get_set_result(settypoid, result, settup);
systable_endscan(scan);
heap_close(pg_set, AccessShareLock);
}
}
static void preprocess_set_value(char *value, Oid settypoid, VarBit **result, Oid collation)
{
bool hasEmpty = false;
if (*value == '\0') {
return;
} else {
int len = strlen(value);
if (*value == ',' || *(value + len - 1) == ',') {
hasEmpty = true;
}
if (strstr(value, ",,")) {
hasEmpty = true;
}
}
if (hasEmpty) {
process_set_label("", settypoid, result, collation);
}
}
VarBit* make_default_varbit_for_set(Oid settypoid)
{
int typmod = sizeof(Oid) * BITS_PER_BYTE;
int len = VARBITTOTALLEN(typmod);
VarBit* result = (VarBit*)palloc(len);
SET_VARSIZE(result, len);
VARBITLEN(result) = typmod;
*(Oid *)VARBITS(result) = settypoid;
return result;
}
static VarBit* get_set_in_result(Oid settypoid, char *setlabels, Oid collation)
{
VarBit *result = NULL;
char* next_token = NULL;
char* labels = pstrdup(setlabels);
preprocess_set_value(setlabels, settypoid, &result, collation);
char* token = strtok_s(labels, SETLABELDELIMIT, &next_token);
while (token != NULL) {
process_set_label(token, settypoid, &result, collation);
token = strtok_s(NULL, SETLABELDELIMIT, &next_token);
}
if (result == NULL) {
result = make_default_varbit_for_set(settypoid);
}
pfree_ext(labels);
return result;
}