Datum Function_invoke(Function self, PG_FUNCTION_ARGS) { Datum retVal; int32 top; jvalue* args; Type invokerType; fcinfo->isnull = false; currentInvocation->function = self; if(self->isUDT) return self->func.udt.udtFunction(self->func.udt.udt, fcinfo); if(self->func.nonudt.isMultiCall && SRF_IS_FIRSTCALL()) Invocation_assertDisconnect(); top = self->func.nonudt.numParams; /* Leave room for one extra parameter. Functions that returns unmapped * composite types must have a single row ResultSet as an OUT parameter. */ args = (jvalue*)palloc((top + 1) * sizeof(jvalue)); invokerType = self->func.nonudt.returnType; if(top > 0) { int32 idx; Type* types = self->func.nonudt.paramTypes; /* a class loader or other mechanism might have connected already. This * connection must be dropped since its parent context is wrong. */ if(Type_isDynamic(invokerType)) invokerType = Type_getRealType(invokerType, get_fn_expr_rettype(fcinfo->flinfo), self->func.nonudt.typeMap); for(idx = 0; idx < top; ++idx) { if(PG_ARGISNULL(idx)) /* * Set this argument to zero (or null in case of object) */ args[idx].j = 0L; else { Type paramType = types[idx]; if(Type_isDynamic(paramType)) paramType = Type_getRealType(paramType, get_fn_expr_argtype(fcinfo->flinfo, idx), self->func.nonudt.typeMap); args[idx] = Type_coerceDatum(paramType, PG_GETARG_DATUM(idx)); } } } retVal = self->func.nonudt.isMultiCall ? Type_invokeSRF(invokerType, self->clazz, self->func.nonudt.method, args, fcinfo) : Type_invoke(invokerType, self->clazz, self->func.nonudt.method, args, fcinfo); pfree(args); return retVal; }
Datum variant_cast_out(PG_FUNCTION_ARGS) { Oid targettypid = get_fn_expr_rettype(fcinfo->flinfo); VariantInt vi; Datum out; if( PG_ARGISNULL(0) ) PG_RETURN_NULL(); /* No reason to format type name, so use IOFunc_input instead of IOFunc_output */ vi = make_variant_int(PG_GETARG_VARIANT(0), fcinfo, IOFunc_input); /* If original was NULL then we MUST return NULL */ if( vi->isnull ) PG_RETURN_NULL(); /* If our types match exactly we don't need to cast */ if( vi->typid == targettypid ) PG_RETURN_DATUM(vi->data); /* Keep cruft localized to just here */ { bool do_pop; int ret; bool isnull; MemoryContext cctx = CurrentMemoryContext; HeapTuple tup; StringInfoData cmdd; StringInfo cmd = &cmdd; char *nulls = " "; do_pop = _SPI_conn(); initStringInfo(cmd); appendStringInfo( cmd, "SELECT $1::%s", format_type_be(targettypid) ); /* command, nargs, Oid *argument_types, *values, *nulls, read_only, count */ if( (ret = SPI_execute_with_args( cmd->data, 1, &vi->typid, &vi->data, nulls, true, 0 )) != SPI_OK_SELECT ) elog( ERROR, "SPI_execute_with_args returned %s", SPI_result_code_string(ret)); /* * Make a copy of result tuple in previous memory context. Copying the * entire tuple is wasteful; it would be better to only copy the actual * attribute; but in this case the difference isn't very large. */ MemoryContextSwitchTo(cctx); tup = heap_copytuple(SPI_tuptable->vals[0]); out = heap_getattr(tup, 1, SPI_tuptable->tupdesc, &isnull); // getTypeOutputInfo(typoid, &foutoid, &typisvarlena); /* Remember this frees everything palloc'd since our connect/push call */ _SPI_disc(do_pop); } /* End cruft */ PG_RETURN_DATUM(out); }
Datum int8_add(PG_FUNCTION_ARGS) { int64 state1; int64 state2; /* * GUARD against an incorrectly defined SQL function by verifying * that the parameters are the types we are expecting: * int8_add(int64, int64) => int64 */ if (PG_NARGS() != 2) { elog(ERROR, "%s defined with %d arguments, expected 2", add_str, PG_NARGS() ); } if (get_fn_expr_argtype(fcinfo->flinfo, 0) != INT8OID || get_fn_expr_argtype(fcinfo->flinfo, 1) != INT8OID) { elog(ERROR, "%s defined with invalid types, expected (int8, int8)", add_str ); } if (get_fn_expr_rettype(fcinfo->flinfo) != INT8OID) { elog(ERROR, "%s defined with invalid return type, expected int8", add_str ); } /* * GUARD against NULL input: * - IF both are null return NULL * - otherwise treat NULL as a zero value */ if (PG_ARGISNULL(0) && PG_ARGISNULL(1)) PG_RETURN_NULL(); state1 = PG_ARGISNULL(0) ? 0 : PG_GETARG_INT64(0); state2 = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT64(1); /* Do the math and return the result */ PG_RETURN_INT64(state1 + state2); }
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 get_power_spectrum(PG_FUNCTION_ARGS) { //the size of the array we are trying to transform int arraySize; int *signals; // 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; // 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); signals = palloc(sizeof(int)*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 for (int i = 0; i < arraySize; i++) { Complex *temp = (Complex*) DatumGetPointer(input_data[i]); signals[i] = temp->x*temp->x + temp->y*temp->y; } 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(int i = 0; i < arraySize; i++) { intermResult[i] = PointerGetDatum(signals[i]); } // construct a result array result = construct_array(intermResult, arraySize, return_type, return_typelen, return_typbyval, return_typalign); // free memory pfree(input_data); pfree(intermResult); // return result PG_RETURN_POINTER(result); }