/* * Compute the difference in bytes between two WAL locations. */ Datum pg_xlog_location_diff(PG_FUNCTION_ARGS) { text *location1 = PG_GETARG_TEXT_P(0); text *location2 = PG_GETARG_TEXT_P(1); char *str1, *str2; XLogRecPtr loc1, loc2; Numeric result; /* * Read and parse input */ str1 = text_to_cstring(location1); str2 = text_to_cstring(location2); validate_xlog_location(str1); validate_xlog_location(str2); if (sscanf(str1, "%X/%X", &loc1.xlogid, &loc1.xrecoff) != 2) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not parse transaction log location \"%s\"", str1))); if (sscanf(str2, "%X/%X", &loc2.xlogid, &loc2.xrecoff) != 2) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not parse transaction log location \"%s\"", str2))); /* * Sanity check */ if (loc1.xrecoff > XLogFileSize) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("xrecoff \"%X\" is out of valid range, 0..%X", loc1.xrecoff, XLogFileSize))); if (loc2.xrecoff > XLogFileSize) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("xrecoff \"%X\" is out of valid range, 0..%X", loc2.xrecoff, XLogFileSize))); /* * result = XLogFileSize * (xlogid1 - xlogid2) + xrecoff1 - xrecoff2 */ result = DatumGetNumeric(DirectFunctionCall2(numeric_sub, DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) loc1.xlogid)), DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) loc2.xlogid)))); result = DatumGetNumeric(DirectFunctionCall2(numeric_mul, DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) XLogFileSize)), NumericGetDatum(result))); result = DatumGetNumeric(DirectFunctionCall2(numeric_add, NumericGetDatum(result), DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) loc1.xrecoff)))); result = DatumGetNumeric(DirectFunctionCall2(numeric_sub, NumericGetDatum(result), DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) loc2.xrecoff)))); PG_RETURN_NUMERIC(result); }
static int numeric_comparator(const void *a, const void *b) { FunctionCallInfoData fcinfo; /* set params */ fcinfo.arg[0] = NumericGetDatum(*(Numeric*)a); fcinfo.arg[1] = NumericGetDatum(*(Numeric*)b); fcinfo.argnull[0] = false; fcinfo.argnull[1] = false; /* return the result */ return DatumGetInt32(numeric_cmp(&fcinfo)); }
static Jsonb * jnumber_op(PGFunction f, Jsonb *l, Jsonb *r) { FunctionCallInfoData fcinfo; JsonbValue *jv; Datum n; AssertArg(r != NULL); if (!((l == NULL || JB_ROOT_IS_SCALAR(l)) && JB_ROOT_IS_SCALAR(r))) ereport_op(f, l, r); InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); if (l != NULL) { jv = getIthJsonbValueFromContainer(&l->root, 0); if (jv->type != jbvNumeric) ereport_op(f, l, r); fcinfo.arg[fcinfo.nargs] = NumericGetDatum(jv->val.numeric); fcinfo.argnull[fcinfo.nargs] = false; fcinfo.nargs++; } jv = getIthJsonbValueFromContainer(&r->root, 0); if (jv->type != jbvNumeric) ereport_op(f, l, r); fcinfo.arg[fcinfo.nargs] = NumericGetDatum(jv->val.numeric); fcinfo.argnull[fcinfo.nargs] = false; fcinfo.nargs++; n = (*f) (&fcinfo); if (fcinfo.isnull) elog(ERROR, "function %p returned NULL", (void *) f); if (f == numeric_power || f == numeric_div) { int s; s = DatumGetInt32(DirectFunctionCall1(numeric_scale, fcinfo.arg[0])) + DatumGetInt32(DirectFunctionCall1(numeric_scale, fcinfo.arg[1])); if (s == 0) n = DirectFunctionCall2(numeric_trunc, n, 0); } return numeric_to_jnumber(DatumGetNumeric(n)); }
Datum HASHAPI_Hash_1_numeric(PG_FUNCTION_ARGS) { int32 num_segs; /* number of segments */ Numeric val1; /* NUMERIC value */ unsigned int targetbucket; /* 0-based */ int16 algorithm; /* hashing algorithm */ Datum d1; Oid oid; /* Get number of segments */ num_segs = PG_GETARG_INT32(0); /* Get hashing algoriithm */ algorithm = PG_GETARG_INT16(1); /* Get the value to hash */ val1 = PG_GETARG_NUMERIC(2); d1 = NumericGetDatum(val1); /* create a CdbHash for this hash test. */ h = makeCdbHash(num_segs, algorithm); /* init cdb hash */ cdbhashinit(h); oid = NUMERICOID; cdbhash(h, d1, oid); /* reduce the result hash value */ targetbucket = cdbhashreduce(h); PG_RETURN_INT32(targetbucket); /* return target bucket (segID) */ }
Datum orafce_to_char_numeric(PG_FUNCTION_ARGS) { Numeric arg0 = PG_GETARG_NUMERIC(0); StringInfo buf = makeStringInfo(); struct lconv *lconv = PGLC_localeconv(); char *p; char *decimal = NULL; appendStringInfoString(buf, DatumGetCString(DirectFunctionCall1(numeric_out, NumericGetDatum(arg0)))); for (p = buf->data; *p; p++) if (*p == '.') { *p = lconv->decimal_point[0]; decimal = p; /* save decimal point position for the next loop */ } /* Simulate the default Oracle to_char template (TM9 - Text Minimum) by removing unneeded digits after the decimal point; if no digits are left, then remove the decimal point too */ for (p = buf->data + buf->len - 1; decimal && p >= decimal; p--) { if (*p == '0' || *p == lconv->decimal_point[0]) *p = 0; else break; /* non-zero digit found, exit the loop */ } PG_RETURN_TEXT_P(cstring_to_text(buf->data)); }
static Datum jsonb_num(Jsonb *j, PGFunction f) { const char *type; if (f == numeric_int8) type = "int8"; else if (f == numeric_int4) type = "int4"; else if (f == numeric_float8) type = "float8"; else elog(ERROR, "unexpected type"); if (JB_ROOT_IS_SCALAR(j)) { JsonbValue *jv; jv = getIthJsonbValueFromContainer(&j->root, 0); if (jv->type == jbvNumeric) { Datum n; n = DirectFunctionCall1(f, NumericGetDatum(jv->val.numeric)); return n; } } ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("%s cannot be converted to %s", JsonbToCString(NULL, &j->root, VARSIZE(j)), type))); return 0; }
Datum gin_numeric_cmp(PG_FUNCTION_ARGS) { Numeric a = (Numeric) PG_GETARG_POINTER(0); Numeric b = (Numeric) PG_GETARG_POINTER(1); int res = 0; if (NUMERIC_IS_LEFTMOST(a)) { res = (NUMERIC_IS_LEFTMOST(b)) ? 0 : -1; } else if (NUMERIC_IS_LEFTMOST(b)) { res = 1; } else { res = DatumGetInt32(DirectFunctionCall2(numeric_cmp, NumericGetDatum(a), NumericGetDatum(b))); } PG_RETURN_INT32(res); }
Datum orafce_to_char_numeric(PG_FUNCTION_ARGS) { Numeric arg0 = PG_GETARG_NUMERIC(0); StringInfo buf = makeStringInfo(); struct lconv *lconv = PGLC_localeconv(); char *p; appendStringInfoString(buf, DatumGetCString(DirectFunctionCall1(numeric_out, NumericGetDatum(arg0)))); for (p = buf->data; *p; p++) if (*p == '.') *p = lconv->decimal_point[0]; PG_RETURN_TEXT_P(cstring_to_text(buf->data)); }
static Datum numeric_to_array(FunctionCallInfo fcinfo, Numeric * d, int len) { ArrayBuildState *astate = NULL; int i; for (i = 0; i < len; i++) { /* stash away this field */ astate = accumArrayResult(astate, NumericGetDatum(d[i]), false, NUMERICOID, CurrentMemoryContext); } PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, CurrentMemoryContext)); }
Datum jsonb_numeric(PG_FUNCTION_ARGS) { Jsonb *j = PG_GETARG_JSONB(0); if (JB_ROOT_IS_SCALAR(j)) { JsonbValue *jv; jv = getIthJsonbValueFromContainer(&j->root, 0); if (jv->type == jbvNumeric) PG_RETURN_DATUM(datumCopy(NumericGetDatum(jv->val.numeric), false, -1)); } ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("%s cannot be converted to numeric", JsonbToCString(NULL, &j->root, VARSIZE(j))))); PG_RETURN_NULL(); }
Datum jsonb_bool(PG_FUNCTION_ARGS) { Jsonb *j = PG_GETARG_JSONB(0); if (JB_ROOT_IS_SCALAR(j)) { JsonbValue *jv; jv = getIthJsonbValueFromContainer(&j->root, 0); switch (jv->type) { case jbvNull: PG_RETURN_NULL(); case jbvString: PG_RETURN_BOOL(jv->val.string.len > 0); case jbvNumeric: { Datum b; if (numeric_is_nan(jv->val.numeric)) PG_RETURN_BOOL(false); b = DirectFunctionCall2(numeric_ne, NumericGetDatum(jv->val.numeric), get_numeric_0_datum()); PG_RETURN_DATUM(b); } case jbvBool: PG_RETURN_BOOL(jv->val.boolean); default: elog(ERROR, "unknown jsonb scalar type"); } } Assert(JB_ROOT_IS_OBJECT(j) || JB_ROOT_IS_ARRAY(j)); PG_RETURN_BOOL(JB_ROOT_COUNT(j) > 0); }
/* * PLyObject_FromJsonbValue * * Transform JsonbValue to PyObject. */ static PyObject * PLyObject_FromJsonbValue(JsonbValue *jsonbValue) { switch (jsonbValue->type) { case jbvNull: Py_RETURN_NONE; case jbvBinary: return PLyObject_FromJsonbContainer(jsonbValue->val.binary.data); case jbvNumeric: { Datum num; char *str; num = NumericGetDatum(jsonbValue->val.numeric); str = DatumGetCString(DirectFunctionCall1(numeric_out, num)); return PyObject_CallFunction(decimal_constructor, "s", str); } case jbvString: return PLyString_FromJsonbValue(jsonbValue); case jbvBool: if (jsonbValue->val.boolean) Py_RETURN_TRUE; else Py_RETURN_FALSE; default: elog(ERROR, "unexpected jsonb value type: %d", jsonbValue->type); return NULL; } }
/* * Deserialize a HeapTuple's data from a byte-array. * * This code is based on the binary input handling functions in copy.c. */ HeapTuple DeserializeTuple(SerTupInfo * pSerInfo, StringInfo serialTup) { MemoryContext oldCtxt; TupleDesc tupdesc; HeapTuple htup; int natts; SerAttrInfo *attrInfo; uint32 attr_size; int i; StringInfoData attr_data; bool fHandled; AssertArg(pSerInfo != NULL); AssertArg(serialTup != NULL); tupdesc = pSerInfo->tupdesc; natts = tupdesc->natts; /* * Flip to our tuple-serialization memory-context, to speed up memory * reclamation operations. */ AssertState(s_tupSerMemCtxt != NULL); oldCtxt = MemoryContextSwitchTo(s_tupSerMemCtxt); /* Receive nulls character-array. */ pq_copymsgbytes(serialTup, pSerInfo->nulls, natts); skipPadding(serialTup); /* Deserialize the non-NULL attributes of this tuple */ initStringInfo(&attr_data); for (i = 0; i < natts; ++i) { attrInfo = pSerInfo->myinfo + i; if (pSerInfo->nulls[i]) /* NULL field. */ { pSerInfo->values[i] = (Datum) 0; continue; } /* * Assume that the data's output will be handled by the special IO * code, and if not then we can handle it the slow way. */ fHandled = true; switch (attrInfo->atttypid) { case INT4OID: pSerInfo->values[i] = Int32GetDatum(stringInfoGetInt32(serialTup)); break; case CHAROID: pSerInfo->values[i] = CharGetDatum(pq_getmsgbyte(serialTup)); skipPadding(serialTup); break; case BPCHAROID: case VARCHAROID: case INT2VECTOROID: /* postgres serialization logic broken, use our own */ case OIDVECTOROID: /* postgres serialization logic broken, use our own */ case ANYARRAYOID: { text *pText; int textSize; textSize = stringInfoGetInt32(serialTup); #ifdef TUPSER_SCRATCH_SPACE if (textSize + VARHDRSZ <= attrInfo->varlen_scratch_size) pText = (text *) attrInfo->pv_varlen_scratch; else pText = (text *) palloc(textSize + VARHDRSZ); #else pText = (text *) palloc(textSize + VARHDRSZ); #endif SET_VARSIZE(pText, textSize + VARHDRSZ); pq_copymsgbytes(serialTup, VARDATA(pText), textSize); skipPadding(serialTup); pSerInfo->values[i] = PointerGetDatum(pText); break; } case DATEOID: { /* * TODO: I would LIKE to do something more efficient, but * DateADT is not strictly limited to 4 bytes by its * definition. */ DateADT date; pq_copymsgbytes(serialTup, (char *) &date, sizeof(DateADT)); skipPadding(serialTup); pSerInfo->values[i] = DateADTGetDatum(date); break; } case NUMERICOID: { /* * Treat the numeric as a varlena variable, and just push * the whole shebang to the output-buffer. We don't care * about the guts of the numeric. */ Numeric num; int numSize; numSize = stringInfoGetInt32(serialTup); #ifdef TUPSER_SCRATCH_SPACE if (numSize + VARHDRSZ <= attrInfo->varlen_scratch_size) num = (Numeric) attrInfo->pv_varlen_scratch; else num = (Numeric) palloc(numSize + VARHDRSZ); #else num = (Numeric) palloc(numSize + VARHDRSZ); #endif SET_VARSIZE(num, numSize + VARHDRSZ); pq_copymsgbytes(serialTup, VARDATA(num), numSize); skipPadding(serialTup); pSerInfo->values[i] = NumericGetDatum(num); break; } case ACLITEMOID: { int aclSize, k, cnt; char *inputstring, *starsfree; aclSize = stringInfoGetInt32(serialTup); inputstring = (char*) palloc(aclSize + 1); starsfree = (char*) palloc(aclSize + 1); cnt = 0; pq_copymsgbytes(serialTup, inputstring, aclSize); skipPadding(serialTup); inputstring[aclSize] = '\0'; for(k=0; k<aclSize; k++) { if( inputstring[k] != '*') { starsfree[cnt] = inputstring[k]; cnt++; } } starsfree[cnt] = '\0'; pSerInfo->values[i] = DirectFunctionCall1(aclitemin, CStringGetDatum(starsfree)); pfree(inputstring); break; } case 210: { int strsize; char *smgrstr; strsize = stringInfoGetInt32(serialTup); smgrstr = (char*) palloc(strsize + 1); pq_copymsgbytes(serialTup, smgrstr, strsize); skipPadding(serialTup); smgrstr[strsize] = '\0'; pSerInfo->values[i] = DirectFunctionCall1(smgrin, CStringGetDatum(smgrstr)); break; } default: fHandled = false; } if (fHandled) continue; attr_size = stringInfoGetInt32(serialTup); /* reset attr_data to empty, and load raw data into it */ attr_data.len = 0; attr_data.data[0] = '\0'; attr_data.cursor = 0; appendBinaryStringInfo(&attr_data, pq_getmsgbytes(serialTup, attr_size), attr_size); skipPadding(serialTup); /* Call the attribute type's binary input converter. */ if (attrInfo->recv_finfo.fn_nargs == 1) pSerInfo->values[i] = FunctionCall1(&attrInfo->recv_finfo, PointerGetDatum(&attr_data)); else if (attrInfo->recv_finfo.fn_nargs == 2) pSerInfo->values[i] = FunctionCall2(&attrInfo->recv_finfo, PointerGetDatum(&attr_data), ObjectIdGetDatum(attrInfo->recv_typio_param)); else if (attrInfo->recv_finfo.fn_nargs == 3) pSerInfo->values[i] = FunctionCall3(&attrInfo->recv_finfo, PointerGetDatum(&attr_data), ObjectIdGetDatum(attrInfo->recv_typio_param), Int32GetDatum(tupdesc->attrs[i]->atttypmod) ); else { ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("Conversion function takes %d args",attrInfo->recv_finfo.fn_nargs))); } /* Trouble if it didn't eat the whole buffer */ if (attr_data.cursor != attr_data.len) { ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("incorrect binary data format"))); } } /* * Construct the tuple from the Datums and nulls values. NOTE: Switch * out of our temporary context before we form the tuple! */ MemoryContextSwitchTo(oldCtxt); htup = heap_form_tuple(tupdesc, pSerInfo->values, pSerInfo->nulls); MemoryContextReset(s_tupSerMemCtxt); /* All done. Return the result. */ return htup; }
Datum gbt_numeric_penalty(PG_FUNCTION_ARGS) { GISTENTRY *o = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *n = (GISTENTRY *) PG_GETARG_POINTER(1); float *result = (float *) PG_GETARG_POINTER(2); Numeric us, os, ds; GBT_VARKEY *org = (GBT_VARKEY *) DatumGetPointer(o->key); GBT_VARKEY *newe = (GBT_VARKEY *) DatumGetPointer(n->key); Datum uni; GBT_VARKEY_R rk, ok, uk; rk = gbt_var_key_readable(org); uni = PointerGetDatum(gbt_var_key_copy(&rk, TRUE)); gbt_var_bin_union(&uni, newe, &tinfo); ok = gbt_var_key_readable(org); uk = gbt_var_key_readable((GBT_VARKEY *) DatumGetPointer(uni)); us = DatumGetNumeric(DirectFunctionCall2( numeric_sub, PointerGetDatum(uk.upper), PointerGetDatum(uk.lower) )); os = DatumGetNumeric(DirectFunctionCall2( numeric_sub, PointerGetDatum(ok.upper), PointerGetDatum(ok.lower) )); ds = DatumGetNumeric(DirectFunctionCall2( numeric_sub, NumericGetDatum(us), NumericGetDatum(os) )); if (numeric_is_nan(us)) { if (numeric_is_nan(os)) *result = 0.0; else *result = 1.0; } else { Numeric nul = DatumGetNumeric(DirectFunctionCall1(int4_numeric, Int32GetDatum(0))); *result = 0.0; if (DirectFunctionCall2(numeric_gt, NumericGetDatum(ds), NumericGetDatum(nul))) { *result += FLT_MIN; os = DatumGetNumeric(DirectFunctionCall2( numeric_div, NumericGetDatum(ds), NumericGetDatum(us) )); *result += (float4) DatumGetFloat8(DirectFunctionCall1(numeric_float8_no_overflow, NumericGetDatum(os))); } } if (*result > 0) *result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1)); PG_RETURN_POINTER(result); }
/* * jsonb_object_agg aggregate function */ Datum jsonb_object_agg_transfn(PG_FUNCTION_ARGS) { MemoryContext oldcontext, aggcontext; JsonbInState elem; JsonbAggState *state; Datum val; JsonbInState *result; bool single_scalar; JsonbIterator *it; Jsonb *jbkey, *jbval; JsonbValue v; JsonbIteratorToken type; if (!AggCheckCallContext(fcinfo, &aggcontext)) { /* cannot be called directly because of internal-type argument */ elog(ERROR, "jsonb_object_agg_transfn called in non-aggregate context"); } /* set up the accumulator on the first go round */ if (PG_ARGISNULL(0)) { Oid arg_type; oldcontext = MemoryContextSwitchTo(aggcontext); state = palloc(sizeof(JsonbAggState)); result = palloc0(sizeof(JsonbInState)); state->res = result; result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_OBJECT, NULL); MemoryContextSwitchTo(oldcontext); arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1); if (arg_type == InvalidOid) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data type"))); jsonb_categorize_type(arg_type, &state->key_category, &state->key_output_func); arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2); if (arg_type == InvalidOid) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data type"))); jsonb_categorize_type(arg_type, &state->val_category, &state->val_output_func); } else { state = (JsonbAggState *) PG_GETARG_POINTER(0); result = state->res; } /* turn the argument into jsonb in the normal function context */ if (PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("field name must not be null"))); val = PG_GETARG_DATUM(1); memset(&elem, 0, sizeof(JsonbInState)); datum_to_jsonb(val, false, &elem, state->key_category, state->key_output_func, true); jbkey = JsonbValueToJsonb(elem.res); val = PG_ARGISNULL(2) ? (Datum) 0 : PG_GETARG_DATUM(2); memset(&elem, 0, sizeof(JsonbInState)); datum_to_jsonb(val, PG_ARGISNULL(2), &elem, state->val_category, state->val_output_func, false); jbval = JsonbValueToJsonb(elem.res); it = JsonbIteratorInit(&jbkey->root); /* switch to the aggregate context for accumulation operations */ oldcontext = MemoryContextSwitchTo(aggcontext); /* * keys should be scalar, and we should have already checked for that * above when calling datum_to_jsonb, so we only need to look for these * things. */ while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) { switch (type) { case WJB_BEGIN_ARRAY: if (!v.val.array.rawScalar) elog(ERROR, "unexpected structure for key"); break; case WJB_ELEM: if (v.type == jbvString) { /* copy string values in the aggregate context */ char *buf = palloc(v.val.string.len + 1); snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val); v.val.string.val = buf; } else { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("object keys must be strings"))); } result->res = pushJsonbValue(&result->parseState, WJB_KEY, &v); break; case WJB_END_ARRAY: break; default: elog(ERROR, "unexpected structure for key"); break; } } it = JsonbIteratorInit(&jbval->root); single_scalar = false; /* * values can be anything, including structured and null, so we treat them * as in json_agg_transfn, except that single scalars are always pushed as * WJB_VALUE items. */ while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) { switch (type) { case WJB_BEGIN_ARRAY: if (v.val.array.rawScalar) single_scalar = true; else result->res = pushJsonbValue(&result->parseState, type, NULL); break; case WJB_END_ARRAY: if (!single_scalar) result->res = pushJsonbValue(&result->parseState, type, NULL); break; case WJB_BEGIN_OBJECT: case WJB_END_OBJECT: result->res = pushJsonbValue(&result->parseState, type, NULL); break; case WJB_ELEM: case WJB_KEY: case WJB_VALUE: if (v.type == jbvString) { /* copy string values in the aggregate context */ char *buf = palloc(v.val.string.len + 1); snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val); v.val.string.val = buf; } else if (v.type == jbvNumeric) { /* same for numeric */ v.val.numeric = DatumGetNumeric(DirectFunctionCall1(numeric_uplus, NumericGetDatum(v.val.numeric))); } result->res = pushJsonbValue(&result->parseState, single_scalar ? WJB_VALUE : type, &v); break; default: elog(ERROR, "unknown jsonb iterator token type"); } } MemoryContextSwitchTo(oldcontext); PG_RETURN_POINTER(state); }
/* * jsonb_agg aggregate function */ Datum jsonb_agg_transfn(PG_FUNCTION_ARGS) { MemoryContext oldcontext, aggcontext; JsonbAggState *state; JsonbInState elem; Datum val; JsonbInState *result; bool single_scalar = false; JsonbIterator *it; Jsonb *jbelem; JsonbValue v; JsonbIteratorToken type; if (!AggCheckCallContext(fcinfo, &aggcontext)) { /* cannot be called directly because of internal-type argument */ elog(ERROR, "jsonb_agg_transfn called in non-aggregate context"); } /* set up the accumulator on the first go round */ if (PG_ARGISNULL(0)) { Oid arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1); if (arg_type == InvalidOid) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data type"))); oldcontext = MemoryContextSwitchTo(aggcontext); state = palloc(sizeof(JsonbAggState)); result = palloc0(sizeof(JsonbInState)); state->res = result; result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, NULL); MemoryContextSwitchTo(oldcontext); jsonb_categorize_type(arg_type, &state->val_category, &state->val_output_func); } else { state = (JsonbAggState *) PG_GETARG_POINTER(0); result = state->res; } /* turn the argument into jsonb in the normal function context */ val = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1); memset(&elem, 0, sizeof(JsonbInState)); datum_to_jsonb(val, PG_ARGISNULL(1), &elem, state->val_category, state->val_output_func, false); jbelem = JsonbValueToJsonb(elem.res); /* switch to the aggregate context for accumulation operations */ oldcontext = MemoryContextSwitchTo(aggcontext); it = JsonbIteratorInit(&jbelem->root); while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) { switch (type) { case WJB_BEGIN_ARRAY: if (v.val.array.rawScalar) single_scalar = true; else result->res = pushJsonbValue(&result->parseState, type, NULL); break; case WJB_END_ARRAY: if (!single_scalar) result->res = pushJsonbValue(&result->parseState, type, NULL); break; case WJB_BEGIN_OBJECT: case WJB_END_OBJECT: result->res = pushJsonbValue(&result->parseState, type, NULL); break; case WJB_ELEM: case WJB_KEY: case WJB_VALUE: if (v.type == jbvString) { /* copy string values in the aggregate context */ char *buf = palloc(v.val.string.len + 1); snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val); v.val.string.val = buf; } else if (v.type == jbvNumeric) { /* same for numeric */ v.val.numeric = DatumGetNumeric(DirectFunctionCall1(numeric_uplus, NumericGetDatum(v.val.numeric))); } result->res = pushJsonbValue(&result->parseState, type, &v); break; default: elog(ERROR, "unknown jsonb iterator token type"); } } MemoryContextSwitchTo(oldcontext); PG_RETURN_POINTER(state); }
Datum _numeric_weighted_mean_intermediate(PG_FUNCTION_ARGS) { WeightedMeanInternalState *state; Datum value, weight, temp_total, old_sum, old_weight; MemoryContext aggcontext, oldcontext; if (!AggCheckCallContext(fcinfo, &aggcontext)) /* cannot be called directly because of internal-type argument */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("_numeric_weighted_mean_intermediate called in non-aggregate context"))); if (PG_ARGISNULL(0)) { oldcontext = MemoryContextSwitchTo(aggcontext); state = (WeightedMeanInternalState *) palloc(sizeof(WeightedMeanInternalState)); state->running_sum = make_numeric(0); state->running_weight = make_numeric(0); MemoryContextSwitchTo(oldcontext); } else state = (WeightedMeanInternalState *) PG_GETARG_POINTER(0); /* * We're non-strict, so we MUST check args for nullity ourselves before * using them. To preserve the behaviour of null inputs, we skip updating * on them. */ if (PG_ARGISNULL(1) || PG_ARGISNULL(2)) PG_RETURN_POINTER(state); /* * We fetch and process the input in the shortlived calling context to * avoid leaking memory in aggcontext per cycle. We force the input to be * detoasted here, too, in the shortlived context. (PG_GETARG_DATUM does * not detoast, but PG_GETARG_NUMERIC does.) */ value = NumericGetDatum(PG_GETARG_NUMERIC(1)); weight = NumericGetDatum(PG_GETARG_NUMERIC(2)); temp_total = DirectFunctionCall2(numeric_mul, value, weight); /* * The new running totals must be allocated in the long-lived context. We * rely on the numeric_* functions to clean up after themselves (which they * currently do, but only if the input is already detoasted); we could play * safe and copy only the final results into aggcontext, but this turns out * to have a measurable performance hit. */ oldcontext = MemoryContextSwitchTo(aggcontext); old_sum = state->running_sum; old_weight = state->running_weight; state->running_sum = DirectFunctionCall2(numeric_add, state->running_sum, temp_total); state->running_weight = DirectFunctionCall2(numeric_add, state->running_weight, weight); pfree(DatumGetPointer(old_sum)); pfree(DatumGetPointer(old_weight)); MemoryContextSwitchTo(oldcontext); PG_RETURN_POINTER(state); }
Datum _numeric_weighted_stddev_samp_intermediate(PG_FUNCTION_ARGS) { WeightedStddevSampInternalState *state; Datum value, weight, old_s_0, old_s_1, old_s_2, w_v, w_v2; MemoryContext aggcontext, oldcontext; if (!AggCheckCallContext(fcinfo, &aggcontext)) /* cannot be called directly because of internal-type argument */ elog(ERROR, "_weighted_stddev_samp_intermediate called in non-aggregate context"); if (PG_ARGISNULL(0)) { oldcontext = MemoryContextSwitchTo(aggcontext); state = (WeightedStddevSampInternalState *) palloc(sizeof(WeightedStddevSampInternalState)); state->s_2 = make_numeric(0); state->s_1 = make_numeric(0); state->s_0 = make_numeric(0); state->zero = make_numeric(0); state->n_prime = 0; MemoryContextSwitchTo(oldcontext); } else state = (WeightedStddevSampInternalState *) PG_GETARG_POINTER(0); /* * We're non-strict, so we MUST check args for nullity ourselves before * using them. To preserve the behaviour of null inputs, we skip updating * on them. */ if (PG_ARGISNULL(1) || PG_ARGISNULL(2)) PG_RETURN_POINTER(state); /* * We fetch and process the input in the shortlived calling context to * avoid leaking memory in aggcontext per cycle. We force the input to be * detoasted here, too, in the shortlived context. (PG_GETARG_DATUM does * not detoast, but PG_GETARG_NUMERIC does.) */ value = NumericGetDatum(PG_GETARG_NUMERIC(1)); weight = NumericGetDatum(PG_GETARG_NUMERIC(2)); /* * We also skip updating when the weight is zero. */ if (DatumGetBool(DirectFunctionCall2(numeric_eq, weight, state->zero))) PG_RETURN_POINTER(state); /* * Compute intermediate values w*v and w*(v^2) in the short-lived context */ w_v = DirectFunctionCall2(numeric_mul, weight, value); w_v2 = DirectFunctionCall2(numeric_mul, w_v, value); /* * The new running totals must be allocated in the long-lived context. We * rely on the numeric_* functions to clean up after themselves (which they * currently do, but only if the input is already detoasted); we could play * safe and copy only the final results into aggcontext, but this turns out * to have a measurable performance hit. */ oldcontext = MemoryContextSwitchTo(aggcontext); old_s_2 = state->s_2; old_s_1 = state->s_1; old_s_0 = state->s_0; state->s_0 = DirectFunctionCall2(numeric_add, old_s_0, weight); state->s_1 = DirectFunctionCall2(numeric_add, old_s_1, w_v); state->s_2 = DirectFunctionCall2(numeric_add, old_s_2, w_v2); state->n_prime += 1; pfree(DatumGetPointer(old_s_2)); pfree(DatumGetPointer(old_s_1)); pfree(DatumGetPointer(old_s_0)); MemoryContextSwitchTo(oldcontext); PG_RETURN_POINTER(state); }
Datum jsonb_add(PG_FUNCTION_ARGS) { Jsonb *l = PG_GETARG_JSONB(0); Jsonb *r = PG_GETARG_JSONB(1); JsonbValue *ljv; JsonbValue *rjv; JsonbValue jv; Size len; char *buf; Datum n; char *nstr; if (!(JB_ROOT_IS_SCALAR(l) && JB_ROOT_IS_SCALAR(r))) { Datum j; if ((JB_ROOT_IS_SCALAR(l) && JB_ROOT_IS_OBJECT(r)) || (JB_ROOT_IS_OBJECT(l) && JB_ROOT_IS_SCALAR(r)) || (JB_ROOT_IS_OBJECT(l) && JB_ROOT_IS_OBJECT(r))) ereport_op_str("+", l, r); j = DirectFunctionCall2(jsonb_concat, JsonbGetDatum(l), JsonbGetDatum(r)); PG_RETURN_DATUM(j); } ljv = getIthJsonbValueFromContainer(&l->root, 0); rjv = getIthJsonbValueFromContainer(&r->root, 0); if (ljv->type == jbvString && rjv->type == jbvString) { len = ljv->val.string.len + rjv->val.string.len; buf = palloc(len + 1); strncpy(buf, ljv->val.string.val, ljv->val.string.len); strncpy(buf + ljv->val.string.len, rjv->val.string.val, rjv->val.string.len); buf[len] = '\0'; jv.type = jbvString; jv.val.string.len = len; jv.val.string.val = buf; PG_RETURN_JSONB(JsonbValueToJsonb(&jv)); } else if (ljv->type == jbvString && rjv->type == jbvNumeric) { n = DirectFunctionCall1(numeric_out, NumericGetDatum(rjv->val.numeric)); nstr = DatumGetCString(n); len = ljv->val.string.len + strlen(nstr); buf = palloc(len + 1); strncpy(buf, ljv->val.string.val, ljv->val.string.len); strcpy(buf + ljv->val.string.len, nstr); jv.type = jbvString; jv.val.string.len = len; jv.val.string.val = buf; PG_RETURN_JSONB(JsonbValueToJsonb(&jv)); } else if (ljv->type == jbvNumeric && rjv->type == jbvString) { Size nlen; n = DirectFunctionCall1(numeric_out, NumericGetDatum(ljv->val.numeric)); nstr = DatumGetCString(n); nlen = strlen(nstr); len = nlen + rjv->val.string.len; buf = palloc(len + 1); strcpy(buf, nstr); strncpy(buf + nlen, rjv->val.string.val, rjv->val.string.len); buf[len] = '\0'; jv.type = jbvString; jv.val.string.len = len; jv.val.string.val = buf; PG_RETURN_JSONB(JsonbValueToJsonb(&jv)); } else if (ljv->type == jbvNumeric && rjv->type == jbvNumeric) { n = DirectFunctionCall2(numeric_add, NumericGetDatum(ljv->val.numeric), NumericGetDatum(rjv->val.numeric)); PG_RETURN_JSONB(numeric_to_jnumber(DatumGetNumeric(n))); } else { ereport_op_str("+", l, r); } PG_RETURN_NULL(); }