#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().
1.7.1