/* * load queue info from pgq.queue table. */ static void load_queue_info(Datum queue_name, struct QueueState *state) { Datum values[1]; int res; TupleDesc desc; HeapTuple row; bool isnull; values[0] = queue_name; res = SPI_execute_plan(queue_plan, values, NULL, false, 0); if (res != SPI_OK_SELECT) elog(ERROR, "Queue fetch failed"); if (SPI_processed == 0) elog(ERROR, "No such queue"); row = SPI_tuptable->vals[0]; desc = SPI_tuptable->tupdesc; state->queue_id = DatumGetInt32(SPI_getbinval(row, desc, COL_QUEUE_ID, &isnull)); if (isnull) elog(ERROR, "queue id NULL"); state->cur_table = DatumGetInt32(SPI_getbinval(row, desc, COL_TBLNO, &isnull)); if (isnull) elog(ERROR, "table nr NULL"); state->table_prefix = SPI_getvalue(row, desc, COL_PREFIX); if (state->table_prefix == NULL) elog(ERROR, "table prefix NULL"); state->next_event_id = SPI_getbinval(row, desc, COL_EVENT_ID, &isnull); if (isnull) elog(ERROR, "Seq name NULL"); }
/* * helper for queue insertion. * * does not support NULL arguments. */ void pgq_simple_insert(const char *queue_name, Datum ev_type, Datum ev_data, Datum ev_extra1, Datum ev_extra2, Datum ev_extra3, Datum ev_extra4) { Datum values[7]; char nulls[7]; static void *plan = NULL; int res; if (!plan) { const char *sql; Oid types[7] = { TEXTOID, TEXTOID, TEXTOID, TEXTOID, TEXTOID, TEXTOID, TEXTOID }; sql = "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"; plan = SPI_saveplan(SPI_prepare(sql, 7, types)); if (plan == NULL) elog(ERROR, "logtriga: SPI_prepare() failed"); } values[0] = DirectFunctionCall1(textin, (Datum)queue_name); values[1] = ev_type; values[2] = ev_data; values[3] = ev_extra1; values[4] = ev_extra2; values[5] = ev_extra3; values[6] = ev_extra4; nulls[0] = ' '; nulls[1] = ev_type ? ' ' : 'n'; nulls[2] = ev_data ? ' ' : 'n'; nulls[3] = ev_extra1 ? ' ' : 'n'; nulls[4] = ev_extra2 ? ' ' : 'n'; nulls[5] = ev_extra3 ? ' ' : 'n'; nulls[6] = ev_extra4 ? ' ' : 'n'; res = SPI_execute_plan(plan, values, nulls, false, 0); if (res != SPI_OK_SELECT) elog(ERROR, "call of pgq.insert_event failed"); }
/* execute prepared plan */ void execute_plan(int expected, SPIPlanPtr plan, Datum *values, const char *nulls) { int ret = SPI_execute_plan(plan, values, nulls, false, 0); if EXEC_FAILED(ret, expected) elog(ERROR, "query failed: (code=%d, expected=%d)", ret, expected); }
/** * Create and run the basic query on the gridvalue table, for use by the wciReadFloat function */ static void runWciReadFloatQueryGrid(struct ReadStore * out, FuncCallContext * funcctx, FunctionCallInfo fcinfo) { initializeGeos(); struct WciReadParameterCollection p; parseReadParameters(& p, fcinfo); const char * whatToSelect = "value, dataprovidername, placename::text, placegeometry, referencetime, validtimefrom, validtimeto, validtimeindeterminatecode, valueparametername, valueunitname, levelparametername, levelunitname, levelfrom, levelto, levelindeterminatecode, dataversion, confidencecode, valuestoretime, valueid, valuetype, placeid"; const char * gridQuery = build_query(& p, GridTable, OutputFloat, whatToSelect, NULL); elog(DEBUG1, gridQuery); // Perform primary query SPIPlanPtr queryPlan = getSpiPlan(gridQuery); if (SPI_OK_SELECT != SPI_execute_plan(queryPlan, NULL, NULL, true, 0)) { ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg( "Error when performing base query"))); } MemoryContext oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); if ( PG_ARGISNULL(1) ) { ReadStoreGridReturnInit(out, SPI_tuptable, SPI_processed, NULL); } else { text * location_t = PG_GETARG_TEXT_P(1); const char * location = TextPGetCString(location_t); ReadStoreGridReturnInit(out, SPI_tuptable, SPI_processed, location); } MemoryContextSwitchTo(oldcontext); }
Datum dbms_alert_signal(PG_FUNCTION_ARGS) { void *plan; Oid argtypes[] = {TEXTOID, TEXTOID}; Datum values[2]; char nulls[2] = {' ',' '}; if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("event name is NULL"), errdetail("Eventname may not be NULL."))); if (PG_ARGISNULL(1)) nulls[1] = 'n'; values[0] = PG_GETARG_DATUM(0); values[1] = PG_GETARG_DATUM(1); if (SPI_connect() < 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("SPI_connect failed"))); SPI_EXEC("SELECT 1 FROM pg_catalog.pg_class c " "WHERE pg_catalog.pg_table_is_visible(c.oid) " "AND c.relkind='r' AND c.relname = 'ora_alerts'", SELECT); if (0 == SPI_processed) { SPI_EXEC("CREATE TEMP TABLE ora_alerts(event text, message text)", UTILITY); SPI_EXEC("REVOKE ALL ON TABLE ora_alerts FROM PUBLIC", UTILITY); SPI_EXEC("CREATE CONSTRAINT TRIGGER ora_alert_signal AFTER INSERT ON ora_alerts " "INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE dbms_alert.defered_signal()", UTILITY); } if (!(plan = SPI_prepare( "INSERT INTO ora_alerts(event,message) VALUES($1, $2)", 2, argtypes))) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("SPI_prepare failed"))); if (SPI_OK_INSERT != SPI_execute_plan(plan, values, nulls, false, 1)) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("can't execute sql"))); SPI_finish(); PG_RETURN_VOID(); }
/* * utl_file_dir security .. is solved with aux. table. * * Raise exception if don't find string in table. */ static void check_secure_locality(const char *path) { static SPIPlanPtr plan = NULL; Oid argtypes[] = {TEXTOID}; Datum values[1]; char nulls[1] = {' '}; /* hack for availbility regress test */ if (strcmp(path, "/tmp/regress_orafce") == 0) return; values[0] = CStringGetTextDatum(path); /* * SELECT 1 FROM utl_file.utl_file_dir * WHERE substring($1, 1, length(dir) + 1) = dir || '/' */ if (SPI_connect() < 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("SPI_connect failed"))); if (!plan) { /* Don't use LIKE not to escape '_' and '%' */ SPIPlanPtr p = SPI_prepare( "SELECT 1 FROM utl_file.utl_file_dir" " WHERE substring($1, 1, length(dir) + 1) = dir || '/'", 1, argtypes); if (p == NULL || (plan = SPI_saveplan(p)) == NULL) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("SPI_prepare_failed"))); } if (SPI_OK_SELECT != SPI_execute_plan(plan, values, nulls, false, 1)) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("can't execute sql"))); if (SPI_processed == 0) ereport(ERROR, (errcode(ERRCODE_RAISE_EXCEPTION), errmsg(INVALID_PATH), errdetail("you cannot access locality"), errhint("locality is not found in utl_file_dir table"))); SPI_finish(); }
/* * spi_exec_query * Execute given SQL command via SPI. * The plan will be cached by SPI_prepare if it hasn't been. */ static void spi_exec_query(const char *query, int nargs, Oid *argtypes, SPIPlanPtr *plan, Datum *values, const char *nulls, int result) { int ret; if (*plan == NULL) *plan = SPI_prepare(query, nargs, argtypes); ret = SPI_execute_plan(*plan, values, nulls, false, 0); if (ret != result) elog(ERROR, "pg_dbms_stats: SPI_execute_plan => %d", ret); }
static int luaP_executeplan (lua_State *L) { luaP_Plan *p = (luaP_Plan *) luaP_checkudata(L, 1, PLLUA_PLANMT); bool ro = (bool) lua_toboolean(L, 3); long c = luaL_optlong(L, 4, 0); int result = -1; if (p->nargs > 0) { luaP_Buffer *b; if (lua_type(L, 2) != LUA_TTABLE) luaP_typeerror(L, 2, "table"); b = luaP_getbuffer(L, p->nargs); luaP_fillbuffer(L, 2, p->type, b); luaP_TRY { result = SPI_execute_plan(p->plan, b->value, b->null, ro, c); } luaP_CATCH; }
int SPI_execute_with_args(const char *src, int nargs, Oid *argtypes, Datum *values, const char *nulls, bool read_only, long tcount) { SPIPlanPtr plan; int ret; plan = SPI_prepare(src, nargs, argtypes); if (plan == NULL) return SPI_result; ret = SPI_execute_plan(plan, values, nulls, read_only, tcount); SPI_freeplan(plan); return ret; }
/* * Fill table information in hash table. */ static void fill_tbl_info(Relation rel, struct PgqTableInfo *info) { StringInfo pkeys; Datum values[1]; const char *name = find_table_name(rel); TupleDesc desc; HeapTuple row; bool isnull; int res, i, attno; /* allow reset ASAP, but ignore it in this call */ info->invalid = false; /* load pkeys */ values[0] = ObjectIdGetDatum(rel->rd_id); res = SPI_execute_plan(pkey_plan, values, NULL, false, 0); if (res != SPI_OK_SELECT) elog(ERROR, "pkey_plan exec failed"); /* * Fill info */ desc = SPI_tuptable->tupdesc; pkeys = makeStringInfo(); info->n_pkeys = SPI_processed; info->table_name = MemoryContextStrdup(tbl_cache_ctx, name); info->pkey_attno = MemoryContextAlloc(tbl_cache_ctx, info->n_pkeys * sizeof(int)); for (i = 0; i < SPI_processed; i++) { row = SPI_tuptable->vals[i]; attno = DatumGetInt16(SPI_getbinval(row, desc, 1, &isnull)); name = SPI_getvalue(row, desc, 2); info->pkey_attno[i] = attno; if (i > 0) appendStringInfoChar(pkeys, ','); appendStringInfoString(pkeys, name); } info->pkey_list = MemoryContextStrdup(tbl_cache_ctx, pkeys->data); info->tg_cache = NULL; }
/** * Create and run the basic query on the floatvalue table, for use by the wciReadFloat function */ static void runWciReadFloatQueryFloat(struct ReadStore * out, FunctionCallInfo fcinfo) { struct WciReadParameterCollection p; parseReadParameters(& p, fcinfo); // This must match exactly the return type for wci.returnfloat const char * whatToSelect = "value::float, dataprovidername, placename::text, st_astext(placegeometry), referencetime, validtimefrom, validtimeto, validtimeindeterminatecode, valueparametername, valueunitname, levelparametername, levelunitname, levelfrom, levelto, levelindeterminatecode, dataversion, confidencecode, valuestoretime, valueid, valuetype"; const char * gridQuery = build_query(& p, FloatTable, OutputFloat, whatToSelect, NULL); elog(DEBUG1, gridQuery); // Perform primary query SPIPlanPtr queryPlan = getSpiPlan(gridQuery); if (SPI_OK_SELECT != SPI_execute_plan(queryPlan, NULL, NULL, true, 0)) { ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg( "Error when performing base query"))); } out->tuples = SPI_tuptable; out->tupleCount = SPI_processed; }
static Oid GetRelOid(Oid filenode) { int ret; Oid relid; bool isnull; Datum value[1] = { ObjectIdGetDatum(filenode) }; static SPIPlanPtr plan = NULL; /* If this is our first time here, create a plan and save it for later calls. */ if (plan == NULL) { StringInfoData buf; Oid paramType[1] = {OIDOID}; initStringInfo(&buf); appendStringInfo(&buf, "select oid from pg_class where pg_relation_filenode(oid) = $1"); plan = SPI_prepare(buf.data, 1, (Oid*)¶mType); if (plan == NULL) elog(ERROR, "SPI_prepare returned %d", SPI_result); } ret = SPI_execute_plan(plan, (Datum*)&value, NULL, true, 1); if (ret != SPI_OK_SELECT) ereport(FATAL, (errmsg("SPI_execute_plan failed: error code %d", ret))); if (SPI_processed < 1) return InvalidOid; relid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull)); if (isnull) return InvalidOid; return relid; }
/* * Execute ProxyQuery locally. * * Result will be in SPI_tuptable. */ void plproxy_query_exec(ProxyFunction *func, FunctionCallInfo fcinfo, ProxyQuery *q, DatumArray **array_params, int array_row) { int i, idx, err; char arg_nulls[FUNC_MAX_ARGS]; Datum arg_values[FUNC_MAX_ARGS]; /* fill args */ for (i = 0; i < q->arg_count; i++) { idx = q->arg_lookup[i]; if (PG_ARGISNULL(idx)) { arg_nulls[i] = 'n'; arg_values[i] = (Datum) NULL; } else if (array_params && IS_SPLIT_ARG(func, idx)) { DatumArray *ats = array_params[idx]; arg_nulls[i] = ats->nulls[array_row] ? 'n' : ' '; arg_values[i] = ats->nulls[array_row] ? (Datum) NULL : ats->values[array_row]; } else { arg_nulls[i] = ' '; arg_values[i] = PG_GETARG_DATUM(idx); } } /* run query */ err = SPI_execute_plan(q->plan, arg_values, arg_nulls, true, 0); if (err != SPI_OK_SELECT) plproxy_error(func, "query '%s' failed: %s", q->sql, SPI_result_code_string(err)); }
static int get_nnode(PlxFn *plx_fn, FunctionCallInfo fcinfo) { PlxQuery *plx_q = plx_fn->hash_query; int err; SPIPlanPtr plan; Oid types[FUNC_MAX_ARGS]; Datum values[FUNC_MAX_ARGS]; char arg_nulls[FUNC_MAX_ARGS]; Datum val; bool isnull; int i; if ((err = SPI_connect()) != SPI_OK_CONNECT) plx_error(plx_fn, "SPI_connect: %s", SPI_result_code_string(err)); for (i = 0; i < plx_q->nargs; i++) { int idx = plx_q->plx_fn_arg_indexes[i]; types[i] = plx_fn->arg_types[idx]->oid; values[i] = PG_GETARG_DATUM(idx); } plan = SPI_prepare(plx_q->sql->data, plx_q->nargs, types); err = SPI_execute_plan(plan, values, arg_nulls, true, 0); if (err != SPI_OK_SELECT) plx_error(plx_fn, "query '%s' failed: %s", plx_q->sql->data, SPI_result_code_string(err)); val = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull); err = SPI_finish(); if (err != SPI_OK_FINISH) plx_error(plx_fn, "SPI_finish: %s", SPI_result_code_string(err)); return DatumGetInt32(val); }
Datum dbms_alert_defered_signal(PG_FUNCTION_ARGS) { TriggerData *trigdata = (TriggerData *) fcinfo->context; TupleDesc tupdesc; HeapTuple rettuple; char *relname; text *name; text *message; int event_col; int message_col; Datum datum; bool isnull; int cycle = 0; float8 endtime; float8 timeout = 2; if (!CALLED_AS_TRIGGER(fcinfo)) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("not called by trigger manager"))); if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("not called on valid event"))); if (SPI_connect() < 0) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("SPI_connect failed"))); if (strcmp((relname = SPI_getrelname(trigdata->tg_relation)), "ora_alerts") != 0) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("not called with valid relation"))); rettuple = trigdata->tg_trigtuple; tupdesc = trigdata->tg_relation->rd_att; if (SPI_ERROR_NOATTRIBUTE == (event_col = SPI_fnumber(tupdesc, "event"))) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("attribute event not found"))); if (SPI_ERROR_NOATTRIBUTE == (message_col = SPI_fnumber(tupdesc, "message"))) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("attribute message not found"))); datum = SPI_getbinval(rettuple, tupdesc, event_col, &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("event name is NULL"), errdetail("Eventname may not be NULL."))); name = DatumGetTextP(datum); datum = SPI_getbinval(rettuple, tupdesc, message_col, &isnull); if (isnull) message = NULL; else message = DatumGetTextP(datum); WATCH_PRE(timeout, endtime, cycle); if (ora_lock_shmem(SHMEMMSGSZ, MAX_PIPES, MAX_EVENTS, MAX_LOCKS, false)) { ItemPointer tid; Oid argtypes[1] = {TIDOID}; char nulls[1] = {' '}; Datum values[1]; void *plan; create_message(name, message); LWLockRelease(shmem_lock); tid = &rettuple->t_data->t_ctid; if (!(plan = SPI_prepare("DELETE FROM ora_alerts WHERE ctid = $1", 1, argtypes))) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("SPI_prepare failed"))); values[0] = ItemPointerGetDatum(tid); if (SPI_OK_DELETE != SPI_execute_plan(plan, values, nulls, false, 1)) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), errmsg("can't execute sql"))); SPI_finish(); return PointerGetDatum(rettuple); } WATCH_POST(timeout, endtime, cycle); LOCK_ERROR(); PG_RETURN_NULL(); }
static PyObject * PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit) { volatile int nargs; int i, rv; PLyPlanObject *plan; volatile MemoryContext oldcontext; volatile ResourceOwner oldowner; PyObject *ret; if (list != NULL) { if (!PySequence_Check(list) || PyString_Check(list) || PyUnicode_Check(list)) { PLy_exception_set(PyExc_TypeError, "plpy.execute takes a sequence as its second argument"); return NULL; } nargs = PySequence_Length(list); } else nargs = 0; plan = (PLyPlanObject *) ob; if (nargs != plan->nargs) { char *sv; PyObject *so = PyObject_Str(list); if (!so) PLy_elog(ERROR, "could not execute plan"); sv = PyString_AsString(so); PLy_exception_set_plural(PyExc_TypeError, "Expected sequence of %d argument, got %d: %s", "Expected sequence of %d arguments, got %d: %s", plan->nargs, plan->nargs, nargs, sv); Py_DECREF(so); return NULL; } oldcontext = CurrentMemoryContext; oldowner = CurrentResourceOwner; PLy_spi_subtransaction_begin(oldcontext, oldowner); PG_TRY(); { char *volatile nulls; volatile int j; if (nargs > 0) nulls = palloc(nargs * sizeof(char)); else nulls = NULL; for (j = 0; j < nargs; j++) { PyObject *elem; elem = PySequence_GetItem(list, j); if (elem != Py_None) { PG_TRY(); { plan->values[j] = plan->args[j].out.d.func(&(plan->args[j].out.d), -1, elem); } PG_CATCH(); { Py_DECREF(elem); PG_RE_THROW(); } PG_END_TRY(); Py_DECREF(elem); nulls[j] = ' '; } else { Py_DECREF(elem); plan->values[j] = InputFunctionCall(&(plan->args[j].out.d.typfunc), NULL, plan->args[j].out.d.typioparam, -1); nulls[j] = 'n'; } } rv = SPI_execute_plan(plan->plan, plan->values, nulls, PLy_curr_procedure->fn_readonly, limit); ret = PLy_spi_execute_fetch_result(SPI_tuptable, SPI_processed, rv); if (nargs > 0) pfree(nulls); PLy_spi_subtransaction_commit(oldcontext, oldowner); } PG_CATCH(); { int k; /* * cleanup plan->values array */ for (k = 0; k < nargs; k++) { if (!plan->args[k].out.d.typbyval && (plan->values[k] != PointerGetDatum(NULL))) { pfree(DatumGetPointer(plan->values[k])); plan->values[k] = PointerGetDatum(NULL); } } PLy_spi_subtransaction_abort(oldcontext, oldowner); return NULL; } PG_END_TRY(); for (i = 0; i < nargs; i++) { if (!plan->args[i].out.d.typbyval && (plan->values[i] != PointerGetDatum(NULL))) { pfree(DatumGetPointer(plan->values[i])); plan->values[i] = PointerGetDatum(NULL); } } if (rv < 0) { PLy_exception_set(PLy_exc_spi_error, "SPI_execute_plan failed: %s", SPI_result_code_string(rv)); return NULL; } return ret; }
Datum payment(PG_FUNCTION_ARGS) { /* Input variables. */ int32 w_id = PG_GETARG_INT32(0); int32 d_id = PG_GETARG_INT32(1); int32 c_id = PG_GETARG_INT32(2); int32 c_w_id = PG_GETARG_INT32(3); int32 c_d_id = PG_GETARG_INT32(4); text *c_last = PG_GETARG_TEXT_P(5); float4 h_amount = PG_GETARG_FLOAT4(6); TupleDesc tupdesc; SPITupleTable *tuptable; HeapTuple tuple; int ret; char *w_name = NULL; char *w_street_1 = NULL; char *w_street_2 = NULL; char *w_city = NULL; char *w_state = NULL; char *w_zip = NULL; char *d_name = NULL; char *d_street_1 = NULL; char *d_street_2 = NULL; char *d_city = NULL; char *d_state = NULL; char *d_zip = NULL; char *tmp_c_id = NULL; int my_c_id = 0; int count; char *c_first = NULL; char *c_middle = NULL; char *my_c_last = NULL; char *c_street_1 = NULL; char *c_street_2 = NULL; char *c_city = NULL; char *c_state = NULL; char *c_zip = NULL; char *c_phone = NULL; char *c_since = NULL; char *c_credit = NULL; char *c_credit_lim = NULL; char *c_discount = NULL; char *c_balance = NULL; char *c_data = NULL; char *c_ytd_payment = NULL; Datum args[8]; char nulls[8] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }; elog(DEBUG1, "w_id = %d", w_id); elog(DEBUG1, "d_id = %d", d_id); elog(DEBUG1, "c_id = %d", c_id); elog(DEBUG1, "c_w_id = %d", c_w_id); elog(DEBUG1, "c_d_id = %d", c_d_id); elog(DEBUG1, "c_last = %s", DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(c_last)))); elog(DEBUG1, "h_amount = %f", h_amount); SPI_connect(); plan_queries(statements); args[0] = Int32GetDatum(w_id); ret = SPI_execute_plan(PAYMENT_1, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[0]; w_name = SPI_getvalue(tuple, tupdesc, 1); w_street_1 = SPI_getvalue(tuple, tupdesc, 2); w_street_2 = SPI_getvalue(tuple, tupdesc, 3); w_city = SPI_getvalue(tuple, tupdesc, 4); w_state = SPI_getvalue(tuple, tupdesc, 5); w_zip = SPI_getvalue(tuple, tupdesc, 6); elog(DEBUG1, "w_name = %s", w_name); elog(DEBUG1, "w_street_1 = %s", w_street_1); elog(DEBUG1, "w_street_2 = %s", w_street_2); elog(DEBUG1, "w_city = %s", w_city); elog(DEBUG1, "w_state = %s", w_state); elog(DEBUG1, "w_zip = %s", w_zip); } else { SPI_finish(); PG_RETURN_INT32(-1); } args[0] = Float4GetDatum(h_amount); args[1] = Int32GetDatum(w_id); ret = SPI_execute_plan(PAYMENT_2, args, nulls, false, 0); if (ret != SPI_OK_UPDATE) { SPI_finish(); PG_RETURN_INT32(-1); } args[0] = Int32GetDatum(d_id); args[1] = Int32GetDatum(w_id); ret = SPI_execute_plan(PAYMENT_3, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[0]; d_name = SPI_getvalue(tuple, tupdesc, 1); d_street_1 = SPI_getvalue(tuple, tupdesc, 2); d_street_2 = SPI_getvalue(tuple, tupdesc, 3); d_city = SPI_getvalue(tuple, tupdesc, 4); d_state = SPI_getvalue(tuple, tupdesc, 5); d_zip = SPI_getvalue(tuple, tupdesc, 6); elog(DEBUG1, "d_name = %s", d_name); elog(DEBUG1, "d_street_1 = %s", d_street_1); elog(DEBUG1, "d_street_2 = %s", d_street_2); elog(DEBUG1, "d_city = %s", d_city); elog(DEBUG1, "d_state = %s", d_state); elog(DEBUG1, "d_zip = %s", d_zip); } else { SPI_finish(); PG_RETURN_INT32(-1); } args[0] = Float4GetDatum(h_amount); args[1] = Int32GetDatum(d_id); args[2] = Int32GetDatum(w_id); ret = SPI_execute_plan(PAYMENT_4, args, nulls, false, 0); if (ret != SPI_OK_UPDATE) { SPI_finish(); PG_RETURN_INT32(-1); } if (c_id == 0) { args[0] = Int32GetDatum(w_id); args[1] = Int32GetDatum(d_id); args[2] = PointerGetDatum(c_last); ret = SPI_execute_plan(PAYMENT_5, args, nulls, true, 0); count = SPI_processed; if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[count / 2]; tmp_c_id = SPI_getvalue(tuple, tupdesc, 1); elog(DEBUG1, "c_id = %s, %d total, selected %d", tmp_c_id, count, count / 2); my_c_id = atoi(tmp_c_id); } else { SPI_finish(); PG_RETURN_INT32(-1); } } else { my_c_id = c_id; } args[0] = Int32GetDatum(c_w_id); args[1] = Int32GetDatum(c_d_id); args[2] = Int32GetDatum(my_c_id); ret = SPI_execute_plan(PAYMENT_6, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[0]; c_first = SPI_getvalue(tuple, tupdesc, 1); c_middle = SPI_getvalue(tuple, tupdesc, 2); my_c_last = SPI_getvalue(tuple, tupdesc, 3); c_street_1 = SPI_getvalue(tuple, tupdesc, 4); c_street_2 = SPI_getvalue(tuple, tupdesc, 5); c_city = SPI_getvalue(tuple, tupdesc, 6); c_state = SPI_getvalue(tuple, tupdesc, 7); c_zip = SPI_getvalue(tuple, tupdesc, 8); c_phone = SPI_getvalue(tuple, tupdesc, 9); c_since = SPI_getvalue(tuple, tupdesc, 10); c_credit = SPI_getvalue(tuple, tupdesc, 11); c_credit_lim = SPI_getvalue(tuple, tupdesc, 12); c_discount = SPI_getvalue(tuple, tupdesc, 13); c_balance = SPI_getvalue(tuple, tupdesc, 14); c_data = SPI_getvalue(tuple, tupdesc, 15); c_ytd_payment = SPI_getvalue(tuple, tupdesc, 16); elog(DEBUG1, "c_first = %s", c_first); elog(DEBUG1, "c_middle = %s", c_middle); elog(DEBUG1, "c_last = %s", my_c_last); elog(DEBUG1, "c_street_1 = %s", c_street_1); elog(DEBUG1, "c_street_2 = %s", c_street_2); elog(DEBUG1, "c_city = %s", c_city); elog(DEBUG1, "c_state = %s", c_state); elog(DEBUG1, "c_zip = %s", c_zip); elog(DEBUG1, "c_phone = %s", c_phone); elog(DEBUG1, "c_since = %s", c_since); elog(DEBUG1, "c_credit = %s", c_credit); elog(DEBUG1, "c_credit_lim = %s", c_credit_lim); elog(DEBUG1, "c_discount = %s", c_discount); elog(DEBUG1, "c_balance = %s", c_balance); elog(DEBUG1, "c_data = %s", c_data); elog(DEBUG1, "c_ytd_payment = %s", c_ytd_payment); } else { SPI_finish(); PG_RETURN_INT32(-1); } /* It's either "BC" or "GC". */ if (c_credit[0] == 'G') { args[0] = Float4GetDatum(h_amount); args[1] = Int32GetDatum(my_c_id); args[2] = Int32GetDatum(c_w_id); args[3] = Int32GetDatum(c_d_id); ret = SPI_execute_plan(PAYMENT_7_GC, args, nulls, false, 0); if (ret != SPI_OK_UPDATE) { SPI_finish(); PG_RETURN_INT32(-1); } } else { char my_c_data[1000]; sprintf(my_c_data, "%d %d %d %d %d %f ", my_c_id, c_d_id, c_w_id, d_id, w_id, h_amount); args[0] = Float4GetDatum(h_amount); args[1] = CStringGetTextDatum(my_c_data); args[2] = Int32GetDatum(my_c_id); args[3] = Int32GetDatum(c_w_id); args[4] = Int32GetDatum(c_d_id); ret = SPI_execute_plan(PAYMENT_7_BC, args, nulls, false, 0); if (ret != SPI_OK_UPDATE) { SPI_finish(); PG_RETURN_INT32(-1); } } args[0] = Int32GetDatum(my_c_id); args[1] = Int32GetDatum(c_d_id); args[2] = Int32GetDatum(c_w_id); args[3] = Int32GetDatum(d_id); args[4] = Int32GetDatum(w_id); args[5] = Float4GetDatum(h_amount); args[6] = CStringGetTextDatum(w_name); args[7] = CStringGetTextDatum(d_name); ret = SPI_execute_plan(PAYMENT_8, args, nulls, false, 0); if (ret != SPI_OK_INSERT) { SPI_finish(); PG_RETURN_INT32(-1); } SPI_finish(); PG_RETURN_INT32(1); }
static int load_rows(PyObj self, PyObj row_iter, uint32 *total) { MemoryContext former = CurrentMemoryContext; volatile PyObj row = NULL; Datum *datums; bool *nulls; char *cnulls; int r = 0; SPIPlanPtr plan; Assert(!ext_state); Assert(PyIter_Check(row_iter)); plan = PyPgStatement_GetPlan(self); if (plan == NULL) return(-1); PG_TRY(); { PyObj tdo = PyPgStatement_GetInput(self); PyObj typs = PyPgTupleDesc_GetTypesTuple(tdo); PyObj namemap = PyPgTupleDesc_GetNameMap(tdo); TupleDesc td = PyPgTupleDesc_GetTupleDesc(tdo); int rnatts = PyPgTupleDesc_GetNatts(tdo); int *freemap = PyPgTupleDesc_GetFreeMap(tdo); int spi_r; datums = palloc(sizeof(Datum) * td->natts); nulls = palloc(sizeof(bool) * td->natts); cnulls = palloc(sizeof(char) * td->natts); while ((row = PyIter_Next(row_iter))) { PyObj pargs; pargs = Py_NormalizeRow(rnatts, td, namemap, row); Py_DECREF(row); if (pargs == NULL) { r = -1; break; } row = pargs; Py_BuildDatumsAndNulls(td, typs, row, datums, nulls); Py_DECREF(row); row = NULL; /* borrow spi_r for a moment */ for (spi_r = 0; spi_r < td->natts; ++spi_r) { cnulls[spi_r] = nulls[spi_r] ? 'n' : ' '; } spi_r = SPI_execute_plan(plan, datums, cnulls, false, 1); /* * Free the built datums. */ FreeReferences(freemap, datums, nulls); if (spi_r < 0) raise_spi_error(spi_r); *total = *total + SPI_processed; } pfree(datums); pfree(nulls); pfree(cnulls); } PG_CATCH(); { /* * WARNING: Leaks datums & nulls on error. Yay, procCxt. */ PyErr_SetPgError(false); Py_XDECREF(row); r = -1; } PG_END_TRY(); MemoryContextSwitchTo(former); return(r); }
/* Clause 3.3.9.3 */ Datum TradeUpdateFrame1(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; AttInMetadata *attinmeta; int call_cntr; int max_calls; int i; int j; char **values = NULL; /* Stuff done only on the first call of the function. */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; enum tuf1 { i_bid_price=0, i_cash_transaction_amount, i_cash_transaction_dts, i_cash_transaction_name, i_exec_name, i_is_cash, i_is_market, i_num_found, i_num_updated, i_settlement_amount, i_settlement_cash_due_date, i_settlement_cash_type, i_trade_history_dts, i_trade_history_status_id, i_trade_price }; int max_trades = PG_GETARG_INT32(0); int max_updates = PG_GETARG_INT32(1); ArrayType *trade_id_p = PG_GETARG_ARRAYTYPE_P(2); int16 typlen; bool typbyval; char typalign; int ndim, nitems; int *dim; long *trade_id; int ret; TupleDesc tupdesc; SPITupleTable *tuptable = NULL; HeapTuple tuple = NULL; #ifdef DEBUG char sql[2048]; #endif Datum args[2]; char nulls[2] = { ' ', ' ' }; int num_found = max_trades; int num_updated = 0; int num_updated4 = 0; int num_updated5 = 0; int num_updated7 = 0; int num_cash = 0; ndim = ARR_NDIM(trade_id_p); dim = ARR_DIMS(trade_id_p); nitems = ArrayGetNItems(ndim, dim); get_typlenbyvalalign(ARR_ELEMTYPE(trade_id_p), &typlen, &typbyval, &typalign); trade_id = (long *) ARR_DATA_PTR(trade_id_p); /* * Prepare a values array for building the returned tuple. * This should be an array of C strings, which will * be processed later by the type input functions. * Don't forget to factor in commas (,) and braces ({}) for the arrays. */ values = (char **) palloc(sizeof(char *) * 15); values[i_bid_price] = (char *) palloc(((S_PRICE_T_LEN + 1) * 20 + 2) * sizeof(char)); values[i_cash_transaction_amount] = (char *) palloc(((VALUE_T_LEN + 1) * 20 + 2) * sizeof(char)); values[i_cash_transaction_dts] = (char *) palloc(((MAXDATELEN + 1) * 20 + 2) * sizeof(char)); values[i_cash_transaction_name] = (char *) palloc(((CT_NAME_LEN + 3) * 20 + 2) * sizeof(char)); values[i_exec_name] = (char *) palloc(((T_EXEC_NAME_LEN + 3) * 20 + 2) * sizeof(char)); values[i_is_cash] = (char *) palloc(((SMALLINT_LEN + 1) * 20 + 2) * sizeof(char)); values[i_is_market] = (char *) palloc(((SMALLINT_LEN + 1) * 20 + 2) * sizeof(char)); values[i_num_found] = (char *) palloc((INTEGER_LEN + 1) * sizeof(char)); values[i_num_updated] = (char *) palloc((INTEGER_LEN + 1) * sizeof(char)); values[i_settlement_amount] = (char *) palloc(((VALUE_T_LEN + 1) * 20 + 2) * sizeof(char)); values[i_settlement_cash_due_date] = (char *) palloc(((MAXDATELEN + 1) * 20 + 2) * sizeof(char)); values[i_settlement_cash_type] = (char *) palloc(((SE_CASH_TYPE_LEN + 3) * 20 + 2) * sizeof(char)); values[i_trade_history_dts] = (char *) palloc(((MAXDATELEN * 3 + 4) * 20 + 22) * sizeof(char)); values[i_trade_history_status_id] = (char *) palloc((((ST_ID_LEN + 2) * 3 + 4) * 20 + 22) * sizeof(char)); values[i_trade_price] = (char *) palloc(((S_PRICE_T_LEN + 1) * 20 + 2) * sizeof(char)); #ifdef DEBUG dump_tuf1_inputs(max_trades, max_updates, trade_id); #endif /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); funcctx->max_calls = 1; /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); SPI_connect(); plan_queries(TUF1_statements); strcpy(values[i_bid_price], "{"); strcpy(values[i_exec_name], "{"); strcpy(values[i_is_cash], "{"); strcpy(values[i_is_market], "{"); strcpy(values[i_trade_price], "{"); strcpy(values[i_settlement_amount], "{"); strcpy(values[i_settlement_cash_due_date], "{"); strcpy(values[i_settlement_cash_type], "{"); strcpy(values[i_cash_transaction_amount], "{"); strcpy(values[i_cash_transaction_dts], "{"); strcpy(values[i_cash_transaction_name], "{"); strcpy(values[i_trade_history_dts], "{"); strcpy(values[i_trade_history_status_id], "{"); for (i = 0; i < max_trades; i++) { char *is_cash_str = NULL; char *is_market_str; if (num_updated < max_updates) { char *ex_name; #ifdef DEBUG sprintf(sql, SQLTUF1_1, trade_id[i]); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = Int64GetDatum(trade_id[i]); ret = SPI_execute_plan(TUF1_1, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[0]; ex_name = SPI_getvalue(tuple, tupdesc, 1); } else { continue; } #ifdef DEBUG elog(NOTICE, "ex_name = %s", ex_name); if (strstr(ex_name, " X ")) { sprintf(sql, SQLTUF1_2a, ex_name); } else { sprintf(sql, SQLTUF1_2b, ex_name); } elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = CStringGetTextDatum(ex_name); if (strstr(ex_name, " X ")) { ret = SPI_execute_plan(TUF1_2a, args, nulls, true, 0); } else { ret = SPI_execute_plan(TUF1_2b, args, nulls, true, 0); } if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[0]; ex_name = SPI_getvalue(tuple, tupdesc, 1); } else { FAIL_FRAME_SET(&funcctx->max_calls, strstr(ex_name, " X ")? TUF1_statements[1].sql: TUF1_statements[2].sql); dump_tuf1_inputs(max_trades, max_updates, trade_id); continue; } #ifdef DEBUG elog(NOTICE, "ex_name = %s", ex_name); sprintf(sql, SQLTUF1_3, ex_name, trade_id[i]); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[1] = Int64GetDatum(trade_id[i]); ret = SPI_execute_plan(TUF1_3, args, nulls, false, 0); if (ret != SPI_OK_UPDATE) { FAIL_FRAME_SET(&funcctx->max_calls, TUF1_statements[4].sql); dump_tuf1_inputs(max_trades, max_updates, trade_id); continue; } num_updated += SPI_processed; } #ifdef DEBUG sprintf(sql, SQLTUF1_4, trade_id[i]); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = Int64GetDatum(trade_id[i]); ret = SPI_execute_plan(TUF1_4, args, nulls, true, 0); if (ret != SPI_OK_SELECT) { FAIL_FRAME_SET(&funcctx->max_calls, TUF1_statements[5].sql); dump_tuf1_inputs(max_trades, max_updates, trade_id); continue; } tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; for (j = 0; j < SPI_processed; j++) { char *trade_price; if (num_updated4 > 0) { strcat(values[i_bid_price], ","); strcat(values[i_exec_name], ","); strcat(values[i_is_cash], ","); strcat(values[i_is_market], ","); strcat(values[i_trade_price], ","); } tuple = tuptable->vals[j]; strcat(values[i_bid_price], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_exec_name], "\""); strcat(values[i_exec_name], SPI_getvalue(tuple, tupdesc, 2)); strcat(values[i_exec_name], "\""); is_cash_str = SPI_getvalue(tuple, tupdesc, 3); strcat(values[i_is_cash], (is_cash_str[0] == 't' ? "1": "0")); is_market_str = SPI_getvalue(tuple, tupdesc, 4); strcat(values[i_is_market], (is_market_str[0] == 't' ? "0" : "1")); trade_price = SPI_getvalue(tuple, tupdesc, 5); if (trade_price != NULL) strcat(values[i_trade_price], SPI_getvalue(tuple, tupdesc, 5)); else strcat(values[i_trade_price], "NULL"); num_updated4++; } #ifdef DEBUG sprintf(sql, SQLTUF1_5, trade_id[i]); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_execute_plan(TUF1_5, args, nulls, true, 0); if (ret != SPI_OK_SELECT) { FAIL_FRAME_SET(&funcctx->max_calls, TUF1_statements[6].sql); dump_tuf1_inputs(max_trades, max_updates, trade_id); continue; } tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; for (j = 0; j < SPI_processed; j++) { if (num_updated5 > 0) { strcat(values[i_settlement_amount], ","); strcat(values[i_settlement_cash_due_date], ","); strcat(values[i_settlement_cash_type], ","); } tuple = tuptable->vals[j]; strcat(values[i_settlement_amount], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_settlement_cash_due_date], SPI_getvalue(tuple, tupdesc, 2)); strcat(values[i_settlement_cash_type], "\""); strcat(values[i_settlement_cash_type], SPI_getvalue(tuple, tupdesc, 3)); strcat(values[i_settlement_cash_type], "\""); num_updated5++; } if (is_cash_str[0] == 't') { if (num_cash > 0) { strcat(values[i_cash_transaction_amount], ","); strcat(values[i_cash_transaction_dts], ","); strcat(values[i_cash_transaction_name], ","); } #ifdef DEBUG sprintf(sql, SQLTUF1_6, trade_id[i]); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_execute_plan(TUF1_6, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[0]; strcat(values[i_cash_transaction_amount], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_cash_transaction_dts], SPI_getvalue(tuple, tupdesc, 2)); strcat(values[i_cash_transaction_name], "\""); strcat(values[i_cash_transaction_name], SPI_getvalue(tuple, tupdesc, 3)); strcat(values[i_cash_transaction_name], "\""); ++num_cash; } else { FAIL_FRAME_SET(&funcctx->max_calls, TUF1_statements[7].sql); dump_tuf1_inputs(max_trades, max_updates, trade_id); continue; } } #ifdef DEBUG sprintf(sql, SQLTUF1_7, trade_id[i]); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_execute_plan(TUF1_7, args, nulls, true, 0); if (ret == SPI_OK_SELECT) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; } else { FAIL_FRAME_SET(&funcctx->max_calls, TUF1_statements[8].sql); dump_tuf1_inputs(max_trades, max_updates, trade_id); continue; } if (num_updated7 > 0) { strcat(values[i_trade_history_dts], ","); strcat(values[i_trade_history_status_id], ","); } strcat(values[i_trade_history_dts], "{"); strcat(values[i_trade_history_status_id], "{"); for (j = 0; j < SPI_processed; j++) { if (j > 0) { strcat(values[i_trade_history_dts], ","); strcat(values[i_trade_history_status_id], ","); } tuple = tuptable->vals[j]; strcat(values[i_trade_history_dts], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_trade_history_status_id], "\""); strcat(values[i_trade_history_status_id], SPI_getvalue(tuple, tupdesc, 2)); strcat(values[i_trade_history_status_id], "\""); num_updated7++; } for (j = SPI_processed; j < 3; j++) { if (j > 0) { strcat(values[i_trade_history_dts], ","); strcat(values[i_trade_history_status_id], ","); } strcat(values[i_trade_history_dts], "NULL"); strcat(values[i_trade_history_status_id], "\"\""); num_updated7++; } strcat(values[i_trade_history_dts], "}"); strcat(values[i_trade_history_status_id], "}"); } strcat(values[i_bid_price], "}"); strcat(values[i_exec_name], "}"); strcat(values[i_is_cash], "}"); strcat(values[i_is_market], "}"); strcat(values[i_trade_price], "}"); strcat(values[i_settlement_amount], "}"); strcat(values[i_settlement_cash_due_date], "}"); strcat(values[i_settlement_cash_type], "}"); strcat(values[i_cash_transaction_amount], "}"); strcat(values[i_cash_transaction_dts], "}"); strcat(values[i_cash_transaction_name], "}"); strcat(values[i_trade_history_dts], "}"); strcat(values[i_trade_history_status_id], "}"); sprintf(values[i_num_found], "%d", num_found); sprintf(values[i_num_updated], "%d", num_updated); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); } /* * generate attribute metadata needed later to produce tuples from raw * C strings */ attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; attinmeta = funcctx->attinmeta; if (call_cntr < max_calls) { /* do when there is more left to send */ HeapTuple tuple; Datum result; #ifdef DEBUG for (i = 0; i < 15; i++) { elog(NOTICE, "TUF1 OUT: %d %s", i, values[i]); } #endif /* DEBUG */ /* Build a tuple. */ tuple = BuildTupleFromCStrings(attinmeta, values); /* Make the tuple into a datum. */ result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else { /* Do when there is no more left. */ SPI_finish(); SRF_RETURN_DONE(funcctx); } }
/* Clause 3.3.1.3 */ Datum BrokerVolumeFrame1(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; AttInMetadata *attinmeta; int call_cntr; int max_calls; int i; int ndim, nitems; int *dim; char *broker_list; char **values = NULL; /* Stuff done only on the first call of the function. */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; ArrayType *broker_list_p = PG_GETARG_ARRAYTYPE_P(0); text *sector_name_p = PG_GETARG_TEXT_P(1); enum bvf1 { i_broker_name=0, i_list_len, i_volume }; int16 typlen; bool typbyval; char typalign; int ret; TupleDesc tupdesc; SPITupleTable *tuptable = NULL; HeapTuple tuple = NULL; #ifdef DEBUG char sql[2048]; #endif char broker_list_array[(B_NAME_LEN + 3) * 40 + 5] = "'{"; Datum args[2]; char nulls[2] = { ' ', ' ' }; /* * Prepare a values array for building the returned tuple. * This should be an array of C strings, which will * be processed later by the type input functions. */ values = (char **) palloc(sizeof(char *) * 3); values[i_list_len] = (char *) palloc((SMALLINT_LEN + 1) * sizeof(char)); /* * This might be overkill since we always expect single dimensions * arrays. */ ndim = ARR_NDIM(broker_list_p); dim = ARR_DIMS(broker_list_p); nitems = ArrayGetNItems(ndim, dim); get_typlenbyvalalign(ARR_ELEMTYPE(broker_list_p), &typlen, &typbyval, &typalign); broker_list = ARR_DATA_PTR(broker_list_p); /* Turn the broker_list input into an array format. */ if (nitems > 0) { strcat(broker_list_array, "\""); strcat(broker_list_array, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(broker_list)))); broker_list = att_addlength_pointer(broker_list, typlen, broker_list); broker_list = (char *) att_align_nominal(broker_list, typalign); strcat(broker_list_array, "\""); } for (i = 1; i < nitems; i++) { strcat(broker_list_array, ",\""); strcat(broker_list_array, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(broker_list)))); broker_list = att_addlength_pointer(broker_list, typlen, broker_list); broker_list = (char *) att_align_nominal(broker_list, typalign); strcat(broker_list_array, "\""); } strcat(broker_list_array, "}'"); #ifdef DEBUG dump_bvf1_inputs(broker_list_p, sector_name_p); #endif /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); funcctx->max_calls = 1; /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); SPI_connect(); plan_queries(BVF1_statements); #ifdef DEBUG sprintf(sql, SQLBVF1_1, broker_list_array, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(sector_name_p)))); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = PointerGetDatum(broker_list_p); args[1] = PointerGetDatum(sector_name_p); ret = SPI_execute_plan(BVF1_1, args, nulls, true, 0); if (ret == SPI_OK_SELECT) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[0]; } else { dump_bvf1_inputs(broker_list_p, sector_name_p); FAIL_FRAME_SET(&funcctx->max_calls, BVF1_statements[0].sql); } sprintf(values[i_list_len], "%d", SPI_processed); values[i_broker_name] = (char *) palloc(((B_NAME_LEN + 2) * (SPI_processed + 1) + 3) * sizeof(char)); values[i_volume] = (char *) palloc((INTEGER_LEN * (SPI_processed + 1) + 3) * sizeof(char)); if (SPI_processed == 0) { strcpy(values[i_broker_name], "{}"); strcpy(values[i_volume], "{}"); } else { strcpy(values[i_broker_name], "{"); strcpy(values[i_volume], "{"); if (SPI_processed > 0) { strcat(values[i_broker_name], "\""); strcat(values[i_broker_name], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_broker_name], "\""); strcat(values[i_volume], SPI_getvalue(tuple, tupdesc, 2)); } for (i = 1; i < SPI_processed; i++) { tuple = tuptable->vals[i]; strcat(values[i_broker_name], ","); strcat(values[i_broker_name], "\""); strcat(values[i_broker_name], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_broker_name], "\""); strcat(values[i_volume], ","); strcat(values[i_volume], SPI_getvalue(tuple, tupdesc, 2)); } strcat(values[i_broker_name], "}"); strcat(values[i_volume], "}"); } /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); } /* * generate attribute metadata needed later to produce tuples from raw * C strings */ attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; attinmeta = funcctx->attinmeta; if (call_cntr < max_calls) { /* do when there is more left to send */ HeapTuple tuple; Datum result; #ifdef DEBUG for (i = 0; i < 3; i++) { elog(NOTICE, "BVF1 OUT: %d %s", i, values[i]); } #endif /* DEBUG */ /* Build a tuple. */ tuple = BuildTupleFromCStrings(attinmeta, values); /* Make the tuple into a datum. */ result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else { /* Do when there is no more left. */ SPI_finish(); SRF_RETURN_DONE(funcctx); } }
/* Clause 3.3.9.3 */ Datum TradeStatusFrame1(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; AttInMetadata *attinmeta; int call_cntr; int max_calls; int i; char **values = NULL; /* Stuff done only on the first call of the function. */ if (SRF_IS_FIRSTCALL()) { enum tsf1 { i_broker_name=0, i_charge, i_cust_f_name, i_cust_l_name, i_ex_name, i_exec_name, i_num_found, i_s_name, i_status_name, i_symbol, i_trade_dts, i_trade_id, i_trade_qty, i_type_name }; long acct_id = PG_GETARG_INT64(0); int ret; TupleDesc tupdesc; SPITupleTable *tuptable = NULL; HeapTuple tuple = NULL; #ifdef DEBUG char sql[2048]; #endif Datum args[1]; char nulls[1] = { ' ' }; /* * Prepare a values array for building the returned tuple. * This should be an array of C strings, which will * be processed later by the type input functions. */ values = (char **) palloc(sizeof(char *) * 14); values[i_charge] = (char *) palloc((VALUE_T_LEN + 1) * sizeof(char) * 50); values[i_ex_name] = (char *) palloc((EX_NAME_LEN + 3) * sizeof(char) * 50); values[i_exec_name] = (char *) palloc((T_EXEC_NAME_LEN + 3) * sizeof(char) * 50); values[i_num_found] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char)); values[i_s_name] = (char *) palloc((S_NAME_LEN + 3) * sizeof(char) * 50); values[i_status_name] = (char *) palloc((ST_NAME_LEN + 3) * sizeof(char) * 50); values[i_symbol] = (char *) palloc((S_SYMB_LEN + 3) * sizeof(char) * 50); values[i_trade_dts] = (char *) palloc((MAXDATELEN + 1) * sizeof(char) * 50); values[i_trade_id] = (char *) palloc((BIGINT_LEN + 1) * sizeof(char) * 50); values[i_trade_qty] = (char *) palloc((INTEGER_LEN + 1) * sizeof(char) * 50); values[i_type_name] = (char *) palloc((TT_NAME_LEN + 3) * sizeof(char) * 50); values[i_cust_l_name] = NULL; values[i_cust_f_name] = NULL; values[i_broker_name] = NULL; #ifdef DEBUG dump_tsf1_inputs(acct_id); #endif /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); funcctx->max_calls = 1; /* switch to memory context appropriate for multiple function calls */ TSF1_savedcxt = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); SPI_connect(); plan_queries(TSF1_statements); #ifdef DEBUG sprintf(sql, SQLTSF1_1, acct_id); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = Int64GetDatum(acct_id); ret = SPI_execute_plan(TSF1_1, args, nulls, true, 0); if (ret == SPI_OK_SELECT) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; } else { FAIL_FRAME_SET(&funcctx->max_calls, TSF1_statements[0].sql); dump_tsf1_inputs(acct_id); } sprintf(values[i_num_found], "%d", SPI_processed); strcpy(values[i_trade_id], "{"); strcpy(values[i_trade_dts], "{"); strcpy(values[i_status_name], "{"); strcpy(values[i_type_name], "{"); strcpy(values[i_symbol], "{"); strcpy(values[i_trade_qty], "{"); strcpy(values[i_exec_name], "{"); strcpy(values[i_charge], "{"); strcpy(values[i_s_name], "{"); strcpy(values[i_ex_name], "{"); for (i = 0; i < SPI_processed; i++) { tuple = tuptable->vals[i]; if (i > 0) { strcat(values[i_trade_id], ","); strcat(values[i_trade_dts], ","); strcat(values[i_status_name], ","); strcat(values[i_type_name], ","); strcat(values[i_symbol], ","); strcat(values[i_trade_qty], ","); strcat(values[i_exec_name], ","); strcat(values[i_charge], ","); strcat(values[i_s_name], ","); strcat(values[i_ex_name], ","); } strcat(values[i_trade_id], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_trade_dts], SPI_getvalue(tuple, tupdesc, 2)); strcat(values[i_status_name], "\""); strcat(values[i_status_name], SPI_getvalue(tuple, tupdesc, 3)); strcat(values[i_status_name], "\""); strcat(values[i_type_name], "\""); strcat(values[i_type_name], SPI_getvalue(tuple, tupdesc, 4)); strcat(values[i_type_name], "\""); strcat(values[i_symbol], "\""); strcat(values[i_symbol], SPI_getvalue(tuple, tupdesc, 5)); strcat(values[i_symbol], "\""); strcat(values[i_trade_qty], SPI_getvalue(tuple, tupdesc, 6)); strcat(values[i_exec_name], "\""); strcat(values[i_exec_name], SPI_getvalue(tuple, tupdesc, 7)); strcat(values[i_exec_name], "\""); strcat(values[i_charge], SPI_getvalue(tuple, tupdesc, 8)); strcat(values[i_s_name], "\""); strcat(values[i_s_name], SPI_getvalue(tuple, tupdesc, 9)); strcat(values[i_s_name], "\""); strcat(values[i_ex_name], "\""); strcat(values[i_ex_name], SPI_getvalue(tuple, tupdesc, 10)); strcat(values[i_ex_name], "\""); } strcat(values[i_trade_id], "}"); strcat(values[i_trade_dts], "}"); strcat(values[i_status_name], "}"); strcat(values[i_type_name], "}"); strcat(values[i_symbol], "}"); strcat(values[i_trade_qty], "}"); strcat(values[i_exec_name], "}"); strcat(values[i_charge], "}"); strcat(values[i_s_name], "}"); strcat(values[i_ex_name], "}"); #ifdef DEBUG sprintf(sql, SQLTSF1_2, acct_id); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_execute_plan(TSF1_2, args, nulls, true, 0); if (ret == SPI_OK_SELECT) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; if (SPI_processed > 0) { tuple = tuptable->vals[0]; values[i_cust_l_name] = SPI_getvalue(tuple, tupdesc, 1); values[i_cust_f_name] = SPI_getvalue(tuple, tupdesc, 2); values[i_broker_name] = SPI_getvalue(tuple, tupdesc, 3); } } else { FAIL_FRAME_SET(&funcctx->max_calls, TSF1_statements[1].sql); dump_tsf1_inputs(acct_id); } /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); } /* * generate attribute metadata needed later to produce tuples from raw * C strings */ attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; MemoryContextSwitchTo(TSF1_savedcxt); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; attinmeta = funcctx->attinmeta; if (call_cntr < max_calls) { /* do when there is more left to send */ HeapTuple tuple; Datum result; #ifdef DEBUG for (i = 0; i < 14; i++) { elog(NOTICE, "TSF1 OUT: %d %s", i, values[i]); } #endif /* DEBUG */ /* Build a tuple. */ tuple = BuildTupleFromCStrings(attinmeta, values); /* Make the tuple into a datum. */ result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else { /* Do when there is no more left. */ SPI_finish(); if (TSF1_savedcxt) MemoryContextSwitchTo(TSF1_savedcxt); SRF_RETURN_DONE(funcctx); } }
static PyObj statement_first(PyObj self, PyObj args, PyObj kw) { MemoryContext former = CurrentMemoryContext; PyObj c, rob = NULL; if (resolve_parameters(self, &args, &kw)) return(NULL); if (DB_IS_NOT_READY()) return(NULL); if (PyPgStatement_ReturnsRows(self)) { c = PyPgCursor_New(self, args, kw, CUR_ROWS(1)); if (c != NULL) { PyObj r; r = PyIter_Next(c); if (!PyErr_Occurred() && r == NULL) { r = Py_None; Py_INCREF(r); } if (PyPgCursor_Close(c)) { Py_DECREF(c); Py_XDECREF(r); return(NULL); } if (r != NULL) { if (r == Py_None) rob = r; else { Py_ssize_t s = PySequence_Size(r); if (s == -1) rob = NULL; else if (s == 1) { rob = PySequence_GetItem(r, 0); Py_DECREF(r); } else { /* * It has multiple columns, so return the first row. */ rob = r; } } } Py_DECREF(c); } } else { SPIPlanPtr plan; PyObj tdo = PyPgStatement_GetInput(self); TupleDesc td = PyPgTupleDesc_GetTupleDesc(tdo); PyObj pargs; plan = PyPgStatement_GetPlan(self); if (plan == NULL) return(NULL); pargs = Py_NormalizeRow( PyPgTupleDesc_GetNatts(tdo), td, PyPgTupleDesc_GetNameMap(tdo), args ); if (pargs == NULL) return(NULL); PG_TRY(); { int r; Datum *datums; bool *nulls; char *cnulls; int *freemap = PyPgTupleDesc_GetFreeMap(tdo); datums = palloc(sizeof(Datum) * td->natts); nulls = palloc(sizeof(bool) * td->natts); cnulls = palloc(sizeof(char) * td->natts); Py_BuildDatumsAndNulls( td, PyPgTupleDesc_GetTypesTuple(tdo), pargs, datums, nulls ); for (r = 0; r < td->natts; ++r) { cnulls[r] = nulls[r] ? 'n' : ' '; } r = SPI_execute_plan(plan, datums, cnulls, PL_FN_READONLY(), 1); if (r < 0) raise_spi_error(r); rob = PyLong_FromUnsignedLong(SPI_processed); FreeDatumsAndNulls(freemap, datums, nulls); pfree(cnulls); } PG_CATCH(); { PyErr_SetPgError(false); Py_XDECREF(rob); rob = NULL; } PG_END_TRY(); Py_DECREF(pargs); } MemoryContextSwitchTo(former); return(rob); }
/* Clause 3.3.9.4 */ Datum TradeUpdateFrame2(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; AttInMetadata *attinmeta; int call_cntr; int max_calls; int i; int j; char **values = NULL; /* Stuff done only on the first call of the function. */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; enum tuf2 { i_bid_price=0, i_cash_transaction_amount, i_cash_transaction_dts, i_cash_transaction_name, i_exec_name, i_is_cash, i_num_found, i_num_updated, i_settlement_amount, i_settlement_cash_due_date, i_settlement_cash_type, i_trade_history_dts, i_trade_history_status_id, i_trade_list, i_trade_price }; long acct_id = PG_GETARG_INT64(0); Timestamp end_trade_dts_ts = PG_GETARG_TIMESTAMP(1); int max_trades = PG_GETARG_INT32(2); int max_updates = PG_GETARG_INT32(3); Timestamp start_trade_dts_ts = PG_GETARG_TIMESTAMP(4); int ret; TupleDesc tupdesc; SPITupleTable *tuptable = NULL; HeapTuple tuple = NULL; struct pg_tm tt, *tm = &tt; fsec_t fsec; char *tzn = NULL; #ifdef DEBUG char sql[2048]; #endif Datum args[4]; char nulls[4] = { ' ', ' ', ' ', ' ' }; char end_trade_dts[MAXDATELEN + 1]; char start_trade_dts[MAXDATELEN + 1]; int num_found; int num_updated = 0; int num_cash = 0; if (timestamp2tm(end_trade_dts_ts, NULL, tm, &fsec, NULL, NULL) == 0) { EncodeDateTimeM(tm, fsec, tzn, end_trade_dts); } if (timestamp2tm(start_trade_dts_ts, NULL, tm, &fsec, NULL, NULL) == 0) { EncodeDateTimeM(tm, fsec, tzn, start_trade_dts); } #ifdef DEBUG dump_tuf2_inputs(acct_id, end_trade_dts, max_trades, max_updates, start_trade_dts); #endif /* * Prepare a values array for building the returned tuple. * This should be an array of C strings, which will * be processed later by the type input functions. * Don't forget to factor in commas (,) and braces ({}) for the arrays. */ values = (char **) palloc(sizeof(char *) * 15); values[i_bid_price] = (char *) palloc(((S_PRICE_T_LEN + 1) * 20 + 2) * sizeof(char)); values[i_cash_transaction_amount] = (char *) palloc(((VALUE_T_LEN + 1) * 20 + 2) * sizeof(char)); values[i_cash_transaction_dts] = (char *) palloc(((MAXDATELEN + 1) * 20 + 2) * sizeof(char)); values[i_cash_transaction_name] = (char *) palloc(((CT_NAME_LEN + 3) * 20 + 2) * sizeof(char)); values[i_exec_name] = (char *) palloc(((T_EXEC_NAME_LEN + 3) * 20 + 2) * sizeof(char)); values[i_is_cash] = (char *) palloc(((SMALLINT_LEN + 1) * 20 + 2) * sizeof(char)); values[i_num_found] = (char *) palloc((INTEGER_LEN + 1) * sizeof(char)); values[i_num_updated] = (char *) palloc((INTEGER_LEN + 1) * sizeof(char)); values[i_settlement_amount] = (char *) palloc(((VALUE_T_LEN + 1) * 20 + 2) * sizeof(char)); values[i_settlement_cash_due_date] = (char *) palloc(((MAXDATELEN + 1) * 20 + 2) * sizeof(char)); values[i_settlement_cash_type] = (char *) palloc(((SE_CASH_TYPE_LEN + 3) * 20 + 2) * sizeof(char)); values[i_trade_history_dts] = (char *) palloc((((MAXDATELEN + 2) * 3 + 2) * 20 + 5) * sizeof(char)); values[i_trade_history_status_id] = (char *) palloc((((ST_ID_LEN + 2) * 3 + 2) * 20 + 5) * sizeof(char)); values[i_trade_list] = (char *) palloc(((BIGINT_LEN + 1) * 20 + 2) * sizeof(char)); values[i_trade_price] = (char *) palloc(((S_PRICE_T_LEN + 1) * 20 + 2) * sizeof(char)); /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); funcctx->max_calls = 1; /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); SPI_connect(); plan_queries(TUF2_statements); #ifdef DEBUG sprintf(sql, SQLTUF2_1, acct_id, start_trade_dts, end_trade_dts, max_trades); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = Int64GetDatum(acct_id); args[1] = TimestampGetDatum(start_trade_dts_ts); args[2] = TimestampGetDatum(end_trade_dts_ts); args[3] = Int32GetDatum(max_trades); ret = SPI_execute_plan(TUF2_1, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; } num_found = SPI_processed; strcpy(values[i_bid_price], "{"); strcpy(values[i_exec_name], "{"); strcpy(values[i_is_cash], "{"); strcpy(values[i_trade_list], "{"); strcpy(values[i_trade_price], "{"); strcpy(values[i_settlement_amount], "{"); strcpy(values[i_settlement_cash_due_date], "{"); strcpy(values[i_settlement_cash_type], "{"); strcpy(values[i_cash_transaction_amount], "{"); strcpy(values[i_cash_transaction_dts], "{"); strcpy(values[i_cash_transaction_name], "{"); strcpy(values[i_trade_history_dts], "{"); strcpy(values[i_trade_history_status_id], "{"); for (i = 0; i < num_found; i++) { TupleDesc l_tupdesc; SPITupleTable *l_tuptable = NULL; HeapTuple l_tuple = NULL; char *is_cash_str; char *trade_list; char cash_type[41]; tuple = tuptable->vals[i]; if (i > 0) { strcat(values[i_bid_price], ","); strcat(values[i_exec_name], ","); strcat(values[i_is_cash], ","); strcat(values[i_trade_list], ","); strcat(values[i_trade_price], ","); strcat(values[i_settlement_amount], ","); strcat(values[i_settlement_cash_due_date], ","); strcat(values[i_settlement_cash_type], ","); strcat(values[i_trade_history_dts], ","); strcat(values[i_trade_history_status_id], ","); } strcat(values[i_bid_price], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_exec_name], "\""); strcat(values[i_exec_name], SPI_getvalue(tuple, tupdesc, 2)); strcat(values[i_exec_name], "\""); is_cash_str = SPI_getvalue(tuple, tupdesc, 3); strcat(values[i_is_cash], (is_cash_str[0] == 't' ? "0" : "1")); trade_list = SPI_getvalue(tuple, tupdesc, 4); strcat(values[i_trade_list], trade_list); strcat(values[i_trade_price], SPI_getvalue(tuple, tupdesc, 5)); if (num_updated < max_updates) { char *old_cash_type; #ifdef DEBUG sprintf(sql, SQLTUF2_2, trade_list); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = Int64GetDatum(atoll(trade_list)); ret = SPI_execute_plan(TUF2_2, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { l_tupdesc = SPI_tuptable->tupdesc; l_tuptable = SPI_tuptable; l_tuple = l_tuptable->vals[0]; old_cash_type = SPI_getvalue(l_tuple, l_tupdesc, 1); } else { FAIL_FRAME_SET(&funcctx->max_calls, TUF2_statements[1].sql); dump_tuf2_inputs(acct_id, end_trade_dts, max_trades, max_updates, start_trade_dts); continue; } #ifdef DEBUG elog(NOTICE, "cash_type = '%s'", old_cash_type); #endif /* DEBUG */ if (is_cash_str[0] == 't') { if (strcmp(old_cash_type, "Cash Account") == 0) { strcpy(cash_type, "Cash"); } else { strcpy(cash_type, "Cash Account"); } } else { if (strcmp(old_cash_type, "Margin Account") == 0) { strcpy(cash_type, "Margin"); } else { strcpy(cash_type, "Margin Account"); } } #ifdef DEBUG sprintf(sql, SQLTUF2_3, cash_type, trade_list); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = CStringGetTextDatum(cash_type); args[1] = Int64GetDatum(atoll(trade_list)); ret = SPI_execute_plan(TUF2_3, args, nulls, false, 0); if (ret != SPI_OK_UPDATE) { FAIL_FRAME_SET(&funcctx->max_calls, TUF2_statements[2].sql); dump_tuf2_inputs(acct_id, end_trade_dts, max_trades, max_updates, start_trade_dts); continue; } num_updated += SPI_processed; } #ifdef DEBUG sprintf(sql, SQLTUF2_4, trade_list); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = Int64GetDatum(atoll(trade_list)); ret = SPI_execute_plan(TUF2_4, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { l_tupdesc = SPI_tuptable->tupdesc; l_tuptable = SPI_tuptable; l_tuple = l_tuptable->vals[0]; strcat(values[i_settlement_amount], SPI_getvalue(l_tuple, l_tupdesc, 1)); strcat(values[i_settlement_cash_due_date], SPI_getvalue(l_tuple, l_tupdesc, 2)); strcat(values[i_settlement_cash_type], "\""); strcat(values[i_settlement_cash_type], SPI_getvalue(l_tuple, l_tupdesc, 3)); strcat(values[i_settlement_cash_type], "\""); } else { FAIL_FRAME_SET(&funcctx->max_calls, TUF2_statements[3].sql); dump_tuf2_inputs(acct_id, end_trade_dts, max_trades, max_updates, start_trade_dts); continue; } if (is_cash_str[0] == 't') { #ifdef DEBUG sprintf(sql, SQLTUF2_5, trade_list); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_execute_plan(TUF2_5, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { l_tupdesc = SPI_tuptable->tupdesc; l_tuptable = SPI_tuptable; l_tuple = l_tuptable->vals[0]; if (num_cash > 0) { strcat(values[i_cash_transaction_amount], ","); strcat(values[i_cash_transaction_dts], ","); strcat(values[i_cash_transaction_name], ","); } strcat(values[i_cash_transaction_amount], SPI_getvalue(l_tuple, l_tupdesc, 1)); strcat(values[i_cash_transaction_dts], SPI_getvalue(l_tuple, l_tupdesc, 2)); strcat(values[i_cash_transaction_name], "\""); strcat(values[i_cash_transaction_name], SPI_getvalue(l_tuple, l_tupdesc, 3)); strcat(values[i_cash_transaction_name], "\""); ++num_cash; } else { FAIL_FRAME_SET(&funcctx->max_calls, TUF2_statements[4].sql); dump_tuf2_inputs(acct_id, end_trade_dts, max_trades, max_updates, start_trade_dts); continue; } } else { if (num_cash > 0) { strcat(values[i_cash_transaction_amount], ","); strcat(values[i_cash_transaction_dts], ","); strcat(values[i_cash_transaction_name], ","); } strcat(values[i_cash_transaction_amount], "0"); strcat(values[i_cash_transaction_dts], "1970-1-1 0:0:0"); strcat(values[i_cash_transaction_name], "\"\""); ++num_cash; } #ifdef DEBUG sprintf(sql, SQLTUF2_6, trade_list); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_execute_plan(TUF2_6, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { l_tupdesc = SPI_tuptable->tupdesc; l_tuptable = SPI_tuptable; } else { FAIL_FRAME_SET(&funcctx->max_calls, TUF2_statements[5].sql); dump_tuf2_inputs(acct_id, end_trade_dts, max_trades, max_updates, start_trade_dts); continue; } strcat(values[i_trade_history_dts], "{"); strcat(values[i_trade_history_status_id], "{"); for (j = 0; j < SPI_processed; j ++) { if (j > 0) { strcat(values[i_trade_history_dts], ","); strcat(values[i_trade_history_status_id], ","); } l_tuple = l_tuptable->vals[j]; strcat(values[i_trade_history_dts], SPI_getvalue(l_tuple, l_tupdesc, 1)); strcat(values[i_trade_history_status_id], "\""); strcat(values[i_trade_history_status_id], SPI_getvalue(l_tuple, l_tupdesc, 2)); strcat(values[i_trade_history_status_id], "\""); } for (j = SPI_processed; j < 3; j++) { if (j > 0) { strcat(values[i_trade_history_dts], ","); strcat(values[i_trade_history_status_id], ","); } strcat(values[i_trade_history_dts], "NULL"); strcat(values[i_trade_history_status_id], "\"\""); } strcat(values[i_trade_history_dts], "}"); strcat(values[i_trade_history_status_id], "}"); } strcat(values[i_bid_price], "}"); strcat(values[i_exec_name], "}"); strcat(values[i_is_cash], "}"); strcat(values[i_trade_list], "}"); strcat(values[i_trade_price], "}"); strcat(values[i_settlement_amount], "}"); strcat(values[i_settlement_cash_due_date], "}"); strcat(values[i_settlement_cash_type], "}"); strcat(values[i_cash_transaction_amount], "}"); strcat(values[i_cash_transaction_dts], "}"); strcat(values[i_cash_transaction_name], "}"); strcat(values[i_trade_history_dts], "}"); strcat(values[i_trade_history_status_id], "}"); sprintf(values[i_num_found], "%d", num_found); sprintf(values[i_num_updated], "%d", num_updated); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); } /* * generate attribute metadata needed later to produce tuples from raw * C strings */ attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; attinmeta = funcctx->attinmeta; if (call_cntr < max_calls) { /* do when there is more left to send */ HeapTuple tuple; Datum result; #ifdef DEBUG for (i = 0; i < 15; i++) { elog(NOTICE, "TUF2 OUT: %d %s", i, values[i]); } #endif /* DEBUG */ /* Build a tuple. */ tuple = BuildTupleFromCStrings(attinmeta, values); /* Make the tuple into a datum. */ result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else { /* Do when there is no more left. */ SPI_finish(); SRF_RETURN_DONE(funcctx); } }
Datum stock_level(PG_FUNCTION_ARGS) { /* Input variables. */ int32 w_id = PG_GETARG_INT32(0); int32 d_id = PG_GETARG_INT32(1); int32 threshold = PG_GETARG_INT32(2); TupleDesc tupdesc; SPITupleTable *tuptable; HeapTuple tuple; int d_next_o_id = 0; int low_stock = 0; int ret; char *buf; Datum args[5]; char nulls[5] = { ' ', ' ', ' ', ' ', ' ' }; SPI_connect(); plan_queries(statements); args[0] = Int32GetDatum(w_id); args[1] = Int32GetDatum(d_id); ret = SPI_execute_plan(STOCK_LEVEL_1, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[0]; buf = SPI_getvalue(tuple, tupdesc, 1); elog(DEBUG1, "d_next_o_id = %s", buf); d_next_o_id = atoi(buf); } else { SPI_finish(); PG_RETURN_INT32(-1); } args[0] = Int32GetDatum(w_id); args[1] = Int32GetDatum(d_id); args[2] = Int32GetDatum(threshold); args[3] = Int32GetDatum(d_next_o_id - 20); args[4] = Int32GetDatum(d_next_o_id - 1); ret = SPI_execute_plan(STOCK_LEVEL_2, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[0]; buf = SPI_getvalue(tuple, tupdesc, 1); elog(DEBUG1, "low_stock = %s", buf); low_stock = atoi(buf); } else { SPI_finish(); PG_RETURN_INT32(-1); } SPI_finish(); PG_RETURN_INT32(low_stock); }
/* Clause 3.3.1.3 */ Datum MarketFeedFrame1(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; AttInMetadata *attinmeta; int call_cntr; int max_calls; int i, j, n; int num_updated = 0; int rows_sent; int send_len = 0; int count = 0; int nitems_pq; int *p_tq; char *p_s; char **values = NULL; /* Stuff done only on the first call of the function. */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; ArrayType *price_quote_p = PG_GETARG_ARRAYTYPE_P(0); char *status_submitted_p = (char *) PG_GETARG_TEXT_P(1); ArrayType *symbol_p = PG_GETARG_ARRAYTYPE_P(2); ArrayType *trade_qty = PG_GETARG_ARRAYTYPE_P(3); char *type_limit_buy_p = (char *) PG_GETARG_TEXT_P(4); char *type_limit_sell_p = (char *) PG_GETARG_TEXT_P(5); char *type_stop_loss_p = (char *) PG_GETARG_TEXT_P(6); enum mff1 { i_num_updated=0, i_send_len, i_symbol, i_trade_id, i_price_quote, i_trade_qty, i_trade_type }; Datum *transdatums_pq; int16 typlen_s; bool typbyval_s; char typalign_s; int16 typlen_tq; bool typbyval_tq; char typalign_tq; int ret; TupleDesc tupdesc; SPITupleTable *tuptable = NULL; HeapTuple tuple = NULL; #ifdef DEBUG char sql[2048]; #endif Datum args[7]; char nulls[] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ' }; char price_quote[S_PRICE_T_LEN + 1]; char status_submitted[ST_ID_LEN + 1]; char symbol[S_SYMB_LEN + 1]; char type_limit_buy[TT_ID_LEN + 1]; char type_limit_sell[TT_ID_LEN + 1]; char type_stop_loss[TT_ID_LEN + 1]; char *trade_id; char *req_price_quote; char *req_trade_type; char *req_trade_qty; /* * Prepare a values array for building the returned tuple. * This should be an array of C strings, which will * be processed later by the type input functions. */ values = (char **) palloc(sizeof(char *) * 7); values[i_num_updated] = (char *) palloc((INTEGER_LEN + 1) * sizeof(char)); values[i_send_len] = (char *) palloc((INTEGER_LEN + 1) * sizeof(char)); /* * FIXME: We don't know how many rows could be returned. The average * is supposed to be 4. Let's be prepared for 100, just to be safe. */ values[i_symbol] = (char *) palloc(((S_SYMB_LEN + 3) * 100 + 3) * sizeof(char)); values[i_trade_id] = (char *) palloc(((IDENT_T_LEN + 1) * 100 + 2) * sizeof(char)); values[i_price_quote] = (char *) palloc(((S_PRICE_T_LEN + 1) * 100 + 2) * sizeof(char)); values[i_trade_qty] = (char *) palloc(((INTEGER_LEN + 1) * 100 + 2) * sizeof(char)); values[i_trade_type] = (char *) palloc(((TT_ID_LEN + 3) * 100 + 3) * sizeof(char)); /* * This might be overkill since we always expect single dimensions * arrays. * Should probably check the count of all the arrays to make sure * they are the same... */ get_typlenbyvalalign(ARR_ELEMTYPE(symbol_p), &typlen_s, &typbyval_s, &typalign_s); p_s = ARR_DATA_PTR(symbol_p); get_typlenbyvalalign(ARR_ELEMTYPE(trade_qty), &typlen_tq, &typbyval_tq, &typalign_tq); p_tq = (int *) ARR_DATA_PTR(trade_qty); deconstruct_array(price_quote_p, NUMERICOID, -1, false, 'i', &transdatums_pq, NULL, &nitems_pq); strcpy(status_submitted, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(status_submitted_p)))); strcpy(type_limit_buy, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(type_limit_buy_p)))); strcpy(type_limit_sell, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(type_limit_sell_p)))); strcpy(type_stop_loss, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(type_stop_loss_p)))); #ifdef DEBUG dump_mff1_inputs(price_quote_p, status_submitted_p, symbol_p, trade_qty, type_limit_buy_p, type_limit_sell_p, type_stop_loss_p); #endif /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); SPI_connect(); plan_queries(MFF1_statements); strcpy(values[i_symbol], "{"); strcpy(values[i_trade_id], "{"); strcpy(values[i_price_quote], "{"); strcpy(values[i_trade_type], "{"); strcpy(values[i_trade_qty], "{"); for (i = 0; i < nitems_pq; i++) { rows_sent = 0; strcpy(price_quote, DatumGetCString(DirectFunctionCall1(numeric_out, transdatums_pq[i]))); strcpy(symbol, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(p_s)))); /* FIXME: BEGIN/COMMIT statements not supported with SPI. */ /* ret = SPI_exec("BEGIN;", 0); if (ret == SPI_OK_SELECT) { } else { elog(NOTICE, "ERROR: BEGIN not ok = %d", ret); } */ #ifdef DEBUG sprintf(sql, SQLMFF1_1, DatumGetCString(DirectFunctionCall1(numeric_out, transdatums_pq[i])), p_tq[i], symbol); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = Float8GetDatum(atof(price_quote)); args[1] = Int64GetDatum(p_tq[i]); args[2] = CStringGetTextDatum(symbol); ret = SPI_execute_plan(MFF1_1, args, nulls, false, 0); if (ret != SPI_OK_UPDATE) { dump_mff1_inputs(price_quote_p, status_submitted_p, symbol_p, trade_qty, type_limit_buy_p, type_limit_sell_p, type_stop_loss_p); FAIL_FRAME_SET(&funcctx->max_calls, MFF1_statements[0].sql); } num_updated += SPI_processed; #ifdef DEBUG elog(NOTICE, "%d row(s) updated", num_updated); sprintf(sql, SQLMFF1_2, symbol, type_stop_loss, price_quote, type_limit_sell, price_quote, type_limit_buy, price_quote); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = CStringGetTextDatum(symbol); args[1] = CStringGetTextDatum(type_stop_loss); args[2] = Float8GetDatum(atof(price_quote)); args[3] = CStringGetTextDatum(type_limit_sell); args[4] = args[2]; args[5] = CStringGetTextDatum(type_limit_buy); args[6] = args[2]; ret = SPI_execute_plan(MFF1_2, args, nulls, true, 0); if (ret != SPI_OK_SELECT) { dump_mff1_inputs(price_quote_p, status_submitted_p, symbol_p, trade_qty, type_limit_buy_p, type_limit_sell_p, type_stop_loss_p); FAIL_FRAME_SET(&funcctx->max_calls, MFF1_statements[1].sql); continue; } #ifdef DEBUG elog(NOTICE, "%d row(s) returned", SPI_processed); #endif /* DEBUG */ tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; n = SPI_processed; for (j = 0; j < n; j++) { tuple = tuptable->vals[j]; trade_id = SPI_getvalue(tuple, tupdesc, 1); req_price_quote = SPI_getvalue(tuple, tupdesc, 2); req_trade_type = SPI_getvalue(tuple, tupdesc, 3); req_trade_qty = SPI_getvalue(tuple, tupdesc, 4); #ifdef DEBUG elog(NOTICE, "trade_id = %s", trade_id); sprintf(sql, SQLMFF1_3, status_submitted, trade_id); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = CStringGetTextDatum(status_submitted); args[1] = Int64GetDatum(atoll(trade_id)); ret = SPI_execute_plan(MFF1_3, args, nulls, false, 0); if (ret != SPI_OK_UPDATE) { dump_mff1_inputs(price_quote_p, status_submitted_p, symbol_p, trade_qty, type_limit_buy_p, type_limit_sell_p, type_stop_loss_p); FAIL_FRAME_SET(&funcctx->max_calls, MFF1_statements[2].sql); } #ifdef DEBUG sprintf(sql, SQLMFF1_4, trade_id); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = Int64GetDatum(atoll(trade_id)); ret = SPI_execute_plan(MFF1_4, args, nulls, false, 0); if (ret != SPI_OK_DELETE) { dump_mff1_inputs(price_quote_p, status_submitted_p, symbol_p, trade_qty, type_limit_buy_p, type_limit_sell_p, type_stop_loss_p); FAIL_FRAME_SET(&funcctx->max_calls, MFF1_statements[3].sql); } #ifdef DEBUG sprintf(sql, SQLMFF1_5, trade_id, status_submitted); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[1] = CStringGetTextDatum(status_submitted); ret = SPI_execute_plan(MFF1_5, args, nulls, false, 0); if (ret != SPI_OK_INSERT) { dump_mff1_inputs(price_quote_p, status_submitted_p, symbol_p, trade_qty, type_limit_buy_p, type_limit_sell_p, type_stop_loss_p); FAIL_FRAME_SET(&funcctx->max_calls, MFF1_statements[4].sql); } ++rows_sent; #ifdef DEBUG elog(NOTICE, "%d row(s) sent", rows_sent); #endif /* DEBUG */ if (count > 0) { strcat(values[i_symbol], ","); strcat(values[i_trade_id], ","); strcat(values[i_price_quote], ","); strcat(values[i_trade_type], ","); strcat(values[i_trade_qty], ","); } strcat(values[i_symbol], symbol); strcat(values[i_trade_id], trade_id); strcat(values[i_price_quote], req_price_quote); strcat(values[i_trade_type], req_trade_type); strcat(values[i_trade_qty], req_trade_qty); ++count; } /* FIXME: BEGIN/COMMIT statements not supported with SPI. */ /* ret = SPI_exec("COMMIT;", 0); if (ret == SPI_OK_SELECT) { } else { elog(NOTICE, "ERROR: COMMIT not ok = %d", ret); } */ send_len += rows_sent; p_s = att_addlength_pointer(p_s, typlen_s, p_s); p_s = (char *) att_align_nominal(p_s, typalign_s); } strcat(values[i_symbol], "}"); strcat(values[i_trade_id], "}"); strcat(values[i_price_quote], "}"); strcat(values[i_trade_qty], "}"); strcat(values[i_trade_type], "}"); sprintf(values[i_num_updated], "%d", num_updated); sprintf(values[i_send_len], "%d", send_len); funcctx->max_calls = 1; /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); } /* * generate attribute metadata needed later to produce tuples from raw * C strings */ attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; attinmeta = funcctx->attinmeta; if (call_cntr < max_calls) { /* do when there is more left to send */ HeapTuple tuple; Datum result; #ifdef DEBUG for (i = 0; i < 7; i++) { elog(NOTICE, "MFF1 OUT: %d %s", i, values[i]); } #endif /* DEBUG */ /* Build a tuple. */ tuple = BuildTupleFromCStrings(attinmeta, values); /* Make the tuple into a datum. */ result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else { /* Do when there is no more left. */ SPI_finish(); SRF_RETURN_DONE(funcctx); } }
/* * Arguments: * 0: queue_name text NOT NULL * 1: ev_id int8 if NULL take from SEQ * 2: ev_time timestamptz if NULL use now() * 3: ev_owner int4 * 4: ev_retry int4 * 5: ev_type text * 6: ev_data text * 7: ev_extra1 text * 8: ev_extra2 text * 9: ev_extra3 text * 10:ev_extra4 text */ Datum pgq_insert_event_raw(PG_FUNCTION_ARGS) { Datum values[11]; char nulls[11]; struct QueueState state; int64 ret_id; void *ins_plan; Datum ev_id, ev_time; int i, res; if (PG_NARGS() < 6) elog(ERROR, "Need at least 6 arguments"); if (PG_ARGISNULL(0)) elog(ERROR, "Queue name must not be NULL"); if (SPI_connect() < 0) elog(ERROR, "SPI_connect() failed"); init_cache(); load_queue_info(PG_GETARG_DATUM(0), &state); if (PG_ARGISNULL(1)) ev_id = state.next_event_id; else ev_id = PG_GETARG_DATUM(1); if (PG_ARGISNULL(2)) ev_time = DirectFunctionCall1(now, 0); else ev_time = PG_GETARG_DATUM(2); /* * Prepare arguments for INSERT */ values[0] = ev_id; nulls[0] = ' '; values[1] = ev_time; nulls[1] = ' '; for (i = 3; i < 11; i++) { int dst = i - 1; if (i >= PG_NARGS() || PG_ARGISNULL(i)) { values[dst] = (Datum)NULL; nulls[dst] = 'n'; } else { values[dst] = PG_GETARG_DATUM(i); nulls[dst] = ' '; } } /* * Perform INSERT into queue table. */ ins_plan = load_insert_plan(&state); res = SPI_execute_plan(ins_plan, values, nulls, false, 0); if (res != SPI_OK_INSERT) elog(ERROR, "Queue insert failed"); /* * ev_id cannot pass SPI_finish() */ ret_id = DatumGetInt64(ev_id); if (SPI_finish() < 0) elog(ERROR, "SPI_finish failed"); PG_RETURN_INT64(ret_id); }
/* Obsolete version of SPI_execute_plan */ int SPI_execp(void *plan, Datum *Values, const char *Nulls, long tcount) { return SPI_execute_plan(plan, Values, Nulls, false, tcount); }
Datum exec_sql_using(PG_FUNCTION_ARGS) { HeapTuple procedureTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fcinfo->flinfo->fn_oid)); if (!HeapTupleIsValid(procedureTuple)) ereport(ERROR, (errmsg("cache lookup failed for function %u", fcinfo->flinfo->fn_oid))); Oid* types = NULL; char** names = NULL; char* modes = NULL; int nargs = get_func_arg_info(procedureTuple, &types, &names, &modes); Oid resultTypeOid; TupleDesc tupleDesc; TypeFuncClass resultType = get_call_result_type(fcinfo, &resultTypeOid, &tupleDesc); bool returnTypeIsByValue; int16 returnTypeLen; get_typlenbyval(resultTypeOid, &returnTypeLen, &returnTypeIsByValue); if (resultType != TYPEFUNC_SCALAR && resultType != TYPEFUNC_COMPOSITE) ereport(ERROR, ( errmsg("function \"%s\" has indeterminable result type", format_procedure(fcinfo->flinfo->fn_oid)) )); bool returnVoid = resultTypeOid == VOIDOID; ReleaseSysCache(procedureTuple); if (nargs < 2) ereport(ERROR, ( errmsg("function \"%s\" has less than 2 arguments", format_procedure(fcinfo->flinfo->fn_oid)) )); else if (modes != NULL) for (int i = 0; i < nargs; i++) { if (modes[i] != PROARGMODE_IN) ereport(ERROR, ( errmsg("function \"%s\" has non-IN arguments", format_procedure(fcinfo->flinfo->fn_oid)) )); } else if (PG_ARGISNULL(0)) ereport(ERROR, ( errmsg("function \"%s\" called with NULL as first argument", format_procedure(fcinfo->flinfo->fn_oid)) )); char* stmt = NULL; if (types[0] == TEXTOID) stmt = DatumGetCString( DirectFunctionCall1(textout, PG_GETARG_DATUM(0))); else if (types[0] == VARCHAROID) stmt = DatumGetCString( DirectFunctionCall1(varcharout, PG_GETARG_DATUM(0))); else ereport(ERROR, ( errmsg("function \"%s\" does not have a leading VARCHAR/TEXT " "argument", format_procedure(fcinfo->flinfo->fn_oid)) )); char* nulls = NULL; for (int i = 1; i < nargs; i++) if (PG_ARGISNULL(i)) { if (nulls == NULL) { nulls = palloc0(sizeof(char) * (nargs - 1)); memset(nulls, ' ', nargs - 1); } nulls[i - 1] = 'n'; } SPI_connect(); SPIPlanPtr plan = SPI_prepare(stmt, nargs - 1, &types[1]); if (plan == NULL) ereport(ERROR, ( errmsg("function \"%s\" could not obtain execution plan for " "SQL statement", format_procedure(fcinfo->flinfo->fn_oid)) )); int result = SPI_execute_plan(plan, &fcinfo->arg[1], nulls, false, returnVoid ? 0 : 1); Datum returnValue = 0; bool returnNull = false; if (!returnVoid) { if (result != SPI_OK_SELECT && result != SPI_OK_INSERT_RETURNING && result != SPI_OK_DELETE_RETURNING && result == SPI_OK_UPDATE_RETURNING) ereport(ERROR, ( errmsg("function \"%s\" could not obtain result from query", format_procedure(fcinfo->flinfo->fn_oid)) )); else if (SPI_tuptable->tupdesc->natts != 1) ereport(ERROR, ( errmsg("function \"%s\" retrieved more than one column from " "query", format_procedure(fcinfo->flinfo->fn_oid)) )); else if (resultTypeOid != SPI_gettypeid(SPI_tuptable->tupdesc, 1)) ereport(ERROR, ( errmsg("function \"%s\" has different return type OID than " "what query returned", format_procedure(fcinfo->flinfo->fn_oid)) )); /* It is important to copy the value into the upper executor context, * i.e., the memory context that was current when SPI_connect was * called */ returnValue = SPI_getbinval(SPI_copytuple(SPI_tuptable->vals[0]), SPI_tuptable->tupdesc, 1, &returnNull); } SPI_freeplan(plan); if (nulls) pfree(nulls); SPI_finish(); if (result < 0) ereport(ERROR, ( errmsg("function \"%s\" encountered error %d during SQL execution", format_procedure(fcinfo->flinfo->fn_oid), result) )); if (returnVoid) PG_RETURN_VOID(); else if (returnNull) PG_RETURN_NULL(); else return returnValue; }