Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Enumerations | Functions | Variables

plpgsql.h File Reference

#include "postgres.h"
#include "access/xact.h"
#include "commands/event_trigger.h"
#include "commands/trigger.h"
#include "executor/spi.h"
Include dependency graph for plpgsql.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PLpgSQL_type
struct  PLpgSQL_datum
struct  PLpgSQL_variable
struct  PLpgSQL_expr
struct  PLpgSQL_var
struct  PLpgSQL_row
struct  PLpgSQL_rec
struct  PLpgSQL_recfield
struct  PLpgSQL_arrayelem
struct  PLpgSQL_nsitem
struct  PLpgSQL_stmt
struct  PLpgSQL_condition
struct  PLpgSQL_exception_block
struct  PLpgSQL_exception
struct  PLpgSQL_stmt_block
struct  PLpgSQL_stmt_assign
struct  PLpgSQL_stmt_perform
struct  PLpgSQL_diag_item
struct  PLpgSQL_stmt_getdiag
struct  PLpgSQL_stmt_if
struct  PLpgSQL_if_elsif
struct  PLpgSQL_stmt_case
struct  PLpgSQL_case_when
struct  PLpgSQL_stmt_loop
struct  PLpgSQL_stmt_while
struct  PLpgSQL_stmt_fori
struct  PLpgSQL_stmt_forq
struct  PLpgSQL_stmt_fors
struct  PLpgSQL_stmt_forc
struct  PLpgSQL_stmt_dynfors
struct  PLpgSQL_stmt_foreach_a
struct  PLpgSQL_stmt_open
struct  PLpgSQL_stmt_fetch
struct  PLpgSQL_stmt_close
struct  PLpgSQL_stmt_exit
struct  PLpgSQL_stmt_return
struct  PLpgSQL_stmt_return_next
struct  PLpgSQL_stmt_return_query
struct  PLpgSQL_stmt_raise
struct  PLpgSQL_raise_option
struct  PLpgSQL_stmt_execsql
struct  PLpgSQL_stmt_dynexecute
struct  PLpgSQL_func_hashkey
struct  PLpgSQL_function
struct  PLpgSQL_execstate
struct  PLpgSQL_plugin
struct  PLword
struct  PLcword
struct  PLwdatum

Defines

#define TEXTDOMAIN   PG_TEXTDOMAIN("plpgsql")
#define _(x)   dgettext(TEXTDOMAIN, x)

Typedefs

typedef struct PLpgSQL_expr PLpgSQL_expr
typedef struct PLpgSQL_nsitem PLpgSQL_nsitem
typedef struct PLpgSQL_condition PLpgSQL_condition
typedef struct PLpgSQL_func_hashkey PLpgSQL_func_hashkey
typedef enum PLpgSQL_trigtype PLpgSQL_trigtype
typedef struct PLpgSQL_function PLpgSQL_function
typedef struct PLpgSQL_execstate PLpgSQL_execstate

Enumerations

enum  { PLPGSQL_NSTYPE_LABEL, PLPGSQL_NSTYPE_VAR, PLPGSQL_NSTYPE_ROW, PLPGSQL_NSTYPE_REC }
enum  {
  PLPGSQL_DTYPE_VAR, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_RECFIELD,
  PLPGSQL_DTYPE_ARRAYELEM, PLPGSQL_DTYPE_EXPR
}
enum  { PLPGSQL_TTYPE_SCALAR, PLPGSQL_TTYPE_ROW, PLPGSQL_TTYPE_REC, PLPGSQL_TTYPE_PSEUDO }
enum  PLpgSQL_stmt_types {
  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_RC_OK, PLPGSQL_RC_EXIT, PLPGSQL_RC_RETURN, PLPGSQL_RC_CONTINUE }
enum  {
  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
}
enum  { PLPGSQL_RAISEOPTION_ERRCODE, PLPGSQL_RAISEOPTION_MESSAGE, PLPGSQL_RAISEOPTION_DETAIL, PLPGSQL_RAISEOPTION_HINT }
enum  PLpgSQL_resolve_option { PLPGSQL_RESOLVE_ERROR, PLPGSQL_RESOLVE_VARIABLE, PLPGSQL_RESOLVE_COLUMN }
enum  PLpgSQL_trigtype { PLPGSQL_DML_TRIGGER, PLPGSQL_EVENT_TRIGGER, PLPGSQL_NOT_TRIGGER }
enum  IdentifierLookup { IDENTIFIER_LOOKUP_NORMAL, IDENTIFIER_LOOKUP_DECLARE, IDENTIFIER_LOOKUP_EXPR }

Functions

PLpgSQL_functionplpgsql_compile (FunctionCallInfo fcinfo, bool forValidator)
PLpgSQL_functionplpgsql_compile_inline (char *proc_source)
void plpgsql_parser_setup (struct ParseState *pstate, PLpgSQL_expr *expr)
bool plpgsql_parse_word (char *word1, const char *yytxt, PLwdatum *wdatum, PLword *word)
bool plpgsql_parse_dblword (char *word1, char *word2, PLwdatum *wdatum, PLcword *cword)
bool plpgsql_parse_tripword (char *word1, char *word2, char *word3, PLwdatum *wdatum, PLcword *cword)
PLpgSQL_typeplpgsql_parse_wordtype (char *ident)
PLpgSQL_typeplpgsql_parse_cwordtype (List *idents)
PLpgSQL_typeplpgsql_parse_wordrowtype (char *ident)
PLpgSQL_typeplpgsql_parse_cwordrowtype (List *idents)
PLpgSQL_typeplpgsql_build_datatype (Oid typeOid, int32 typmod, Oid collation)
PLpgSQL_variableplpgsql_build_variable (const char *refname, int lineno, PLpgSQL_type *dtype, bool add2namespace)
PLpgSQL_recplpgsql_build_record (const char *refname, int lineno, bool add2namespace)
int plpgsql_recognize_err_condition (const char *condname, bool allow_sqlstate)
PLpgSQL_conditionplpgsql_parse_err_condition (char *condname)
void plpgsql_adddatum (PLpgSQL_datum *new)
int plpgsql_add_initdatums (int **varnos)
void plpgsql_HashTableInit (void)
void _PG_init (void)
Datum plpgsql_call_handler (PG_FUNCTION_ARGS)
Datum plpgsql_inline_handler (PG_FUNCTION_ARGS)
Datum plpgsql_validator (PG_FUNCTION_ARGS)
Datum plpgsql_exec_function (PLpgSQL_function *func, FunctionCallInfo fcinfo)
HeapTuple plpgsql_exec_trigger (PLpgSQL_function *func, TriggerData *trigdata)
void plpgsql_exec_event_trigger (PLpgSQL_function *func, EventTriggerData *trigdata)
void plpgsql_xact_cb (XactEvent event, void *arg)
void plpgsql_subxact_cb (SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg)
Oid exec_get_datum_type (PLpgSQL_execstate *estate, PLpgSQL_datum *datum)
void exec_get_datum_type_info (PLpgSQL_execstate *estate, PLpgSQL_datum *datum, Oid *typeid, int32 *typmod, Oid *collation)
void plpgsql_ns_init (void)
void plpgsql_ns_push (const char *label)
void plpgsql_ns_pop (void)
PLpgSQL_nsitemplpgsql_ns_top (void)
void plpgsql_ns_additem (int itemtype, int itemno, const char *name)
PLpgSQL_nsitemplpgsql_ns_lookup (PLpgSQL_nsitem *ns_cur, bool localmode, const char *name1, const char *name2, const char *name3, int *names_used)
PLpgSQL_nsitemplpgsql_ns_lookup_label (PLpgSQL_nsitem *ns_cur, const char *name)
const char * plpgsql_stmt_typename (PLpgSQL_stmt *stmt)
const char * plpgsql_getdiag_kindname (int kind)
void plpgsql_free_function_memory (PLpgSQL_function *func)
void plpgsql_dumptree (PLpgSQL_function *func)
int plpgsql_base_yylex (void)
int plpgsql_yylex (void)
void plpgsql_push_back_token (int token)
bool plpgsql_token_is_unreserved_keyword (int token)
void plpgsql_append_source_text (StringInfo buf, int startlocation, int endlocation)
int plpgsql_peek (void)
void plpgsql_peek2 (int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc)
int plpgsql_scanner_errposition (int location)
void plpgsql_yyerror (const char *message)
int plpgsql_location_to_lineno (int location)
int plpgsql_latest_lineno (void)
void plpgsql_scanner_init (const char *str)
void plpgsql_scanner_finish (void)
int plpgsql_yyparse (void)

Variables

IdentifierLookup plpgsql_IdentifierLookup
int plpgsql_variable_conflict
bool plpgsql_check_syntax
bool plpgsql_DumpExecTree
PLpgSQL_stmt_blockplpgsql_parse_result
int plpgsql_nDatums
PLpgSQL_datum ** plpgsql_Datums
char * plpgsql_error_funcname
PLpgSQL_functionplpgsql_curr_compile
MemoryContext compile_tmp_cxt
PLpgSQL_plugin ** plugin_ptr

Define Documentation

#define _ (   x  )     dgettext(TEXTDOMAIN, x)

Definition at line 35 of file plpgsql.h.

#define TEXTDOMAIN   PG_TEXTDOMAIN("plpgsql")

Definition at line 32 of file plpgsql.h.


Typedef Documentation

typedef struct PLpgSQL_expr PLpgSQL_expr

Enumeration Type Documentation

anonymous enum
Enumerator:
PLPGSQL_NSTYPE_LABEL 
PLPGSQL_NSTYPE_VAR 
PLPGSQL_NSTYPE_ROW 
PLPGSQL_NSTYPE_REC 

Definition at line 41 of file plpgsql.h.

{
    PLPGSQL_NSTYPE_LABEL,
    PLPGSQL_NSTYPE_VAR,
    PLPGSQL_NSTYPE_ROW,
    PLPGSQL_NSTYPE_REC
};

anonymous enum
Enumerator:
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
Enumerator:
PLPGSQL_TTYPE_SCALAR 
PLPGSQL_TTYPE_ROW 
PLPGSQL_TTYPE_REC 
PLPGSQL_TTYPE_PSEUDO 

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
Enumerator:
PLPGSQL_RC_OK 
PLPGSQL_RC_EXIT 
PLPGSQL_RC_RETURN 
PLPGSQL_RC_CONTINUE 

Definition at line 111 of file plpgsql.h.

{
    PLPGSQL_RC_OK,
    PLPGSQL_RC_EXIT,
    PLPGSQL_RC_RETURN,
    PLPGSQL_RC_CONTINUE
};

anonymous enum
Enumerator:
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 

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
Enumerator:
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
};

Enumerator:
IDENTIFIER_LOOKUP_NORMAL 
IDENTIFIER_LOOKUP_DECLARE 
IDENTIFIER_LOOKUP_EXPR 

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;

Enumerator:
PLPGSQL_RESOLVE_ERROR 
PLPGSQL_RESOLVE_VARIABLE 
PLPGSQL_RESOLVE_COLUMN 

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;

Enumerator:
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 

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
};

Enumerator:
PLPGSQL_DML_TRIGGER 
PLPGSQL_EVENT_TRIGGER 
PLPGSQL_NOT_TRIGGER 

Definition at line 679 of file plpgsql.h.

{
    PLPGSQL_DML_TRIGGER,
    PLPGSQL_EVENT_TRIGGER,
    PLPGSQL_NOT_TRIGGER
} PLpgSQL_trigtype;


Function Documentation

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  ) 
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.

{
    while (ns_cur != NULL)
    {
        if (ns_cur->itemtype == PLPGSQL_NSTYPE_LABEL &&
            strcmp(ns_cur->name, name) == 0)
            return ns_cur;
        ns_cur = ns_cur->prev;
    }

    return NULL;                /* label not found */
}

void plpgsql_ns_pop ( void   ) 
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().

PLpgSQL_nsitem* plpgsql_ns_top ( void   ) 
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;
}

bool plpgsql_parse_dblword ( char *  word1,
char *  word2,
PLwdatum wdatum,
PLcword cword 
)

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;
}

bool plpgsql_parse_word ( char *  word1,
const char *  yytxt,
PLwdatum wdatum,
PLword word 
)

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 
)
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   ) 

Variable Documentation

Definition at line 54 of file pl_comp.c.

Definition at line 49 of file pl_comp.c.

Referenced by do_compile(), and plpgsql_compile_inline().

Definition at line 51 of file pl_comp.c.

Definition at line 44 of file pl_comp.c.

Definition at line 48 of file pl_comp.c.

Referenced by do_compile(), and plpgsql_compile_inline().

Definition at line 47 of file pl_comp.c.

Referenced by do_compile(), plpgsql_compile_error_callback(), and plpgsql_compile_inline().

Definition at line 40 of file pl_comp.c.

Definition at line 38 of file pl_handler.c.

Referenced by _PG_init(), do_compile(), and plpgsql_compile_inline().