Datum textne(PG_FUNCTION_ARGS) { Datum arg1 = PG_GETARG_DATUM(0); Datum arg2 = PG_GETARG_DATUM(1); bool result; Size len1, len2; /* See comment in texteq() */ len1 = toast_raw_datum_size(arg1); len2 = toast_raw_datum_size(arg2); if (len1 != len2) result = true; else { text *targ1 = DatumGetTextPP(arg1); text *targ2 = DatumGetTextPP(arg2); result = (memcmp(VARDATA_ANY(targ1), VARDATA_ANY(targ2), len1 - VARHDRSZ) != 0); PG_FREE_IF_COPY(targ1, 0); PG_FREE_IF_COPY(targ2, 1); } PG_RETURN_BOOL(result); }
Datum citext_ne(PG_FUNCTION_ARGS) { text *left = PG_GETARG_TEXT_PP(0); text *right = PG_GETARG_TEXT_PP(1); char *lcstr, *rcstr; bool result; /* We can't compare lengths in advance of downcasing ... */ lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left)); rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right)); /* * Since we only care about equality or not-equality, we can avoid all the * expense of strcoll() here, and just do bitwise comparison. */ result = (strcmp(lcstr, rcstr) != 0); pfree(lcstr); pfree(rcstr); PG_FREE_IF_COPY(left, 0); PG_FREE_IF_COPY(right, 1); PG_RETURN_BOOL(result); }
Datum ora_concat(PG_FUNCTION_ARGS) { text *t1; text *t2; int l1; int l2; text *result; if (PG_ARGISNULL(0) && PG_ARGISNULL(1)) PG_RETURN_NULL(); if (PG_ARGISNULL(0)) PG_RETURN_DATUM(PG_GETARG_DATUM(1)); if (PG_ARGISNULL(1)) PG_RETURN_DATUM(PG_GETARG_DATUM(0)); t1 = PG_GETARG_TEXT_PP(0); t2 = PG_GETARG_TEXT_PP(1); l1 = VARSIZE_ANY_EXHDR(t1); l2 = VARSIZE_ANY_EXHDR(t2); result = palloc(l1+l2+VARHDRSZ); memcpy(VARDATA(result), VARDATA_ANY(t1), l1); memcpy(VARDATA(result) + l1, VARDATA_ANY(t2), l2); SET_VARSIZE(result, l1 + l2 + VARHDRSZ); PG_RETURN_TEXT_P(result); }
/* * citextcmp() * Internal comparison function for citext strings. * Returns int32 negative, zero, or positive. */ static int32 citextcmp(text *left, text *right, Oid collid) { char *lcstr, *rcstr; int32 result; /* * We must do our str_tolower calls with DEFAULT_COLLATION_OID, not the * input collation as you might expect. This is so that the behavior of * citext's equality and hashing functions is not collation-dependent. We * should change this once the core infrastructure is able to cope with * collation-dependent equality and hashing functions. */ lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID); rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID); result = varstr_cmp(lcstr, strlen(lcstr), rcstr, strlen(rcstr), collid); pfree(lcstr); pfree(rcstr); return result; }
Datum levenshtein_less_equal_with_costs(PG_FUNCTION_ARGS) { text *src = PG_GETARG_TEXT_PP(0); text *dst = PG_GETARG_TEXT_PP(1); int ins_c = PG_GETARG_INT32(2); int del_c = PG_GETARG_INT32(3); int sub_c = PG_GETARG_INT32(4); int max_d = PG_GETARG_INT32(5); const char *s_data; const char *t_data; int s_bytes, t_bytes; /* Extract a pointer to the actual character data */ s_data = VARDATA_ANY(src); t_data = VARDATA_ANY(dst); /* Determine length of each string in bytes and characters */ s_bytes = VARSIZE_ANY_EXHDR(src); t_bytes = VARSIZE_ANY_EXHDR(dst); PG_RETURN_INT32(varstr_levenshtein_less_equal(s_data, s_bytes, t_data, t_bytes, ins_c, del_c, sub_c, max_d)); }
Datum variant_image_eq(PG_FUNCTION_ARGS) { Variant l = (Variant) PG_GETARG_DATUM(0); Variant r = (Variant) PG_GETARG_DATUM(1); int cmp; /* * To avoid detoasting we use _ANY variations on VAR*, but that means we must * make sure to use VARSIZE_ANY_EXHDR, *not* VARSIZE_ANY! */ if(VARSIZE_ANY_EXHDR(l) != VARSIZE_ANY_EXHDR(r)) PG_RETURN_BOOL(false); /* * At this point we need to detoast. We could theoretically leave data * compressed, but since there's no direct support for that we don't bother. */ l = (Variant) PG_DETOAST_DATUM_PACKED(l); r = (Variant) PG_DETOAST_DATUM_PACKED(r); cmp = memcmp(VARDATA_ANY(l), VARDATA_ANY(r), VARSIZE_ANY_EXHDR(l)); PG_FREE_IF_COPY(l, 0); PG_FREE_IF_COPY(r, 1); PG_RETURN_BOOL( cmp == 0 ? true : false); }
/* * citext_pattern_cmp() * Internal character-by-character comparison function for citext strings. * Returns int32 negative, zero, or positive. */ static int32 internal_citext_pattern_cmp(text *left, text *right, Oid collid) { char *lcstr, *rcstr; int llen, rlen; int32 result; lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID); rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID); llen = strlen(lcstr); rlen = strlen(rcstr); result = memcmp((void *) lcstr, (void *) rcstr, Min(llen, rlen)); if (result == 0) { if (llen < rlen) result = -1; else if (llen > rlen) result = 1; } pfree(lcstr); pfree(rcstr); return result; }
Datum gin_compare_jsonb(PG_FUNCTION_ARGS) { text *arg1 = PG_GETARG_TEXT_PP(0); text *arg2 = PG_GETARG_TEXT_PP(1); int32 result; char *a1p, *a2p; int len1, len2; a1p = VARDATA_ANY(arg1); a2p = VARDATA_ANY(arg2); len1 = VARSIZE_ANY_EXHDR(arg1); len2 = VARSIZE_ANY_EXHDR(arg2); /* Compare text as bttextcmp does, but always using C collation */ result = varstr_cmp(a1p, len1, a2p, len2, C_COLLATION_OID); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); PG_RETURN_INT32(result); }
Datum texteq(PG_FUNCTION_ARGS) { Datum arg1 = PG_GETARG_DATUM(0); Datum arg2 = PG_GETARG_DATUM(1); bool result; Size len1, len2; /* * Since we only care about equality or not-equality, we can avoid all the * expense of strcoll() here, and just do bitwise comparison. In fact, we * don't even have to do a bitwise comparison if we can show the lengths * of the strings are unequal; which might save us from having to detoast * one or both values. */ len1 = toast_raw_datum_size(arg1); len2 = toast_raw_datum_size(arg2); if (len1 != len2) result = false; else { text *targ1 = DatumGetTextPP(arg1); text *targ2 = DatumGetTextPP(arg2); result = (memcmp(VARDATA_ANY(targ1), VARDATA_ANY(targ2), len1 - VARHDRSZ) == 0); PG_FREE_IF_COPY(targ1, 0); PG_FREE_IF_COPY(targ2, 1); } PG_RETURN_BOOL(result); }
Datum hstore_from_text(PG_FUNCTION_ARGS) { text *key; text *val = NULL; Pairs p; HStore *out; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); p.needfree = false; key = PG_GETARG_TEXT_PP(0); p.key = VARDATA_ANY(key); p.keylen = hstoreCheckKeyLen(VARSIZE_ANY_EXHDR(key)); if (PG_ARGISNULL(1)) { p.vallen = 0; p.isnull = true; } else { val = PG_GETARG_TEXT_PP(1); p.val = VARDATA_ANY(val); p.vallen = hstoreCheckValLen(VARSIZE_ANY_EXHDR(val)); p.isnull = false; } out = hstorePairs(&p, 1, p.keylen + p.vallen); PG_RETURN_POINTER(out); }
/* * byteaout - converts to printable representation of byte array * * In the traditional escaped format, non-printable characters are * printed as '\nnn' (octal) and '\' as '\\'. */ Datum probabilistic_out(PG_FUNCTION_ARGS) { bytea *vlena = PG_GETARG_BYTEA_PP(0); char *result; char *rp; if (bytea_output == BYTEA_OUTPUT_HEX) { /* Print hex format */ rp = result = palloc(VARSIZE_ANY_EXHDR(vlena) * 2 + 2 + 1); *rp++ = '\\'; *rp++ = 'x'; rp += hex_encode(VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena), rp); } else if (bytea_output == BYTEA_OUTPUT_ESCAPE) { /* Print traditional escaped format */ char *vp; int len; int i; len = 1; /* empty string has 1 char */ vp = VARDATA_ANY(vlena); for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++) { if (*vp == '\\') len += 2; else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e) len += 4; else len++; } rp = result = (char *) palloc(len); vp = VARDATA_ANY(vlena); for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++) { if (*vp == '\\') { *rp++ = '\\'; *rp++ = '\\'; } else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e) { int val; /* holds unprintable chars */ val = *vp; rp[0] = '\\'; rp[3] = DIG(val & 07); val >>= 3; rp[2] = DIG(val & 07); val >>= 3; rp[1] = DIG(val & 03); rp += 4; } else
Datum rtrim(PG_FUNCTION_ARGS) { text *string = PG_GETARG_TEXT_PP(0); text *set = PG_GETARG_TEXT_PP(1); text *ret; ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string), VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set), false, true); PG_RETURN_TEXT_P(ret); }
Datum pg_decrypt_iv(PG_FUNCTION_ARGS) { int err; bytea *data, *key, *iv, *res; text *type; PX_Combo *c; unsigned dlen, klen, rlen, ivlen; type = PG_GETARG_TEXT_PP(3); c = find_provider(type, (PFN) px_find_combo, "Cipher", 0); data = PG_GETARG_BYTEA_PP(0); key = PG_GETARG_BYTEA_PP(1); iv = PG_GETARG_BYTEA_PP(2); dlen = VARSIZE_ANY_EXHDR(data); klen = VARSIZE_ANY_EXHDR(key); ivlen = VARSIZE_ANY_EXHDR(iv); rlen = px_combo_decrypt_len(c, dlen); res = palloc(VARHDRSZ + rlen); err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen, (uint8 *) VARDATA_ANY(iv), ivlen); if (!err) err = px_combo_decrypt(c, (uint8 *) VARDATA_ANY(data), dlen, (uint8 *) VARDATA(res), &rlen); px_combo_free(c); if (err) ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), errmsg("decrypt_iv error: %s", px_strerror(err)))); SET_VARSIZE(res, VARHDRSZ + rlen); PG_FREE_IF_COPY(data, 0); PG_FREE_IF_COPY(key, 1); PG_FREE_IF_COPY(iv, 2); PG_FREE_IF_COPY(type, 3); PG_RETURN_BYTEA_P(res); }
Datum strict_word_similarity_commutator_op(PG_FUNCTION_ARGS) { text *in1 = PG_GETARG_TEXT_PP(0); text *in2 = PG_GETARG_TEXT_PP(1); float4 res; res = calc_word_similarity(VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2), VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1), WORD_SIMILARITY_CHECK_ONLY | WORD_SIMILARITY_STRICT); PG_FREE_IF_COPY(in1, 0); PG_FREE_IF_COPY(in2, 1); PG_RETURN_BOOL(res >= strict_word_similarity_threshold); }
Datum word_similarity_commutator_op(PG_FUNCTION_ARGS) { text *in1 = PG_GETARG_TEXT_PP(0); text *in2 = PG_GETARG_TEXT_PP(1); float4 res; res = calc_word_similarity(VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2), VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1), true); PG_FREE_IF_COPY(in1, 0); PG_FREE_IF_COPY(in2, 1); PG_RETURN_BOOL(res >= word_similarity_threshold); }
Datum strict_word_similarity_dist_op(PG_FUNCTION_ARGS) { text *in1 = PG_GETARG_TEXT_PP(0); text *in2 = PG_GETARG_TEXT_PP(1); float4 res; res = calc_word_similarity(VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1), VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2), WORD_SIMILARITY_STRICT); PG_FREE_IF_COPY(in1, 0); PG_FREE_IF_COPY(in2, 1); PG_RETURN_FLOAT4(1.0 - res); }
Datum gin_cmp_tslexeme(PG_FUNCTION_ARGS) { text *a = PG_GETARG_TEXT_PP(0); text *b = PG_GETARG_TEXT_PP(1); int cmp; cmp = tsCompareString(VARDATA_ANY(a), VARSIZE_ANY_EXHDR(a), VARDATA_ANY(b), VARSIZE_ANY_EXHDR(b), false); PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(b, 1); PG_RETURN_INT32(cmp); }
Datum word_similarity_dist_commutator_op(PG_FUNCTION_ARGS) { text *in1 = PG_GETARG_TEXT_PP(0); text *in2 = PG_GETARG_TEXT_PP(1); float4 res; res = calc_word_similarity(VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2), VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1), false); PG_FREE_IF_COPY(in1, 0); PG_FREE_IF_COPY(in2, 1); PG_RETURN_FLOAT4(1.0 - res); }
/* * Converts a VARCHAR2 type to the specified size. * * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes. * isExplicit is true if this is for an explicit cast to varchar2(N). * * Truncation rules: for an explicit cast, silently truncate to the given * length; for an implicit cast, raise error if length limit is exceeded */ PGDLLEXPORT Datum varchar2(PG_FUNCTION_ARGS) { VarChar *source = PG_GETARG_VARCHAR_PP(0); int32 typmod = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); int32 len, maxlen; char *s_data; len = VARSIZE_ANY_EXHDR(source); s_data = VARDATA_ANY(source); maxlen = typmod - VARHDRSZ; /* No work if typmod is invalid or supplied data fits it already */ if (maxlen < 0 || len <= maxlen) PG_RETURN_VARCHAR_P(source); /* error out if value too long unless it's an explicit cast */ if (!isExplicit) { if (len > maxlen) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input value length is %d; too long for type varchar2(%d)",len ,maxlen))); } PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(s_data,maxlen)); }
Datum ipaddr_cast_from_text(PG_FUNCTION_ARGS) { text *txt = PG_GETARG_TEXT_PP(0); int tlen = VARSIZE_ANY_EXHDR(txt); char buf[IP6_STRING_MAX]; if (tlen < sizeof(buf)) { IP ip; memcpy(buf, VARDATA_ANY(txt), tlen); buf[tlen] = 0; if (strchr(buf,':')) { if (ip6_raw_input(buf, ip.ip6.bits)) PG_RETURN_IP_P(ip_pack(PGSQL_AF_INET6, &ip)); } else { if (ip4_raw_input(buf, &ip.ip4)) PG_RETURN_IP_P(ip_pack(PGSQL_AF_INET, &ip)); } } ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid IP value in text"))); PG_RETURN_NULL(); }
Datum ipaddr_hash(PG_FUNCTION_ARGS) { IP_P arg1 = PG_GETARG_IP_P(0); return hash_any((void*)(VARDATA_ANY(arg1)), VARSIZE_ANY_EXHDR(arg1)); }
Datum count_distinct_deserial(PG_FUNCTION_ARGS) { element_set_t *eset = (element_set_t *)palloc(sizeof(element_set_t)); bytea *state = (bytea *)PG_GETARG_POINTER(0); #ifdef USE_ASSERT_CHECKING Size len = VARSIZE_ANY_EXHDR(state); #endif char *ptr = VARDATA_ANY(state); CHECK_AGG_CONTEXT("count_distinct_deserial", fcinfo); Assert(len > 0); Assert((len - offsetof(element_set_t, data)) > 0); /* copy the header */ memcpy(eset, ptr, offsetof(element_set_t, data)); ptr += offsetof(element_set_t, data); Assert((eset->nall > 0) && (eset->nall == eset->nsorted)); Assert(len == offsetof(element_set_t, data) + eset->nall * eset->item_size); /* we only allocate the necessary space */ eset->data = palloc(eset->nall * eset->item_size); eset->nbytes = eset->nall * eset->item_size; memcpy((void *)eset->data, ptr, eset->nall * eset->item_size); PG_RETURN_POINTER(eset); }
/* * ConvertDatumToBytes converts datum to byte array and saves it in the given * datum string. */ static void ConvertDatumToBytes(Datum datum, TypeCacheEntry *datumTypeCacheEntry, StringInfo datumString) { int16 datumTypeLength = datumTypeCacheEntry->typlen; bool datumTypeByValue = datumTypeCacheEntry->typbyval; Size datumSize = 0; if (datumTypeLength == -1) { datumSize = VARSIZE_ANY_EXHDR(DatumGetPointer(datum)); } else { datumSize = datumGetSize(datum, datumTypeByValue, datumTypeLength); } if (datumTypeByValue) { appendBinaryStringInfo(datumString, (char *) &datum, datumSize); } else { appendBinaryStringInfo(datumString, VARDATA_ANY(datum), datumSize); } }
Datum jsonb_exists(PG_FUNCTION_ARGS) { Jsonb *jb = PG_GETARG_JSONB(0); text *key = PG_GETARG_TEXT_PP(1); JsonbValue kval; JsonbValue *v = NULL; /* * We only match Object keys (which are naturally always Strings), or * string elements in arrays. In particular, we do not match non-string * scalar elements. Existence of a key/element is only considered at the * top level. No recursion occurs. */ kval.type = jbvString; kval.val.string.val = VARDATA_ANY(key); kval.val.string.len = VARSIZE_ANY_EXHDR(key); v = findJsonbValueFromSuperHeader(VARDATA(jb), JB_FOBJECT | JB_FARRAY, NULL, &kval); PG_RETURN_BOOL(v != NULL); }
/* * Update range within LO */ Datum be_lo_put(PG_FUNCTION_ARGS) { Oid loOid = PG_GETARG_OID(0); int64 offset = PG_GETARG_INT64(1); bytea *str = PG_GETARG_BYTEA_PP(2); LargeObjectDesc *loDesc; int written PG_USED_FOR_ASSERTS_ONLY; CreateFSContext(); loDesc = inv_open(loOid, INV_WRITE, fscxt); /* Permission check */ if (!lo_compat_privileges && pg_largeobject_aclcheck_snapshot(loDesc->id, GetUserId(), ACL_UPDATE, loDesc->snapshot) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for large object %u", loDesc->id))); inv_seek(loDesc, offset, SEEK_SET); written = inv_write(loDesc, VARDATA_ANY(str), VARSIZE_ANY_EXHDR(str)); Assert(written == VARSIZE_ANY_EXHDR(str)); inv_close(loDesc); PG_RETURN_VOID(); }
/* * len < 0 means "length is not specified". */ static text * ora_substr(Datum str, int start, int len) { if (start == 0) start = 1; /* 0 is interpreted as 1 */ else if (start < 0) { text *t; int32 n; t = DatumGetTextPP(str); n = pg_mbstrlen_with_len(VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t)); start = n + start + 1; if (start <= 0) return cstring_to_text(""); str = PointerGetDatum(t); /* save detoasted text */ } if (len < 0) return DatumGetTextP(DirectFunctionCall2(text_substr_no_len, str, Int32GetDatum(start))); else return DatumGetTextP(DirectFunctionCall3(text_substr, str, Int32GetDatum(start), Int32GetDatum(len))); }
int ora_mb_strlen1(text *str) { int r_len; int c; char *p; r_len = VARSIZE_ANY_EXHDR(str); if (pg_database_encoding_max_length() == 1) return r_len; p = VARDATA_ANY(str); c = 0; while (r_len > 0) { int sz; sz = _pg_mblen(p); p += sz; r_len -= sz; c += 1; } return c; }
Datum pg_digest(PG_FUNCTION_ARGS) { bytea *arg; text *name; unsigned len, hlen; PX_MD *md; bytea *res; name = PG_GETARG_TEXT_PP(1); /* will give error if fails */ md = find_provider(name, (PFN) px_find_digest, "Digest", 0); hlen = px_md_result_size(md); res = (text *) palloc(hlen + VARHDRSZ); SET_VARSIZE(res, hlen + VARHDRSZ); arg = PG_GETARG_BYTEA_PP(0); len = VARSIZE_ANY_EXHDR(arg); px_md_update(md, (uint8 *) VARDATA_ANY(arg), len); px_md_finish(md, (uint8 *) VARDATA(res)); px_md_free(md); PG_FREE_IF_COPY(arg, 0); PG_FREE_IF_COPY(name, 1); PG_RETURN_BYTEA_P(res); }
/* * Make substring, can handle negative start * */ int ora_mb_strlen(text *str, char **sizes, int **positions) { int r_len; int cur_size = 0; int sz; char *p; int cur = 0; p = VARDATA_ANY(str); r_len = VARSIZE_ANY_EXHDR(str); if (NULL != sizes) *sizes = palloc(r_len * sizeof(char)); if (NULL != positions) *positions = palloc(r_len * sizeof(int)); while (cur < r_len) { sz = _pg_mblen(p); if (sizes) (*sizes)[cur_size] = sz; if (positions) (*positions)[cur_size] = cur; cur += sz; p += sz; cur_size += 1; } return cur_size; }
/* text_cmp() * Internal comparison function for text strings. * Returns -1, 0 or 1 */ static int text_cmp(text *arg1, text *arg2, Oid collid) { char *a1p, *a2p; int len1, len2; a1p = VARDATA_ANY(arg1); a2p = VARDATA_ANY(arg2); len1 = VARSIZE_ANY_EXHDR(arg1); len2 = VARSIZE_ANY_EXHDR(arg2); return varstr_cmp(a1p, len1, a2p, len2, collid); }