Datum linterp_Numeric(PG_FUNCTION_ARGS) { float8 p; Numeric y0 = PG_GETARG_NUMERIC(2); Numeric y1 = PG_GETARG_NUMERIC(4); Numeric result = NULL; bool eq_bounds = false; bool eq_abscissas = false; /* Common */ p = linterp_abscissa(fcinfo, &eq_bounds, &eq_abscissas); /* Ordinate type specific code*/ if ( eq_bounds ) { if ( eq_abscissas && cmp_numerics(y0,y1) == 0 ) result = y0; else PG_RETURN_NULL(); } else { result = numeric_li_value(p, y0, y1); } PG_RETURN_NUMERIC(result); }
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)); }
Datum gpupreagg_psum_numeric(PG_FUNCTION_ARGS) { Assert(PG_NARGS() == 1); if (PG_ARGISNULL(0)) PG_RETURN_NULL(); PG_RETURN_NUMERIC(PG_GETARG_NUMERIC(0)); }
Datum dbms_pipe_pack_message_number(PG_FUNCTION_ARGS) { Numeric num = PG_GETARG_NUMERIC(0); output_buffer = check_buffer(output_buffer, LOCALMSGSZ); pack_field(output_buffer, IT_NUMBER, VARSIZE(num) - VARHDRSZ, VARDATA(num), InvalidOid); PG_RETURN_VOID(); }
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)); }
Datum quantile_append_numeric_array(PG_FUNCTION_ARGS) { struct_numeric * data; MemoryContext oldcontext; MemoryContext aggcontext; GET_AGG_CONTEXT("quantile_append_numeric_array", fcinfo, aggcontext); oldcontext = MemoryContextSwitchTo(aggcontext); if (PG_ARGISNULL(0)) { data = (struct_numeric*)palloc(sizeof(struct_numeric)); data->elements = (Numeric*)palloc(SLICE_SIZE*sizeof(Numeric)); data->nelements = SLICE_SIZE; data->next = 0; /* read the array of quantiles */ data->quantiles = array_to_double(fcinfo, PG_GETARG_ARRAYTYPE_P(2), &data->nquantiles); } else { data = (struct_numeric*)PG_GETARG_POINTER(0); } /* ignore NULL values */ if (! PG_ARGISNULL(1)) { Numeric element = PG_GETARG_NUMERIC(1); if (data->next > data->nelements-1) { data->elements = (Numeric*)repalloc(data->elements, sizeof(Numeric)*(data->nelements + SLICE_SIZE)); data->nelements = data->nelements + SLICE_SIZE; } data->elements[data->next++] = element; } MemoryContextSwitchTo(oldcontext); PG_RETURN_POINTER(data); }
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); }
/* * linterp_abscissa * * Common code that checks arguments. The result is a floating point value * representing what fraction of the distance x lies along the interval from * x0 to x1. It can be negative or greater than one (extrapolation) though * this isn't the intended use. If x0 == x1, then the fraction is not * determined and the function returns 0 and sets *notnull false. In all * other cases (except error exits) *notnull is set to true. An additional * flag indicates whether the abscissa value is equal to the lower boundary * value. */ static float8 linterp_abscissa(PG_FUNCTION_ARGS, bool *p_eq_bounds, bool *p_eq_abscissas) { Oid x_type; Oid x0_type; Oid x1_type; Oid y0_type; Oid y1_type; float8 p = 0; bool eq_bounds = false; bool eq_abscissas = false; /* The abscissa (x) arguments are nominally declared anyelement. * All the type checking is up to us. We insist that the types * are exactly alike. Explicit casts may be needed. */ x_type = get_fn_expr_argtype(fcinfo->flinfo, 0); x0_type = get_fn_expr_argtype(fcinfo->flinfo, 1); x1_type = get_fn_expr_argtype(fcinfo->flinfo, 3); if (!OidIsValid(x_type)||!OidIsValid(x0_type)||!OidIsValid(x1_type)) { elog(ERROR, "could not determine argument data types"); } if ( x_type!=x0_type || x_type!=x1_type ) { elog(ERROR, "abscissa types unequal"); } /* The ordinate (y) arguments are specifically declared in the SQL * function declaration. Here we just check and insist they are * identical. */ y0_type = get_fn_expr_argtype(fcinfo->flinfo, 2); y1_type = get_fn_expr_argtype(fcinfo->flinfo, 4); if ( y0_type != y1_type ) { elog(ERROR, "mismatched ordinate types"); } switch (x_type) { case INT8OID: { float8 x = (float8)PG_GETARG_INT64(0); float8 x0 = (float8)PG_GETARG_INT64(1); float8 x1 = (float8)PG_GETARG_INT64(3); if ( x1 == x0 ) { eq_bounds = true; eq_abscissas = ( x == x0 ); } else p = (x-x0)/(x1-x0); } break; case INT4OID: { float8 x = (float8)PG_GETARG_INT32(0); float8 x0 = (float8)PG_GETARG_INT32(1); float8 x1 = (float8)PG_GETARG_INT32(3); if ( x1 == x0 ) { eq_bounds = true; eq_abscissas = ( x == x0 ); } else p = (x-x0)/(x1-x0); } break; case INT2OID: { float8 x = (float8)PG_GETARG_INT16(0); float8 x0 = (float8)PG_GETARG_INT16(1); float8 x1 = (float8)PG_GETARG_INT16(3); if ( x1 == x0 ) { eq_bounds = true; eq_abscissas = ( x == x0 ); } else p = (x-x0)/(x1-x0); } break; case FLOAT4OID: { float8 x = (float8)PG_GETARG_FLOAT4(0); float8 x0 = (float8)PG_GETARG_FLOAT4(1); float8 x1 = (float8)PG_GETARG_FLOAT4(3); if ( x1 == x0 ) { eq_bounds = true; eq_abscissas = ( x == x0 ); } else p = (x-x0)/(x1-x0); } break; case FLOAT8OID: { float8 x = PG_GETARG_FLOAT8(0); float8 x0 = PG_GETARG_FLOAT8(1); float8 x1 = PG_GETARG_FLOAT8(3); if ( x1 == x0 ) { eq_bounds = true; eq_abscissas = ( x == x0 ); } else p = (x-x0)/(x1-x0); } break; case DATEOID: { DateADT x = PG_GETARG_DATEADT(0); DateADT x0 = PG_GETARG_DATEADT(1); DateADT x1 = PG_GETARG_DATEADT(3); int32 x_x0 = date_diff(x, x0); int32 x1_x0 = date_diff(x1, x0); if ( x1 == x0 ) { eq_bounds = true; eq_abscissas = ( x_x0 == 0 ); } else p = ((float8)x_x0)/((float8)x1_x0); } break; case TIMEOID: { TimeADT x = PG_GETARG_TIMEADT(0); TimeADT x0 = PG_GETARG_TIMEADT(1); TimeADT x1 = PG_GETARG_TIMEADT(3); p = time_li_fraction(x, x0, x1, &eq_bounds, &eq_abscissas); } break; case TIMESTAMPOID: { Timestamp x = PG_GETARG_TIMESTAMP(0); Timestamp x0 = PG_GETARG_TIMESTAMP(1); Timestamp x1 = PG_GETARG_TIMESTAMP(3); p = timestamp_li_fraction(x, x0, x1, &eq_bounds, &eq_abscissas); } break; case TIMESTAMPTZOID: { TimestampTz x = PG_GETARG_TIMESTAMPTZ(0); TimestampTz x0 = PG_GETARG_TIMESTAMPTZ(1); TimestampTz x1 = PG_GETARG_TIMESTAMPTZ(3); p = timestamptz_li_fraction(x, x0, x1, &eq_bounds, &eq_abscissas); } break; case INTERVALOID: { Interval * x = PG_GETARG_INTERVAL_P(0); Interval * x0 = PG_GETARG_INTERVAL_P(1); Interval * x1 = PG_GETARG_INTERVAL_P(3); p = interval_li_fraction(x, x0, x1, &eq_bounds, &eq_abscissas); } break; case NUMERICOID: { Numeric x = PG_GETARG_NUMERIC(0); Numeric x0 = PG_GETARG_NUMERIC(1); Numeric x1 = PG_GETARG_NUMERIC(3); p = numeric_li_fraction(x, x0, x1, &eq_bounds, &eq_abscissas); } break; default: elog(ERROR, "abscissa type not supported"); } if ( p_eq_bounds ) *p_eq_bounds = eq_bounds; if ( p_eq_abscissas ) *p_eq_abscissas = eq_abscissas; return p; }