/* * Free cached plan. */ void plproxy_query_freeplan(ProxyQuery *q) { if (!q || !q->plan) return; SPI_freeplan(q->plan); q->plan = NULL; }
static PyObject * PLy_cursor_query(const char *query) { PLyCursorObject *cursor; volatile MemoryContext oldcontext; volatile ResourceOwner oldowner; if ((cursor = PyObject_New(PLyCursorObject, &PLy_CursorType)) == NULL) return NULL; cursor->portalname = NULL; cursor->closed = false; cursor->mcxt = AllocSetContextCreate(TopMemoryContext, "PL/Python cursor context", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); PLy_typeinfo_init(&cursor->result, cursor->mcxt); oldcontext = CurrentMemoryContext; oldowner = CurrentResourceOwner; PLy_spi_subtransaction_begin(oldcontext, oldowner); PG_TRY(); { PLyExecutionContext *exec_ctx = PLy_current_execution_context(); SPIPlanPtr plan; Portal portal; pg_verifymbstr(query, strlen(query), false); plan = SPI_prepare(query, 0, NULL); if (plan == NULL) elog(ERROR, "SPI_prepare failed: %s", SPI_result_code_string(SPI_result)); portal = SPI_cursor_open(NULL, plan, NULL, NULL, exec_ctx->curr_proc->fn_readonly); SPI_freeplan(plan); if (portal == NULL) elog(ERROR, "SPI_cursor_open() failed: %s", SPI_result_code_string(SPI_result)); cursor->portalname = MemoryContextStrdup(cursor->mcxt, portal->name); PLy_spi_subtransaction_commit(oldcontext, oldowner); } PG_CATCH(); { PLy_spi_subtransaction_abort(oldcontext, oldowner); return NULL; } PG_END_TRY(); Assert(cursor->portalname != NULL); return (PyObject *) cursor; }
Oid name2id_cfg(text *name) { Oid arg[1]; bool isnull; Datum pars[1]; int stat; Oid id = findSNMap_t(&(CList.name2id_map), name); void *plan; char *nsp; char buf[1024]; arg[0] = TEXTOID; pars[0] = PointerGetDatum(name); if (id) return id; nsp = get_namespace(TSNSP_FunctionOid); SPI_connect(); sprintf(buf, "select oid from %s.pg_ts_cfg where ts_name = $1", nsp); plan = SPI_prepare(buf, 1, arg); if (!plan) /* internal error */ elog(ERROR, "SPI_prepare() failed"); stat = SPI_execp(plan, pars, " ", 1); if (stat < 0) /* internal error */ elog(ERROR, "SPI_execp return %d", stat); if (SPI_processed > 0) { id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull)); if (isnull) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("null id for tsearch config"))); } else ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("no tsearch config"))); SPI_freeplan(plan); SPI_finish(); addSNMap_t(&(CList.name2id_map), name, id); return id; }
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; }
void init_dict(Oid id, DictInfo * dict) { Oid arg[1]; bool isnull; Datum pars[1]; int stat; void *plan; char buf[1024]; char *nsp = get_namespace(TSNSP_FunctionOid); arg[0] = OIDOID; pars[0] = ObjectIdGetDatum(id); memset(dict, 0, sizeof(DictInfo)); SPI_connect(); sprintf(buf, "select dict_init, dict_initoption, dict_lexize from %s.pg_ts_dict where oid = $1", nsp); pfree(nsp); plan = SPI_prepare(buf, 1, arg); if (!plan) ts_error(ERROR, "SPI_prepare() failed"); stat = SPI_execp(plan, pars, " ", 1); if (stat < 0) ts_error(ERROR, "SPI_execp return %d", stat); if (SPI_processed > 0) { Datum opt; Oid oid = InvalidOid; oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull)); if (!(isnull || oid == InvalidOid)) { opt = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull); dict->dictionary = (void *) DatumGetPointer(OidFunctionCall1(oid, opt)); } oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 3, &isnull)); if (isnull || oid == InvalidOid) ts_error(ERROR, "Null dict_lexize for dictonary %d", id); fmgr_info_cxt(oid, &(dict->lexize_info), TopMemoryContext); dict->dict_id = id; } else ts_error(ERROR, "No dictionary with id %d", id); SPI_freeplan(plan); SPI_finish(); }
static void PLy_plan_dealloc(PyObject *arg) { PLyPlanObject *ob = (PLyPlanObject *) arg; if (ob->plan) { SPI_freeplan(ob->plan); ob->plan = NULL; } if (ob->mcxt) { MemoryContextDelete(ob->mcxt); ob->mcxt = NULL; } arg->ob_type->tp_free(arg); }
void init_prs(Oid id, WParserInfo * prs) { Oid arg[1]; bool isnull; Datum pars[1]; int stat; void *plan; char buf[1024], *nsp; arg[0] = OIDOID; pars[0] = ObjectIdGetDatum(id); memset(prs, 0, sizeof(WParserInfo)); SPI_connect(); nsp = get_namespace(TSNSP_FunctionOid); sprintf(buf, "select prs_start, prs_nexttoken, prs_end, prs_lextype, prs_headline from %s.pg_ts_parser where oid = $1", nsp); pfree(nsp); plan = SPI_prepare(buf, 1, arg); if (!plan) ts_error(ERROR, "SPI_prepare() failed"); stat = SPI_execp(plan, pars, " ", 1); if (stat < 0) ts_error(ERROR, "SPI_execp return %d", stat); if (SPI_processed > 0) { Oid oid = InvalidOid; oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull)); fmgr_info_cxt(oid, &(prs->start_info), TopMemoryContext); oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull)); fmgr_info_cxt(oid, &(prs->getlexeme_info), TopMemoryContext); oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 3, &isnull)); fmgr_info_cxt(oid, &(prs->end_info), TopMemoryContext); prs->lextype = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 4, &isnull)); oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 5, &isnull)); fmgr_info_cxt(oid, &(prs->headline_info), TopMemoryContext); prs->prs_id = id; } else ts_error(ERROR, "No parser with id %d", id); SPI_freeplan(plan); SPI_finish(); }
/* * fetch insert plan from cache. */ static void *load_insert_plan(struct QueueState *state) { struct InsertCacheEntry *entry; Oid queue_id = state->queue_id; bool did_exist = false; entry = hash_search(insert_cache, &queue_id, HASH_ENTER, &did_exist); if (did_exist) { if (state->cur_table == entry->cur_table) return entry->plan; SPI_freeplan(entry->plan); } entry->cur_table = state->cur_table; entry->plan = make_plan(state); return entry->plan; }
int get_currcfg(void) { Oid arg[1] = {TEXTOID}; const char *curlocale; Datum pars[1]; bool isnull; int stat; char buf[1024]; char *nsp; void *plan; if (current_cfg_id > 0) return current_cfg_id; nsp = get_namespace(TSNSP_FunctionOid); SPI_connect(); sprintf(buf, "select oid from %s.pg_ts_cfg where locale = $1 ", nsp); pfree(nsp); plan = SPI_prepare(buf, 1, arg); if (!plan) /* internal error */ elog(ERROR, "SPI_prepare() failed"); curlocale = setlocale(LC_CTYPE, NULL); pars[0] = PointerGetDatum(char2text((char *) curlocale)); stat = SPI_execp(plan, pars, " ", 1); if (stat < 0) /* internal error */ elog(ERROR, "SPI_execp return %d", stat); if (SPI_processed > 0) current_cfg_id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull)); else ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not find tsearch config by locale"))); pfree(DatumGetPointer(pars[0])); SPI_freeplan(plan); SPI_finish(); return current_cfg_id; }
Oid name2id_prs(text *name) { Oid arg[1]; bool isnull; Datum pars[1]; int stat; Oid id = findSNMap_t(&(PList.name2id_map), name); char buf[1024], *nsp; void *plan; arg[0] = TEXTOID; pars[0] = PointerGetDatum(name); if (id) return id; SPI_connect(); nsp = get_namespace(TSNSP_FunctionOid); sprintf(buf, "select oid from %s.pg_ts_parser where prs_name = $1", nsp); pfree(nsp); plan = SPI_prepare(buf, 1, arg); if (!plan) ts_error(ERROR, "SPI_prepare() failed"); stat = SPI_execp(plan, pars, " ", 1); if (stat < 0) ts_error(ERROR, "SPI_execp return %d", stat); if (SPI_processed > 0) id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull)); else ts_error(ERROR, "No parser '%s'", text2char(name)); SPI_freeplan(plan); SPI_finish(); addSNMap_t(&(PList.name2id_map), name, id); return id; }
/* * fetch insert plan from cache. */ static void *load_insert_plan(Datum qname, struct QueueState *state) { struct InsertCacheEntry *entry; Oid queue_id = state->queue_id; bool did_exist = false; entry = hash_search(insert_cache, &queue_id, HASH_ENTER, &did_exist); if (did_exist) { if (entry->plan && state->cur_table == entry->cur_table) goto valid_table; if (entry->plan) SPI_freeplan(entry->plan); } entry->cur_table = state->cur_table; entry->last_xid = 0; entry->plan = NULL; /* this can fail, struct must be valid before */ entry->plan = make_plan(state); valid_table: if (state->per_tx_limit >= 0) { TransactionId xid = GetTopTransactionId(); if (entry->last_xid != xid) { entry->last_xid = xid; entry->last_count = 0; } entry->last_count++; if (entry->last_count > state->per_tx_limit) elog(ERROR, "Queue '%s' allows max %d events from one TX", TextDatumGetCString(qname), state->per_tx_limit); } return entry->plan; }
Datum tsquery_rewrite_query(PG_FUNCTION_ARGS) { TSQuery query = PG_GETARG_TSQUERY_COPY(0); text *in = PG_GETARG_TEXT_P(1); TSQuery rewrited = query; MemoryContext outercontext = CurrentMemoryContext; MemoryContext oldcontext; QTNode *tree; char *buf; SPIPlanPtr plan; Portal portal; bool isnull; if (query->size == 0) { PG_FREE_IF_COPY(in, 1); PG_RETURN_POINTER(rewrited); } tree = QT2QTN(GETQUERY(query), GETOPERAND(query)); QTNTernary(tree); QTNSort(tree); buf = text_to_cstring(in); SPI_connect(); if ((plan = SPI_prepare(buf, 0, NULL)) == NULL) elog(ERROR, "SPI_prepare(\"%s\") failed", buf); if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, true)) == NULL) elog(ERROR, "SPI_cursor_open(\"%s\") failed", buf); SPI_cursor_fetch(portal, true, 100); if (SPI_tuptable == NULL || SPI_tuptable->tupdesc->natts != 2 || SPI_gettypeid(SPI_tuptable->tupdesc, 1) != TSQUERYOID || SPI_gettypeid(SPI_tuptable->tupdesc, 2) != TSQUERYOID) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("ts_rewrite query must return two tsquery columns"))); while (SPI_processed > 0 && tree) { uint64 i; for (i = 0; i < SPI_processed && tree; i++) { Datum qdata = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull); Datum sdata; if (isnull) continue; sdata = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &isnull); if (!isnull) { TSQuery qtex = DatumGetTSQuery(qdata); TSQuery qtsubs = DatumGetTSQuery(sdata); QTNode *qex, *qsubs = NULL; if (qtex->size == 0) { if (qtex != (TSQuery) DatumGetPointer(qdata)) pfree(qtex); if (qtsubs != (TSQuery) DatumGetPointer(sdata)) pfree(qtsubs); continue; } qex = QT2QTN(GETQUERY(qtex), GETOPERAND(qtex)); QTNTernary(qex); QTNSort(qex); if (qtsubs->size) qsubs = QT2QTN(GETQUERY(qtsubs), GETOPERAND(qtsubs)); oldcontext = MemoryContextSwitchTo(outercontext); tree = findsubquery(tree, qex, qsubs, NULL); MemoryContextSwitchTo(oldcontext); QTNFree(qex); if (qtex != (TSQuery) DatumGetPointer(qdata)) pfree(qtex); QTNFree(qsubs); if (qtsubs != (TSQuery) DatumGetPointer(sdata)) pfree(qtsubs); if (tree) { /* ready the tree for another pass */ QTNClearFlags(tree, QTN_NOCHANGE); QTNSort(tree); } } } SPI_freetuptable(SPI_tuptable); SPI_cursor_fetch(portal, true, 100); } SPI_freetuptable(SPI_tuptable); SPI_cursor_close(portal); SPI_freeplan(plan); SPI_finish(); if (tree) { QTNBinary(tree); rewrited = QTN2QT(tree); QTNFree(tree); PG_FREE_IF_COPY(query, 0); } else { SET_VARSIZE(rewrited, HDRSIZETQ); rewrited->size = 0; } pfree(buf); PG_FREE_IF_COPY(in, 1); PG_RETURN_POINTER(rewrited); }
/* ---------- * Generate a prepared plan - this is copy from pl_exec.c * ---------- */ static void exec_prepare_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr, int cursorOptions) { #if PG_VERSION_NUM >= 90000 SPIPlanPtr plan; /* * The grammar can't conveniently set expr->func while building the parse * tree, so make sure it's set before parser hooks need it. */ expr->func = estate->func; /* * Generate and save the plan */ plan = SPI_prepare_params(expr->query, (ParserSetupHook) plpgsql_parser_setup, (void *) expr, cursorOptions); if (plan == NULL) { /* Some SPI errors deserve specific error messages */ switch (SPI_result) { case SPI_ERROR_COPY: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot COPY to/from client in PL/pgSQL"))); case SPI_ERROR_TRANSACTION: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot begin/end transactions in PL/pgSQL"), errhint("Use a BEGIN block with an EXCEPTION clause instead."))); default: elog(ERROR, "SPI_prepare_params failed for \"%s\": %s", expr->query, SPI_result_code_string(SPI_result)); } } expr->plan = SPI_saveplan(plan); SPI_freeplan(plan); #else int i; SPIPlanPtr plan; Oid *argtypes; /* * We need a temporary argtypes array to load with data. (The finished * plan structure will contain a copy of it.) */ argtypes = (Oid *) palloc(expr->nparams * sizeof(Oid)); for (i = 0; i < expr->nparams; i++) { argtypes[i] = exec_get_datum_type(estate, estate->datums[expr->params[i]]); } /* * Generate and save the plan */ plan = SPI_prepare_cursor(expr->query, expr->nparams, argtypes, cursorOptions); if (plan == NULL) { /* Some SPI errors deserve specific error messages */ switch (SPI_result) { case SPI_ERROR_COPY: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot COPY to/from client in PL/pgSQL"))); case SPI_ERROR_TRANSACTION: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot begin/end transactions in PL/pgSQL"), errhint("Use a BEGIN block with an EXCEPTION clause instead."))); default: elog(ERROR, "SPI_prepare_cursor failed for \"%s\": %s", expr->query, SPI_result_code_string(SPI_result)); } } expr->plan = SPI_saveplan(plan); SPI_freeplan(plan); pfree(argtypes); #endif }
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; }
/* * plr_SPI_prepare - The builtin SPI_prepare command for the R interpreter */ SEXP plr_SPI_prepare(SEXP rsql, SEXP rargtypes) { const char *sql; int nargs; int i; Oid *typeids = NULL; Oid *typelems = NULL; FmgrInfo *typinfuncs = NULL; void *pplan = NULL; void *saved_plan; saved_plan_desc *plan_desc; SEXP result; MemoryContext oldcontext; PREPARE_PG_TRY; /* set up error context */ PUSH_PLERRCONTEXT(rsupport_error_callback, "pg.spi.prepare"); /* switch to long lived context to create plan description */ oldcontext = MemoryContextSwitchTo(TopMemoryContext); plan_desc = (saved_plan_desc *) palloc(sizeof(saved_plan_desc)); MemoryContextSwitchTo(oldcontext); PROTECT(rsql = AS_CHARACTER(rsql)); sql = CHAR(STRING_ELT(rsql, 0)); UNPROTECT(1); if (sql == NULL) error("%s", "cannot prepare empty query"); PROTECT(rargtypes = AS_INTEGER(rargtypes)); if (!isVector(rargtypes) || !isInteger(rargtypes)) error("%s", "second parameter must be a vector of PostgreSQL datatypes"); /* deal with case of no parameters for the prepared query */ if (rargtypes == R_MissingArg || INTEGER(rargtypes)[0] == NA_INTEGER) nargs = 0; else nargs = length(rargtypes); if (nargs < 0) /* can this even happen?? */ error("%s", "second parameter must be a vector of PostgreSQL datatypes"); if (nargs > 0) { /* switch to long lived context to create plan description elements */ oldcontext = MemoryContextSwitchTo(TopMemoryContext); typeids = (Oid *) palloc(nargs * sizeof(Oid)); typelems = (Oid *) palloc(nargs * sizeof(Oid)); typinfuncs = (FmgrInfo *) palloc(nargs * sizeof(FmgrInfo)); MemoryContextSwitchTo(oldcontext); for (i = 0; i < nargs; i++) { int16 typlen; bool typbyval; char typdelim; Oid typinput, typelem; char typalign; FmgrInfo typinfunc; typeids[i] = INTEGER(rargtypes)[i]; /* switch to long lived context to create plan description elements */ oldcontext = MemoryContextSwitchTo(TopMemoryContext); get_type_io_data(typeids[i], IOFunc_input, &typlen, &typbyval, &typalign, &typdelim, &typelem, &typinput); typelems[i] = typelem; MemoryContextSwitchTo(oldcontext); /* perm_fmgr_info already uses TopMemoryContext */ perm_fmgr_info(typinput, &typinfunc); typinfuncs[i] = typinfunc; } } else typeids = NULL; UNPROTECT(1); /* switch to SPI memory context */ oldcontext = MemoryContextSwitchTo(plr_SPI_context); /* * trap elog/ereport so we can let R finish up gracefully * and generate the error once we exit the interpreter */ PG_TRY(); { /* Prepare plan for query */ pplan = SPI_prepare(sql, nargs, typeids); } PLR_PG_CATCH(); PLR_PG_END_TRY(); if (pplan == NULL) { char buf[128]; char *reason; switch (SPI_result) { case SPI_ERROR_ARGUMENT: reason = "SPI_ERROR_ARGUMENT"; break; case SPI_ERROR_UNCONNECTED: reason = "SPI_ERROR_UNCONNECTED"; break; case SPI_ERROR_COPY: reason = "SPI_ERROR_COPY"; break; case SPI_ERROR_CURSOR: reason = "SPI_ERROR_CURSOR"; break; case SPI_ERROR_TRANSACTION: reason = "SPI_ERROR_TRANSACTION"; break; case SPI_ERROR_OPUNKNOWN: reason = "SPI_ERROR_OPUNKNOWN"; break; default: snprintf(buf, sizeof(buf), "unknown RC %d", SPI_result); reason = buf; break; } /* internal error */ error("SPI_prepare() failed: %s", reason); } /* SPI_saveplan already uses TopMemoryContext */ saved_plan = SPI_saveplan(pplan); if (saved_plan == NULL) { char buf[128]; char *reason; switch (SPI_result) { case SPI_ERROR_ARGUMENT: reason = "SPI_ERROR_ARGUMENT"; break; case SPI_ERROR_UNCONNECTED: reason = "SPI_ERROR_UNCONNECTED"; break; default: snprintf(buf, sizeof(buf), "unknown RC %d", SPI_result); reason = buf; break; } /* internal error */ error("SPI_saveplan() failed: %s", reason); } /* back to caller's memory context */ MemoryContextSwitchTo(oldcontext); /* no longer need this */ SPI_freeplan(pplan); plan_desc->saved_plan = saved_plan; plan_desc->nargs = nargs; plan_desc->typeids = typeids; plan_desc->typelems = typelems; plan_desc->typinfuncs = typinfuncs; result = R_MakeExternalPtr(plan_desc, R_NilValue, R_NilValue); POP_PLERRCONTEXT; return result; }
static void test_spi_exec_query(int *passed, int *total) { int rc; volatile int caseno = 0; SPIPlanPtr ptr = NULL; SPIPlanPtr org_ptr; /* Initialize */ rc = SPI_connect(); if (rc != SPI_OK_CONNECT) elog(ERROR, "could not connect SPI: %s", SPI_result_code_string(rc)); /* * *-*-1 * - plan is not cached */ caseno++; BeginInternalSubTransaction("test"); PG_TRY(); { spi_exec_query("SELECT 1", 0, NULL, &ptr, NULL, NULL, SPI_OK_SELECT); if (ptr != NULL && SPI_processed == 1) { elog(WARNING, "%s-%d ok", __FUNCTION__, caseno); (*passed)++; } ReleaseCurrentSubTransaction(); } PG_CATCH(); { elog(WARNING, "*-*-%d failed", caseno); RollbackAndReleaseCurrentSubTransaction(); SPI_restore_connection(); } PG_END_TRY(); /* * *-*-2 * - plan is cached */ caseno++; BeginInternalSubTransaction("test"); PG_TRY(); { org_ptr = ptr; spi_exec_query(NULL, 0, NULL, &ptr, NULL, NULL, SPI_OK_SELECT); if (ptr == org_ptr && SPI_processed == 1) { elog(WARNING, "%s-%d ok", __FUNCTION__, caseno); (*passed)++; } ReleaseCurrentSubTransaction(); } PG_CATCH(); { elog(WARNING, "*-*-%d failed", caseno); RollbackAndReleaseCurrentSubTransaction(); FlushErrorState(); SPI_restore_connection(); } PG_END_TRY(); SPI_freeplan(ptr); ptr = NULL; /* * *-*-3 * - query error */ caseno++; BeginInternalSubTransaction("test"); PG_TRY(); { spi_exec_query("SELECT 1 / 0", 0, NULL, &ptr, NULL, NULL, SPI_OK_SELECT); elog(WARNING, "*-*-%d failed", caseno); ReleaseCurrentSubTransaction(); } PG_CATCH(); { elog(WARNING, "%s-%d ok", __FUNCTION__, caseno); (*passed)++; RollbackAndReleaseCurrentSubTransaction(); FlushErrorState(); SPI_restore_connection(); } PG_END_TRY(); SPI_freeplan(ptr); ptr = NULL; /* * *-*-4 * - query success */ caseno++; BeginInternalSubTransaction("test"); PG_TRY(); { spi_exec_query("SELECT 1", 0, NULL, &ptr, NULL, NULL, SPI_OK_SELECT); if (ptr != NULL && SPI_processed == 1) { elog(WARNING, "%s-%d ok", __FUNCTION__, caseno); (*passed)++; } ReleaseCurrentSubTransaction(); } PG_CATCH(); { elog(WARNING, "*-*-%d failed", caseno); PG_RE_THROW(); RollbackAndReleaseCurrentSubTransaction(); SPI_restore_connection(); } PG_END_TRY(); SPI_freeplan(ptr); ptr = NULL; /* report # of tests */ (*total) += caseno; /* Cleanup */ rc = SPI_finish(); if (rc != SPI_OK_FINISH && rc != SPI_ERROR_UNCONNECTED) elog(ERROR, "could not finish SPI: %s", SPI_result_code_string(rc)); }
/* * dbms_stats_import * Import exported statistics from stdin or a file. * * Order of arguments: * 1) schema name * 2) relation oid * 3) attribute name * 4) absolute path of source file, or 'stdin' (case insensitive) */ Datum dbms_stats_import(PG_FUNCTION_ARGS) { char *nspname; char *relname; char *attname; char *filename; /* filename, or NULL for STDIN */ int ret; int i; uint32 r_num; HeapTuple *r_tups; TupleDesc r_tupdesc; SPIPlanPtr r_upd_plan = NULL; SPIPlanPtr r_ins_plan = NULL; SPIPlanPtr c_sel_plan = NULL; SPIPlanPtr c_del_plan = NULL; SPIPlanPtr c_ins_plan = NULL; /* get validated arguments */ get_args(fcinfo, &nspname, &relname, &attname, &filename); /* for debug use */ elog(DEBUG3, "%s() f=%s n=%s r=%s a=%s", __FUNCTION__, filename ? filename : "(null)", nspname ? nspname : "(null)", relname ? relname : "(null)", attname ? attname : "(null)"); /* connect to SPI */ ret = SPI_connect(); if (ret != SPI_OK_CONNECT) elog(ERROR, "pg_dbms_stats: SPI_connect => %d", ret); /* lock dummy statistics tables. */ spi_exec_utility("LOCK dbms_stats.relation_stats_locked" " IN SHARE UPDATE EXCLUSIVE MODE"); spi_exec_utility("LOCK dbms_stats.column_stats_locked" " IN SHARE UPDATE EXCLUSIVE MODE"); /* * Create a temp table to save the statistics to import. * This table should fit with the content of export files. */ spi_exec_utility("CREATE TEMP TABLE dbms_stats_work_stats (" "nspname name NOT NULL," "relname name NOT NULL," "relpages int4 NOT NULL," "reltuples float4 NOT NULL," #if PG_VERSION_NUM >= 90200 "relallvisible int4 NOT NULL," #endif "curpages int4 NOT NULL," "last_analyze timestamp with time zone," "last_autoanalyze timestamp with time zone," "attname name," "nspname_of_typename name," "typname name," "atttypmod int4," "stainherit bool," "stanullfrac float4," "stawidth int4," "stadistinct float4," "stakind1 int2," "stakind2 int2," "stakind3 int2," "stakind4 int2," #if PG_VERSION_NUM >= 90200 "stakind5 int2," #endif "staop1 oid," "staop2 oid," "staop3 oid," "staop4 oid," #if PG_VERSION_NUM >= 90200 "staop5 oid," #endif "stanumbers1 float4[]," "stanumbers2 float4[]," "stanumbers3 float4[]," "stanumbers4 float4[]," #if PG_VERSION_NUM >= 90200 "stanumbers5 float4[]," #endif "stavalues1 dbms_stats.anyarray," "stavalues2 dbms_stats.anyarray," "stavalues3 dbms_stats.anyarray," "stavalues4 dbms_stats.anyarray" #if PG_VERSION_NUM >= 90200 ",stavalues5 dbms_stats.anyarray" #endif ")"); /* load the statistics from export file to the temp table */ import_stats_from_file(filename, nspname, relname, attname); /* Determine the Oid of local table from the tablename and schemaname. */ ret = SPI_execute("SELECT DISTINCT w.nspname, w.relname, c.oid, " "w.relpages, w.reltuples, " "w.curpages, w.last_analyze, w.last_autoanalyze " #if PG_VERSION_NUM >= 90200 ",w.relallvisible " #endif "FROM pg_catalog.pg_class c " "JOIN pg_catalog.pg_namespace n " "ON (c.relnamespace = n.oid) " "RIGHT JOIN dbms_stats_work_stats w " "ON (w.relname = c.relname AND w.nspname = n.nspname) " "ORDER BY 1, 2", false, 0); if (ret != SPI_OK_SELECT) elog(ERROR, "pg_dbms_stats: SPI_execute => %d", ret); /* * If there is no record in the staging table after loading source and * deleting unnecessary records, we treat it as an error. */ if (SPI_processed == 0) elog(ERROR, "no per-table statistic data to be imported"); /* */ r_num = SPI_processed; r_tups = SPI_tuptable->vals; r_tupdesc = SPI_tuptable->tupdesc; for (i = 0; i < r_num; i++) { bool isnull; Datum w_nspname; Datum w_relname; Datum w_relid; Datum values[9]; char nulls[9] = {'t', 't', 't', 't', 't', 't', 't', 't', 't'}; Oid r_types[9] = {NAMEOID, NAMEOID, INT4OID, FLOAT4OID, INT4OID, TIMESTAMPTZOID, TIMESTAMPTZOID, OIDOID, INT4OID}; Oid c_types[5] = {OIDOID, INT2OID, NAMEOID, NAMEOID, NAMEOID}; uint32 c_num; TupleDesc c_tupdesc; HeapTuple *c_tups; int j; values[0] = w_nspname = SPI_getbinval(r_tups[i], r_tupdesc, 1, &isnull); values[1] = w_relname = SPI_getbinval(r_tups[i], r_tupdesc, 2, &isnull); values[7] = w_relid = SPI_getbinval(r_tups[i], r_tupdesc, 3, &isnull); if (isnull) { elog(WARNING, "relation \"%s.%s\" does not exist", DatumGetName(w_nspname)->data, DatumGetName(w_relname)->data); continue; } values[2] = SPI_getbinval(r_tups[i], r_tupdesc, 4, &isnull); values[3] = SPI_getbinval(r_tups[i], r_tupdesc, 5, &isnull); values[4] = SPI_getbinval(r_tups[i], r_tupdesc, 6, &isnull); values[5] = SPI_getbinval(r_tups[i], r_tupdesc, 7, &isnull); nulls[5] = isnull ? 'n' : 't'; values[6] = SPI_getbinval(r_tups[i], r_tupdesc, 8, &isnull); nulls[6] = isnull ? 'n' : 't'; values[8] = SPI_getbinval(r_tups[i], r_tupdesc, 9, &isnull); /* * First we try UPDATE with the oid. When no record matched, try * INSERT. We can't use DELETE-then-INSERT method because we have FK * on relation_stats_locked so DELETE would delete child records in * column_stats_locked undesirably. */ spi_exec_query("UPDATE dbms_stats.relation_stats_locked SET " "relname = quote_ident($1) || '.' || quote_ident($2), " "relpages = $3, reltuples = $4, " #if PG_VERSION_NUM >= 90200 "relallvisible = $9, " #endif "curpages = $5, last_analyze = $6, last_autoanalyze = $7 " "WHERE relid = $8", RELATION_PARAM_NUM, r_types, &r_upd_plan, values, nulls, SPI_OK_UPDATE); if (SPI_processed == 0) { spi_exec_query("INSERT INTO dbms_stats.relation_stats_locked " "(relname, relpages, reltuples, curpages, " "last_analyze, last_autoanalyze, relid" #if PG_VERSION_NUM >= 90200 ", relallvisible" #endif ") VALUES (quote_ident($1) || '.' || quote_ident($2), " "$3, $4, $5, $6, $7, $8" #if PG_VERSION_NUM >= 90200 ", $9" #endif ")", RELATION_PARAM_NUM, r_types, &r_ins_plan, values, nulls, SPI_OK_INSERT); /* If we failed to insert, we can't proceed. */ if (SPI_processed != 1) elog(ERROR, "failed to insert import data"); } elog(DEBUG2, "\"%s.%s\" relation statistic import", DatumGetName(w_nspname)->data, DatumGetName(w_relname)->data); /* * Determine the attnum of the attribute with given name, and load * statistics from temp table into dbms.column_stats_locked. */ spi_exec_query("SELECT w.stainherit, w.attname, a.attnum, " "w.nspname_of_typename, tn.nspname, " "w.typname, t.typname, w.atttypmod, a.atttypmod " "FROM pg_catalog.pg_class c " "JOIN pg_catalog.pg_namespace cn " "ON (cn.oid = c.relnamespace) " "JOIN pg_catalog.pg_attribute a " "ON (a.attrelid = c.oid) " "JOIN pg_catalog.pg_type t " "ON (t.oid = a.atttypid) " "JOIN pg_catalog.pg_namespace tn " "ON (tn.oid = t.typnamespace) " "RIGHT JOIN dbms_stats_work_stats w " "ON (w.nspname = cn.nspname AND w.relname = c.relname " "AND (w.attname = a.attname OR w.attname = '')) " "WHERE w.nspname = $1 AND w.relname = $2 " "AND a.attnum > 0" "ORDER BY 1, 3, 2", 2, r_types, &c_sel_plan, values, NULL, SPI_OK_SELECT); /* This query ought to return at least one record. */ if (SPI_processed == 0) elog(ERROR, "no per-column statistic data to be imported"); values[0] = w_relid; values[2] = w_nspname; values[3] = w_relname; c_num = SPI_processed; c_tups = SPI_tuptable->vals; c_tupdesc = SPI_tuptable->tupdesc; for (j = 0; j < c_num; j++) { char *w_typnamespace; char *a_typnamespace; char *w_typname; char *a_typname; int w_typmod; int a_typmod; /* * If we have only per-relation statistics in source, all of * column_stats_effective for per-column statistics are NULL. */ (void) SPI_getbinval(c_tups[j], c_tupdesc, 1, &isnull); if (isnull) continue; /* * If there is no column with given name, we skip the rest of * import process. */ values[4] = SPI_getbinval(c_tups[j], c_tupdesc, 2, &isnull); values[1] = SPI_getbinval(c_tups[j], c_tupdesc, 3, &isnull); if (isnull) { elog(WARNING, "column \"%s\" of \"%s.%s\" does not exist", DatumGetName(values[4])->data, DatumGetName(w_nspname)->data, DatumGetName(w_relname)->data); continue; } /* * If the destination column has different data type from source * column, we stop importing to avoid corrupted statistics. */ w_typnamespace = DatumGetName(SPI_getbinval(c_tups[j], c_tupdesc, 4, &isnull))->data; a_typnamespace = DatumGetName(SPI_getbinval(c_tups[j], c_tupdesc, 5, &isnull))->data; w_typname = DatumGetName(SPI_getbinval(c_tups[j], c_tupdesc, 6, &isnull))->data; a_typname = DatumGetName(SPI_getbinval(c_tups[j], c_tupdesc, 7, &isnull))->data; if (strcmp(w_typnamespace, a_typnamespace) != 0 || strcmp(w_typname, a_typname) != 0) { ereport(WARNING, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("column \"%s\" is of type \"%s.%s\"" " but import data is of type \"%s.%s\"", DatumGetName(values[4])->data, a_typnamespace, a_typname, w_typnamespace, w_typname))); continue; } /* * If the atttypmod of the destination column is different from the * one of source, column, we stop importing to avoid corrupted * statistics. */ w_typmod = DatumGetInt32(SPI_getbinval(c_tups[j], c_tupdesc, 8, &isnull)); a_typmod = DatumGetInt32(SPI_getbinval(c_tups[j], c_tupdesc, 9, &isnull)); if (w_typmod != a_typmod) { ereport(WARNING, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("column \"%s\" is of atttypmod %d" " but import data is of atttypmod %d", DatumGetName(values[4])->data, a_typmod, a_typmod))); continue; } /* * First delete old dummy statistics, and import new one. We use * DELETE-then-INSERT method here to simplify codes. */ spi_exec_query("DELETE FROM dbms_stats.column_stats_locked " "WHERE starelid = $1 AND staattnum = $2", 2, c_types, &c_del_plan, values, NULL, SPI_OK_DELETE); spi_exec_query("INSERT INTO dbms_stats.column_stats_locked " "SELECT $1, $2, " "stainherit, stanullfrac, stawidth, stadistinct, " "stakind1, stakind2, stakind3, stakind4, " #if PG_VERSION_NUM >= 90200 "stakind5, " #endif "staop1, staop2, staop3, staop4, " #if PG_VERSION_NUM >= 90200 "staop5, " #endif "stanumbers1, stanumbers2, stanumbers3, stanumbers4, " #if PG_VERSION_NUM >= 90200 "stanumbers5, " #endif "stavalues1, stavalues2, stavalues3, stavalues4 " #if PG_VERSION_NUM >= 90200 ", stavalues5 " #endif "FROM dbms_stats_work_stats " "WHERE nspname = $3 AND relname = $4 " "AND attname = $5 " "ORDER BY 3", 5, c_types, &c_ins_plan, values, NULL, SPI_OK_INSERT); elog(DEBUG2, "\"%s.%s.%s\" column statistic import", DatumGetName(w_nspname)->data, DatumGetName(w_relname)->data, DatumGetName(values[4])->data); } if (c_num == 0) elog(DEBUG2, "\"%s.%s\" column statistic no data", DatumGetName(w_nspname)->data, DatumGetName(w_relname)->data); } /* release the cached plan */ SPI_freeplan(r_upd_plan); SPI_freeplan(r_ins_plan); SPI_freeplan(c_sel_plan); SPI_freeplan(c_del_plan); SPI_freeplan(c_ins_plan); /* delete the temp table */ spi_exec_utility("DROP TABLE dbms_stats_work_stats"); /* disconnect SPI */ ret = SPI_finish(); if (ret != SPI_OK_FINISH) elog(ERROR, "pg_dbms_stats: SPI_finish => %d", ret); /* * Recover the protocol state because it has been invalidated by our * COPY-from-stdin. */ if (filename == NULL) pq_puttextmessage('C', "dbms_stats_import"); PG_RETURN_VOID(); }
void init_cfg(Oid id, TSCfgInfo * cfg) { Oid arg[2]; bool isnull; Datum pars[2]; int stat, i, j; text *ptr; text *prsname = NULL; char *nsp = get_namespace(TSNSP_FunctionOid); char buf[1024]; MemoryContext oldcontext; void *plan; arg[0] = OIDOID; arg[1] = OIDOID; pars[0] = ObjectIdGetDatum(id); pars[1] = ObjectIdGetDatum(id); memset(cfg, 0, sizeof(TSCfgInfo)); SPI_connect(); sprintf(buf, "select prs_name from %s.pg_ts_cfg where oid = $1", nsp); plan = SPI_prepare(buf, 1, arg); if (!plan) ts_error(ERROR, "SPI_prepare() failed"); stat = SPI_execp(plan, pars, " ", 1); if (stat < 0) ts_error(ERROR, "SPI_execp return %d", stat); if (SPI_processed > 0) { prsname = (text *) DatumGetPointer( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull) ); oldcontext = MemoryContextSwitchTo(TopMemoryContext); prsname = ptextdup(prsname); MemoryContextSwitchTo(oldcontext); cfg->id = id; } else ts_error(ERROR, "No tsearch cfg with id %d", id); SPI_freeplan(plan); arg[0] = TEXTOID; sprintf(buf, "select lt.tokid, map.dict_name from %s.pg_ts_cfgmap as map, %s.pg_ts_cfg as cfg, %s.token_type( $1 ) as lt where lt.alias = map.tok_alias and map.ts_name = cfg.ts_name and cfg.oid= $2 order by lt.tokid desc;", nsp, nsp, nsp); plan = SPI_prepare(buf, 2, arg); if (!plan) ts_error(ERROR, "SPI_prepare() failed"); pars[0] = PointerGetDatum(prsname); stat = SPI_execp(plan, pars, " ", 0); if (stat < 0) ts_error(ERROR, "SPI_execp return %d", stat); if (SPI_processed <= 0) ts_error(ERROR, "No parser with id %d", id); for (i = 0; i < SPI_processed; i++) { int lexid = DatumGetInt32(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull)); ArrayType *toasted_a = (ArrayType *) PointerGetDatum(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &isnull)); ArrayType *a; if (!cfg->map) { cfg->len = lexid + 1; cfg->map = (ListDictionary *) malloc(sizeof(ListDictionary) * cfg->len); if (!cfg->map) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); memset(cfg->map, 0, sizeof(ListDictionary) * cfg->len); } if (isnull) continue; a = (ArrayType *) PointerGetDatum(PG_DETOAST_DATUM(DatumGetPointer(toasted_a))); if (ARR_NDIM(a) != 1) ts_error(ERROR, "Wrong dimension"); if (ARRNELEMS(a) < 1) continue; if (ARR_HASNULL(a)) ts_error(ERROR, "Array must not contain nulls"); cfg->map[lexid].len = ARRNELEMS(a); cfg->map[lexid].dict_id = (Datum *) malloc(sizeof(Datum) * cfg->map[lexid].len); if (!cfg->map[lexid].dict_id) ts_error(ERROR, "No memory"); memset(cfg->map[lexid].dict_id, 0, sizeof(Datum) * cfg->map[lexid].len); ptr = (text *) ARR_DATA_PTR(a); oldcontext = MemoryContextSwitchTo(TopMemoryContext); for (j = 0; j < cfg->map[lexid].len; j++) { cfg->map[lexid].dict_id[j] = PointerGetDatum(ptextdup(ptr)); ptr = NEXTVAL(ptr); } MemoryContextSwitchTo(oldcontext); if (a != toasted_a) pfree(a); } SPI_freeplan(plan); SPI_finish(); cfg->prs_id = name2id_prs(prsname); pfree(prsname); pfree(nsp); for (i = 0; i < cfg->len; i++) { for (j = 0; j < cfg->map[i].len; j++) { ptr = (text *) DatumGetPointer(cfg->map[i].dict_id[j]); cfg->map[i].dict_id[j] = ObjectIdGetDatum(name2id_dict(ptr)); pfree(ptr); } } }
Datum tsquery_rewrite(PG_FUNCTION_ARGS) { QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0))); text *in = PG_GETARG_TEXT_P(1); QUERYTYPE *rewrited = query; QTNode *tree; char *buf; void *plan; Portal portal; bool isnull; int i; if (query->size == 0) { PG_FREE_IF_COPY(in, 1); PG_RETURN_POINTER(rewrited); } tree = QT2QTN(GETQUERY(query), GETOPERAND(query)); QTNTernary(tree); QTNSort(tree); buf = (char *) palloc(VARSIZE(in)); memcpy(buf, VARDATA(in), VARSIZE(in) - VARHDRSZ); buf[VARSIZE(in) - VARHDRSZ] = '\0'; SPI_connect(); if (tsqOid == InvalidOid) get_tsq_Oid(); if ((plan = SPI_prepare(buf, 0, NULL)) == NULL) elog(ERROR, "SPI_prepare('%s') returns NULL", buf); if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, false)) == NULL) elog(ERROR, "SPI_cursor_open('%s') returns NULL", buf); SPI_cursor_fetch(portal, true, 100); if (SPI_tuptable->tupdesc->natts != 2) elog(ERROR, "number of fields doesn't equal to 2"); if (SPI_gettypeid(SPI_tuptable->tupdesc, 1) != tsqOid) elog(ERROR, "column #1 isn't of tsquery type"); if (SPI_gettypeid(SPI_tuptable->tupdesc, 2) != tsqOid) elog(ERROR, "column #2 isn't of tsquery type"); while (SPI_processed > 0 && tree) { for (i = 0; i < SPI_processed && tree; i++) { Datum qdata = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull); Datum sdata; if (isnull) continue; sdata = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &isnull); if (!isnull) { QUERYTYPE *qtex = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(qdata)); QUERYTYPE *qtsubs = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(sdata)); QTNode *qex, *qsubs = NULL; if (qtex->size == 0) { if (qtex != (QUERYTYPE *) DatumGetPointer(qdata)) pfree(qtex); if (qtsubs != (QUERYTYPE *) DatumGetPointer(sdata)) pfree(qtsubs); continue; } qex = QT2QTN(GETQUERY(qtex), GETOPERAND(qtex)); QTNTernary(qex); QTNSort(qex); if (qtsubs->size) qsubs = QT2QTN(GETQUERY(qtsubs), GETOPERAND(qtsubs)); tree = findsubquery(tree, qex, SPIMemory, qsubs, NULL); QTNFree(qex); if (qtex != (QUERYTYPE *) DatumGetPointer(qdata)) pfree(qtex); QTNFree(qsubs); if (qtsubs != (QUERYTYPE *) DatumGetPointer(sdata)) pfree(qtsubs); } } SPI_freetuptable(SPI_tuptable); SPI_cursor_fetch(portal, true, 100); } SPI_freetuptable(SPI_tuptable); SPI_cursor_close(portal); SPI_freeplan(plan); SPI_finish(); if (tree) { QTNBinary(tree); rewrited = QTN2QT(tree, PlainMemory); QTNFree(tree); PG_FREE_IF_COPY(query, 0); } else { rewrited->len = HDRSIZEQT; rewrited->size = 0; } pfree(buf); PG_FREE_IF_COPY(in, 1); PG_RETURN_POINTER(rewrited); }
static void statement_dealloc(PyObj self) { PyPgStatement ps; SPIPlanPtr plan, splan; MemoryContext memory; PyObj ob; ob = PyPgStatement_GetString(self); PyPgStatement_SetString(self, NULL); Py_XDECREF(ob); ob = PyPgStatement_GetInput(self); PyPgStatement_SetInput(self, NULL); Py_XDECREF(ob); ob = PyPgStatement_GetOutput(self); PyPgStatement_SetOutput(self, NULL); Py_XDECREF(ob); ob = PyPgStatement_GetParameters(self); PyPgStatement_SetParameters(self, NULL); Py_XDECREF(ob); ps = (PyPgStatement) self; plan = ps->ps_plan; splan = ps->ps_scroll_plan; ps->ps_plan = NULL; ps->ps_scroll_plan = NULL; memory = PyPgStatement_GetMemory(self); /* * It's allocated in the statment's memory context, so just NULL it. */ PyPgStatement_SetParameterTypes(self, NULL); PyPgStatement_SetPath(self, NULL); if (plan != NULL || splan != NULL || memory != NULL) { MemoryContext former = CurrentMemoryContext; PG_TRY(); { if (memory) MemoryContextDelete(memory); if (plan) SPI_freeplan(plan); if (splan) SPI_freeplan(splan); /* * When PLPY_STRANGE_THINGS is defined. */ RaiseAStrangeError } PG_CATCH(); { PyErr_EmitPgErrorAsWarning("could not deallocate statement plans"); } PG_END_TRY(); MemoryContextSwitchTo(former); }
static TSVectorStat * ts_stat_sql(MemoryContext persistentContext, text *txt, text *ws) { char *query = text_to_cstring(txt); int i; TSVectorStat *stat; bool isnull; Portal portal; SPIPlanPtr plan; if ((plan = SPI_prepare(query, 0, NULL)) == NULL) /* internal error */ elog(ERROR, "SPI_prepare(\"%s\") failed", query); if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, true)) == NULL) /* internal error */ elog(ERROR, "SPI_cursor_open(\"%s\") failed", query); SPI_cursor_fetch(portal, true, 100); if (SPI_tuptable == NULL || SPI_tuptable->tupdesc->natts != 1 || !IsBinaryCoercible(SPI_gettypeid(SPI_tuptable->tupdesc, 1), TSVECTOROID)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("ts_stat query must return one tsvector column"))); stat = MemoryContextAllocZero(persistentContext, sizeof(TSVectorStat)); stat->maxdepth = 1; if (ws) { char *buf; buf = VARDATA(ws); while (buf - VARDATA(ws) < VARSIZE(ws) - VARHDRSZ) { if (pg_mblen(buf) == 1) { switch (*buf) { case 'A': case 'a': stat->weight |= 1 << 3; break; case 'B': case 'b': stat->weight |= 1 << 2; break; case 'C': case 'c': stat->weight |= 1 << 1; break; case 'D': case 'd': stat->weight |= 1; break; default: stat->weight |= 0; } } buf += pg_mblen(buf); } } while (SPI_processed > 0) { for (i = 0; i < SPI_processed; i++) { Datum data = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull); if (!isnull) stat = ts_accum(persistentContext, stat, data); } SPI_freetuptable(SPI_tuptable); SPI_cursor_fetch(portal, true, 100); } SPI_freetuptable(SPI_tuptable); SPI_cursor_close(portal); SPI_freeplan(plan); pfree(query); return stat; }
static int luaP_plangc (lua_State *L) { luaP_Plan *p = (luaP_Plan *) lua_touserdata(L, 1); if (p->issaved) SPI_freeplan(p->plan); return 0; }