Datum transform_eeg(PG_FUNCTION_ARGS)
{
//the size of the array we are trying to transform
int arraySize;
// a Datum for the constructred and deconstructed input arrays
Datum *intermResult;
Datum *input_data;
// the final result to return and the input to the function
ArrayType *result, *input;
Oid element_type, return_type, input_type;
//next 6 variables are inputted into get_typlenbyvalalign() and are used for construct and deconstruct array
//small int in postgreSQL is int16
int16 return_typelen, input_typelen;
bool return_typbyval, input_typbyval;
char return_typalign, input_typalign;
//the arrays we are transforming. Transforming array in[] into array out[]
//fftw_complex, a data structure with real (in[i].re) and imaginary (in[i].im) floating-point components.
fftw_complex *in, *out;
fftw_plan my_plan;
// get input row
input = PG_GETARG_ARRAYTYPE_P(0);
// get input array element type
input_type = ARR_ELEMTYPE(input);
//get needed variabels
get_typlenbyvalalign(input_type, &input_typelen, &input_typbyval, &input_typalign);
// deconstruct inupt array and save the array as Datum input_data
deconstruct_array(input, input_type, input_typelen, input_typbyval, input_typalign, &input_data, NULL, &arraySize);
// get element type of return vale (Complex[])
element_type = get_fn_expr_rettype(fcinfo->flinfo);
// get element type of an element in the return value (Complex)
return_type = get_element_type(element_type);
//get needed variabels
get_typlenbyvalalign(return_type, &return_typelen, &return_typbyval, &return_typalign);
// in and out array and plan declarations
in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*arraySize);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*arraySize);
my_plan = fftw_plan_dft_1d(arraySize, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
// set the in variable to the array we got as input.
// the real parts are from the input_data array
// the imaginary part is set to 0
for (int i = 0; i < arraySize; i++) {
in[i][0] = (double) DatumGetInt16(input_data[i]);
in[i][1] = 0;
}
// run the plan
fftw_execute(my_plan);
// array to store the out array (the transformed in array)
intermResult = palloc(sizeof(Datum)*arraySize);
// for each variable in the out array.
// Create a complex variable then set its real and imaginary party from the processed array
// get the datum from the pointer and save it in the result array
for(int32 i = 0; i < arraySize; i++)
{
Complex *temp = palloc(sizeof(Complex));
temp->x = out[i][0];
temp->y = out[i][1];
intermResult[i] = PointerGetDatum(temp);
}
// construct a result array
result = construct_array(intermResult, arraySize, return_type, return_typelen, return_typbyval, return_typalign);
// free memory
fftw_destroy_plan(my_plan);
fftw_free(in);
fftw_free(out);
pfree(input_data);
pfree(intermResult);
// return result
PG_RETURN_POINTER(result);
}
Datum
variant_typmod_in(PG_FUNCTION_ARGS)
{
ArrayType *arr = PG_GETARG_ARRAYTYPE_P(0);
Datum *elem_values;
int arr_nelem;
char *inputCString;
Datum inputDatum;
Datum out;
Assert(fcinfo->flinfo->fn_strict); /* Must be strict */
deconstruct_array(arr, CSTRINGOID,
-2, false, 'c', /* elmlen, elmbyval, elmalign */
&elem_values, NULL, &arr_nelem); /* elements, nulls, number_of_elements */
/* TODO: Sanity check array */
/* PointerGetDatum is equivalent to TextGetDatum, which doesn't exist */
inputCString = DatumGetCString(elem_values[0]);
inputDatum = PointerGetDatum( cstring_to_text( inputCString ) );
/* TODO: cache this stuff */
/* Keep cruft localized to just here */
{
bool do_pop = _SPI_conn();
bool isnull;
int ret;
Oid type = TEXTOID;
/* This should arguably be FOR KEY SHARE. See comment in variant_get_variant_name() */
char *cmd = "SELECT variant_typmod, variant_enabled FROM variant._registered WHERE lower(variant_name) = lower($1)";
/* command, nargs, Oid *argument_types, *values, *nulls, read_only, count */
if( (ret = SPI_execute_with_args( cmd, 1, &type, &inputDatum, " ", true, 0 )) != SPI_OK_SELECT )
elog( ERROR, "SPI_execute_with_args(%s) returned %s", cmd, SPI_result_code_string(ret));
Assert( SPI_tuptable );
if ( SPI_processed > 1 )
ereport(ERROR,
( errmsg( "Got %u records for variant.variant(%s)", SPI_processed, inputCString ),
errhint( "This means _variant._registered is corrupted" )
)
);
if ( SPI_processed < 1 )
elog( ERROR, "variant.variant(%s) is not registered", inputCString );
/* Note 0 vs 1 based numbering */
Assert(SPI_tuptable->tupdesc->attrs[0]->atttypid == INT4OID);
Assert(SPI_tuptable->tupdesc->attrs[1]->atttypid == BOOLOID);
out = heap_getattr( SPI_tuptable->vals[0], 2, SPI_tuptable->tupdesc, &isnull );
if( !DatumGetBool(out) )
ereport( ERROR,
( errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg( "variant.variant(%s) is disabled", inputCString )
)
);
/* Don't need to copy the tuple because int is pass by value */
out = heap_getattr( SPI_tuptable->vals[0], 1, SPI_tuptable->tupdesc, &isnull );
if( isnull )
ereport( ERROR,
( errmsg( "Found NULL variant_typmod for variant.variant(%s)", inputCString ),
errhint( "This should never happen; is _variant._registered corrupted?" )
)
);
_SPI_disc(do_pop);
}
PG_RETURN_INT32(out);
}
开发者ID:decibel,项目名称:variant,代码行数:71,代码来源:variant.c
示例3: get_func_arg_info
/*
* get_func_arg_info
*
* Fetch info about the argument types, names, and IN/OUT modes from the
* pg_proc tuple. Return value is the total number of arguments.
* Other results are palloc'd. *p_argtypes is always filled in, but
* *p_argnames and *p_argmodes will be set NULL in the default cases
* (no names, and all IN arguments, respectively).
*
* Note that this function simply fetches what is in the pg_proc tuple;
* it doesn't do any interpretation of polymorphic types.
*/
int
get_func_arg_info(HeapTuple procTup,
Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
{
Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
Datum proallargtypes;
Datum proargmodes;
Datum proargnames;
bool isNull;
ArrayType *arr;
int numargs;
Datum *elems;
int nelems;
int i;
/* First discover the total number of parameters and get their types */
proallargtypes = SysCacheGetAttr(PROCOID, procTup,
Anum_pg_proc_proallargtypes,
&isNull);
if (!isNull)
{
/*
* We expect the arrays to be 1-D arrays of the right types; verify
* that. For the OID and char arrays, we don't need to use
* deconstruct_array() since the array data is just going to look like
* a C array of values.
*/
arr = DatumGetArrayTypeP(proallargtypes); /* ensure not toasted */
numargs = ARR_DIMS(arr)[0];
if (ARR_NDIM(arr) != 1 ||
numargs < 0 ||
ARR_HASNULL(arr) ||
ARR_ELEMTYPE(arr) != OIDOID)
elog(ERROR, "proallargtypes is not a 1-D Oid array");
Assert(numargs >= procStruct->pronargs);
*p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
memcpy(*p_argtypes, ARR_DATA_PTR(arr),
numargs * sizeof(Oid));
}
else
{
/* If no proallargtypes, use proargtypes */
numargs = procStruct->proargtypes.dim1;
Assert(numargs == procStruct->pronargs);
*p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));
memcpy(*p_argtypes, procStruct->proargtypes.values,
numargs * sizeof(Oid));
}
/* Get argument names, if available */
proargnames = SysCacheGetAttr(PROCOID, procTup,
Anum_pg_proc_proargnames,
&isNull);
if (isNull)
*p_argnames = NULL;
else
{
deconstruct_array(DatumGetArrayTypeP(proargnames),
TEXTOID, -1, false, 'i',
&elems, NULL, &nelems);
if (nelems != numargs) /* should not happen */
elog(ERROR, "proargnames must have the same number of elements as the function has arguments");
*p_argnames = (char **) palloc(sizeof(char *) * numargs);
for (i = 0; i < numargs; i++)
(*p_argnames)[i] = TextDatumGetCString(elems[i]);
}
/* Get argument modes, if available */
proargmodes = SysCacheGetAttr(PROCOID, procTup,
Anum_pg_proc_proargmodes,
&isNull);
if (isNull)
*p_argmodes = NULL;
else
{
arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
if (ARR_NDIM(arr) != 1 ||
ARR_DIMS(arr)[0] != numargs ||
ARR_HASNULL(arr) ||
ARR_ELEMTYPE(arr) != CHAROID)
elog(ERROR, "proargmodes is not a 1-D char array");
*p_argmodes = (char *) palloc(numargs * sizeof(char));
memcpy(*p_argmodes, ARR_DATA_PTR(arr),
numargs * sizeof(char));
}
return numargs;
}
/*
* ExecIndexEvalArrayKeys
* Evaluate any array key values, and set up to iterate through arrays.
*
* Returns TRUE if there are array elements to consider; FALSE means there
* is at least one null or empty array, so no match is possible. On TRUE
* result, the scankeys are initialized with the first elements of the arrays.
*/
bool
ExecIndexEvalArrayKeys(ExprContext *econtext,
IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
{
bool result = true;
int j;
MemoryContext oldContext;
/* We want to keep the arrays in per-tuple memory */
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
for (j = 0; j < numArrayKeys; j++)
{
ScanKey scan_key = arrayKeys[j].scan_key;
ExprState *array_expr = arrayKeys[j].array_expr;
Datum arraydatum;
bool isNull;
ArrayType *arrayval;
int16 elmlen;
bool elmbyval;
char elmalign;
int num_elems;
Datum *elem_values;
bool *elem_nulls;
/*
* Compute and deconstruct the array expression. (Notes in
* ExecIndexEvalRuntimeKeys() apply here too.)
*/
arraydatum = ExecEvalExpr(array_expr,
econtext,
&isNull,
NULL);
if (isNull)
{
result = false;
break; /* no point in evaluating more */
}
arrayval = DatumGetArrayTypeP(arraydatum);
/* We could cache this data, but not clear it's worth it */
get_typlenbyvalalign(ARR_ELEMTYPE(arrayval),
&elmlen, &elmbyval, &elmalign);
deconstruct_array(arrayval,
ARR_ELEMTYPE(arrayval),
elmlen, elmbyval, elmalign,
&elem_values, &elem_nulls, &num_elems);
if (num_elems <= 0)
{
result = false;
break; /* no point in evaluating more */
}
/*
* Note: we expect the previous array data, if any, to be
* automatically freed by resetting the per-tuple context; hence no
* pfree's here.
*/
arrayKeys[j].elem_values = elem_values;
arrayKeys[j].elem_nulls = elem_nulls;
arrayKeys[j].num_elems = num_elems;
scan_key->sk_argument = elem_values[0];
if (elem_nulls[0])
scan_key->sk_flags |= SK_ISNULL;
else
scan_key->sk_flags &= ~SK_ISNULL;
arrayKeys[j].next_elem = 1;
}
MemoryContextSwitchTo(oldContext);
return result;
}
/*
* get_func_result_name
*
* If the function has exactly one output parameter, and that parameter
* is named, return the name (as a palloc'd string). Else return NULL.
*
* This is used to determine the default output column name for functions
* returning scalar types.
*/
char *
get_func_result_name(Oid functionId)
{
char *result;
HeapTuple procTuple;
Datum proargmodes;
Datum proargnames;
bool isnull;
ArrayType *arr;
int numargs;
char *argmodes;
Datum *argnames;
int numoutargs;
int nargnames;
int i;
/* First fetch the function's pg_proc row */
procTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
if (!HeapTupleIsValid(procTuple))
elog(ERROR, "cache lookup failed for function %u", functionId);
/* If there are no named OUT parameters, return NULL */
if (heap_attisnull(procTuple, Anum_pg_proc_proargmodes) ||
heap_attisnull(procTuple, Anum_pg_proc_proargnames))
result = NULL;
else
{
/* Get the data out of the tuple */
proargmodes = SysCacheGetAttr(PROCOID, procTuple,
Anum_pg_proc_proargmodes,
&isnull);
Assert(!isnull);
proargnames = SysCacheGetAttr(PROCOID, procTuple,
Anum_pg_proc_proargnames,
&isnull);
Assert(!isnull);
/*
* We expect the arrays to be 1-D arrays of the right types; verify
* that. For the char array, we don't need to use deconstruct_array()
* since the array data is just going to look like a C array of
* values.
*/
arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
numargs = ARR_DIMS(arr)[0];
if (ARR_NDIM(arr) != 1 ||
numargs < 0 ||
ARR_HASNULL(arr) ||
ARR_ELEMTYPE(arr) != CHAROID)
elog(ERROR, "proargmodes is not a 1-D char array");
argmodes = (char *) ARR_DATA_PTR(arr);
arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */
if (ARR_NDIM(arr) != 1 ||
ARR_DIMS(arr)[0] != numargs ||
ARR_HASNULL(arr) ||
ARR_ELEMTYPE(arr) != TEXTOID)
elog(ERROR, "proargnames is not a 1-D text array");
deconstruct_array(arr, TEXTOID, -1, false, 'i',
&argnames, NULL, &nargnames);
Assert(nargnames == numargs);
/* scan for output argument(s) */
result = NULL;
numoutargs = 0;
for (i = 0; i < numargs; i++)
{
if (argmodes[i] == PROARGMODE_IN ||
argmodes[i] == PROARGMODE_VARIADIC)
continue;
Assert(argmodes[i] == PROARGMODE_OUT ||
argmodes[i] == PROARGMODE_INOUT ||
argmodes[i] == PROARGMODE_TABLE);
if (++numoutargs > 1)
{
/* multiple out args, so forget it */
result = NULL;
break;
}
result = TextDatumGetCString(argnames[i]);
if (result == NULL || result[0] == '\0')
{
/* Parameter is not named, so forget it */
result = NULL;
break;
}
}
}
ReleaseSysCache(procTuple);
return result;
//.........这里部分代码省略.........
static uint32 gserialized_typmod_in(ArrayType *arr, int is_geography)
{
uint32 typmod = 0;
Datum *elem_values;
int n = 0;
int i = 0;
if (ARR_ELEMTYPE(arr) != CSTRINGOID)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("typmod array must be type cstring[]")));
if (ARR_NDIM(arr) != 1)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("typmod array must be one-dimensional")));
if (ARR_HASNULL(arr))
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("typmod array must not contain nulls")));
deconstruct_array(arr,
CSTRINGOID, -2, false, 'c', /* hardwire cstring representation details */
&elem_values, NULL, &n);
/* Set the SRID to the default value first */
if ( is_geography)
TYPMOD_SET_SRID(typmod, SRID_DEFAULT);
else
TYPMOD_SET_SRID(typmod, SRID_UNKNOWN);
for (i = 0; i < n; i++)
{
if ( i == 0 ) /* TYPE */
{
char *s = DatumGetCString(elem_values[i]);
uint8_t type = 0;
int z = 0;
int m = 0;
if ( geometry_type_from_string(s, &type, &z, &m) == LW_FAILURE )
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("Invalid geometry type modifier: %s", s)));
}
else
{
TYPMOD_SET_TYPE(typmod, type);
if ( z )
TYPMOD_SET_Z(typmod);
if ( m )
TYPMOD_SET_M(typmod);
}
}
if ( i == 1 ) /* SRID */
{
int srid = pg_atoi(DatumGetCString(elem_values[i]),
sizeof(int32), '\0');
srid = clamp_srid(srid);
POSTGIS_DEBUGF(3, "srid: %d", srid);
if ( srid != SRID_UNKNOWN )
{
TYPMOD_SET_SRID(typmod, srid);
}
}
}
pfree(elem_values);
return typmod;
}
static PyObj
array_item(PyObj self, Py_ssize_t item)
{
volatile PyObj rob = NULL;
PyPgTypeInfo typinfo, atypinfo;
ArrayType *at;
Datum rd;
bool isnull = false;
int index = (int) item;
PyObj elm;
elm = PyPgType_GetElementType(Py_TYPE(self));
typinfo = PyPgTypeInfo(elm);
atypinfo = PyPgTypeInfo(Py_TYPE(self));
at = DatumGetArrayTypeP(PyPgObject_GetDatum(self));
/* convert index */
++index;
if (ARR_NDIM(at) == 0)
{
PyErr_SetString(PyExc_IndexError, "empty array");
return(NULL);
}
/*
* Note that the comparison is '>', not '>='.
*/
if (index > ARR_DIMS(at)[0])
{
PyErr_Format(PyExc_IndexError, "index %d out of range %d",
item, ARR_DIMS(at)[0]);
return(NULL);
}
/*
* Single dimenion array? Get an element.
*/
if (ARR_NDIM(at) == 1)
{
PG_TRY();
{
rd = array_ref(at, 1, &index, atypinfo->typlen,
typinfo->typlen, typinfo->typbyval, typinfo->typalign, &isnull);
if (isnull)
{
rob = Py_None;
Py_INCREF(rob);
}
else
{
/*
* It points into the array structure, so there's no need to free.
*/
rob = PyPgObject_New(elm, rd);
}
}
PG_CATCH();
{
Py_XDECREF(rob);
rob = NULL;
PyErr_SetPgError(false);
return(NULL);
}
PG_END_TRY();
}
else
{
ArrayType *rat;
int lower[MAXDIM] = {index,0,};
int upper[MAXDIM] = {index,0,};
/*
* Multiple dimensions, so get a slice.
*/
PG_TRY();
{
ArrayType *xat;
Datum *elements;
bool *nulls;
int nelems;
int ndims, i;
int lbs[MAXDIM];
int dims[MAXDIM];
xat = array_get_slice(at, 1, upper, lower, atypinfo->typlen,
typinfo->typlen, typinfo->typbyval, typinfo->typalign);
/*
* Eventually, this should probably be changed to change the already
* allocated ArrayType at 'xat', but for now use the available
* interfaces for creating the expected result.
*/
deconstruct_array(xat,
typinfo->typoid, typinfo->typlen, typinfo->typbyval, typinfo->typalign,
&elements, &nulls, &nelems
);
/*
//.........这里部分代码省略.........
static DTYPE *get_pgarray(int *num, ArrayType *input)
{
int ndims, *dims, *lbs;
bool *nulls;
Oid i_eltype;
int16 i_typlen;
bool i_typbyval;
char i_typalign;
Datum *i_data;
int i, n;
DTYPE *data;
/* get input array element type */
i_eltype = ARR_ELEMTYPE(input);
get_typlenbyvalalign(i_eltype, &i_typlen, &i_typbyval, &i_typalign);
/* validate input data type */
switch(i_eltype) {
case INT2OID:
case INT4OID:
case FLOAT4OID:
case FLOAT8OID:
break;
default:
elog(ERROR, "Invalid input data type");
break;
}
/* get various pieces of data from the input array */
ndims = ARR_NDIM(input);
dims = ARR_DIMS(input);
lbs = ARR_LBOUND(input);
if (ndims != 2 || dims[0] != dims[1]) {
elog(ERROR, "Error: matrix[num][num] in its definition.");
}
/* get src data */
deconstruct_array(input, i_eltype, i_typlen, i_typbyval, i_typalign,
&i_data, &nulls, &n);
DBG("get_pgarray: ndims=%d, n=%d", ndims, n);
#ifdef DEBUG
for (i=0; i<ndims; i++) {
DBG(" dims[%d]=%d, lbs[%d]=%d", i, dims[i], i, lbs[i]);
}
#endif
/* construct a C array */
data = (DTYPE *) palloc(n * sizeof(DTYPE));
if (!data) {
elog(ERROR, "Error: Out of memory!");
}
for (i=0; i<n; i++) {
if (nulls[i]) {
data[i] = INFINITY;
}
else {
switch(i_eltype) {
case INT2OID:
data[i] = (DTYPE) DatumGetInt16(i_data[i]);
break;
case INT4OID:
data[i] = (DTYPE) DatumGetInt32(i_data[i]);
break;
case FLOAT4OID:
data[i] = (DTYPE) DatumGetFloat4(i_data[i]);
break;
case FLOAT8OID:
data[i] = (DTYPE) DatumGetFloat8(i_data[i]);
break;
}
/* we assume negative values are INFINTY */
/********************************************************
TODO: based on trying to add an endpt it is likely
that this will not work and you will get and error in
findEulerianPath
**********************************************************/
if (data[i] < 0)
data[i] = INFINITY;
}
DBG(" data[%d]=%.4f", i, data[i]);
}
pfree(nulls);
pfree(i_data);
*num = dims[0];
return data;
}
/*
* Array selectivity estimation based on most common elements statistics
*
* This function just deconstructs and sorts the array constant's contents,
* and then passes the problem on to mcelem_array_contain_overlap_selec or
* mcelem_array_contained_selec depending on the operator.
*/
static Selectivity
mcelem_array_selec(ArrayType *array, TypeCacheEntry *typentry,
Datum *mcelem, int nmcelem,
float4 *numbers, int nnumbers,
float4 *hist, int nhist,
Oid operator, FmgrInfo *cmpfunc)
{
Selectivity selec;
int num_elems;
Datum *elem_values;
bool *elem_nulls;
bool null_present;
int nonnull_nitems;
int i;
/*
* Prepare constant array data for sorting. Sorting lets us find unique
* elements and efficiently merge with the MCELEM array.
*/
deconstruct_array(array,
typentry->type_id,
typentry->typlen,
typentry->typbyval,
typentry->typalign,
&elem_values, &elem_nulls, &num_elems);
/* Collapse out any null elements */
nonnull_nitems = 0;
null_present = false;
for (i = 0; i < num_elems; i++)
{
if (elem_nulls[i])
null_present = true;
else
elem_values[nonnull_nitems++] = elem_values[i];
}
/*
* Query "column @> '{anything, null}'" matches nothing. For the other
* two operators, presence of a null in the constant can be ignored.
*/
if (null_present && operator == OID_ARRAY_CONTAINS_OP)
{
pfree(elem_values);
pfree(elem_nulls);
return (Selectivity) 0.0;
}
/* Sort extracted elements using their default comparison function. */
qsort_arg(elem_values, nonnull_nitems, sizeof(Datum),
element_compare, cmpfunc);
/* Separate cases according to operator */
if (operator == OID_ARRAY_CONTAINS_OP || operator == OID_ARRAY_OVERLAP_OP)
selec = mcelem_array_contain_overlap_selec(mcelem, nmcelem,
numbers, nnumbers,
elem_values, nonnull_nitems,
operator, cmpfunc);
else if (operator == OID_ARRAY_CONTAINED_OP)
selec = mcelem_array_contained_selec(mcelem, nmcelem,
numbers, nnumbers,
elem_values, nonnull_nitems,
hist, nhist,
operator, cmpfunc);
else
{
elog(ERROR, "arraycontsel called for unrecognized operator %u",
operator);
selec = 0.0; /* keep compiler quiet */
}
pfree(elem_values);
pfree(elem_nulls);
return selec;
}
/*
* SQL function jsonb_object(text[])
*
* take a one or two dimensional array of text as name value pairs
* for a jsonb object.
*
*/
Datum
jsonb_object(PG_FUNCTION_ARGS)
{
ArrayType *in_array = PG_GETARG_ARRAYTYPE_P(0);
int ndims = ARR_NDIM(in_array);
Datum *in_datums;
bool *in_nulls;
int in_count,
count,
i;
JsonbInState result;
memset(&result, 0, sizeof(JsonbInState));
(void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
switch (ndims)
{
case 0:
goto close_object;
break;
case 1:
if ((ARR_DIMS(in_array)[0]) % 2)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("array must have even number of elements")));
break;
case 2:
if ((ARR_DIMS(in_array)[1]) != 2)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("array must have two columns")));
break;
default:
ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("wrong number of array subscripts")));
}
deconstruct_array(in_array,
TEXTOID, -1, false, 'i',
&in_datums, &in_nulls, &in_count);
count = in_count / 2;
for (i = 0; i < count; ++i)
{
JsonbValue v;
char *str;
int len;
if (in_nulls[i * 2])
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("null value not allowed for object key")));
str = TextDatumGetCString(in_datums[i * 2]);
len = strlen(str);
v.type = jbvString;
v.val.string.len = len;
v.val.string.val = str;
(void) pushJsonbValue(&result.parseState, WJB_KEY, &v);
if (in_nulls[i * 2 + 1])
{
v.type = jbvNull;
}
else
{
str = TextDatumGetCString(in_datums[i * 2 + 1]);
len = strlen(str);
v.type = jbvString;
v.val.string.len = len;
v.val.string.val = str;
}
(void) pushJsonbValue(&result.parseState, WJB_VALUE, &v);
}
pfree(in_datums);
pfree(in_nulls);
close_object:
result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
//.........这里部分代码省略.........
/*
* Helper function for the various SQL callable logical decoding functions.
*/
static Datum
pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool binary)
{
Name name;
XLogRecPtr upto_lsn;
int32 upto_nchanges;
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
MemoryContext per_query_ctx;
MemoryContext oldcontext;
XLogRecPtr end_of_wal;
XLogRecPtr startptr;
LogicalDecodingContext *ctx;
ResourceOwner old_resowner = CurrentResourceOwner;
ArrayType *arr;
Size ndim;
List *options = NIL;
DecodingOutputState *p;
check_permissions();
CheckLogicalDecodingRequirements();
if (PG_ARGISNULL(0))
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("slot name must not be null")));
name = PG_GETARG_NAME(0);
if (PG_ARGISNULL(1))
upto_lsn = InvalidXLogRecPtr;
else
upto_lsn = PG_GETARG_LSN(1);
if (PG_ARGISNULL(2))
upto_nchanges = InvalidXLogRecPtr;
else
upto_nchanges = PG_GETARG_INT32(2);
if (PG_ARGISNULL(3))
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("options array must not be null")));
arr = PG_GETARG_ARRAYTYPE_P(3);
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
if (!(rsinfo->allowedModes & SFRM_Materialize))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("materialize mode required, but it is not allowed in this context")));
/* state to write output to */
p = palloc0(sizeof(DecodingOutputState));
p->binary_output = binary;
/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &p->tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
/* Deconstruct options array */
ndim = ARR_NDIM(arr);
if (ndim > 1)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("array must be one-dimensional")));
}
else if (array_contains_nulls(arr))
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("array must not contain nulls")));
}
else if (ndim == 1)
{
int nelems;
Datum *datum_opts;
int i;
Assert(ARR_ELEMTYPE(arr) == TEXTOID);
deconstruct_array(arr, TEXTOID, -1, false, 'i',
&datum_opts, NULL, &nelems);
if (nelems % 2 != 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("array must have even number of elements")));
for (i = 0; i < nelems; i += 2)
//.........这里部分代码省略.........
/*
* extract_variadic_args
*
* Extract a set of argument values, types and NULL markers for a given
* input function which makes use of a VARIADIC input whose argument list
* depends on the caller context. When doing a VARIADIC call, the caller
* has provided one argument made of an array of values, so deconstruct the
* array data before using it for the next processing. If no VARIADIC call
* is used, just fill in the status data based on all the arguments given
* by the caller.
*
* This function returns the number of arguments generated, or -1 in the
* case of "VARIADIC NULL".
*/
int
extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start,
bool convert_unknown, Datum **args, Oid **types,
bool **nulls)
{
bool variadic = get_fn_expr_variadic(fcinfo->flinfo);
Datum *args_res;
bool *nulls_res;
Oid *types_res;
int nargs,
i;
*args = NULL;
*types = NULL;
*nulls = NULL;
if (variadic)
{
ArrayType *array_in;
Oid element_type;
bool typbyval;
char typalign;
int16 typlen;
Assert(PG_NARGS() == variadic_start + 1);
if (PG_ARGISNULL(variadic_start))
return -1;
array_in = PG_GETARG_ARRAYTYPE_P(variadic_start);
element_type = ARR_ELEMTYPE(array_in);
get_typlenbyvalalign(element_type,
&typlen, &typbyval, &typalign);
deconstruct_array(array_in, element_type, typlen, typbyval,
typalign, &args_res, &nulls_res,
&nargs);
/* All the elements of the array have the same type */
types_res = (Oid *) palloc0(nargs * sizeof(Oid));
for (i = 0; i < nargs; i++)
types_res[i] = element_type;
}
else
{
nargs = PG_NARGS() - variadic_start;
Assert(nargs > 0);
nulls_res = (bool *) palloc0(nargs * sizeof(bool));
args_res = (Datum *) palloc0(nargs * sizeof(Datum));
types_res = (Oid *) palloc0(nargs * sizeof(Oid));
for (i = 0; i < nargs; i++)
{
nulls_res[i] = PG_ARGISNULL(i + variadic_start);
types_res[i] = get_fn_expr_argtype(fcinfo->flinfo,
i + variadic_start);
/*
* Turn a constant (more or less literal) value that's of unknown
* type into text if required. Unknowns come in as a cstring
* pointer. Note: for functions declared as taking type "any", the
* parser will not do any type conversion on unknown-type literals
* (that is, undecorated strings or NULLs).
*/
if (convert_unknown &&
types_res[i] == UNKNOWNOID &&
get_fn_expr_arg_stable(fcinfo->flinfo, i + variadic_start))
{
types_res[i] = TEXTOID;
if (PG_ARGISNULL(i + variadic_start))
args_res[i] = (Datum) 0;
else
args_res[i] =
CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start));
}
else
{
/* no conversion needed, just take the datum as given */
args_res[i] = PG_GETARG_DATUM(i + variadic_start);
}
if (!OidIsValid(types_res[i]) ||
(convert_unknown && types_res[i] == UNKNOWNOID))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
//.........这里部分代码省略.........
Datum
get_power_in(PG_FUNCTION_ARGS)
{
//the size of the array we are trying to transform
int arraySize;
int power;
int32 duration;
float startRange;
float endRange;
char* freq;
text *tempFreq;
// a Datum for the constructred and deconstructed input arrays
Datum *input_data;
// the final result to return and the input to the function
ArrayType *input;
Oid input_type;
//next 6 variables are inputted into get_typlenbyvalalign() and are used for construct and deconstruct array
//small int in postgreSQL is int16
int16 input_typelen;
bool input_typbyval;
char input_typalign;
// get input row
input = PG_GETARG_ARRAYTYPE_P(0);
// get duration
duration = PG_GETARG_INT32(1);
tempFreq = PG_GETARG_TEXT_P(2);
freq = dup_pgtext(tempFreq);
//get ranges
if(strcmp(freq, "beta") == 0)
{
startRange = 13;
endRange = 30;
} else if(strcmp(freq, "alpha") == 0)
{
startRange = 7.5;
endRange = 13;
} else if(strcmp(freq, "theta") == 0)
{
startRange = 4;
endRange = 7.5;
} else
{
startRange = 1;
endRange = 4;
}
input_type = ARR_ELEMTYPE(input);
//get needed variabels
get_typlenbyvalalign(input_type, &input_typelen, &input_typbyval, &input_typalign);
// deconstruct inupt array and save the array as Datum input_data
deconstruct_array(input, input_type, input_typelen, input_typbyval, input_typalign, &input_data, NULL, &arraySize);
// set the in variable to the array we got as input.
// the real parts are from the input_data array
// the imaginary part is set to 0
power = 0;
for (int i = 0; i < arraySize; i++) {
if(startRange < i/duration && i/duration <= endRange)
{
Complex *temp = (Complex*) DatumGetPointer(input_data[i]);
power += temp->x*temp->x + temp->y*temp->y;
}
}
// free memory
pfree(input_data);
// return result
PG_RETURN_INT32(power);
}
/*
* Compute the list of TIDs to be visited, by evaluating the expressions
* for them.
*
* (The result is actually an array, not a list.)
*/
static void
TidListCreate(TidScanState *tidstate)
{
List *evalList = tidstate->tss_tidquals;
ExprContext *econtext = tidstate->ss.ps.ps_ExprContext;
BlockNumber nblocks;
ItemPointerData *tidList;
int numAllocTids;
int numTids;
ListCell *l;
/*
* We silently discard any TIDs that are out of range at the time of scan
* start. (Since we hold at least AccessShareLock on the table, it won't
* be possible for someone to truncate away the blocks we intend to
* visit.)
*/
nblocks = RelationGetNumberOfBlocks(tidstate->ss.ss_currentRelation);
/*
* We initialize the array with enough slots for the case that all quals
* are simple OpExprs or CurrentOfExprs. If there are any
* ScalarArrayOpExprs, we may have to enlarge the array.
*/
numAllocTids = list_length(evalList);
tidList = (ItemPointerData *)
palloc(numAllocTids * sizeof(ItemPointerData));
numTids = 0;
tidstate->tss_isCurrentOf = false;
foreach(l, evalList)
{
ExprState *exstate = (ExprState *) lfirst(l);
Expr *expr = exstate->expr;
ItemPointer itemptr;
bool isNull;
if (is_opclause(expr))
{
FuncExprState *fexstate = (FuncExprState *) exstate;
Node *arg1;
Node *arg2;
arg1 = get_leftop(expr);
arg2 = get_rightop(expr);
if (IsCTIDVar(arg1))
exstate = (ExprState *) lsecond(fexstate->args);
else if (IsCTIDVar(arg2))
exstate = (ExprState *) linitial(fexstate->args);
else
elog(ERROR, "could not identify CTID variable");
itemptr = (ItemPointer)
DatumGetPointer(ExecEvalExprSwitchContext(exstate,
econtext,
&isNull,
NULL));
if (!isNull &&
ItemPointerIsValid(itemptr) &&
ItemPointerGetBlockNumber(itemptr) < nblocks)
{
if (numTids >= numAllocTids)
{
numAllocTids *= 2;
tidList = (ItemPointerData *)
repalloc(tidList,
numAllocTids * sizeof(ItemPointerData));
}
tidList[numTids++] = *itemptr;
}
}
else if (expr && IsA(expr, ScalarArrayOpExpr))
{
ScalarArrayOpExprState *saexstate = (ScalarArrayOpExprState *) exstate;
Datum arraydatum;
ArrayType *itemarray;
Datum *ipdatums;
bool *ipnulls;
int ndatums;
int i;
exstate = (ExprState *) lsecond(saexstate->fxprstate.args);
arraydatum = ExecEvalExprSwitchContext(exstate,
econtext,
&isNull,
NULL);
if (isNull)
continue;
itemarray = DatumGetArrayTypeP(arraydatum);
deconstruct_array(itemarray,
TIDOID, sizeof(ItemPointerData), false, 's',
&ipdatums, &ipnulls, &ndatums);
if (numTids + ndatums > numAllocTids)
{
//.........这里部分代码省略.........
请发表评论