#include "postgres.h"
#include "access/xact.h"
#include "commands/event_trigger.h"
#include "commands/trigger.h"
#include "executor/spi.h"
Go to the source code of this file.
typedef struct PLpgSQL_condition PLpgSQL_condition |
typedef struct PLpgSQL_execstate PLpgSQL_execstate |
typedef struct PLpgSQL_expr PLpgSQL_expr |
typedef struct PLpgSQL_func_hashkey PLpgSQL_func_hashkey |
typedef struct PLpgSQL_function PLpgSQL_function |
typedef struct PLpgSQL_nsitem PLpgSQL_nsitem |
typedef enum PLpgSQL_trigtype PLpgSQL_trigtype |
anonymous enum |
Definition at line 41 of file plpgsql.h.
{ PLPGSQL_NSTYPE_LABEL, PLPGSQL_NSTYPE_VAR, PLPGSQL_NSTYPE_ROW, PLPGSQL_NSTYPE_REC };
anonymous enum |
PLPGSQL_DTYPE_VAR | |
PLPGSQL_DTYPE_ROW | |
PLPGSQL_DTYPE_REC | |
PLPGSQL_DTYPE_RECFIELD | |
PLPGSQL_DTYPE_ARRAYELEM | |
PLPGSQL_DTYPE_EXPR |
Definition at line 53 of file plpgsql.h.
{ PLPGSQL_DTYPE_VAR, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ARRAYELEM, PLPGSQL_DTYPE_EXPR };
anonymous enum |
Definition at line 67 of file plpgsql.h.
{ PLPGSQL_TTYPE_SCALAR, /* scalar types and domains */ PLPGSQL_TTYPE_ROW, /* composite types */ PLPGSQL_TTYPE_REC, /* RECORD pseudotype */ PLPGSQL_TTYPE_PSEUDO /* other pseudotypes */ };
anonymous enum |
Definition at line 111 of file plpgsql.h.
{ PLPGSQL_RC_OK, PLPGSQL_RC_EXIT, PLPGSQL_RC_RETURN, PLPGSQL_RC_CONTINUE };
anonymous enum |
Definition at line 123 of file plpgsql.h.
{ PLPGSQL_GETDIAG_ROW_COUNT, PLPGSQL_GETDIAG_RESULT_OID, PLPGSQL_GETDIAG_ERROR_CONTEXT, PLPGSQL_GETDIAG_ERROR_DETAIL, PLPGSQL_GETDIAG_ERROR_HINT, PLPGSQL_GETDIAG_RETURNED_SQLSTATE, PLPGSQL_GETDIAG_MESSAGE_TEXT };
anonymous enum |
PLPGSQL_RAISEOPTION_ERRCODE | |
PLPGSQL_RAISEOPTION_MESSAGE | |
PLPGSQL_RAISEOPTION_DETAIL | |
PLPGSQL_RAISEOPTION_HINT |
Definition at line 138 of file plpgsql.h.
{ PLPGSQL_RAISEOPTION_ERRCODE, PLPGSQL_RAISEOPTION_MESSAGE, PLPGSQL_RAISEOPTION_DETAIL, PLPGSQL_RAISEOPTION_HINT };
enum IdentifierLookup |
Definition at line 854 of file plpgsql.h.
{ IDENTIFIER_LOOKUP_NORMAL, /* normal processing of var names */ IDENTIFIER_LOOKUP_DECLARE, /* In DECLARE --- don't look up names */ IDENTIFIER_LOOKUP_EXPR /* In SQL expression --- special case */ } IdentifierLookup;
Definition at line 150 of file plpgsql.h.
{ PLPGSQL_RESOLVE_ERROR, /* throw error if ambiguous */ PLPGSQL_RESOLVE_VARIABLE, /* prefer plpgsql var to table column */ PLPGSQL_RESOLVE_COLUMN /* prefer table column to plpgsql var */ } PLpgSQL_resolve_option;
enum PLpgSQL_stmt_types |
Definition at line 79 of file plpgsql.h.
{ PLPGSQL_STMT_BLOCK, PLPGSQL_STMT_ASSIGN, PLPGSQL_STMT_IF, PLPGSQL_STMT_CASE, PLPGSQL_STMT_LOOP, PLPGSQL_STMT_WHILE, PLPGSQL_STMT_FORI, PLPGSQL_STMT_FORS, PLPGSQL_STMT_FORC, PLPGSQL_STMT_FOREACH_A, PLPGSQL_STMT_EXIT, PLPGSQL_STMT_RETURN, PLPGSQL_STMT_RETURN_NEXT, PLPGSQL_STMT_RETURN_QUERY, PLPGSQL_STMT_RAISE, PLPGSQL_STMT_EXECSQL, PLPGSQL_STMT_DYNEXECUTE, PLPGSQL_STMT_DYNFORS, PLPGSQL_STMT_GETDIAG, PLPGSQL_STMT_OPEN, PLPGSQL_STMT_FETCH, PLPGSQL_STMT_CLOSE, PLPGSQL_STMT_PERFORM };
enum PLpgSQL_trigtype |
Definition at line 679 of file plpgsql.h.
{ PLPGSQL_DML_TRIGGER, PLPGSQL_EVENT_TRIGGER, PLPGSQL_NOT_TRIGGER } PLpgSQL_trigtype;
void _PG_init | ( | void | ) |
Definition at line 54 of file auth_delay.c.
References auth_delay_milliseconds, auto_explain_log_analyze, auto_explain_log_buffers, auto_explain_log_format, auto_explain_log_min_duration, auto_explain_log_nested_statements, auto_explain_log_timing, auto_explain_log_verbose, BackgroundWorker::bgw_flags, BackgroundWorker::bgw_main, BackgroundWorker::bgw_main_arg, BackgroundWorker::bgw_name, BackgroundWorker::bgw_restart_time, BackgroundWorker::bgw_sighup, BackgroundWorker::bgw_sigterm, BackgroundWorker::bgw_start_time, BGWORKER_SHMEM_ACCESS, check_password_hook, ClientAuthentication_hook, DefineCustomBoolVariable(), DefineCustomEnumVariable(), DefineCustomIntVariable(), DefineCustomStringVariable(), dummy_object_relabel(), elog, EmitWarningsOnPlaceholders(), HASHCTL::entrysize, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, ExecutorCheckPerms_hook, ExecutorEnd_hook, ExecutorFinish_hook, ExecutorRun_hook, ExecutorStart_hook, EXPLAIN_FORMAT_TEXT, explicit_subtransactions, FATAL, find_rendezvous_variable(), gettext_noop, GUC_NOT_IN_SAMPLE, GUC_UNIT_MS, HASHCTL::hash, hash_create(), HASH_ELEM, HASH_FUNCTION, i, init_procedure_caches(), IsUnderPostmaster, HASHCTL::keysize, worktable::name, name, next_exec_check_perms_hook, next_object_access_hook, next_ProcessUtility_hook, NULL, object_access_hook, original_client_auth_hook, palloc(), pg_bindtextdomain(), PGC_POSTMASTER, PGC_SIGHUP, PGC_SUSET, PGC_USERSET, pgss_max, pgss_memsize(), pgss_save, pgss_track, PGSS_TRACK_TOP, pgss_track_utility, plperl_held_interp, plperl_init_interp(), plperl_on_init, plperl_on_plperl_init, plperl_on_plperlu_init, plperl_opmask, plperl_use_strict, plpgsql_HashTableInit(), PLPGSQL_RESOLVE_ERROR, plpgsql_subxact_cb(), plpgsql_variable_conflict, plpgsql_xact_cb(), plpython_python_version, PLy_elog(), PLy_init_interp(), PLy_init_plpy(), post_parse_analyze_hook, prev_ExecutorEnd, prev_ExecutorFinish, prev_ExecutorRun, prev_ExecutorStart, prev_post_parse_analyze_hook, prev_ProcessUtility, prev_shmem_startup_hook, process_shared_preload_libraries_in_progress, ProcessUtility_hook, pstrdup(), register_label_provider(), RegisterBackgroundWorker(), RegisterSubXactCallback(), RegisterXactCallback(), RequestAddinLWLocks(), RequestAddinShmemSpace(), worktable::schema, sepgsql_avc_init(), sepgsql_debug_audit, sepgsql_init_client_label(), SEPGSQL_LABEL_TAG, SEPGSQL_MODE_DISABLED, sepgsql_object_relabel(), sepgsql_permissive, sepgsql_set_mode(), shmem_startup_hook, TEXTDOMAIN, walrcv_connect, walrcv_disconnect, walrcv_endstreaming, walrcv_identify_system, walrcv_readtimelinehistoryfile, walrcv_receive, walrcv_send, walrcv_startstreaming, worker_spi_naptime, and worker_spi_total_workers.
{ /* Define custom GUC variables */ DefineCustomIntVariable("auth_delay.milliseconds", "Milliseconds to delay before reporting authentication failure", NULL, &auth_delay_milliseconds, 0, 0, INT_MAX / 1000, PGC_SIGHUP, GUC_UNIT_MS, NULL, NULL, NULL); /* Install Hooks */ original_client_auth_hook = ClientAuthentication_hook; ClientAuthentication_hook = auth_delay_checks; }
Oid exec_get_datum_type | ( | PLpgSQL_execstate * | estate, | |
PLpgSQL_datum * | datum | |||
) |
Definition at line 4412 of file pl_exec.c.
References BlessTupleDesc(), PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, PLpgSQL_recfield::fieldname, NULL, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, PLpgSQL_recfield::recparentno, PLpgSQL_rec::refname, PLpgSQL_row::rowtupdesc, SPI_ERROR_NOATTRIBUTE, SPI_fnumber(), SPI_gettypeid(), tupleDesc::tdtypeid, PLpgSQL_rec::tupdesc, and PLpgSQL_type::typoid.
Referenced by exec_stmt_foreach_a().
{ Oid typeid; switch (datum->dtype) { case PLPGSQL_DTYPE_VAR: { PLpgSQL_var *var = (PLpgSQL_var *) datum; typeid = var->datatype->typoid; break; } case PLPGSQL_DTYPE_ROW: { PLpgSQL_row *row = (PLpgSQL_row *) datum; if (!row->rowtupdesc) /* should not happen */ elog(ERROR, "row variable has no tupdesc"); /* Make sure we have a valid type/typmod setting */ BlessTupleDesc(row->rowtupdesc); typeid = row->rowtupdesc->tdtypeid; break; } case PLPGSQL_DTYPE_REC: { PLpgSQL_rec *rec = (PLpgSQL_rec *) datum; if (rec->tupdesc == NULL) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("record \"%s\" is not assigned yet", rec->refname), errdetail("The tuple structure of a not-yet-assigned record is indeterminate."))); /* Make sure we have a valid type/typmod setting */ BlessTupleDesc(rec->tupdesc); typeid = rec->tupdesc->tdtypeid; break; } case PLPGSQL_DTYPE_RECFIELD: { PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum; PLpgSQL_rec *rec; int fno; rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]); if (rec->tupdesc == NULL) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("record \"%s\" is not assigned yet", rec->refname), errdetail("The tuple structure of a not-yet-assigned record is indeterminate."))); fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); if (fno == SPI_ERROR_NOATTRIBUTE) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("record \"%s\" has no field \"%s\"", rec->refname, recfield->fieldname))); typeid = SPI_gettypeid(rec->tupdesc, fno); break; } default: elog(ERROR, "unrecognized dtype: %d", datum->dtype); typeid = InvalidOid; /* keep compiler quiet */ break; } return typeid; }
void exec_get_datum_type_info | ( | PLpgSQL_execstate * | estate, | |
PLpgSQL_datum * | datum, | |||
Oid * | typeid, | |||
int32 * | typmod, | |||
Oid * | collation | |||
) |
Definition at line 4494 of file pl_exec.c.
References tupleDesc::attrs, PLpgSQL_type::atttypmod, BlessTupleDesc(), PLpgSQL_type::collation, PLpgSQL_var::datatype, PLpgSQL_execstate::datums, PLpgSQL_datum::dtype, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, PLpgSQL_recfield::fieldname, NULL, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, PLpgSQL_recfield::recparentno, PLpgSQL_rec::refname, PLpgSQL_row::rowtupdesc, SPI_ERROR_NOATTRIBUTE, SPI_fnumber(), SPI_gettypeid(), tupleDesc::tdtypeid, PLpgSQL_rec::tupdesc, and PLpgSQL_type::typoid.
Referenced by make_datum_param().
{ switch (datum->dtype) { case PLPGSQL_DTYPE_VAR: { PLpgSQL_var *var = (PLpgSQL_var *) datum; *typeid = var->datatype->typoid; *typmod = var->datatype->atttypmod; *collation = var->datatype->collation; break; } case PLPGSQL_DTYPE_ROW: { PLpgSQL_row *row = (PLpgSQL_row *) datum; if (!row->rowtupdesc) /* should not happen */ elog(ERROR, "row variable has no tupdesc"); /* Make sure we have a valid type/typmod setting */ BlessTupleDesc(row->rowtupdesc); *typeid = row->rowtupdesc->tdtypeid; /* do NOT return the mutable typmod of a RECORD variable */ *typmod = -1; /* composite types are never collatable */ *collation = InvalidOid; break; } case PLPGSQL_DTYPE_REC: { PLpgSQL_rec *rec = (PLpgSQL_rec *) datum; if (rec->tupdesc == NULL) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("record \"%s\" is not assigned yet", rec->refname), errdetail("The tuple structure of a not-yet-assigned record is indeterminate."))); /* Make sure we have a valid type/typmod setting */ BlessTupleDesc(rec->tupdesc); *typeid = rec->tupdesc->tdtypeid; /* do NOT return the mutable typmod of a RECORD variable */ *typmod = -1; /* composite types are never collatable */ *collation = InvalidOid; break; } case PLPGSQL_DTYPE_RECFIELD: { PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum; PLpgSQL_rec *rec; int fno; rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]); if (rec->tupdesc == NULL) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("record \"%s\" is not assigned yet", rec->refname), errdetail("The tuple structure of a not-yet-assigned record is indeterminate."))); fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); if (fno == SPI_ERROR_NOATTRIBUTE) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("record \"%s\" has no field \"%s\"", rec->refname, recfield->fieldname))); *typeid = SPI_gettypeid(rec->tupdesc, fno); /* XXX there's no SPI_gettypmod, for some reason */ if (fno > 0) *typmod = rec->tupdesc->attrs[fno - 1]->atttypmod; else *typmod = -1; /* XXX there's no SPI_getcollation either */ if (fno > 0) *collation = rec->tupdesc->attrs[fno - 1]->attcollation; else /* no system column types have collation */ *collation = InvalidOid; break; } default: elog(ERROR, "unrecognized dtype: %d", datum->dtype); *typeid = InvalidOid; /* keep compiler quiet */ *typmod = -1; *collation = InvalidOid; break; } }
int plpgsql_add_initdatums | ( | int ** | varnos | ) |
Definition at line 2326 of file pl_comp.c.
References datums_last, PLpgSQL_datum::dno, i, NULL, palloc(), PLPGSQL_DTYPE_VAR, and plpgsql_nDatums.
{ int i; int n = 0; for (i = datums_last; i < plpgsql_nDatums; i++) { switch (plpgsql_Datums[i]->dtype) { case PLPGSQL_DTYPE_VAR: n++; break; default: break; } } if (varnos != NULL) { if (n > 0) { *varnos = (int *) palloc(sizeof(int) * n); n = 0; for (i = datums_last; i < plpgsql_nDatums; i++) { switch (plpgsql_Datums[i]->dtype) { case PLPGSQL_DTYPE_VAR: (*varnos)[n++] = plpgsql_Datums[i]->dno; default: break; } } } else *varnos = NULL; } datums_last = plpgsql_nDatums; return n; }
void plpgsql_adddatum | ( | PLpgSQL_datum * | new | ) |
Definition at line 2298 of file pl_comp.c.
References datums_alloc, plpgsql_nDatums, and repalloc().
Referenced by do_compile(), plpgsql_build_record(), plpgsql_build_variable(), plpgsql_parse_dblword(), and plpgsql_parse_tripword().
{ if (plpgsql_nDatums == datums_alloc) { datums_alloc *= 2; plpgsql_Datums = repalloc(plpgsql_Datums, sizeof(PLpgSQL_datum *) * datums_alloc); } new->dno = plpgsql_nDatums; plpgsql_Datums[plpgsql_nDatums++] = new; }
void plpgsql_append_source_text | ( | StringInfo | buf, | |
int | startlocation, | |||
int | endlocation | |||
) |
Definition at line 437 of file pl_scanner.c.
References appendBinaryStringInfo(), Assert, and scanorig.
{ Assert(startlocation <= endlocation); appendBinaryStringInfo(buf, scanorig + startlocation, endlocation - startlocation); }
int plpgsql_base_yylex | ( | void | ) |
PLpgSQL_type* plpgsql_build_datatype | ( | Oid | typeOid, | |
int32 | typmod, | |||
Oid | collation | |||
) |
Definition at line 2131 of file pl_comp.c.
References build_datatype(), elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), SearchSysCache1, and TYPEOID.
Referenced by build_row_from_class(), do_compile(), exec_stmt_case(), plpgsql_compile_inline(), plpgsql_parse_cwordrowtype(), and plpgsql_parse_wordrowtype().
{ HeapTuple typeTup; PLpgSQL_type *typ; typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid)); if (!HeapTupleIsValid(typeTup)) elog(ERROR, "cache lookup failed for type %u", typeOid); typ = build_datatype(typeTup, typmod, collation); ReleaseSysCache(typeTup); return typ; }
PLpgSQL_rec* plpgsql_build_record | ( | const char * | refname, | |
int | lineno, | |||
bool | add2namespace | |||
) |
Definition at line 1950 of file pl_comp.c.
References PLpgSQL_datum::dno, PLpgSQL_rec::dtype, PLpgSQL_rec::freetup, PLpgSQL_rec::lineno, palloc0(), plpgsql_adddatum(), plpgsql_ns_additem(), PLPGSQL_NSTYPE_REC, pstrdup(), PLpgSQL_rec::refname, PLpgSQL_rec::tup, and PLpgSQL_rec::tupdesc.
Referenced by do_compile(), and plpgsql_build_variable().
{ PLpgSQL_rec *rec; rec = palloc0(sizeof(PLpgSQL_rec)); rec->dtype = PLPGSQL_DTYPE_REC; rec->refname = pstrdup(refname); rec->lineno = lineno; rec->tup = NULL; rec->tupdesc = NULL; rec->freetup = false; plpgsql_adddatum((PLpgSQL_datum *) rec); if (add2namespace) plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->dno, rec->refname); return rec; }
PLpgSQL_variable* plpgsql_build_variable | ( | const char * | refname, | |
int | lineno, | |||
PLpgSQL_type * | dtype, | |||
bool | add2namespace | |||
) |
Definition at line 1870 of file pl_comp.c.
References build_row_from_class(), PLpgSQL_var::datatype, PLpgSQL_datum::dno, PLpgSQL_row::dtype, PLpgSQL_var::dtype, elog, ereport, errcode(), errmsg(), ERROR, format_type_be(), PLpgSQL_var::freeval, PLpgSQL_var::isnull, PLpgSQL_row::lineno, PLpgSQL_var::lineno, palloc0(), plpgsql_adddatum(), plpgsql_build_record(), plpgsql_ns_additem(), PLPGSQL_NSTYPE_ROW, PLPGSQL_NSTYPE_VAR, PLPGSQL_TTYPE_PSEUDO, PLPGSQL_TTYPE_REC, PLPGSQL_TTYPE_ROW, PLPGSQL_TTYPE_SCALAR, pstrdup(), PLpgSQL_row::refname, PLpgSQL_var::refname, PLpgSQL_type::ttype, PLpgSQL_type::typoid, PLpgSQL_type::typrelid, and PLpgSQL_var::value.
Referenced by build_row_from_class(), do_compile(), and plpgsql_compile_inline().
{ PLpgSQL_variable *result; switch (dtype->ttype) { case PLPGSQL_TTYPE_SCALAR: { /* Ordinary scalar datatype */ PLpgSQL_var *var; var = palloc0(sizeof(PLpgSQL_var)); var->dtype = PLPGSQL_DTYPE_VAR; var->refname = pstrdup(refname); var->lineno = lineno; var->datatype = dtype; /* other fields might be filled by caller */ /* preset to NULL */ var->value = 0; var->isnull = true; var->freeval = false; plpgsql_adddatum((PLpgSQL_datum *) var); if (add2namespace) plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->dno, refname); result = (PLpgSQL_variable *) var; break; } case PLPGSQL_TTYPE_ROW: { /* Composite type -- build a row variable */ PLpgSQL_row *row; row = build_row_from_class(dtype->typrelid); row->dtype = PLPGSQL_DTYPE_ROW; row->refname = pstrdup(refname); row->lineno = lineno; plpgsql_adddatum((PLpgSQL_datum *) row); if (add2namespace) plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, row->dno, refname); result = (PLpgSQL_variable *) row; break; } case PLPGSQL_TTYPE_REC: { /* "record" type -- build a record variable */ PLpgSQL_rec *rec; rec = plpgsql_build_record(refname, lineno, add2namespace); result = (PLpgSQL_variable *) rec; break; } case PLPGSQL_TTYPE_PSEUDO: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("variable \"%s\" has pseudo-type %s", refname, format_type_be(dtype->typoid)))); result = NULL; /* keep compiler quiet */ break; default: elog(ERROR, "unrecognized ttype: %d", dtype->ttype); result = NULL; /* keep compiler quiet */ break; } return result; }
Datum plpgsql_call_handler | ( | PG_FUNCTION_ARGS | ) |
Definition at line 91 of file pl_handler.c.
References CALLED_AS_EVENT_TRIGGER, CALLED_AS_TRIGGER, PLpgSQL_function::cur_estate, elog, ERROR, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, plpgsql_compile(), plpgsql_exec_event_trigger(), plpgsql_exec_function(), plpgsql_exec_trigger(), PointerGetDatum, SPI_connect(), SPI_finish(), SPI_OK_CONNECT, SPI_OK_FINISH, SPI_result_code_string(), and PLpgSQL_function::use_count.
{ PLpgSQL_function *func; PLpgSQL_execstate *save_cur_estate; Datum retval; int rc; /* * Connect to SPI manager */ if ((rc = SPI_connect()) != SPI_OK_CONNECT) elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc)); /* Find or compile the function */ func = plpgsql_compile(fcinfo, false); /* Must save and restore prior value of cur_estate */ save_cur_estate = func->cur_estate; /* Mark the function as busy, so it can't be deleted from under us */ func->use_count++; PG_TRY(); { /* * Determine if called as function or trigger and call appropriate * subhandler */ if (CALLED_AS_TRIGGER(fcinfo)) retval = PointerGetDatum(plpgsql_exec_trigger(func, (TriggerData *) fcinfo->context)); else if (CALLED_AS_EVENT_TRIGGER(fcinfo)) { plpgsql_exec_event_trigger(func, (EventTriggerData *) fcinfo->context); retval = (Datum) 0; } else retval = plpgsql_exec_function(func, fcinfo); } PG_CATCH(); { /* Decrement use-count, restore cur_estate, and propagate error */ func->use_count--; func->cur_estate = save_cur_estate; PG_RE_THROW(); } PG_END_TRY(); func->use_count--; func->cur_estate = save_cur_estate; /* * Disconnect from SPI manager */ if ((rc = SPI_finish()) != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc)); return retval; }
PLpgSQL_function* plpgsql_compile | ( | FunctionCallInfo | fcinfo, | |
bool | forValidator | |||
) |
Definition at line 132 of file pl_comp.c.
References compute_function_hashkey(), delete_function(), do_compile(), elog, ERROR, FunctionCallInfoData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_oid, PLpgSQL_function::fn_tid, PLpgSQL_function::fn_xmin, function, GETSTRUCT, HeapTupleHeaderGetXmin, HeapTupleIsValid, ItemPointerEquals(), ObjectIdGetDatum, plpgsql_HashTableLookup(), PROCOID, ReleaseSysCache(), SearchSysCache1, HeapTupleData::t_data, HeapTupleData::t_self, and PLpgSQL_function::use_count.
Referenced by plpgsql_call_handler(), and plpgsql_validator().
{ Oid funcOid = fcinfo->flinfo->fn_oid; HeapTuple procTup; Form_pg_proc procStruct; PLpgSQL_function *function; PLpgSQL_func_hashkey hashkey; bool function_valid = false; bool hashkey_valid = false; /* * Lookup the pg_proc tuple by Oid; we'll need it in any case */ procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid)); if (!HeapTupleIsValid(procTup)) elog(ERROR, "cache lookup failed for function %u", funcOid); procStruct = (Form_pg_proc) GETSTRUCT(procTup); /* * See if there's already a cache entry for the current FmgrInfo. If not, * try to find one in the hash table. */ function = (PLpgSQL_function *) fcinfo->flinfo->fn_extra; recheck: if (!function) { /* Compute hashkey using function signature and actual arg types */ compute_function_hashkey(fcinfo, procStruct, &hashkey, forValidator); hashkey_valid = true; /* And do the lookup */ function = plpgsql_HashTableLookup(&hashkey); } if (function) { /* We have a compiled function, but is it still valid? */ if (function->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) && ItemPointerEquals(&function->fn_tid, &procTup->t_self)) function_valid = true; else { /* * Nope, so remove it from hashtable and try to drop associated * storage (if not done already). */ delete_function(function); /* * If the function isn't in active use then we can overwrite the * func struct with new data, allowing any other existing fn_extra * pointers to make use of the new definition on their next use. * If it is in use then just leave it alone and make a new one. * (The active invocations will run to completion using the * previous definition, and then the cache entry will just be * leaked; doesn't seem worth adding code to clean it up, given * what a corner case this is.) * * If we found the function struct via fn_extra then it's possible * a replacement has already been made, so go back and recheck the * hashtable. */ if (function->use_count != 0) { function = NULL; if (!hashkey_valid) goto recheck; } } } /* * If the function wasn't found or was out-of-date, we have to compile it */ if (!function_valid) { /* * Calculate hashkey if we didn't already; we'll need it to store the * completed function. */ if (!hashkey_valid) compute_function_hashkey(fcinfo, procStruct, &hashkey, forValidator); /* * Do the hard part. */ function = do_compile(fcinfo, procTup, function, &hashkey, forValidator); } ReleaseSysCache(procTup); /* * Save pointer in FmgrInfo to avoid search on subsequent calls */ fcinfo->flinfo->fn_extra = (void *) function; /* * Finally return the compiled function */ return function; }
PLpgSQL_function* plpgsql_compile_inline | ( | char * | proc_source | ) |
Definition at line 797 of file pl_comp.c.
References PLpgSQL_function::action, add_dummy_return(), ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), ErrorContextCallback::arg, BOOLOID, ErrorContextCallback::callback, check_function_bodies, CurrentMemoryContext, PLpgSQL_function::datums, datums_alloc, datums_last, PLpgSQL_variable::dno, elog, ERROR, error_context_stack, fmgr_info(), PLpgSQL_function::fn_cxt, PLpgSQL_function::fn_input_collation, PLpgSQL_function::fn_is_trigger, PLpgSQL_function::fn_nargs, PLpgSQL_function::fn_readonly, PLpgSQL_function::fn_retbyval, PLpgSQL_function::fn_retinput, PLpgSQL_function::fn_retistuple, PLpgSQL_function::fn_retset, PLpgSQL_function::fn_rettype, PLpgSQL_function::fn_rettypioparam, PLpgSQL_function::fn_rettyplen, PLpgSQL_function::fn_signature, PLpgSQL_function::found_varno, function, getTypeInputInfo(), i, InvalidOid, MemoryContextSwitchTo(), PLpgSQL_function::ndatums, NULL, PLpgSQL_function::out_param_varno, palloc(), palloc0(), plpgsql_build_datatype(), plpgsql_build_variable(), plpgsql_check_syntax, plpgsql_DumpExecTree, plpgsql_error_funcname, plpgsql_nDatums, plpgsql_ns_init(), plpgsql_ns_push(), plpgsql_scanner_finish(), plpgsql_scanner_init(), plpgsql_variable_conflict, plpgsql_yyparse(), ErrorContextCallback::previous, pstrdup(), PLpgSQL_function::resolve_option, and VOIDOID.
Referenced by plpgsql_inline_handler().
{ char *func_name = "inline_code_block"; PLpgSQL_function *function; ErrorContextCallback plerrcontext; Oid typinput; PLpgSQL_variable *var; int parse_rc; MemoryContext func_cxt; int i; /* * Setup the scanner input and error info. We assume that this function * cannot be invoked recursively, so there's no need to save and restore * the static variables used here. */ plpgsql_scanner_init(proc_source); plpgsql_error_funcname = func_name; /* * Setup error traceback support for ereport() */ plerrcontext.callback = plpgsql_compile_error_callback; plerrcontext.arg = proc_source; plerrcontext.previous = error_context_stack; error_context_stack = &plerrcontext; /* Do extra syntax checking if check_function_bodies is on */ plpgsql_check_syntax = check_function_bodies; /* Function struct does not live past current statement */ function = (PLpgSQL_function *) palloc0(sizeof(PLpgSQL_function)); plpgsql_curr_compile = function; /* * All the rest of the compile-time storage (e.g. parse tree) is kept in * its own memory context, so it can be reclaimed easily. */ func_cxt = AllocSetContextCreate(CurrentMemoryContext, "PL/pgSQL function context", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); compile_tmp_cxt = MemoryContextSwitchTo(func_cxt); function->fn_signature = pstrdup(func_name); function->fn_is_trigger = PLPGSQL_NOT_TRIGGER; function->fn_input_collation = InvalidOid; function->fn_cxt = func_cxt; function->out_param_varno = -1; /* set up for no OUT param */ function->resolve_option = plpgsql_variable_conflict; plpgsql_ns_init(); plpgsql_ns_push(func_name); plpgsql_DumpExecTree = false; datums_alloc = 128; plpgsql_nDatums = 0; plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc); datums_last = 0; /* Set up as though in a function returning VOID */ function->fn_rettype = VOIDOID; function->fn_retset = false; function->fn_retistuple = false; /* a bit of hardwired knowledge about type VOID here */ function->fn_retbyval = true; function->fn_rettyplen = sizeof(int32); getTypeInputInfo(VOIDOID, &typinput, &function->fn_rettypioparam); fmgr_info(typinput, &(function->fn_retinput)); /* * Remember if function is STABLE/IMMUTABLE. XXX would it be better to * set this TRUE inside a read-only transaction? Not clear. */ function->fn_readonly = false; /* * Create the magic FOUND variable. */ var = plpgsql_build_variable("found", 0, plpgsql_build_datatype(BOOLOID, -1, InvalidOid), true); function->found_varno = var->dno; /* * Now parse the function's text */ parse_rc = plpgsql_yyparse(); if (parse_rc != 0) elog(ERROR, "plpgsql parser returned %d", parse_rc); function->action = plpgsql_parse_result; plpgsql_scanner_finish(); /* * If it returns VOID (always true at the moment), we allow control to * fall off the end without an explicit RETURN statement. */ if (function->fn_rettype == VOIDOID) add_dummy_return(function); /* * Complete the function's info */ function->fn_nargs = 0; function->ndatums = plpgsql_nDatums; function->datums = palloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums); for (i = 0; i < plpgsql_nDatums; i++) function->datums[i] = plpgsql_Datums[i]; /* * Pop the error context stack */ error_context_stack = plerrcontext.previous; plpgsql_error_funcname = NULL; plpgsql_check_syntax = false; MemoryContextSwitchTo(compile_tmp_cxt); compile_tmp_cxt = NULL; return function; }
void plpgsql_dumptree | ( | PLpgSQL_function * | func | ) |
Definition at line 1458 of file pl_funcs.c.
References PLpgSQL_function::action, PLpgSQL_type::atttypmod, PLpgSQL_var::cursor_explicit_argrow, PLpgSQL_var::cursor_explicit_expr, PLpgSQL_var::datatype, PLpgSQL_function::datums, PLpgSQL_var::default_val, PLpgSQL_arrayelem::dtype, PLpgSQL_datum::dtype, dump_block(), dump_expr(), dump_indent, PLpgSQL_row::fieldnames, PLpgSQL_function::fn_signature, i, PLpgSQL_var::isconst, PLpgSQL_stmt_block::lineno, PLpgSQL_function::ndatums, PLpgSQL_row::nfields, PLpgSQL_var::notnull, NULL, PLPGSQL_DTYPE_ARRAYELEM, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, PLpgSQL_row::refname, PLpgSQL_var::refname, PLpgSQL_type::typname, PLpgSQL_type::typoid, and PLpgSQL_row::varnos.
Referenced by do_compile().
{ int i; PLpgSQL_datum *d; printf("\nExecution tree of successfully compiled PL/pgSQL function %s:\n", func->fn_signature); printf("\nFunction's data area:\n"); for (i = 0; i < func->ndatums; i++) { d = func->datums[i]; printf(" entry %d: ", i); switch (d->dtype) { case PLPGSQL_DTYPE_VAR: { PLpgSQL_var *var = (PLpgSQL_var *) d; printf("VAR %-16s type %s (typoid %u) atttypmod %d\n", var->refname, var->datatype->typname, var->datatype->typoid, var->datatype->atttypmod); if (var->isconst) printf(" CONSTANT\n"); if (var->notnull) printf(" NOT NULL\n"); if (var->default_val != NULL) { printf(" DEFAULT "); dump_expr(var->default_val); printf("\n"); } if (var->cursor_explicit_expr != NULL) { if (var->cursor_explicit_argrow >= 0) printf(" CURSOR argument row %d\n", var->cursor_explicit_argrow); printf(" CURSOR IS "); dump_expr(var->cursor_explicit_expr); printf("\n"); } } break; case PLPGSQL_DTYPE_ROW: { PLpgSQL_row *row = (PLpgSQL_row *) d; int i; printf("ROW %-16s fields", row->refname); for (i = 0; i < row->nfields; i++) { if (row->fieldnames[i]) printf(" %s=var %d", row->fieldnames[i], row->varnos[i]); } printf("\n"); } break; case PLPGSQL_DTYPE_REC: printf("REC %s\n", ((PLpgSQL_rec *) d)->refname); break; case PLPGSQL_DTYPE_RECFIELD: printf("RECFIELD %-16s of REC %d\n", ((PLpgSQL_recfield *) d)->fieldname, ((PLpgSQL_recfield *) d)->recparentno); break; case PLPGSQL_DTYPE_ARRAYELEM: printf("ARRAYELEM of VAR %d subscript ", ((PLpgSQL_arrayelem *) d)->arrayparentno); dump_expr(((PLpgSQL_arrayelem *) d)->subscript); printf("\n"); break; default: printf("??? unknown data type %d\n", d->dtype); } } printf("\nFunction's statements:\n"); dump_indent = 0; printf("%3d:", func->action->lineno); dump_block(func->action); printf("\nEnd of execution tree of function %s\n\n", func->fn_signature); fflush(stdout); }
void plpgsql_exec_event_trigger | ( | PLpgSQL_function * | func, | |
EventTriggerData * | trigdata | |||
) |
Definition at line 769 of file pl_exec.c.
References PLpgSQL_function::action, ErrorContextCallback::arg, ErrorContextCallback::callback, copy_plpgsql_datum(), CStringGetTextDatum, PLpgSQL_function::datums, PLpgSQL_execstate::datums, ereport, PLpgSQL_execstate::err_stmt, PLpgSQL_execstate::err_text, errcode(), errmsg(), ERROR, error_context_stack, EventTriggerData::event, exec_eval_cleanup(), exec_stmt_block(), PLpgSQL_var::freeval, PLpgSQL_plugin::func_beg, PLpgSQL_plugin::func_end, gettext_noop, i, PLpgSQL_var::isnull, PLpgSQL_execstate::ndatums, NULL, plpgsql_destroy_econtext(), plpgsql_estate_setup(), PLPGSQL_RC_CONTINUE, PLPGSQL_RC_RETURN, plugin_ptr, ErrorContextCallback::previous, EventTriggerData::tag, PLpgSQL_function::tg_event_varno, PLpgSQL_function::tg_tag_varno, and PLpgSQL_var::value.
Referenced by plpgsql_call_handler().
{ PLpgSQL_execstate estate; ErrorContextCallback plerrcontext; int i; int rc; PLpgSQL_var *var; /* * Setup the execution state */ plpgsql_estate_setup(&estate, func, NULL); /* * Setup error traceback support for ereport() */ plerrcontext.callback = plpgsql_exec_error_callback; plerrcontext.arg = &estate; plerrcontext.previous = error_context_stack; error_context_stack = &plerrcontext; /* * Make local execution copies of all the datums */ estate.err_text = gettext_noop("during initialization of execution state"); for (i = 0; i < estate.ndatums; i++) estate.datums[i] = copy_plpgsql_datum(func->datums[i]); /* * Assign the special tg_ variables */ var = (PLpgSQL_var *) (estate.datums[func->tg_event_varno]); var->value = CStringGetTextDatum(trigdata->event); var->isnull = false; var->freeval = true; var = (PLpgSQL_var *) (estate.datums[func->tg_tag_varno]); var->value = CStringGetTextDatum(trigdata->tag); var->isnull = false; var->freeval = true; /* * Let the instrumentation plugin peek at this function */ if (*plugin_ptr && (*plugin_ptr)->func_beg) ((*plugin_ptr)->func_beg) (&estate, func); /* * Now call the toplevel block of statements */ estate.err_text = NULL; estate.err_stmt = (PLpgSQL_stmt *) (func->action); rc = exec_stmt_block(&estate, func->action); if (rc != PLPGSQL_RC_RETURN) { estate.err_stmt = NULL; estate.err_text = NULL; /* * Provide a more helpful message if a CONTINUE or RAISE has been used * outside the context it can work in. */ if (rc == PLPGSQL_RC_CONTINUE) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("CONTINUE cannot be used outside a loop"))); else ereport(ERROR, (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), errmsg("control reached end of trigger procedure without RETURN"))); } estate.err_stmt = NULL; estate.err_text = gettext_noop("during function exit"); /* * Let the instrumentation plugin peek at this function */ if (*plugin_ptr && (*plugin_ptr)->func_end) ((*plugin_ptr)->func_end) (&estate, func); /* Clean up any leftover temporary memory */ plpgsql_destroy_econtext(&estate); exec_eval_cleanup(&estate); /* * Pop the error context stack */ error_context_stack = plerrcontext.previous; return; }
Datum plpgsql_exec_function | ( | PLpgSQL_function * | func, | |
FunctionCallInfo | fcinfo | |||
) |
Definition at line 231 of file pl_exec.c.
References PLpgSQL_function::action, ReturnSetInfo::allowedModes, FunctionCallInfoData::arg, ErrorContextCallback::arg, FunctionCallInfoData::argnull, ErrorContextCallback::callback, convert_tuples_by_position(), copy_plpgsql_datum(), CreateTupleDescCopy(), DatumGetPointer, datumGetSize(), PLpgSQL_function::datums, PLpgSQL_execstate::datums, do_convert_tuple(), PLpgSQL_datum::dtype, elog, ereport, PLpgSQL_execstate::err_stmt, PLpgSQL_execstate::err_text, errcode(), errmsg(), ERROR, error_context_stack, exec_cast_value(), exec_eval_cleanup(), exec_move_row(), exec_move_row_from_datum(), exec_set_found(), exec_stmt_block(), PLpgSQL_function::fn_argvarnos, PLpgSQL_function::fn_nargs, PLpgSQL_function::fn_retbyval, PLpgSQL_function::fn_retinput, PLpgSQL_function::fn_rettype, PLpgSQL_function::fn_rettypioparam, PLpgSQL_function::fn_rettyplen, PLpgSQL_var::freeval, PLpgSQL_plugin::func_beg, PLpgSQL_plugin::func_end, get_call_result_type(), gettext_noop, i, IsA, FunctionCallInfoData::isnull, PLpgSQL_var::isnull, MemoryContextSwitchTo(), PLpgSQL_execstate::ndatums, NULL, plpgsql_destroy_econtext(), PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, plpgsql_estate_setup(), PLPGSQL_RC_CONTINUE, PLPGSQL_RC_RETURN, plugin_ptr, PointerGetDatum, ErrorContextCallback::previous, FunctionCallInfoData::resultinfo, PLpgSQL_execstate::retisnull, PLpgSQL_execstate::retisset, PLpgSQL_execstate::retistuple, PLpgSQL_execstate::rettupdesc, PLpgSQL_execstate::rettype, ReturnSetInfo::returnMode, PLpgSQL_execstate::retval, PLpgSQL_execstate::rsi, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, SPI_palloc(), SPI_returntuple(), PLpgSQL_execstate::tuple_store, PLpgSQL_execstate::tuple_store_cxt, TYPEFUNC_COMPOSITE, TYPEFUNC_RECORD, and PLpgSQL_var::value.
Referenced by plpgsql_call_handler(), and plpgsql_inline_handler().
{ PLpgSQL_execstate estate; ErrorContextCallback plerrcontext; int i; int rc; /* * Setup the execution state */ plpgsql_estate_setup(&estate, func, (ReturnSetInfo *) fcinfo->resultinfo); /* * Setup error traceback support for ereport() */ plerrcontext.callback = plpgsql_exec_error_callback; plerrcontext.arg = &estate; plerrcontext.previous = error_context_stack; error_context_stack = &plerrcontext; /* * Make local execution copies of all the datums */ estate.err_text = gettext_noop("during initialization of execution state"); for (i = 0; i < estate.ndatums; i++) estate.datums[i] = copy_plpgsql_datum(func->datums[i]); /* * Store the actual call argument values into the appropriate variables */ estate.err_text = gettext_noop("while storing call arguments into local variables"); for (i = 0; i < func->fn_nargs; i++) { int n = func->fn_argvarnos[i]; switch (estate.datums[n]->dtype) { case PLPGSQL_DTYPE_VAR: { PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[n]; var->value = fcinfo->arg[i]; var->isnull = fcinfo->argnull[i]; var->freeval = false; } break; case PLPGSQL_DTYPE_ROW: { PLpgSQL_row *row = (PLpgSQL_row *) estate.datums[n]; if (!fcinfo->argnull[i]) { /* Assign row value from composite datum */ exec_move_row_from_datum(&estate, NULL, row, fcinfo->arg[i]); } else { /* If arg is null, treat it as an empty row */ exec_move_row(&estate, NULL, row, NULL, NULL); } /* clean up after exec_move_row() */ exec_eval_cleanup(&estate); } break; default: elog(ERROR, "unrecognized dtype: %d", func->datums[i]->dtype); } } estate.err_text = gettext_noop("during function entry"); /* * Set the magic variable FOUND to false */ exec_set_found(&estate, false); /* * Let the instrumentation plugin peek at this function */ if (*plugin_ptr && (*plugin_ptr)->func_beg) ((*plugin_ptr)->func_beg) (&estate, func); /* * Now call the toplevel block of statements */ estate.err_text = NULL; estate.err_stmt = (PLpgSQL_stmt *) (func->action); rc = exec_stmt_block(&estate, func->action); if (rc != PLPGSQL_RC_RETURN) { estate.err_stmt = NULL; estate.err_text = NULL; /* * Provide a more helpful message if a CONTINUE or RAISE has been used * outside the context it can work in. */ if (rc == PLPGSQL_RC_CONTINUE) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("CONTINUE cannot be used outside a loop"))); else ereport(ERROR, (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), errmsg("control reached end of function without RETURN"))); } /* * We got a return value - process it */ estate.err_stmt = NULL; estate.err_text = gettext_noop("while casting return value to function's return type"); fcinfo->isnull = estate.retisnull; if (estate.retisset) { ReturnSetInfo *rsi = estate.rsi; /* Check caller can handle a set result */ if (!rsi || !IsA(rsi, ReturnSetInfo) || (rsi->allowedModes & SFRM_Materialize) == 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); rsi->returnMode = SFRM_Materialize; /* If we produced any tuples, send back the result */ if (estate.tuple_store) { rsi->setResult = estate.tuple_store; if (estate.rettupdesc) { MemoryContext oldcxt; oldcxt = MemoryContextSwitchTo(estate.tuple_store_cxt); rsi->setDesc = CreateTupleDescCopy(estate.rettupdesc); MemoryContextSwitchTo(oldcxt); } } estate.retval = (Datum) 0; fcinfo->isnull = true; } else if (!estate.retisnull) { if (estate.retistuple) { /* * We have to check that the returned tuple actually matches the * expected result type. XXX would be better to cache the tupdesc * instead of repeating get_call_result_type() */ HeapTuple rettup = (HeapTuple) DatumGetPointer(estate.retval); TupleDesc tupdesc; TupleConversionMap *tupmap; switch (get_call_result_type(fcinfo, NULL, &tupdesc)) { case TYPEFUNC_COMPOSITE: /* got the expected result rowtype, now check it */ tupmap = convert_tuples_by_position(estate.rettupdesc, tupdesc, gettext_noop("returned record type does not match expected record type")); /* it might need conversion */ if (tupmap) rettup = do_convert_tuple(rettup, tupmap); /* no need to free map, we're about to return anyway */ break; case TYPEFUNC_RECORD: /* * Failed to determine actual type of RECORD. We could * raise an error here, but what this means in practice is * that the caller is expecting any old generic rowtype, * so we don't really need to be restrictive. Pass back * the generated result type, instead. */ tupdesc = estate.rettupdesc; if (tupdesc == NULL) /* shouldn't happen */ elog(ERROR, "return type must be a row type"); break; default: /* shouldn't get here if retistuple is true ... */ elog(ERROR, "return type must be a row type"); break; } /* * Copy tuple to upper executor memory, as a tuple Datum. Make * sure it is labeled with the caller-supplied tuple type. */ estate.retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc)); } else { /* Cast value to proper type */ estate.retval = exec_cast_value(&estate, estate.retval, estate.rettype, func->fn_rettype, &(func->fn_retinput), func->fn_rettypioparam, -1, fcinfo->isnull); /* * If the function's return type isn't by value, copy the value * into upper executor memory context. */ if (!fcinfo->isnull && !func->fn_retbyval) { Size len; void *tmp; len = datumGetSize(estate.retval, false, func->fn_rettyplen); tmp = SPI_palloc(len); memcpy(tmp, DatumGetPointer(estate.retval), len); estate.retval = PointerGetDatum(tmp); } } } estate.err_text = gettext_noop("during function exit"); /* * Let the instrumentation plugin peek at this function */ if (*plugin_ptr && (*plugin_ptr)->func_end) ((*plugin_ptr)->func_end) (&estate, func); /* Clean up any leftover temporary memory */ plpgsql_destroy_econtext(&estate); exec_eval_cleanup(&estate); /* * Pop the error context stack */ error_context_stack = plerrcontext.previous; /* * Return the function's result */ return estate.retval; }
HeapTuple plpgsql_exec_trigger | ( | PLpgSQL_function * | func, | |
TriggerData * | trigdata | |||
) |
Definition at line 486 of file pl_exec.c.
References PLpgSQL_function::action, ErrorContextCallback::arg, ErrorContextCallback::callback, construct_md_array(), convert_tuples_by_position(), copy_plpgsql_datum(), CStringGetDatum, CStringGetTextDatum, DatumGetPointer, PLpgSQL_function::datums, PLpgSQL_execstate::datums, DirectFunctionCall1, do_convert_tuple(), elog, ereport, PLpgSQL_execstate::err_stmt, PLpgSQL_execstate::err_text, errcode(), errmsg(), ERROR, error_context_stack, exec_eval_cleanup(), exec_set_found(), exec_stmt_block(), PLpgSQL_rec::freetup, PLpgSQL_rec::freetupdesc, PLpgSQL_var::freeval, PLpgSQL_plugin::func_beg, PLpgSQL_plugin::func_end, get_namespace_name(), gettext_noop, i, Int16GetDatum, PLpgSQL_var::isnull, namein(), PLpgSQL_execstate::ndatums, PLpgSQL_function::new_varno, NULL, ObjectIdGetDatum, PLpgSQL_function::old_varno, palloc(), plpgsql_destroy_econtext(), plpgsql_estate_setup(), PLPGSQL_RC_CONTINUE, PLPGSQL_RC_RETURN, plugin_ptr, PointerGetDatum, ErrorContextCallback::previous, RelationData::rd_att, RelationData::rd_id, RelationGetNamespace, RelationGetRelationName, PLpgSQL_execstate::retisnull, PLpgSQL_execstate::retisset, PLpgSQL_execstate::rettupdesc, PLpgSQL_execstate::retval, SPI_copytuple(), TEXTOID, PLpgSQL_function::tg_argv_varno, TriggerData::tg_event, PLpgSQL_function::tg_level_varno, PLpgSQL_function::tg_name_varno, PLpgSQL_function::tg_nargs_varno, TriggerData::tg_newtuple, PLpgSQL_function::tg_op_varno, TriggerData::tg_relation, PLpgSQL_function::tg_relid_varno, PLpgSQL_function::tg_relname_varno, PLpgSQL_function::tg_table_name_varno, PLpgSQL_function::tg_table_schema_varno, TriggerData::tg_trigger, TriggerData::tg_trigtuple, PLpgSQL_function::tg_when_varno, Trigger::tgargs, Trigger::tgname, Trigger::tgnargs, TRIGGER_FIRED_AFTER, TRIGGER_FIRED_BEFORE, TRIGGER_FIRED_BY_DELETE, TRIGGER_FIRED_BY_INSERT, TRIGGER_FIRED_BY_TRUNCATE, TRIGGER_FIRED_BY_UPDATE, TRIGGER_FIRED_FOR_ROW, TRIGGER_FIRED_FOR_STATEMENT, TRIGGER_FIRED_INSTEAD, PLpgSQL_rec::tup, PLpgSQL_rec::tupdesc, and PLpgSQL_var::value.
Referenced by plpgsql_call_handler().
{ PLpgSQL_execstate estate; ErrorContextCallback plerrcontext; int i; int rc; PLpgSQL_var *var; PLpgSQL_rec *rec_new, *rec_old; HeapTuple rettup; /* * Setup the execution state */ plpgsql_estate_setup(&estate, func, NULL); /* * Setup error traceback support for ereport() */ plerrcontext.callback = plpgsql_exec_error_callback; plerrcontext.arg = &estate; plerrcontext.previous = error_context_stack; error_context_stack = &plerrcontext; /* * Make local execution copies of all the datums */ estate.err_text = gettext_noop("during initialization of execution state"); for (i = 0; i < estate.ndatums; i++) estate.datums[i] = copy_plpgsql_datum(func->datums[i]); /* * Put the OLD and NEW tuples into record variables * * We make the tupdescs available in both records even though only one may * have a value. This allows parsing of record references to succeed in * functions that are used for multiple trigger types. For example, we * might have a test like "if (TG_OP = 'INSERT' and NEW.foo = 'xyz')", * which should parse regardless of the current trigger type. */ rec_new = (PLpgSQL_rec *) (estate.datums[func->new_varno]); rec_new->freetup = false; rec_new->tupdesc = trigdata->tg_relation->rd_att; rec_new->freetupdesc = false; rec_old = (PLpgSQL_rec *) (estate.datums[func->old_varno]); rec_old->freetup = false; rec_old->tupdesc = trigdata->tg_relation->rd_att; rec_old->freetupdesc = false; if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) { /* * Per-statement triggers don't use OLD/NEW variables */ rec_new->tup = NULL; rec_old->tup = NULL; } else if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) { rec_new->tup = trigdata->tg_trigtuple; rec_old->tup = NULL; } else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) { rec_new->tup = trigdata->tg_newtuple; rec_old->tup = trigdata->tg_trigtuple; } else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) { rec_new->tup = NULL; rec_old->tup = trigdata->tg_trigtuple; } else elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, or UPDATE"); /* * Assign the special tg_ variables */ var = (PLpgSQL_var *) (estate.datums[func->tg_op_varno]); if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) var->value = CStringGetTextDatum("INSERT"); else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) var->value = CStringGetTextDatum("UPDATE"); else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) var->value = CStringGetTextDatum("DELETE"); else if (TRIGGER_FIRED_BY_TRUNCATE(trigdata->tg_event)) var->value = CStringGetTextDatum("TRUNCATE"); else elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, UPDATE, or TRUNCATE"); var->isnull = false; var->freeval = true; var = (PLpgSQL_var *) (estate.datums[func->tg_name_varno]); var->value = DirectFunctionCall1(namein, CStringGetDatum(trigdata->tg_trigger->tgname)); var->isnull = false; var->freeval = true; var = (PLpgSQL_var *) (estate.datums[func->tg_when_varno]); if (TRIGGER_FIRED_BEFORE(trigdata->tg_event)) var->value = CStringGetTextDatum("BEFORE"); else if (TRIGGER_FIRED_AFTER(trigdata->tg_event)) var->value = CStringGetTextDatum("AFTER"); else if (TRIGGER_FIRED_INSTEAD(trigdata->tg_event)) var->value = CStringGetTextDatum("INSTEAD OF"); else elog(ERROR, "unrecognized trigger execution time: not BEFORE, AFTER, or INSTEAD OF"); var->isnull = false; var->freeval = true; var = (PLpgSQL_var *) (estate.datums[func->tg_level_varno]); if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) var->value = CStringGetTextDatum("ROW"); else if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event)) var->value = CStringGetTextDatum("STATEMENT"); else elog(ERROR, "unrecognized trigger event type: not ROW or STATEMENT"); var->isnull = false; var->freeval = true; var = (PLpgSQL_var *) (estate.datums[func->tg_relid_varno]); var->value = ObjectIdGetDatum(trigdata->tg_relation->rd_id); var->isnull = false; var->freeval = false; var = (PLpgSQL_var *) (estate.datums[func->tg_relname_varno]); var->value = DirectFunctionCall1(namein, CStringGetDatum(RelationGetRelationName(trigdata->tg_relation))); var->isnull = false; var->freeval = true; var = (PLpgSQL_var *) (estate.datums[func->tg_table_name_varno]); var->value = DirectFunctionCall1(namein, CStringGetDatum(RelationGetRelationName(trigdata->tg_relation))); var->isnull = false; var->freeval = true; var = (PLpgSQL_var *) (estate.datums[func->tg_table_schema_varno]); var->value = DirectFunctionCall1(namein, CStringGetDatum( get_namespace_name( RelationGetNamespace( trigdata->tg_relation)))); var->isnull = false; var->freeval = true; var = (PLpgSQL_var *) (estate.datums[func->tg_nargs_varno]); var->value = Int16GetDatum(trigdata->tg_trigger->tgnargs); var->isnull = false; var->freeval = false; var = (PLpgSQL_var *) (estate.datums[func->tg_argv_varno]); if (trigdata->tg_trigger->tgnargs > 0) { /* * For historical reasons, tg_argv[] subscripts start at zero not one. * So we can't use construct_array(). */ int nelems = trigdata->tg_trigger->tgnargs; Datum *elems; int dims[1]; int lbs[1]; elems = palloc(sizeof(Datum) * nelems); for (i = 0; i < nelems; i++) elems[i] = CStringGetTextDatum(trigdata->tg_trigger->tgargs[i]); dims[0] = nelems; lbs[0] = 0; var->value = PointerGetDatum(construct_md_array(elems, NULL, 1, dims, lbs, TEXTOID, -1, false, 'i')); var->isnull = false; var->freeval = true; } else { var->value = (Datum) 0; var->isnull = true; var->freeval = false; } estate.err_text = gettext_noop("during function entry"); /* * Set the magic variable FOUND to false */ exec_set_found(&estate, false); /* * Let the instrumentation plugin peek at this function */ if (*plugin_ptr && (*plugin_ptr)->func_beg) ((*plugin_ptr)->func_beg) (&estate, func); /* * Now call the toplevel block of statements */ estate.err_text = NULL; estate.err_stmt = (PLpgSQL_stmt *) (func->action); rc = exec_stmt_block(&estate, func->action); if (rc != PLPGSQL_RC_RETURN) { estate.err_stmt = NULL; estate.err_text = NULL; /* * Provide a more helpful message if a CONTINUE or RAISE has been used * outside the context it can work in. */ if (rc == PLPGSQL_RC_CONTINUE) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("CONTINUE cannot be used outside a loop"))); else ereport(ERROR, (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), errmsg("control reached end of trigger procedure without RETURN"))); } estate.err_stmt = NULL; estate.err_text = gettext_noop("during function exit"); if (estate.retisset) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("trigger procedure cannot return a set"))); /* * Check that the returned tuple structure has the same attributes, the * relation that fired the trigger has. A per-statement trigger always * needs to return NULL, so we ignore any return value the function itself * produces (XXX: is this a good idea?) * * XXX This way it is possible, that the trigger returns a tuple where * attributes don't have the correct atttypmod's length. It's up to the * trigger's programmer to ensure that this doesn't happen. Jan */ if (estate.retisnull || !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) rettup = NULL; else { TupleConversionMap *tupmap; rettup = (HeapTuple) DatumGetPointer(estate.retval); /* check rowtype compatibility */ tupmap = convert_tuples_by_position(estate.rettupdesc, trigdata->tg_relation->rd_att, gettext_noop("returned row structure does not match the structure of the triggering table")); /* it might need conversion */ if (tupmap) rettup = do_convert_tuple(rettup, tupmap); /* no need to free map, we're about to return anyway */ /* Copy tuple to upper executor memory */ rettup = SPI_copytuple(rettup); } /* * Let the instrumentation plugin peek at this function */ if (*plugin_ptr && (*plugin_ptr)->func_end) ((*plugin_ptr)->func_end) (&estate, func); /* Clean up any leftover temporary memory */ plpgsql_destroy_econtext(&estate); exec_eval_cleanup(&estate); /* * Pop the error context stack */ error_context_stack = plerrcontext.previous; /* * Return the trigger's result */ return rettup; }
void plpgsql_free_function_memory | ( | PLpgSQL_function * | func | ) |
Definition at line 648 of file pl_funcs.c.
References PLpgSQL_function::action, Assert, PLpgSQL_var::cursor_explicit_expr, PLpgSQL_function::datums, PLpgSQL_var::default_val, PLpgSQL_arrayelem::dtype, PLpgSQL_datum::dtype, elog, ERROR, PLpgSQL_function::fn_cxt, free_block(), free_expr(), i, MemoryContextDelete(), PLpgSQL_function::ndatums, PLPGSQL_DTYPE_ARRAYELEM, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, and PLpgSQL_function::use_count.
Referenced by delete_function(), and plpgsql_inline_handler().
{ int i; /* Better not call this on an in-use function */ Assert(func->use_count == 0); /* Release plans associated with variable declarations */ for (i = 0; i < func->ndatums; i++) { PLpgSQL_datum *d = func->datums[i]; switch (d->dtype) { case PLPGSQL_DTYPE_VAR: { PLpgSQL_var *var = (PLpgSQL_var *) d; free_expr(var->default_val); free_expr(var->cursor_explicit_expr); } break; case PLPGSQL_DTYPE_ROW: break; case PLPGSQL_DTYPE_REC: break; case PLPGSQL_DTYPE_RECFIELD: break; case PLPGSQL_DTYPE_ARRAYELEM: free_expr(((PLpgSQL_arrayelem *) d)->subscript); break; default: elog(ERROR, "unrecognized data type: %d", d->dtype); } } func->ndatums = 0; /* Release plans in statement tree */ if (func->action) free_block(func->action); func->action = NULL; /* * And finally, release all memory except the PLpgSQL_function struct * itself (which has to be kept around because there may be multiple * fn_extra pointers to it). */ if (func->fn_cxt) MemoryContextDelete(func->fn_cxt); func->fn_cxt = NULL; }
const char* plpgsql_getdiag_kindname | ( | int | kind | ) |
Definition at line 272 of file pl_funcs.c.
References PLPGSQL_GETDIAG_ERROR_CONTEXT, PLPGSQL_GETDIAG_ERROR_DETAIL, PLPGSQL_GETDIAG_ERROR_HINT, PLPGSQL_GETDIAG_MESSAGE_TEXT, PLPGSQL_GETDIAG_RESULT_OID, PLPGSQL_GETDIAG_RETURNED_SQLSTATE, and PLPGSQL_GETDIAG_ROW_COUNT.
Referenced by dump_getdiag().
{ switch (kind) { case PLPGSQL_GETDIAG_ROW_COUNT: return "ROW_COUNT"; case PLPGSQL_GETDIAG_RESULT_OID: return "RESULT_OID"; case PLPGSQL_GETDIAG_ERROR_CONTEXT: return "PG_EXCEPTION_CONTEXT"; case PLPGSQL_GETDIAG_ERROR_DETAIL: return "PG_EXCEPTION_DETAIL"; case PLPGSQL_GETDIAG_ERROR_HINT: return "PG_EXCEPTION_HINT"; case PLPGSQL_GETDIAG_RETURNED_SQLSTATE: return "RETURNED_SQLSTATE"; case PLPGSQL_GETDIAG_MESSAGE_TEXT: return "MESSAGE_TEXT"; } return "unknown"; }
void plpgsql_HashTableInit | ( | void | ) |
Definition at line 2500 of file pl_comp.c.
References Assert, HASHCTL::entrysize, FUNCS_PER_USER, HASHCTL::hash, hash_create(), HASH_ELEM, HASH_FUNCTION, HASHCTL::keysize, and NULL.
Referenced by _PG_init().
{ HASHCTL ctl; /* don't allow double-initialization */ Assert(plpgsql_HashTable == NULL); memset(&ctl, 0, sizeof(ctl)); ctl.keysize = sizeof(PLpgSQL_func_hashkey); ctl.entrysize = sizeof(plpgsql_HashEnt); ctl.hash = tag_hash; plpgsql_HashTable = hash_create("PLpgSQL function cache", FUNCS_PER_USER, &ctl, HASH_ELEM | HASH_FUNCTION); }
Datum plpgsql_inline_handler | ( | PG_FUNCTION_ARGS | ) |
Definition at line 162 of file pl_handler.c.
References Assert, CurrentMemoryContext, DatumGetPointer, elog, ERROR, FunctionCallInfoData::flinfo, FmgrInfo::fn_mcxt, FmgrInfo::fn_oid, IsA, MemSet, PG_GETARG_DATUM, plpgsql_compile_inline(), plpgsql_exec_function(), plpgsql_free_function_memory(), InlineCodeBlock::source_text, SPI_connect(), SPI_finish(), SPI_OK_CONNECT, SPI_OK_FINISH, SPI_result_code_string(), and PLpgSQL_function::use_count.
{ InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0)); PLpgSQL_function *func; FunctionCallInfoData fake_fcinfo; FmgrInfo flinfo; Datum retval; int rc; Assert(IsA(codeblock, InlineCodeBlock)); /* * Connect to SPI manager */ if ((rc = SPI_connect()) != SPI_OK_CONNECT) elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc)); /* Compile the anonymous code block */ func = plpgsql_compile_inline(codeblock->source_text); /* Mark the function as busy, just pro forma */ func->use_count++; /* * Set up a fake fcinfo with just enough info to satisfy * plpgsql_exec_function(). In particular note that this sets things up * with no arguments passed. */ MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo)); MemSet(&flinfo, 0, sizeof(flinfo)); fake_fcinfo.flinfo = &flinfo; flinfo.fn_oid = InvalidOid; flinfo.fn_mcxt = CurrentMemoryContext; retval = plpgsql_exec_function(func, &fake_fcinfo); /* Function should now have no remaining use-counts ... */ func->use_count--; Assert(func->use_count == 0); /* ... so we can free subsidiary storage */ plpgsql_free_function_memory(func); /* * Disconnect from SPI manager */ if ((rc = SPI_finish()) != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc)); return retval; }
int plpgsql_latest_lineno | ( | void | ) |
Definition at line 605 of file pl_scanner.c.
References cur_line_num.
Referenced by plpgsql_compile_error_callback().
{ return cur_line_num; }
int plpgsql_location_to_lineno | ( | int | location | ) |
Definition at line 571 of file pl_scanner.c.
References cur_line_end, cur_line_num, cur_line_start, location_lineno_init(), NULL, and scanorig.
{ const char *loc; if (location < 0 || scanorig == NULL) return 0; /* garbage in, garbage out */ loc = scanorig + location; /* be correct, but not fast, if input location goes backwards */ if (loc < cur_line_start) location_lineno_init(); while (cur_line_end != NULL && loc > cur_line_end) { cur_line_start = cur_line_end + 1; cur_line_num++; cur_line_end = strchr(cur_line_start, '\n'); } return cur_line_num; }
void plpgsql_ns_additem | ( | int | itemtype, | |
int | itemno, | |||
const char * | name | |||
) |
Definition at line 92 of file pl_funcs.c.
References Assert, PLpgSQL_nsitem::itemno, PLpgSQL_nsitem::itemtype, PLpgSQL_nsitem::name, NULL, palloc(), PLPGSQL_NSTYPE_LABEL, and PLpgSQL_nsitem::prev.
Referenced by add_parameter_name(), plpgsql_build_record(), plpgsql_build_variable(), and plpgsql_ns_push().
{ PLpgSQL_nsitem *nse; Assert(name != NULL); /* first item added must be a label */ Assert(ns_top != NULL || itemtype == PLPGSQL_NSTYPE_LABEL); nse = palloc(sizeof(PLpgSQL_nsitem) + strlen(name)); nse->itemtype = itemtype; nse->itemno = itemno; nse->prev = ns_top; strcpy(nse->name, name); ns_top = nse; }
void plpgsql_ns_init | ( | void | ) |
Definition at line 43 of file pl_funcs.c.
Referenced by do_compile(), and plpgsql_compile_inline().
{ ns_top = NULL; }
PLpgSQL_nsitem* plpgsql_ns_lookup | ( | PLpgSQL_nsitem * | ns_cur, | |
bool | localmode, | |||
const char * | name1, | |||
const char * | name2, | |||
const char * | name3, | |||
int * | names_used | |||
) |
Definition at line 130 of file pl_funcs.c.
References PLpgSQL_nsitem::itemtype, PLpgSQL_nsitem::name, NULL, PLPGSQL_NSTYPE_VAR, and PLpgSQL_nsitem::prev.
Referenced by add_parameter_name(), plpgsql_param_ref(), plpgsql_parse_cwordtype(), plpgsql_parse_dblword(), plpgsql_parse_tripword(), plpgsql_parse_word(), plpgsql_parse_wordtype(), and resolve_column_ref().
{ /* Outer loop iterates once per block level in the namespace chain */ while (ns_cur != NULL) { PLpgSQL_nsitem *nsitem; /* Check this level for unqualified match to variable name */ for (nsitem = ns_cur; nsitem->itemtype != PLPGSQL_NSTYPE_LABEL; nsitem = nsitem->prev) { if (strcmp(nsitem->name, name1) == 0) { if (name2 == NULL || nsitem->itemtype != PLPGSQL_NSTYPE_VAR) { if (names_used) *names_used = 1; return nsitem; } } } /* Check this level for qualified match to variable name */ if (name2 != NULL && strcmp(nsitem->name, name1) == 0) { for (nsitem = ns_cur; nsitem->itemtype != PLPGSQL_NSTYPE_LABEL; nsitem = nsitem->prev) { if (strcmp(nsitem->name, name2) == 0) { if (name3 == NULL || nsitem->itemtype != PLPGSQL_NSTYPE_VAR) { if (names_used) *names_used = 2; return nsitem; } } } } if (localmode) break; /* do not look into upper levels */ ns_cur = nsitem->prev; } /* This is just to suppress possibly-uninitialized-variable warnings */ if (names_used) *names_used = 0; return NULL; /* No match found */ }
PLpgSQL_nsitem* plpgsql_ns_lookup_label | ( | PLpgSQL_nsitem * | ns_cur, | |
const char * | name | |||
) |
Definition at line 195 of file pl_funcs.c.
References PLpgSQL_nsitem::itemtype, PLpgSQL_nsitem::name, NULL, PLPGSQL_NSTYPE_LABEL, and PLpgSQL_nsitem::prev.
void plpgsql_ns_pop | ( | void | ) |
Definition at line 67 of file pl_funcs.c.
References Assert, PLpgSQL_nsitem::itemtype, NULL, PLPGSQL_NSTYPE_LABEL, and PLpgSQL_nsitem::prev.
void plpgsql_ns_push | ( | const char * | label | ) |
Definition at line 54 of file pl_funcs.c.
References NULL, plpgsql_ns_additem(), and PLPGSQL_NSTYPE_LABEL.
Referenced by do_compile(), and plpgsql_compile_inline().
{ if (label == NULL) label = ""; plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, 0, label); }
PLpgSQL_nsitem* plpgsql_ns_top | ( | void | ) |
Definition at line 81 of file pl_funcs.c.
Referenced by add_parameter_name(), plpgsql_parse_cwordtype(), plpgsql_parse_dblword(), plpgsql_parse_tripword(), plpgsql_parse_word(), and plpgsql_parse_wordtype().
{ return ns_top; }
PLpgSQL_type* plpgsql_parse_cwordrowtype | ( | List * | idents | ) |
Definition at line 1836 of file pl_comp.c.
References get_rel_type_id(), InvalidOid, linitial, list_length(), lsecond, makeRangeVar(), MemoryContextSwitchTo(), NoLock, plpgsql_build_datatype(), RangeVarGetRelid, and strVal.
{ Oid classOid; RangeVar *relvar; MemoryContext oldCxt; if (list_length(idents) != 2) return NULL; /* Avoid memory leaks in long-term function context */ oldCxt = MemoryContextSwitchTo(compile_tmp_cxt); /* Look up relation name. Can't lock it - we might not have privileges. */ relvar = makeRangeVar(strVal(linitial(idents)), strVal(lsecond(idents)), -1); classOid = RangeVarGetRelid(relvar, NoLock, false); MemoryContextSwitchTo(oldCxt); /* Build and return the row type struct */ return plpgsql_build_datatype(get_rel_type_id(classOid), -1, InvalidOid); }
PLpgSQL_type* plpgsql_parse_cwordtype | ( | List * | idents | ) |
Definition at line 1698 of file pl_comp.c.
References build_datatype(), elog, ERROR, GETSTRUCT, HeapTupleIsValid, PLpgSQL_nsitem::itemno, PLpgSQL_nsitem::itemtype, linitial, list_length(), lsecond, lthird, makeRangeVar(), MemoryContextSwitchTo(), NoLock, NULL, ObjectIdGetDatum, OidIsValid, plpgsql_ns_lookup(), plpgsql_ns_top(), PLPGSQL_NSTYPE_VAR, RangeVarGetRelid, ReleaseSysCache(), RELKIND_COMPOSITE_TYPE, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, RelnameGetRelid(), RELOID, SearchSysCache1, SearchSysCacheAttName(), strVal, and TYPEOID.
{ PLpgSQL_type *dtype = NULL; PLpgSQL_nsitem *nse; const char *fldname; Oid classOid; HeapTuple classtup = NULL; HeapTuple attrtup = NULL; HeapTuple typetup = NULL; Form_pg_class classStruct; Form_pg_attribute attrStruct; MemoryContext oldCxt; /* Avoid memory leaks in the long-term function context */ oldCxt = MemoryContextSwitchTo(compile_tmp_cxt); if (list_length(idents) == 2) { /* * Do a lookup in the current namespace stack. We don't need to check * number of names matched, because we will only consider scalar * variables. */ nse = plpgsql_ns_lookup(plpgsql_ns_top(), false, strVal(linitial(idents)), strVal(lsecond(idents)), NULL, NULL); if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_VAR) { dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; goto done; } /* * First word could also be a table name */ classOid = RelnameGetRelid(strVal(linitial(idents))); if (!OidIsValid(classOid)) goto done; fldname = strVal(lsecond(idents)); } else if (list_length(idents) == 3) { RangeVar *relvar; relvar = makeRangeVar(strVal(linitial(idents)), strVal(lsecond(idents)), -1); /* Can't lock relation - we might not have privileges. */ classOid = RangeVarGetRelid(relvar, NoLock, true); if (!OidIsValid(classOid)) goto done; fldname = strVal(lthird(idents)); } else goto done; classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classOid)); if (!HeapTupleIsValid(classtup)) goto done; classStruct = (Form_pg_class) GETSTRUCT(classtup); /* * It must be a relation, sequence, view, materialized view, composite * type, or foreign table */ if (classStruct->relkind != RELKIND_RELATION && classStruct->relkind != RELKIND_SEQUENCE && classStruct->relkind != RELKIND_VIEW && classStruct->relkind != RELKIND_MATVIEW && classStruct->relkind != RELKIND_COMPOSITE_TYPE && classStruct->relkind != RELKIND_FOREIGN_TABLE) goto done; /* * Fetch the named table field and its type */ attrtup = SearchSysCacheAttName(classOid, fldname); if (!HeapTupleIsValid(attrtup)) goto done; attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup); typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(attrStruct->atttypid)); if (!HeapTupleIsValid(typetup)) elog(ERROR, "cache lookup failed for type %u", attrStruct->atttypid); /* * Found that - build a compiler type struct in the caller's cxt and * return it */ MemoryContextSwitchTo(oldCxt); dtype = build_datatype(typetup, attrStruct->atttypmod, attrStruct->attcollation); MemoryContextSwitchTo(compile_tmp_cxt); done: if (HeapTupleIsValid(classtup)) ReleaseSysCache(classtup); if (HeapTupleIsValid(attrtup)) ReleaseSysCache(attrtup); if (HeapTupleIsValid(typetup)) ReleaseSysCache(typetup); MemoryContextSwitchTo(oldCxt); return dtype; }
Definition at line 1418 of file pl_comp.c.
References PLwdatum::datum, PLpgSQL_row::fieldnames, i, PLwdatum::ident, IDENTIFIER_LOOKUP_DECLARE, PLcword::idents, PLwdatum::idents, PLpgSQL_nsitem::itemno, PLpgSQL_nsitem::itemtype, list_make2, makeString(), PLpgSQL_row::nfields, NULL, palloc(), plpgsql_adddatum(), plpgsql_IdentifierLookup, plpgsql_ns_lookup(), plpgsql_ns_top(), PLPGSQL_NSTYPE_REC, PLPGSQL_NSTYPE_ROW, PLPGSQL_NSTYPE_VAR, pstrdup(), PLwdatum::quoted, and PLpgSQL_row::varnos.
Referenced by plpgsql_yylex().
{ PLpgSQL_nsitem *ns; List *idents; int nnames; idents = list_make2(makeString(word1), makeString(word2)); /* * We should do nothing in DECLARE sections. In SQL expressions, we * really only need to make sure that RECFIELD datums are created when * needed. */ if (plpgsql_IdentifierLookup != IDENTIFIER_LOOKUP_DECLARE) { /* * Do a lookup in the current namespace stack */ ns = plpgsql_ns_lookup(plpgsql_ns_top(), false, word1, word2, NULL, &nnames); if (ns != NULL) { switch (ns->itemtype) { case PLPGSQL_NSTYPE_VAR: /* Block-qualified reference to scalar variable. */ wdatum->datum = plpgsql_Datums[ns->itemno]; wdatum->ident = NULL; wdatum->quoted = false; /* not used */ wdatum->idents = idents; return true; case PLPGSQL_NSTYPE_REC: if (nnames == 1) { /* * First word is a record name, so second word could * be a field in this record. We build a RECFIELD * datum whether it is or not --- any error will be * detected later. */ PLpgSQL_recfield *new; new = palloc(sizeof(PLpgSQL_recfield)); new->dtype = PLPGSQL_DTYPE_RECFIELD; new->fieldname = pstrdup(word2); new->recparentno = ns->itemno; plpgsql_adddatum((PLpgSQL_datum *) new); wdatum->datum = (PLpgSQL_datum *) new; } else { /* Block-qualified reference to record variable. */ wdatum->datum = plpgsql_Datums[ns->itemno]; } wdatum->ident = NULL; wdatum->quoted = false; /* not used */ wdatum->idents = idents; return true; case PLPGSQL_NSTYPE_ROW: if (nnames == 1) { /* * First word is a row name, so second word could be a * field in this row. Again, no error now if it * isn't. */ PLpgSQL_row *row; int i; row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]); for (i = 0; i < row->nfields; i++) { if (row->fieldnames[i] && strcmp(row->fieldnames[i], word2) == 0) { wdatum->datum = plpgsql_Datums[row->varnos[i]]; wdatum->ident = NULL; wdatum->quoted = false; /* not used */ wdatum->idents = idents; return true; } } /* fall through to return CWORD */ } else { /* Block-qualified reference to row variable. */ wdatum->datum = plpgsql_Datums[ns->itemno]; wdatum->ident = NULL; wdatum->quoted = false; /* not used */ wdatum->idents = idents; return true; } break; default: break; } } } /* Nothing found */ cword->idents = idents; return false; }
PLpgSQL_condition* plpgsql_parse_err_condition | ( | char * | condname | ) |
Definition at line 2246 of file pl_comp.c.
References ereport, errcode(), errmsg(), ERROR, i, label, ExceptionLabelMap::label, palloc(), and ExceptionLabelMap::sqlerrstate.
{ int i; PLpgSQL_condition *new; PLpgSQL_condition *prev; /* * XXX Eventually we will want to look for user-defined exception names * here. */ /* * OTHERS is represented as code 0 (which would map to '00000', but we * have no need to represent that as an exception condition). */ if (strcmp(condname, "others") == 0) { new = palloc(sizeof(PLpgSQL_condition)); new->sqlerrstate = 0; new->condname = condname; new->next = NULL; return new; } prev = NULL; for (i = 0; exception_label_map[i].label != NULL; i++) { if (strcmp(condname, exception_label_map[i].label) == 0) { new = palloc(sizeof(PLpgSQL_condition)); new->sqlerrstate = exception_label_map[i].sqlerrstate; new->condname = condname; new->next = prev; prev = new; } } if (!prev) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("unrecognized exception condition \"%s\"", condname))); return prev; }
bool plpgsql_parse_tripword | ( | char * | word1, | |
char * | word2, | |||
char * | word3, | |||
PLwdatum * | wdatum, | |||
PLcword * | cword | |||
) |
Definition at line 1538 of file pl_comp.c.
References PLwdatum::datum, PLpgSQL_row::fieldnames, i, PLwdatum::ident, IDENTIFIER_LOOKUP_DECLARE, PLcword::idents, PLwdatum::idents, PLpgSQL_nsitem::itemno, PLpgSQL_nsitem::itemtype, list_make3, makeString(), PLpgSQL_row::nfields, NULL, palloc(), plpgsql_adddatum(), plpgsql_IdentifierLookup, plpgsql_ns_lookup(), plpgsql_ns_top(), PLPGSQL_NSTYPE_REC, PLPGSQL_NSTYPE_ROW, pstrdup(), PLwdatum::quoted, and PLpgSQL_row::varnos.
Referenced by plpgsql_yylex().
{ PLpgSQL_nsitem *ns; List *idents; int nnames; idents = list_make3(makeString(word1), makeString(word2), makeString(word3)); /* * We should do nothing in DECLARE sections. In SQL expressions, we * really only need to make sure that RECFIELD datums are created when * needed. */ if (plpgsql_IdentifierLookup != IDENTIFIER_LOOKUP_DECLARE) { /* * Do a lookup in the current namespace stack. Must find a qualified * reference, else ignore. */ ns = plpgsql_ns_lookup(plpgsql_ns_top(), false, word1, word2, word3, &nnames); if (ns != NULL && nnames == 2) { switch (ns->itemtype) { case PLPGSQL_NSTYPE_REC: { /* * words 1/2 are a record name, so third word could be * a field in this record. */ PLpgSQL_recfield *new; new = palloc(sizeof(PLpgSQL_recfield)); new->dtype = PLPGSQL_DTYPE_RECFIELD; new->fieldname = pstrdup(word3); new->recparentno = ns->itemno; plpgsql_adddatum((PLpgSQL_datum *) new); wdatum->datum = (PLpgSQL_datum *) new; wdatum->ident = NULL; wdatum->quoted = false; /* not used */ wdatum->idents = idents; return true; } case PLPGSQL_NSTYPE_ROW: { /* * words 1/2 are a row name, so third word could be a * field in this row. */ PLpgSQL_row *row; int i; row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]); for (i = 0; i < row->nfields; i++) { if (row->fieldnames[i] && strcmp(row->fieldnames[i], word3) == 0) { wdatum->datum = plpgsql_Datums[row->varnos[i]]; wdatum->ident = NULL; wdatum->quoted = false; /* not used */ wdatum->idents = idents; return true; } } /* fall through to return CWORD */ break; } default: break; } } } /* Nothing found */ cword->idents = idents; return false; }
Definition at line 1362 of file pl_comp.c.
References PLwdatum::datum, elog, ERROR, PLword::ident, PLwdatum::ident, IDENTIFIER_LOOKUP_NORMAL, PLwdatum::idents, PLpgSQL_nsitem::itemno, PLpgSQL_nsitem::itemtype, NULL, plpgsql_IdentifierLookup, plpgsql_ns_lookup(), plpgsql_ns_top(), PLPGSQL_NSTYPE_REC, PLPGSQL_NSTYPE_ROW, PLPGSQL_NSTYPE_VAR, PLword::quoted, and PLwdatum::quoted.
Referenced by plpgsql_yylex().
{ PLpgSQL_nsitem *ns; /* * We should do nothing in DECLARE sections. In SQL expressions, there's * no need to do anything either --- lookup will happen when the * expression is compiled. */ if (plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_NORMAL) { /* * Do a lookup in the current namespace stack */ ns = plpgsql_ns_lookup(plpgsql_ns_top(), false, word1, NULL, NULL, NULL); if (ns != NULL) { switch (ns->itemtype) { case PLPGSQL_NSTYPE_VAR: case PLPGSQL_NSTYPE_ROW: case PLPGSQL_NSTYPE_REC: wdatum->datum = plpgsql_Datums[ns->itemno]; wdatum->ident = word1; wdatum->quoted = (yytxt[0] == '"'); wdatum->idents = NIL; return true; default: /* plpgsql_ns_lookup should never return anything else */ elog(ERROR, "unrecognized plpgsql itemtype: %d", ns->itemtype); } } } /* * Nothing found - up to now it's a word without any special meaning for * us. */ word->ident = word1; word->quoted = (yytxt[0] == '"'); return false; }
PLpgSQL_type* plpgsql_parse_wordrowtype | ( | char * | ident | ) |
Definition at line 1815 of file pl_comp.c.
References ereport, errcode(), errmsg(), ERROR, get_rel_type_id(), InvalidOid, OidIsValid, plpgsql_build_datatype(), and RelnameGetRelid().
{ Oid classOid; /* Lookup the relation */ classOid = RelnameGetRelid(ident); if (!OidIsValid(classOid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s\" does not exist", ident))); /* Build and return the row type struct */ return plpgsql_build_datatype(get_rel_type_id(classOid), -1, InvalidOid); }
PLpgSQL_type* plpgsql_parse_wordtype | ( | char * | ident | ) |
Definition at line 1635 of file pl_comp.c.
References build_datatype(), PLpgSQL_function::fn_input_collation, GETSTRUCT, InvalidOid, PLpgSQL_nsitem::itemno, PLpgSQL_nsitem::itemtype, LookupTypeName(), makeTypeName(), NULL, plpgsql_ns_lookup(), plpgsql_ns_top(), PLPGSQL_NSTYPE_VAR, and ReleaseSysCache().
{ PLpgSQL_type *dtype; PLpgSQL_nsitem *nse; HeapTuple typeTup; /* * Do a lookup in the current namespace stack */ nse = plpgsql_ns_lookup(plpgsql_ns_top(), false, ident, NULL, NULL, NULL); if (nse != NULL) { switch (nse->itemtype) { case PLPGSQL_NSTYPE_VAR: return ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; /* XXX perhaps allow REC/ROW here? */ default: return NULL; } } /* * Word wasn't found in the namespace stack. Try to find a data type with * that name, but ignore shell types and complex types. */ typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL); if (typeTup) { Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); if (!typeStruct->typisdefined || typeStruct->typrelid != InvalidOid) { ReleaseSysCache(typeTup); return NULL; } dtype = build_datatype(typeTup, -1, plpgsql_curr_compile->fn_input_collation); ReleaseSysCache(typeTup); return dtype; } /* * Nothing found - up to now it's a word without any special meaning for * us. */ return NULL; }
void plpgsql_parser_setup | ( | struct ParseState * | pstate, | |
PLpgSQL_expr * | expr | |||
) |
Definition at line 1025 of file pl_comp.c.
References ParseState::p_paramref_hook, ParseState::p_post_columnref_hook, ParseState::p_pre_columnref_hook, and ParseState::p_ref_hook_state.
Referenced by exec_prepare_plan(), and setup_param_list().
{ pstate->p_pre_columnref_hook = plpgsql_pre_column_ref; pstate->p_post_columnref_hook = plpgsql_post_column_ref; pstate->p_paramref_hook = plpgsql_param_ref; /* no need to use p_coerce_param_hook */ pstate->p_ref_hook_state = (void *) expr; }
int plpgsql_peek | ( | void | ) |
Definition at line 453 of file pl_scanner.c.
References internal_yylex(), and push_back_token().
{ int tok1; TokenAuxData aux1; tok1 = internal_yylex(&aux1); push_back_token(tok1, &aux1); return tok1; }
void plpgsql_peek2 | ( | int * | tok1_p, | |
int * | tok2_p, | |||
int * | tok1_loc, | |||
int * | tok2_loc | |||
) |
Definition at line 472 of file pl_scanner.c.
References internal_yylex(), TokenAuxData::lloc, and push_back_token().
{ int tok1, tok2; TokenAuxData aux1, aux2; tok1 = internal_yylex(&aux1); tok2 = internal_yylex(&aux2); *tok1_p = tok1; if (tok1_loc) *tok1_loc = aux1.lloc; *tok2_p = tok2; if (tok2_loc) *tok2_loc = aux2.lloc; push_back_token(tok2, &aux2); push_back_token(tok1, &aux1); }
void plpgsql_push_back_token | ( | int | token | ) |
Definition at line 403 of file pl_scanner.c.
References TokenAuxData::leng, TokenAuxData::lloc, TokenAuxData::lval, plpgsql_yyleng, and push_back_token().
{ TokenAuxData auxdata; auxdata.lval = plpgsql_yylval; auxdata.lloc = plpgsql_yylloc; auxdata.leng = plpgsql_yyleng; push_back_token(token, &auxdata); }
int plpgsql_recognize_err_condition | ( | const char * | condname, | |
bool | allow_sqlstate | |||
) |
Definition at line 2210 of file pl_comp.c.
References ereport, errcode(), errmsg(), ERROR, i, label, ExceptionLabelMap::label, MAKE_SQLSTATE, and ExceptionLabelMap::sqlerrstate.
Referenced by exec_stmt_raise().
{ int i; if (allow_sqlstate) { if (strlen(condname) == 5 && strspn(condname, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") == 5) return MAKE_SQLSTATE(condname[0], condname[1], condname[2], condname[3], condname[4]); } for (i = 0; exception_label_map[i].label != NULL; i++) { if (strcmp(condname, exception_label_map[i].label) == 0) return exception_label_map[i].sqlerrstate; } ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("unrecognized exception condition \"%s\"", condname))); return 0; /* keep compiler quiet */ }
int plpgsql_scanner_errposition | ( | int | location | ) |
Definition at line 505 of file pl_scanner.c.
References internalerrposition(), internalerrquery(), NULL, pg_mbstrlen_with_len(), and scanorig.
Referenced by __attribute__().
{ int pos; if (location < 0 || scanorig == NULL) return 0; /* no-op if location is unknown */ /* Convert byte offset to character number */ pos = pg_mbstrlen_with_len(scanorig, location) + 1; /* And pass it to the ereport mechanism */ (void) internalerrposition(pos); /* Also pass the function body string */ return internalerrquery(scanorig); }
void plpgsql_scanner_finish | ( | void | ) |
Definition at line 645 of file pl_scanner.c.
References scanner_finish(), scanorig, and yyscanner.
Referenced by do_compile(), and plpgsql_compile_inline().
{ /* release storage */ scanner_finish(yyscanner); /* avoid leaving any dangling pointers */ yyscanner = NULL; scanorig = NULL; }
void plpgsql_scanner_init | ( | const char * | str | ) |
Definition at line 619 of file pl_scanner.c.
References location_lineno_init(), num_pushbacks, num_reserved_keywords, plpgsql_IdentifierLookup, scanner_init(), scanorig, and yyscanner.
Referenced by do_compile(), and plpgsql_compile_inline().
{ /* Start up the core scanner */ yyscanner = scanner_init(str, &core_yy, reserved_keywords, num_reserved_keywords); /* * scanorig points to the original string, which unlike the scanner's * scanbuf won't be modified on-the-fly by flex. Notice that although * yytext points into scanbuf, we rely on being able to apply locations * (offsets from string start) to scanorig as well. */ scanorig = str; /* Other setup */ plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL; num_pushbacks = 0; location_lineno_init(); }
const char* plpgsql_stmt_typename | ( | PLpgSQL_stmt * | stmt | ) |
Definition at line 213 of file pl_funcs.c.
References _, PLpgSQL_stmt::cmd_type, PLPGSQL_STMT_ASSIGN, PLPGSQL_STMT_BLOCK, PLPGSQL_STMT_CASE, PLPGSQL_STMT_CLOSE, PLPGSQL_STMT_DYNEXECUTE, PLPGSQL_STMT_DYNFORS, PLPGSQL_STMT_EXECSQL, PLPGSQL_STMT_EXIT, PLPGSQL_STMT_FETCH, PLPGSQL_STMT_FORC, PLPGSQL_STMT_FOREACH_A, PLPGSQL_STMT_FORI, PLPGSQL_STMT_FORS, PLPGSQL_STMT_GETDIAG, PLPGSQL_STMT_IF, PLPGSQL_STMT_LOOP, PLPGSQL_STMT_OPEN, PLPGSQL_STMT_PERFORM, PLPGSQL_STMT_RAISE, PLPGSQL_STMT_RETURN, PLPGSQL_STMT_RETURN_NEXT, PLPGSQL_STMT_RETURN_QUERY, and PLPGSQL_STMT_WHILE.
Referenced by plpgsql_exec_error_callback().
{ switch ((enum PLpgSQL_stmt_types) stmt->cmd_type) { case PLPGSQL_STMT_BLOCK: return _("statement block"); case PLPGSQL_STMT_ASSIGN: return _("assignment"); case PLPGSQL_STMT_IF: return "IF"; case PLPGSQL_STMT_CASE: return "CASE"; case PLPGSQL_STMT_LOOP: return "LOOP"; case PLPGSQL_STMT_WHILE: return "WHILE"; case PLPGSQL_STMT_FORI: return _("FOR with integer loop variable"); case PLPGSQL_STMT_FORS: return _("FOR over SELECT rows"); case PLPGSQL_STMT_FORC: return _("FOR over cursor"); case PLPGSQL_STMT_FOREACH_A: return _("FOREACH over array"); case PLPGSQL_STMT_EXIT: return "EXIT"; case PLPGSQL_STMT_RETURN: return "RETURN"; case PLPGSQL_STMT_RETURN_NEXT: return "RETURN NEXT"; case PLPGSQL_STMT_RETURN_QUERY: return "RETURN QUERY"; case PLPGSQL_STMT_RAISE: return "RAISE"; case PLPGSQL_STMT_EXECSQL: return _("SQL statement"); case PLPGSQL_STMT_DYNEXECUTE: return _("EXECUTE statement"); case PLPGSQL_STMT_DYNFORS: return _("FOR over EXECUTE statement"); case PLPGSQL_STMT_GETDIAG: return "GET DIAGNOSTICS"; case PLPGSQL_STMT_OPEN: return "OPEN"; case PLPGSQL_STMT_FETCH: return "FETCH"; case PLPGSQL_STMT_CLOSE: return "CLOSE"; case PLPGSQL_STMT_PERFORM: return "PERFORM"; } return "unknown"; }
void plpgsql_subxact_cb | ( | SubXactEvent | event, | |
SubTransactionId | mySubid, | |||
SubTransactionId | parentSubid, | |||
void * | arg | |||
) |
Definition at line 6178 of file pl_exec.c.
References FreeExprContext(), SimpleEcontextStackEntry::next, NULL, pfree(), SimpleEcontextStackEntry::stack_econtext, SUBXACT_EVENT_ABORT_SUB, SUBXACT_EVENT_COMMIT_SUB, and SimpleEcontextStackEntry::xact_subxid.
Referenced by _PG_init().
{ if (event == SUBXACT_EVENT_COMMIT_SUB || event == SUBXACT_EVENT_ABORT_SUB) { while (simple_econtext_stack != NULL && simple_econtext_stack->xact_subxid == mySubid) { SimpleEcontextStackEntry *next; FreeExprContext(simple_econtext_stack->stack_econtext, (event == SUBXACT_EVENT_COMMIT_SUB)); next = simple_econtext_stack->next; pfree(simple_econtext_stack); simple_econtext_stack = next; } } }
bool plpgsql_token_is_unreserved_keyword | ( | int | token | ) |
Definition at line 420 of file pl_scanner.c.
References i, num_unreserved_keywords, and value.
{ int i; for (i = 0; i < num_unreserved_keywords; i++) { if (unreserved_keywords[i].value == token) return true; } return false; }
Datum plpgsql_validator | ( | PG_FUNCTION_ARGS | ) |
Definition at line 224 of file pl_handler.c.
References check_function_bodies, FunctionCallInfoData::context, CurrentMemoryContext, elog, ereport, errcode(), errmsg(), ERROR, EVTTRIGGEROID, FunctionCallInfoData::flinfo, FmgrInfo::fn_mcxt, FmgrInfo::fn_oid, format_type_be(), get_func_arg_info(), get_typtype(), GETSTRUCT, HeapTupleIsValid, i, IsPolymorphicType, MemSet, ObjectIdGetDatum, OPAQUEOID, PG_GETARG_OID, PG_RETURN_VOID, plpgsql_compile(), PROCOID, RECORDOID, ReleaseSysCache(), SearchSysCache1, SPI_connect(), SPI_finish(), SPI_OK_CONNECT, SPI_OK_FINISH, SPI_result_code_string(), TRIGGEROID, EventTriggerData::type, TriggerData::type, TYPTYPE_PSEUDO, and VOIDOID.
{ Oid funcoid = PG_GETARG_OID(0); HeapTuple tuple; Form_pg_proc proc; char functyptype; int numargs; Oid *argtypes; char **argnames; char *argmodes; bool is_dml_trigger = false; bool is_event_trigger = false; int i; /* Get the new function's pg_proc entry */ tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid)); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for function %u", funcoid); proc = (Form_pg_proc) GETSTRUCT(tuple); functyptype = get_typtype(proc->prorettype); /* Disallow pseudotype result */ /* except for TRIGGER, RECORD, VOID, or polymorphic */ if (functyptype == TYPTYPE_PSEUDO) { /* we assume OPAQUE with no arguments means a trigger */ if (proc->prorettype == TRIGGEROID || (proc->prorettype == OPAQUEOID && proc->pronargs == 0)) is_dml_trigger = true; else if (proc->prorettype == EVTTRIGGEROID) is_event_trigger = true; else if (proc->prorettype != RECORDOID && proc->prorettype != VOIDOID && !IsPolymorphicType(proc->prorettype)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/pgSQL functions cannot return type %s", format_type_be(proc->prorettype)))); } /* Disallow pseudotypes in arguments (either IN or OUT) */ /* except for polymorphic */ numargs = get_func_arg_info(tuple, &argtypes, &argnames, &argmodes); for (i = 0; i < numargs; i++) { if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO) { if (!IsPolymorphicType(argtypes[i])) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/pgSQL functions cannot accept type %s", format_type_be(argtypes[i])))); } } /* Postpone body checks if !check_function_bodies */ if (check_function_bodies) { FunctionCallInfoData fake_fcinfo; FmgrInfo flinfo; int rc; TriggerData trigdata; EventTriggerData etrigdata; /* * Connect to SPI manager (is this needed for compilation?) */ if ((rc = SPI_connect()) != SPI_OK_CONNECT) elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc)); /* * Set up a fake fcinfo with just enough info to satisfy * plpgsql_compile(). */ MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo)); MemSet(&flinfo, 0, sizeof(flinfo)); fake_fcinfo.flinfo = &flinfo; flinfo.fn_oid = funcoid; flinfo.fn_mcxt = CurrentMemoryContext; if (is_dml_trigger) { MemSet(&trigdata, 0, sizeof(trigdata)); trigdata.type = T_TriggerData; fake_fcinfo.context = (Node *) &trigdata; } else if (is_event_trigger) { MemSet(&etrigdata, 0, sizeof(etrigdata)); etrigdata.type = T_EventTriggerData; fake_fcinfo.context = (Node *) &etrigdata; } /* Test-compile the function */ plpgsql_compile(&fake_fcinfo, true); /* * Disconnect from SPI manager */ if ((rc = SPI_finish()) != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc)); } ReleaseSysCache(tuple); PG_RETURN_VOID(); }
void plpgsql_xact_cb | ( | XactEvent | event, | |
void * | arg | |||
) |
Definition at line 6145 of file pl_exec.c.
References Assert, FreeExecutorState(), NULL, XACT_EVENT_ABORT, XACT_EVENT_COMMIT, and XACT_EVENT_PREPARE.
Referenced by _PG_init().
{ /* * If we are doing a clean transaction shutdown, free the EState (so that * any remaining resources will be released correctly). In an abort, we * expect the regular abort recovery procedures to release everything of * interest. */ if (event == XACT_EVENT_COMMIT || event == XACT_EVENT_PREPARE) { /* Shouldn't be any econtext stack entries left at commit */ Assert(simple_econtext_stack == NULL); if (simple_eval_estate) FreeExecutorState(simple_eval_estate); simple_eval_estate = NULL; } else if (event == XACT_EVENT_ABORT) { simple_econtext_stack = NULL; simple_eval_estate = NULL; } }
void plpgsql_yyerror | ( | const char * | message | ) |
int plpgsql_yylex | ( | void | ) |
Definition at line 211 of file pl_scanner.c.
References internal_yylex(), TokenAuxData::leng, TokenAuxData::lloc, TokenAuxData::lval, ScanKeyword::name, num_unreserved_keywords, plpgsql_parse_dblword(), plpgsql_parse_tripword(), plpgsql_parse_word(), plpgsql_yyleng, push_back_token(), core_yy_extra_type::scanbuf, ScanKeywordLookup(), and ScanKeyword::value.
{ int tok1; TokenAuxData aux1; const ScanKeyword *kw; tok1 = internal_yylex(&aux1); if (tok1 == IDENT || tok1 == PARAM) { int tok2; TokenAuxData aux2; tok2 = internal_yylex(&aux2); if (tok2 == '.') { int tok3; TokenAuxData aux3; tok3 = internal_yylex(&aux3); if (tok3 == IDENT) { int tok4; TokenAuxData aux4; tok4 = internal_yylex(&aux4); if (tok4 == '.') { int tok5; TokenAuxData aux5; tok5 = internal_yylex(&aux5); if (tok5 == IDENT) { if (plpgsql_parse_tripword(aux1.lval.str, aux3.lval.str, aux5.lval.str, &aux1.lval.wdatum, &aux1.lval.cword)) tok1 = T_DATUM; else tok1 = T_CWORD; } else { /* not A.B.C, so just process A.B */ push_back_token(tok5, &aux5); push_back_token(tok4, &aux4); if (plpgsql_parse_dblword(aux1.lval.str, aux3.lval.str, &aux1.lval.wdatum, &aux1.lval.cword)) tok1 = T_DATUM; else tok1 = T_CWORD; } } else { /* not A.B.C, so just process A.B */ push_back_token(tok4, &aux4); if (plpgsql_parse_dblword(aux1.lval.str, aux3.lval.str, &aux1.lval.wdatum, &aux1.lval.cword)) tok1 = T_DATUM; else tok1 = T_CWORD; } } else { /* not A.B, so just process A */ push_back_token(tok3, &aux3); push_back_token(tok2, &aux2); if (plpgsql_parse_word(aux1.lval.str, core_yy.scanbuf + aux1.lloc, &aux1.lval.wdatum, &aux1.lval.word)) tok1 = T_DATUM; else if (!aux1.lval.word.quoted && (kw = ScanKeywordLookup(aux1.lval.word.ident, unreserved_keywords, num_unreserved_keywords))) { aux1.lval.keyword = kw->name; tok1 = kw->value; } else tok1 = T_WORD; } } else { /* not A.B, so just process A */ push_back_token(tok2, &aux2); if (plpgsql_parse_word(aux1.lval.str, core_yy.scanbuf + aux1.lloc, &aux1.lval.wdatum, &aux1.lval.word)) tok1 = T_DATUM; else if (!aux1.lval.word.quoted && (kw = ScanKeywordLookup(aux1.lval.word.ident, unreserved_keywords, num_unreserved_keywords))) { aux1.lval.keyword = kw->name; tok1 = kw->value; } else tok1 = T_WORD; } } else { /* Not a potential plpgsql variable name, just return the data */ } plpgsql_yylval = aux1.lval; plpgsql_yylloc = aux1.lloc; plpgsql_yyleng = aux1.leng; return tok1; }
int plpgsql_yyparse | ( | void | ) |
Referenced by do_compile(), and plpgsql_compile_inline().
Definition at line 49 of file pl_comp.c.
Referenced by do_compile(), and plpgsql_compile_inline().
Definition at line 48 of file pl_comp.c.
Referenced by do_compile(), and plpgsql_compile_inline().
char* plpgsql_error_funcname |
Definition at line 47 of file pl_comp.c.
Referenced by do_compile(), plpgsql_compile_error_callback(), and plpgsql_compile_inline().
Definition at line 27 of file pl_scanner.c.
Referenced by plpgsql_parse_dblword(), plpgsql_parse_tripword(), plpgsql_parse_word(), and plpgsql_scanner_init().
int plpgsql_nDatums |
Definition at line 43 of file pl_comp.c.
Referenced by do_compile(), plpgsql_add_initdatums(), plpgsql_adddatum(), and plpgsql_compile_inline().
Definition at line 38 of file pl_handler.c.
Referenced by _PG_init(), do_compile(), and plpgsql_compile_inline().
Definition at line 41 of file pl_handler.c.
Referenced by exec_stmt(), plpgsql_estate_setup(), plpgsql_exec_event_trigger(), plpgsql_exec_function(), and plpgsql_exec_trigger().