Header And Logo

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

Data Structures | Defines | Typedefs | Functions | Variables

pl_comp.c File Reference

#include "plpgsql.h"
#include <ctype.h>
#include "access/htup_details.h"
#include "catalog/namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_proc_fn.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "nodes/makefuncs.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/syscache.h"
#include "plerrcodes.h"
Include dependency graph for pl_comp.c:

Go to the source code of this file.

Data Structures

struct  plpgsql_hashent
struct  ExceptionLabelMap

Defines

#define FUNCS_PER_USER   128

Typedefs

typedef struct plpgsql_hashent plpgsql_HashEnt

Functions

static PLpgSQL_functiondo_compile (FunctionCallInfo fcinfo, HeapTuple procTup, PLpgSQL_function *function, PLpgSQL_func_hashkey *hashkey, bool forValidator)
static void plpgsql_compile_error_callback (void *arg)
static void add_parameter_name (int itemtype, int itemno, const char *name)
static void add_dummy_return (PLpgSQL_function *function)
static Nodeplpgsql_pre_column_ref (ParseState *pstate, ColumnRef *cref)
static Nodeplpgsql_post_column_ref (ParseState *pstate, ColumnRef *cref, Node *var)
static Nodeplpgsql_param_ref (ParseState *pstate, ParamRef *pref)
static Noderesolve_column_ref (ParseState *pstate, PLpgSQL_expr *expr, ColumnRef *cref, bool error_if_no_field)
static Nodemake_datum_param (PLpgSQL_expr *expr, int dno, int location)
static PLpgSQL_rowbuild_row_from_class (Oid classOid)
static PLpgSQL_rowbuild_row_from_vars (PLpgSQL_variable **vars, int numvars)
static PLpgSQL_typebuild_datatype (HeapTuple typeTup, int32 typmod, Oid collation)
static void compute_function_hashkey (FunctionCallInfo fcinfo, Form_pg_proc procStruct, PLpgSQL_func_hashkey *hashkey, bool forValidator)
static void plpgsql_resolve_polymorphic_argtypes (int numargs, Oid *argtypes, char *argmodes, Node *call_expr, bool forValidator, const char *proname)
static PLpgSQL_functionplpgsql_HashTableLookup (PLpgSQL_func_hashkey *func_key)
static void plpgsql_HashTableInsert (PLpgSQL_function *function, PLpgSQL_func_hashkey *func_key)
static void plpgsql_HashTableDelete (PLpgSQL_function *function)
static void delete_function (PLpgSQL_function *func)
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_variableplpgsql_build_variable (const char *refname, int lineno, PLpgSQL_type *dtype, bool add2namespace)
PLpgSQL_recplpgsql_build_record (const char *refname, int lineno, bool add2namespace)
PLpgSQL_typeplpgsql_build_datatype (Oid typeOid, int32 typmod, Oid collation)
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)

Variables

PLpgSQL_stmt_blockplpgsql_parse_result
static int datums_alloc
int plpgsql_nDatums
PLpgSQL_datum ** plpgsql_Datums
static int datums_last = 0
char * plpgsql_error_funcname
bool plpgsql_DumpExecTree = false
bool plpgsql_check_syntax = false
PLpgSQL_functionplpgsql_curr_compile
MemoryContext compile_tmp_cxt
static HTABplpgsql_HashTable = NULL
static const ExceptionLabelMap exception_label_map []

Define Documentation

#define FUNCS_PER_USER   128

Definition at line 68 of file pl_comp.c.

Referenced by plpgsql_HashTableInit().


Typedef Documentation


Function Documentation

static void add_dummy_return ( PLpgSQL_function function  )  [static]

Definition at line 984 of file pl_comp.c.

References PLpgSQL_function::action, PLpgSQL_stmt_block::body, PLpgSQL_stmt_block::exceptions, lappend(), list_make1, llast, NIL, NULL, PLpgSQL_function::out_param_varno, palloc0(), and PLPGSQL_STMT_RETURN.

Referenced by do_compile(), and plpgsql_compile_inline().

{
    /*
     * If the outer block has an EXCEPTION clause, we need to make a new outer
     * block, since the added RETURN shouldn't act like it is inside the
     * EXCEPTION clause.
     */
    if (function->action->exceptions != NULL)
    {
        PLpgSQL_stmt_block *new;

        new = palloc0(sizeof(PLpgSQL_stmt_block));
        new->cmd_type = PLPGSQL_STMT_BLOCK;
        new->body = list_make1(function->action);

        function->action = new;
    }
    if (function->action->body == NIL ||
        ((PLpgSQL_stmt *) llast(function->action->body))->cmd_type != PLPGSQL_STMT_RETURN)
    {
        PLpgSQL_stmt_return *new;

        new = palloc0(sizeof(PLpgSQL_stmt_return));
        new->cmd_type = PLPGSQL_STMT_RETURN;
        new->expr = NULL;
        new->retvarno = function->out_param_varno;

        function->action->body = lappend(function->action->body, new);
    }
}

static void add_parameter_name ( int  itemtype,
int  itemno,
const char *  name 
) [static]

Definition at line 959 of file pl_comp.c.

References ereport, errcode(), errmsg(), ERROR, NULL, plpgsql_ns_additem(), plpgsql_ns_lookup(), and plpgsql_ns_top().

Referenced by do_compile().

{
    /*
     * Before adding the name, check for duplicates.  We need this even though
     * functioncmds.c has a similar check, because that code explicitly
     * doesn't complain about conflicting IN and OUT parameter names.  In
     * plpgsql, such names are in the same namespace, so there is no way to
     * disambiguate.
     */
    if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
                          name, NULL, NULL,
                          NULL) != NULL)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                 errmsg("parameter name \"%s\" used more than once",
                        name)));

    /* OK, add the name */
    plpgsql_ns_additem(itemtype, itemno, name);
}

static PLpgSQL_type * build_datatype ( HeapTuple  typeTup,
int32  typmod,
Oid  collation 
) [static]

Definition at line 2151 of file pl_comp.c.

References Assert, PLpgSQL_type::atttypmod, PLpgSQL_type::collation, elog, ereport, errcode(), errmsg(), ERROR, fmgr_info(), GETSTRUCT, getTypeIOParam(), HeapTupleGetOid, NameStr, OidIsValid, palloc(), pstrdup(), RECORDOID, PLpgSQL_type::ttype, PLpgSQL_type::typbyval, PLpgSQL_type::typinput, PLpgSQL_type::typioparam, PLpgSQL_type::typlen, PLpgSQL_type::typname, PLpgSQL_type::typoid, PLpgSQL_type::typrelid, TYPTYPE_BASE, TYPTYPE_COMPOSITE, TYPTYPE_DOMAIN, TYPTYPE_ENUM, TYPTYPE_PSEUDO, and TYPTYPE_RANGE.

Referenced by do_compile(), plpgsql_build_datatype(), plpgsql_parse_cwordtype(), and plpgsql_parse_wordtype().

{
    Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
    PLpgSQL_type *typ;

    if (!typeStruct->typisdefined)
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("type \"%s\" is only a shell",
                        NameStr(typeStruct->typname))));

    typ = (PLpgSQL_type *) palloc(sizeof(PLpgSQL_type));

    typ->typname = pstrdup(NameStr(typeStruct->typname));
    typ->typoid = HeapTupleGetOid(typeTup);
    switch (typeStruct->typtype)
    {
        case TYPTYPE_BASE:
        case TYPTYPE_DOMAIN:
        case TYPTYPE_ENUM:
        case TYPTYPE_RANGE:
            typ->ttype = PLPGSQL_TTYPE_SCALAR;
            break;
        case TYPTYPE_COMPOSITE:
            Assert(OidIsValid(typeStruct->typrelid));
            typ->ttype = PLPGSQL_TTYPE_ROW;
            break;
        case TYPTYPE_PSEUDO:
            if (typ->typoid == RECORDOID)
                typ->ttype = PLPGSQL_TTYPE_REC;
            else
                typ->ttype = PLPGSQL_TTYPE_PSEUDO;
            break;
        default:
            elog(ERROR, "unrecognized typtype: %d",
                 (int) typeStruct->typtype);
            break;
    }
    typ->typlen = typeStruct->typlen;
    typ->typbyval = typeStruct->typbyval;
    typ->typrelid = typeStruct->typrelid;
    typ->typioparam = getTypeIOParam(typeTup);
    typ->collation = typeStruct->typcollation;
    if (OidIsValid(collation) && OidIsValid(typ->collation))
        typ->collation = collation;
    fmgr_info(typeStruct->typinput, &(typ->typinput));
    typ->atttypmod = typmod;

    return typ;
}

static PLpgSQL_row * build_row_from_class ( Oid  classOid  )  [static]

Definition at line 1972 of file pl_comp.c.

References AccessShareLock, tupleDesc::attrs, CreateTupleDescCopy(), PLpgSQL_row::dtype, ereport, errcode(), errmsg(), ERROR, PLpgSQL_row::fieldnames, i, NAMEDATALEN, NameStr, PLpgSQL_row::nfields, palloc(), palloc0(), plpgsql_build_datatype(), plpgsql_build_variable(), relation_close(), relation_open(), RelationGetDescr, RelationGetForm, RelationGetRelationName, RELKIND_COMPOSITE_TYPE, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, PLpgSQL_row::rowtupdesc, snprintf(), and PLpgSQL_row::varnos.

Referenced by plpgsql_build_variable().

{
    PLpgSQL_row *row;
    Relation    rel;
    Form_pg_class classStruct;
    const char *relname;
    int         i;

    /*
     * Open the relation to get info.
     */
    rel = relation_open(classOid, AccessShareLock);
    classStruct = RelationGetForm(rel);
    relname = RelationGetRelationName(rel);

    /*
     * Accept 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)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("relation \"%s\" is not a table", relname)));

    /*
     * Create a row datum entry and all the required variables that it will
     * point to.
     */
    row = palloc0(sizeof(PLpgSQL_row));
    row->dtype = PLPGSQL_DTYPE_ROW;
    row->rowtupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
    row->nfields = classStruct->relnatts;
    row->fieldnames = palloc(sizeof(char *) * row->nfields);
    row->varnos = palloc(sizeof(int) * row->nfields);

    for (i = 0; i < row->nfields; i++)
    {
        Form_pg_attribute attrStruct;

        /*
         * Get the attribute and check for dropped column
         */
        attrStruct = row->rowtupdesc->attrs[i];

        if (!attrStruct->attisdropped)
        {
            char       *attname;
            char        refname[(NAMEDATALEN * 2) + 100];
            PLpgSQL_variable *var;

            attname = NameStr(attrStruct->attname);
            snprintf(refname, sizeof(refname), "%s.%s", relname, attname);

            /*
             * Create the internal variable for the field
             *
             * We know if the table definitions contain a default value or if
             * the field is declared in the table as NOT NULL. But it's
             * possible to create a table field as NOT NULL without a default
             * value and that would lead to problems later when initializing
             * the variables due to entering a block at execution time. Thus
             * we ignore this information for now.
             */
            var = plpgsql_build_variable(refname, 0,
                                 plpgsql_build_datatype(attrStruct->atttypid,
                                                        attrStruct->atttypmod,
                                                   attrStruct->attcollation),
                                         false);

            /* Add the variable to the row */
            row->fieldnames[i] = attname;
            row->varnos[i] = var->dno;
        }
        else
        {
            /* Leave a hole in the row structure for the dropped col */
            row->fieldnames[i] = NULL;
            row->varnos[i] = -1;
        }
    }

    relation_close(rel, AccessShareLock);

    return row;
}

static PLpgSQL_row * build_row_from_vars ( PLpgSQL_variable **  vars,
int  numvars 
) [static]

Definition at line 2067 of file pl_comp.c.

References CreateTemplateTupleDesc(), PLpgSQL_variable::dno, PLpgSQL_variable::dtype, PLpgSQL_row::dtype, elog, ERROR, PLpgSQL_row::fieldnames, i, PLpgSQL_row::nfields, palloc(), palloc0(), PLPGSQL_DTYPE_REC, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, PLpgSQL_variable::refname, PLpgSQL_row::rowtupdesc, TupleDescInitEntry(), TupleDescInitEntryCollation(), and PLpgSQL_row::varnos.

Referenced by do_compile().

{
    PLpgSQL_row *row;
    int         i;

    row = palloc0(sizeof(PLpgSQL_row));
    row->dtype = PLPGSQL_DTYPE_ROW;
    row->rowtupdesc = CreateTemplateTupleDesc(numvars, false);
    row->nfields = numvars;
    row->fieldnames = palloc(numvars * sizeof(char *));
    row->varnos = palloc(numvars * sizeof(int));

    for (i = 0; i < numvars; i++)
    {
        PLpgSQL_variable *var = vars[i];
        Oid         typoid = RECORDOID;
        int32       typmod = -1;
        Oid         typcoll = InvalidOid;

        switch (var->dtype)
        {
            case PLPGSQL_DTYPE_VAR:
                typoid = ((PLpgSQL_var *) var)->datatype->typoid;
                typmod = ((PLpgSQL_var *) var)->datatype->atttypmod;
                typcoll = ((PLpgSQL_var *) var)->datatype->collation;
                break;

            case PLPGSQL_DTYPE_REC:
                break;

            case PLPGSQL_DTYPE_ROW:
                if (((PLpgSQL_row *) var)->rowtupdesc)
                {
                    typoid = ((PLpgSQL_row *) var)->rowtupdesc->tdtypeid;
                    typmod = ((PLpgSQL_row *) var)->rowtupdesc->tdtypmod;
                    /* composite types have no collation */
                }
                break;

            default:
                elog(ERROR, "unrecognized dtype: %d", var->dtype);
        }

        row->fieldnames[i] = var->refname;
        row->varnos[i] = var->dno;

        TupleDescInitEntry(row->rowtupdesc, i + 1,
                           var->refname,
                           typoid, typmod,
                           0);
        TupleDescInitEntryCollation(row->rowtupdesc, i + 1, typcoll);
    }

    return row;
}

static void compute_function_hashkey ( FunctionCallInfo  fcinfo,
Form_pg_proc  procStruct,
PLpgSQL_func_hashkey hashkey,
bool  forValidator 
) [static]

Definition at line 2378 of file pl_comp.c.

References PLpgSQL_func_hashkey::argtypes, CALLED_AS_TRIGGER, FunctionCallInfoData::context, FunctionCallInfoData::flinfo, FmgrInfo::fn_expr, FmgrInfo::fn_oid, FunctionCallInfoData::fncollation, PLpgSQL_func_hashkey::funcOid, PLpgSQL_func_hashkey::inputCollation, PLpgSQL_func_hashkey::isTrigger, MemSet, NameStr, NULL, plpgsql_resolve_polymorphic_argtypes(), RelationGetRelid, TriggerData::tg_relation, and PLpgSQL_func_hashkey::trigrelOid.

Referenced by plpgsql_compile().

{
    /* Make sure any unused bytes of the struct are zero */
    MemSet(hashkey, 0, sizeof(PLpgSQL_func_hashkey));

    /* get function OID */
    hashkey->funcOid = fcinfo->flinfo->fn_oid;

    /* get call context */
    hashkey->isTrigger = CALLED_AS_TRIGGER(fcinfo);

    /*
     * if trigger, get relation OID.  In validation mode we do not know what
     * relation is intended to be used, so we leave trigrelOid zero; the hash
     * entry built in this case will never really be used.
     */
    if (hashkey->isTrigger && !forValidator)
    {
        TriggerData *trigdata = (TriggerData *) fcinfo->context;

        hashkey->trigrelOid = RelationGetRelid(trigdata->tg_relation);
    }

    /* get input collation, if known */
    hashkey->inputCollation = fcinfo->fncollation;

    if (procStruct->pronargs > 0)
    {
        /* get the argument types */
        memcpy(hashkey->argtypes, procStruct->proargtypes.values,
               procStruct->pronargs * sizeof(Oid));

        /* resolve any polymorphic argument types */
        plpgsql_resolve_polymorphic_argtypes(procStruct->pronargs,
                                             hashkey->argtypes,
                                             NULL,
                                             fcinfo->flinfo->fn_expr,
                                             forValidator,
                                             NameStr(procStruct->proname));
    }
}

static void delete_function ( PLpgSQL_function func  )  [static]

Definition at line 2488 of file pl_comp.c.

References plpgsql_free_function_memory(), plpgsql_HashTableDelete(), and PLpgSQL_function::use_count.

Referenced by plpgsql_compile().

{
    /* remove function from hash table (might be done already) */
    plpgsql_HashTableDelete(func);

    /* release the function's storage if safe and not done already */
    if (func->use_count == 0)
        plpgsql_free_function_memory(func);
}

static PLpgSQL_function * do_compile ( FunctionCallInfo  fcinfo,
HeapTuple  procTup,
PLpgSQL_function function,
PLpgSQL_func_hashkey hashkey,
bool  forValidator 
) [static]

Definition at line 260 of file pl_comp.c.

References PLpgSQL_function::action, add_dummy_return(), add_parameter_name(), ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), Anum_pg_proc_prosrc, ANYARRAYOID, ANYRANGEOID, ErrorContextCallback::arg, Assert, BOOLOID, buf, build_datatype(), build_row_from_vars(), ErrorContextCallback::callback, CALLED_AS_EVENT_TRIGGER, CALLED_AS_TRIGGER, PLpgSQL_function::datums, datums_alloc, datums_last, PLpgSQL_rec::dno, PLpgSQL_datum::dno, PLpgSQL_variable::dno, PLpgSQL_variable::dtype, elog, ereport, errcode(), errhint(), errmsg(), ERROR, error_context_stack, EVTTRIGGEROID, FunctionCallInfoData::flinfo, fmgr_info(), PLpgSQL_function::fn_argvarnos, PLpgSQL_function::fn_cxt, FmgrInfo::fn_expr, PLpgSQL_function::fn_input_collation, PLpgSQL_function::fn_is_trigger, PLpgSQL_function::fn_nargs, PLpgSQL_function::fn_oid, FmgrInfo::fn_oid, 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::fn_tid, PLpgSQL_function::fn_xmin, FunctionCallInfoData::fncollation, format_procedure(), format_type_be(), PLpgSQL_function::found_varno, get_fn_expr_rettype(), get_func_arg_info(), GETSTRUCT, getTypeIOParam(), HeapTupleHeaderGetXmin, HeapTupleIsValid, i, INT4OID, InvalidOid, IsPolymorphicType, MemoryContextAlloc(), MemoryContextAllocZero(), MemoryContextSwitchTo(), NAMEOID, NameStr, PLpgSQL_function::ndatums, PLpgSQL_function::new_varno, NULL, ObjectIdGetDatum, OidIsValid, OIDOID, PLpgSQL_function::old_varno, PLpgSQL_function::out_param_varno, palloc(), pfree(), plpgsql_adddatum(), plpgsql_build_datatype(), plpgsql_build_record(), plpgsql_build_variable(), plpgsql_check_syntax, PLPGSQL_DML_TRIGGER, PLPGSQL_DTYPE_ROW, PLPGSQL_DTYPE_VAR, plpgsql_DumpExecTree, plpgsql_dumptree(), plpgsql_error_funcname, PLPGSQL_EVENT_TRIGGER, plpgsql_HashTableInsert(), plpgsql_nDatums, PLPGSQL_NOT_TRIGGER, plpgsql_ns_init(), plpgsql_ns_push(), plpgsql_resolve_polymorphic_argtypes(), plpgsql_scanner_finish(), plpgsql_scanner_init(), PLPGSQL_TTYPE_ROW, PLPGSQL_TTYPE_SCALAR, plpgsql_variable_conflict, plpgsql_yyparse(), ErrorContextCallback::previous, PROARGMODE_IN, PROARGMODE_INOUT, PROARGMODE_OUT, PROARGMODE_TABLE, PROARGMODE_VARIADIC, PROCOID, pstrdup(), RECORDOID, ReleaseSysCache(), PLpgSQL_function::resolve_option, SearchSysCache1, snprintf(), SysCacheGetAttr(), HeapTupleData::t_data, HeapTupleData::t_self, TEXTARRAYOID, TextDatumGetCString, TEXTOID, PLpgSQL_function::tg_argv_varno, PLpgSQL_function::tg_event_varno, PLpgSQL_function::tg_level_varno, PLpgSQL_function::tg_name_varno, PLpgSQL_function::tg_nargs_varno, PLpgSQL_function::tg_op_varno, PLpgSQL_function::tg_relid_varno, PLpgSQL_function::tg_relname_varno, PLpgSQL_function::tg_table_name_varno, PLpgSQL_function::tg_table_schema_varno, PLpgSQL_function::tg_tag_varno, PLpgSQL_function::tg_when_varno, TopMemoryContext, TRIGGEROID, PLpgSQL_type::ttype, TYPEOID, TYPTYPE_PSEUDO, and VOIDOID.

Referenced by plpgsql_compile().

{
    Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
    bool        is_dml_trigger = CALLED_AS_TRIGGER(fcinfo);
    bool        is_event_trigger = CALLED_AS_EVENT_TRIGGER(fcinfo);
    Datum       prosrcdatum;
    bool        isnull;
    char       *proc_source;
    HeapTuple   typeTup;
    Form_pg_type typeStruct;
    PLpgSQL_variable *var;
    PLpgSQL_rec *rec;
    int         i;
    ErrorContextCallback plerrcontext;
    int         parse_rc;
    Oid         rettypeid;
    int         numargs;
    int         num_in_args = 0;
    int         num_out_args = 0;
    Oid        *argtypes;
    char      **argnames;
    char       *argmodes;
    int        *in_arg_varnos = NULL;
    PLpgSQL_variable **out_arg_variables;
    MemoryContext func_cxt;

    /*
     * 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.
     */
    prosrcdatum = SysCacheGetAttr(PROCOID, procTup,
                                  Anum_pg_proc_prosrc, &isnull);
    if (isnull)
        elog(ERROR, "null prosrc");
    proc_source = TextDatumGetCString(prosrcdatum);
    plpgsql_scanner_init(proc_source);

    plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));

    /*
     * Setup error traceback support for ereport()
     */
    plerrcontext.callback = plpgsql_compile_error_callback;
    plerrcontext.arg = forValidator ? proc_source : NULL;
    plerrcontext.previous = error_context_stack;
    error_context_stack = &plerrcontext;

    /*
     * Do extra syntax checks when validating the function definition. We skip
     * this when actually compiling functions for execution, for performance
     * reasons.
     */
    plpgsql_check_syntax = forValidator;

    /*
     * Create the new function struct, if not done already.  The function
     * structs are never thrown away, so keep them in TopMemoryContext.
     */
    if (function == NULL)
    {
        function = (PLpgSQL_function *)
            MemoryContextAllocZero(TopMemoryContext, sizeof(PLpgSQL_function));
    }
    else
    {
        /* re-using a previously existing struct, so clear it out */
        memset(function, 0, sizeof(PLpgSQL_function));
    }
    plpgsql_curr_compile = function;

    /*
     * All the permanent output of compilation (e.g. parse tree) is kept in a
     * per-function memory context, so it can be reclaimed easily.
     */
    func_cxt = AllocSetContextCreate(TopMemoryContext,
                                     "PL/pgSQL function context",
                                     ALLOCSET_DEFAULT_MINSIZE,
                                     ALLOCSET_DEFAULT_INITSIZE,
                                     ALLOCSET_DEFAULT_MAXSIZE);
    compile_tmp_cxt = MemoryContextSwitchTo(func_cxt);

    function->fn_signature = format_procedure(fcinfo->flinfo->fn_oid);
    function->fn_oid = fcinfo->flinfo->fn_oid;
    function->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
    function->fn_tid = procTup->t_self;
    function->fn_input_collation = fcinfo->fncollation;
    function->fn_cxt = func_cxt;
    function->out_param_varno = -1;     /* set up for no OUT param */
    function->resolve_option = plpgsql_variable_conflict;

    if (is_dml_trigger)
        function->fn_is_trigger = PLPGSQL_DML_TRIGGER;
    else if (is_event_trigger)
        function->fn_is_trigger = PLPGSQL_EVENT_TRIGGER;
    else
        function->fn_is_trigger = PLPGSQL_NOT_TRIGGER;

    /*
     * Initialize the compiler, particularly the namespace stack.  The
     * outermost namespace contains function parameters and other special
     * variables (such as FOUND), and is named after the function itself.
     */
    plpgsql_ns_init();
    plpgsql_ns_push(NameStr(procStruct->proname));
    plpgsql_DumpExecTree = false;

    datums_alloc = 128;
    plpgsql_nDatums = 0;
    /* This is short-lived, so needn't allocate in function's cxt */
    plpgsql_Datums = MemoryContextAlloc(compile_tmp_cxt,
                                     sizeof(PLpgSQL_datum *) * datums_alloc);
    datums_last = 0;

    switch (function->fn_is_trigger)
    {
        case PLPGSQL_NOT_TRIGGER:

            /*
             * Fetch info about the procedure's parameters. Allocations aren't
             * needed permanently, so make them in tmp cxt.
             *
             * We also need to resolve any polymorphic input or output
             * argument types.  In validation mode we won't be able to, so we
             * arbitrarily assume we are dealing with integers.
             */
            MemoryContextSwitchTo(compile_tmp_cxt);

            numargs = get_func_arg_info(procTup,
                                        &argtypes, &argnames, &argmodes);

            plpgsql_resolve_polymorphic_argtypes(numargs, argtypes, argmodes,
                                                 fcinfo->flinfo->fn_expr,
                                                 forValidator,
                                                 plpgsql_error_funcname);

            in_arg_varnos = (int *) palloc(numargs * sizeof(int));
            out_arg_variables = (PLpgSQL_variable **) palloc(numargs * sizeof(PLpgSQL_variable *));

            MemoryContextSwitchTo(func_cxt);

            /*
             * Create the variables for the procedure's parameters.
             */
            for (i = 0; i < numargs; i++)
            {
                char        buf[32];
                Oid         argtypeid = argtypes[i];
                char        argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
                PLpgSQL_type *argdtype;
                PLpgSQL_variable *argvariable;
                int         argitemtype;

                /* Create $n name for variable */
                snprintf(buf, sizeof(buf), "$%d", i + 1);

                /* Create datatype info */
                argdtype = plpgsql_build_datatype(argtypeid,
                                                  -1,
                                               function->fn_input_collation);

                /* Disallow pseudotype argument */
                /* (note we already replaced polymorphic types) */
                /* (build_variable would do this, but wrong message) */
                if (argdtype->ttype != PLPGSQL_TTYPE_SCALAR &&
                    argdtype->ttype != PLPGSQL_TTYPE_ROW)
                    ereport(ERROR,
                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                           errmsg("PL/pgSQL functions cannot accept type %s",
                                  format_type_be(argtypeid))));

                /* Build variable and add to datum list */
                argvariable = plpgsql_build_variable(buf, 0,
                                                     argdtype, false);

                if (argvariable->dtype == PLPGSQL_DTYPE_VAR)
                {
                    argitemtype = PLPGSQL_NSTYPE_VAR;
                }
                else
                {
                    Assert(argvariable->dtype == PLPGSQL_DTYPE_ROW);
                    argitemtype = PLPGSQL_NSTYPE_ROW;
                }

                /* Remember arguments in appropriate arrays */
                if (argmode == PROARGMODE_IN ||
                    argmode == PROARGMODE_INOUT ||
                    argmode == PROARGMODE_VARIADIC)
                    in_arg_varnos[num_in_args++] = argvariable->dno;
                if (argmode == PROARGMODE_OUT ||
                    argmode == PROARGMODE_INOUT ||
                    argmode == PROARGMODE_TABLE)
                    out_arg_variables[num_out_args++] = argvariable;

                /* Add to namespace under the $n name */
                add_parameter_name(argitemtype, argvariable->dno, buf);

                /* If there's a name for the argument, make an alias */
                if (argnames && argnames[i][0] != '\0')
                    add_parameter_name(argitemtype, argvariable->dno,
                                       argnames[i]);
            }

            /*
             * If there's just one OUT parameter, out_param_varno points
             * directly to it.  If there's more than one, build a row that
             * holds all of them.
             */
            if (num_out_args == 1)
                function->out_param_varno = out_arg_variables[0]->dno;
            else if (num_out_args > 1)
            {
                PLpgSQL_row *row = build_row_from_vars(out_arg_variables,
                                                       num_out_args);

                plpgsql_adddatum((PLpgSQL_datum *) row);
                function->out_param_varno = row->dno;
            }

            /*
             * Check for a polymorphic returntype. If found, use the actual
             * returntype type from the caller's FuncExpr node, if we have
             * one.  (In validation mode we arbitrarily assume we are dealing
             * with integers.)
             *
             * Note: errcode is FEATURE_NOT_SUPPORTED because it should always
             * work; if it doesn't we're in some context that fails to make
             * the info available.
             */
            rettypeid = procStruct->prorettype;
            if (IsPolymorphicType(rettypeid))
            {
                if (forValidator)
                {
                    if (rettypeid == ANYARRAYOID)
                        rettypeid = INT4ARRAYOID;
                    else if (rettypeid == ANYRANGEOID)
                        rettypeid = INT4RANGEOID;
                    else    /* ANYELEMENT or ANYNONARRAY */
                        rettypeid = INT4OID;
                    /* XXX what could we use for ANYENUM? */
                }
                else
                {
                    rettypeid = get_fn_expr_rettype(fcinfo->flinfo);
                    if (!OidIsValid(rettypeid))
                        ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                             errmsg("could not determine actual return type "
                                    "for polymorphic function \"%s\"",
                                    plpgsql_error_funcname)));
                }
            }

            /*
             * Normal function has a defined returntype
             */
            function->fn_rettype = rettypeid;
            function->fn_retset = procStruct->proretset;

            /*
             * Lookup the function's return type
             */
            typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettypeid));
            if (!HeapTupleIsValid(typeTup))
                elog(ERROR, "cache lookup failed for type %u", rettypeid);
            typeStruct = (Form_pg_type) GETSTRUCT(typeTup);

            /* Disallow pseudotype result, except VOID or RECORD */
            /* (note we already replaced polymorphic types) */
            if (typeStruct->typtype == TYPTYPE_PSEUDO)
            {
                if (rettypeid == VOIDOID ||
                    rettypeid == RECORDOID)
                     /* okay */ ;
                else if (rettypeid == TRIGGEROID || rettypeid == EVTTRIGGEROID)
                    ereport(ERROR,
                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                             errmsg("trigger functions can only be called as triggers")));
                else
                    ereport(ERROR,
                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                           errmsg("PL/pgSQL functions cannot return type %s",
                                  format_type_be(rettypeid))));
            }

            if (typeStruct->typrelid != InvalidOid ||
                rettypeid == RECORDOID)
                function->fn_retistuple = true;
            else
            {
                function->fn_retbyval = typeStruct->typbyval;
                function->fn_rettyplen = typeStruct->typlen;
                function->fn_rettypioparam = getTypeIOParam(typeTup);
                fmgr_info(typeStruct->typinput, &(function->fn_retinput));

                /*
                 * install $0 reference, but only for polymorphic return
                 * types, and not when the return is specified through an
                 * output parameter.
                 */
                if (IsPolymorphicType(procStruct->prorettype) &&
                    num_out_args == 0)
                {
                    (void) plpgsql_build_variable("$0", 0,
                                                  build_datatype(typeTup,
                                                                 -1,
                                               function->fn_input_collation),
                                                  true);
                }
            }
            ReleaseSysCache(typeTup);
            break;

        case PLPGSQL_DML_TRIGGER:
            /* Trigger procedure's return type is unknown yet */
            function->fn_rettype = InvalidOid;
            function->fn_retbyval = false;
            function->fn_retistuple = true;
            function->fn_retset = false;

            /* shouldn't be any declared arguments */
            if (procStruct->pronargs != 0)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                  errmsg("trigger functions cannot have declared arguments"),
                         errhint("The arguments of the trigger can be accessed through TG_NARGS and TG_ARGV instead.")));

            /* Add the record for referencing NEW */
            rec = plpgsql_build_record("new", 0, true);
            function->new_varno = rec->dno;

            /* Add the record for referencing OLD */
            rec = plpgsql_build_record("old", 0, true);
            function->old_varno = rec->dno;

            /* Add the variable tg_name */
            var = plpgsql_build_variable("tg_name", 0,
                                         plpgsql_build_datatype(NAMEOID,
                                                                -1,
                                                                InvalidOid),
                                         true);
            function->tg_name_varno = var->dno;

            /* Add the variable tg_when */
            var = plpgsql_build_variable("tg_when", 0,
                                         plpgsql_build_datatype(TEXTOID,
                                                                -1,
                                               function->fn_input_collation),
                                         true);
            function->tg_when_varno = var->dno;

            /* Add the variable tg_level */
            var = plpgsql_build_variable("tg_level", 0,
                                         plpgsql_build_datatype(TEXTOID,
                                                                -1,
                                               function->fn_input_collation),
                                         true);
            function->tg_level_varno = var->dno;

            /* Add the variable tg_op */
            var = plpgsql_build_variable("tg_op", 0,
                                         plpgsql_build_datatype(TEXTOID,
                                                                -1,
                                               function->fn_input_collation),
                                         true);
            function->tg_op_varno = var->dno;

            /* Add the variable tg_relid */
            var = plpgsql_build_variable("tg_relid", 0,
                                         plpgsql_build_datatype(OIDOID,
                                                                -1,
                                                                InvalidOid),
                                         true);
            function->tg_relid_varno = var->dno;

            /* Add the variable tg_relname */
            var = plpgsql_build_variable("tg_relname", 0,
                                         plpgsql_build_datatype(NAMEOID,
                                                                -1,
                                                                InvalidOid),
                                         true);
            function->tg_relname_varno = var->dno;

            /* tg_table_name is now preferred to tg_relname */
            var = plpgsql_build_variable("tg_table_name", 0,
                                         plpgsql_build_datatype(NAMEOID,
                                                                -1,
                                                                InvalidOid),
                                         true);
            function->tg_table_name_varno = var->dno;

            /* add the variable tg_table_schema */
            var = plpgsql_build_variable("tg_table_schema", 0,
                                         plpgsql_build_datatype(NAMEOID,
                                                                -1,
                                                                InvalidOid),
                                         true);
            function->tg_table_schema_varno = var->dno;

            /* Add the variable tg_nargs */
            var = plpgsql_build_variable("tg_nargs", 0,
                                         plpgsql_build_datatype(INT4OID,
                                                                -1,
                                                                InvalidOid),
                                         true);
            function->tg_nargs_varno = var->dno;

            /* Add the variable tg_argv */
            var = plpgsql_build_variable("tg_argv", 0,
                                         plpgsql_build_datatype(TEXTARRAYOID,
                                                                -1,
                                               function->fn_input_collation),
                                         true);
            function->tg_argv_varno = var->dno;

            break;

        case PLPGSQL_EVENT_TRIGGER:
            function->fn_rettype = VOIDOID;
            function->fn_retbyval = false;
            function->fn_retistuple = true;
            function->fn_retset = false;

            /* shouldn't be any declared arguments */
            if (procStruct->pronargs != 0)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                         errmsg("event trigger functions cannot have declared arguments")));

            /* Add the variable tg_event */
            var = plpgsql_build_variable("tg_event", 0,
                                         plpgsql_build_datatype(TEXTOID,
                                                                -1,
                                               function->fn_input_collation),
                                         true);
            function->tg_event_varno = var->dno;

            /* Add the variable tg_tag */
            var = plpgsql_build_variable("tg_tag", 0,
                                         plpgsql_build_datatype(TEXTOID,
                                                                -1,
                                               function->fn_input_collation),
                                         true);
            function->tg_tag_varno = var->dno;

            break;

        default:
            elog(ERROR, "unrecognized function typecode: %d",
                 (int) function->fn_is_trigger);
            break;
    }

    /* Remember if function is STABLE/IMMUTABLE */
    function->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);

    /*
     * 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();
    pfree(proc_source);

    /*
     * If it has OUT parameters or returns VOID or returns a set, we allow
     * control to fall off the end without an explicit RETURN statement. The
     * easiest way to implement this is to add a RETURN statement to the end
     * of the statement list during parsing.
     */
    if (num_out_args > 0 || function->fn_rettype == VOIDOID ||
        function->fn_retset)
        add_dummy_return(function);

    /*
     * Complete the function's info
     */
    function->fn_nargs = procStruct->pronargs;
    for (i = 0; i < function->fn_nargs; i++)
        function->fn_argvarnos[i] = in_arg_varnos[i];
    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];

    /* Debug dump for completed functions */
    if (plpgsql_DumpExecTree)
        plpgsql_dumptree(function);

    /*
     * add it to the hash table
     */
    plpgsql_HashTableInsert(function, hashkey);

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

static Node * make_datum_param ( PLpgSQL_expr expr,
int  dno,
int  location 
) [static]

Definition at line 1312 of file pl_comp.c.

References Assert, bms_add_member(), PLpgSQL_function::cur_estate, PLpgSQL_execstate::datums, exec_get_datum_type_info(), PLpgSQL_function::fn_cxt, PLpgSQL_expr::func, Param::location, makeNode, MemoryContextSwitchTo(), Param::paramcollid, Param::paramid, Param::paramkind, PLpgSQL_expr::paramnos, Param::paramtype, and Param::paramtypmod.

Referenced by plpgsql_param_ref(), and resolve_column_ref().

{
    PLpgSQL_execstate *estate;
    PLpgSQL_datum *datum;
    Param      *param;
    MemoryContext oldcontext;

    /* see comment in resolve_column_ref */
    estate = expr->func->cur_estate;
    Assert(dno >= 0 && dno < estate->ndatums);
    datum = estate->datums[dno];

    /*
     * Bitmapset must be allocated in function's permanent memory context
     */
    oldcontext = MemoryContextSwitchTo(expr->func->fn_cxt);
    expr->paramnos = bms_add_member(expr->paramnos, dno);
    MemoryContextSwitchTo(oldcontext);

    param = makeNode(Param);
    param->paramkind = PARAM_EXTERN;
    param->paramid = dno + 1;
    exec_get_datum_type_info(estate,
                             datum,
                             &param->paramtype,
                             &param->paramtypmod,
                             &param->paramcollid);
    param->location = location;

    return (Node *) param;
}

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

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

static void plpgsql_compile_error_callback ( void *  arg  )  [static]

Definition at line 932 of file pl_comp.c.

References errcontext, function_parse_error_transpose(), plpgsql_error_funcname, and plpgsql_latest_lineno().

{
    if (arg)
    {
        /*
         * Try to convert syntax error position to reference text of original
         * CREATE FUNCTION or DO command.
         */
        if (function_parse_error_transpose((const char *) arg))
            return;

        /*
         * Done if a syntax error position was reported; otherwise we have to
         * fall back to a "near line N" report.
         */
    }

    if (plpgsql_error_funcname)
        errcontext("compilation of PL/pgSQL function \"%s\" near line %d",
                   plpgsql_error_funcname, plpgsql_latest_lineno());
}

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

static void plpgsql_HashTableDelete ( PLpgSQL_function function  )  [static]

Definition at line 2552 of file pl_comp.c.

References elog, PLpgSQL_function::fn_hashkey, hash_search(), NULL, and WARNING.

Referenced by delete_function().

{
    plpgsql_HashEnt *hentry;

    /* do nothing if not in table */
    if (function->fn_hashkey == NULL)
        return;

    hentry = (plpgsql_HashEnt *) hash_search(plpgsql_HashTable,
                                             (void *) function->fn_hashkey,
                                             HASH_REMOVE,
                                             NULL);
    if (hentry == NULL)
        elog(WARNING, "trying to delete function that does not exist");

    /* remove back link, which no longer points to allocated storage */
    function->fn_hashkey = NULL;
}

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

static void plpgsql_HashTableInsert ( PLpgSQL_function function,
PLpgSQL_func_hashkey func_key 
) [static]

Definition at line 2533 of file pl_comp.c.

References elog, PLpgSQL_function::fn_hashkey, plpgsql_hashent::function, hash_search(), plpgsql_hashent::key, and WARNING.

Referenced by do_compile().

{
    plpgsql_HashEnt *hentry;
    bool        found;

    hentry = (plpgsql_HashEnt *) hash_search(plpgsql_HashTable,
                                             (void *) func_key,
                                             HASH_ENTER,
                                             &found);
    if (found)
        elog(WARNING, "trying to insert a function that already exists");

    hentry->function = function;
    /* prepare back link from function to hashtable key */
    function->fn_hashkey = &hentry->key;
}

static PLpgSQL_function * plpgsql_HashTableLookup ( PLpgSQL_func_hashkey func_key  )  [static]

Definition at line 2518 of file pl_comp.c.

References plpgsql_hashent::function, and hash_search().

Referenced by plpgsql_compile().

{
    plpgsql_HashEnt *hentry;

    hentry = (plpgsql_HashEnt *) hash_search(plpgsql_HashTable,
                                             (void *) func_key,
                                             HASH_FIND,
                                             NULL);
    if (hentry)
        return hentry->function;
    else
        return NULL;
}

static Node * plpgsql_param_ref ( ParseState pstate,
ParamRef pref 
) [static]

Definition at line 1096 of file pl_comp.c.

References ParamRef::location, make_datum_param(), PLpgSQL_expr::ns, NULL, ParamRef::number, ParseState::p_ref_hook_state, plpgsql_ns_lookup(), and snprintf().

{
    PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
    char        pname[32];
    PLpgSQL_nsitem *nse;

    snprintf(pname, sizeof(pname), "$%d", pref->number);

    nse = plpgsql_ns_lookup(expr->ns, false,
                            pname, NULL, NULL,
                            NULL);

    if (nse == NULL)
        return NULL;            /* name not known to plpgsql */

    return make_datum_param(expr, nse->itemno, pref->location);
}

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

static Node * plpgsql_post_column_ref ( ParseState pstate,
ColumnRef cref,
Node var 
) [static]

Definition at line 1052 of file pl_comp.c.

References ereport, errcode(), errdetail(), errmsg(), ERROR, ColumnRef::fields, PLpgSQL_expr::func, ColumnRef::location, NameListToString(), NULL, ParseState::p_ref_hook_state, parser_errposition(), PLPGSQL_RESOLVE_COLUMN, PLPGSQL_RESOLVE_VARIABLE, resolve_column_ref(), and PLpgSQL_function::resolve_option.

{
    PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
    Node       *myvar;

    if (expr->func->resolve_option == PLPGSQL_RESOLVE_VARIABLE)
        return NULL;            /* we already found there's no match */

    if (expr->func->resolve_option == PLPGSQL_RESOLVE_COLUMN && var != NULL)
        return NULL;            /* there's a table column, prefer that */

    /*
     * If we find a record/row variable but can't match a field name, throw
     * error if there was no core resolution for the ColumnRef either.  In
     * that situation, the reference is inevitably going to fail, and
     * complaining about the record/row variable is likely to be more on-point
     * than the core parser's error message.  (It's too bad we don't have
     * access to transformColumnRef's internal crerr state here, as in case of
     * a conflict with a table name this could still be less than the most
     * helpful error message possible.)
     */
    myvar = resolve_column_ref(pstate, expr, cref, (var == NULL));

    if (myvar != NULL && var != NULL)
    {
        /*
         * We could leave it to the core parser to throw this error, but we
         * can add a more useful detail message than the core could.
         */
        ereport(ERROR,
                (errcode(ERRCODE_AMBIGUOUS_COLUMN),
                 errmsg("column reference \"%s\" is ambiguous",
                        NameListToString(cref->fields)),
                 errdetail("It could refer to either a PL/pgSQL variable or a table column."),
                 parser_errposition(pstate, cref->location)));
    }

    return myvar;
}

static Node * plpgsql_pre_column_ref ( ParseState pstate,
ColumnRef cref 
) [static]
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 */
}

static void plpgsql_resolve_polymorphic_argtypes ( int  numargs,
Oid argtypes,
char *  argmodes,
Node call_expr,
bool  forValidator,
const char *  proname 
) [static]

Definition at line 2430 of file pl_comp.c.

References ANYARRAYOID, ANYELEMENTOID, ANYENUMOID, ANYNONARRAYOID, ANYRANGEOID, ereport, errcode(), errmsg(), ERROR, i, and resolve_polymorphic_argtypes().

Referenced by compute_function_hashkey(), and do_compile().

{
    int         i;

    if (!forValidator)
    {
        /* normal case, pass to standard routine */
        if (!resolve_polymorphic_argtypes(numargs, argtypes, argmodes,
                                          call_expr))
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("could not determine actual argument "
                            "type for polymorphic function \"%s\"",
                            proname)));
    }
    else
    {
        /* special validation case */
        for (i = 0; i < numargs; i++)
        {
            switch (argtypes[i])
            {
                case ANYELEMENTOID:
                case ANYNONARRAYOID:
                case ANYENUMOID:        /* XXX dubious */
                    argtypes[i] = INT4OID;
                    break;
                case ANYARRAYOID:
                    argtypes[i] = INT4ARRAYOID;
                    break;
                case ANYRANGEOID:
                    argtypes[i] = INT4RANGEOID;
                    break;
                default:
                    break;
            }
        }
    }
}

static Node * resolve_column_ref ( ParseState pstate,
PLpgSQL_expr expr,
ColumnRef cref,
bool  error_if_no_field 
) [static]

Definition at line 1123 of file pl_comp.c.

References Assert, PLpgSQL_function::cur_estate, PLpgSQL_execstate::datums, PLpgSQL_recfield::dtype, elog, ereport, errcode(), errmsg(), ERROR, PLpgSQL_recfield::fieldname, PLpgSQL_row::fieldnames, ColumnRef::fields, PLpgSQL_expr::func, i, IsA, PLpgSQL_nsitem::itemno, PLpgSQL_nsitem::itemtype, linitial, list_length(), ColumnRef::location, lsecond, lthird, make_datum_param(), PLpgSQL_execstate::ndatums, PLpgSQL_row::nfields, PLpgSQL_expr::ns, NULL, parser_errposition(), PLPGSQL_DTYPE_RECFIELD, plpgsql_ns_lookup(), PLPGSQL_NSTYPE_REC, PLPGSQL_NSTYPE_ROW, PLPGSQL_NSTYPE_VAR, PLpgSQL_recfield::recparentno, strVal, and PLpgSQL_row::varnos.

Referenced by plpgsql_post_column_ref(), and plpgsql_pre_column_ref().

{
    PLpgSQL_execstate *estate;
    PLpgSQL_nsitem *nse;
    const char *name1;
    const char *name2 = NULL;
    const char *name3 = NULL;
    const char *colname = NULL;
    int         nnames;
    int         nnames_scalar = 0;
    int         nnames_wholerow = 0;
    int         nnames_field = 0;

    /*
     * We use the function's current estate to resolve parameter data types.
     * This is really pretty bogus because there is no provision for updating
     * plans when those types change ...
     */
    estate = expr->func->cur_estate;

    /*----------
     * The allowed syntaxes are:
     *
     * A        Scalar variable reference, or whole-row record reference.
     * A.B      Qualified scalar or whole-row reference, or field reference.
     * A.B.C    Qualified record field reference.
     * A.*      Whole-row record reference.
     * A.B.*    Qualified whole-row record reference.
     *----------
     */
    switch (list_length(cref->fields))
    {
        case 1:
            {
                Node       *field1 = (Node *) linitial(cref->fields);

                Assert(IsA(field1, String));
                name1 = strVal(field1);
                nnames_scalar = 1;
                nnames_wholerow = 1;
                break;
            }
        case 2:
            {
                Node       *field1 = (Node *) linitial(cref->fields);
                Node       *field2 = (Node *) lsecond(cref->fields);

                Assert(IsA(field1, String));
                name1 = strVal(field1);

                /* Whole-row reference? */
                if (IsA(field2, A_Star))
                {
                    /* Set name2 to prevent matches to scalar variables */
                    name2 = "*";
                    nnames_wholerow = 1;
                    break;
                }

                Assert(IsA(field2, String));
                name2 = strVal(field2);
                colname = name2;
                nnames_scalar = 2;
                nnames_wholerow = 2;
                nnames_field = 1;
                break;
            }
        case 3:
            {
                Node       *field1 = (Node *) linitial(cref->fields);
                Node       *field2 = (Node *) lsecond(cref->fields);
                Node       *field3 = (Node *) lthird(cref->fields);

                Assert(IsA(field1, String));
                name1 = strVal(field1);
                Assert(IsA(field2, String));
                name2 = strVal(field2);

                /* Whole-row reference? */
                if (IsA(field3, A_Star))
                {
                    /* Set name3 to prevent matches to scalar variables */
                    name3 = "*";
                    nnames_wholerow = 2;
                    break;
                }

                Assert(IsA(field3, String));
                name3 = strVal(field3);
                colname = name3;
                nnames_field = 2;
                break;
            }
        default:
            /* too many names, ignore */
            return NULL;
    }

    nse = plpgsql_ns_lookup(expr->ns, false,
                            name1, name2, name3,
                            &nnames);

    if (nse == NULL)
        return NULL;            /* name not known to plpgsql */

    switch (nse->itemtype)
    {
        case PLPGSQL_NSTYPE_VAR:
            if (nnames == nnames_scalar)
                return make_datum_param(expr, nse->itemno, cref->location);
            break;
        case PLPGSQL_NSTYPE_REC:
            if (nnames == nnames_wholerow)
                return make_datum_param(expr, nse->itemno, cref->location);
            if (nnames == nnames_field)
            {
                /* colname could be a field in this record */
                int         i;

                /* search for a datum referencing this field */
                for (i = 0; i < estate->ndatums; i++)
                {
                    PLpgSQL_recfield *fld = (PLpgSQL_recfield *) estate->datums[i];

                    if (fld->dtype == PLPGSQL_DTYPE_RECFIELD &&
                        fld->recparentno == nse->itemno &&
                        strcmp(fld->fieldname, colname) == 0)
                    {
                        return make_datum_param(expr, i, cref->location);
                    }
                }

                /*
                 * We should not get here, because a RECFIELD datum should
                 * have been built at parse time for every possible qualified
                 * reference to fields of this record.  But if we do, handle
                 * it like field-not-found: throw error or return NULL.
                 */
                if (error_if_no_field)
                    ereport(ERROR,
                            (errcode(ERRCODE_UNDEFINED_COLUMN),
                             errmsg("record \"%s\" has no field \"%s\"",
                                    (nnames_field == 1) ? name1 : name2,
                                    colname),
                             parser_errposition(pstate, cref->location)));
            }
            break;
        case PLPGSQL_NSTYPE_ROW:
            if (nnames == nnames_wholerow)
                return make_datum_param(expr, nse->itemno, cref->location);
            if (nnames == nnames_field)
            {
                /* colname could be a field in this row */
                PLpgSQL_row *row = (PLpgSQL_row *) estate->datums[nse->itemno];
                int         i;

                for (i = 0; i < row->nfields; i++)
                {
                    if (row->fieldnames[i] &&
                        strcmp(row->fieldnames[i], colname) == 0)
                    {
                        return make_datum_param(expr, row->varnos[i],
                                                cref->location);
                    }
                }
                /* Not found, so throw error or return NULL */
                if (error_if_no_field)
                    ereport(ERROR,
                            (errcode(ERRCODE_UNDEFINED_COLUMN),
                             errmsg("record \"%s\" has no field \"%s\"",
                                    (nnames_field == 1) ? name1 : name2,
                                    colname),
                             parser_errposition(pstate, cref->location)));
            }
            break;
        default:
            elog(ERROR, "unrecognized plpgsql itemtype: %d", nse->itemtype);
    }

    /* Name format doesn't match the plpgsql variable type */
    return NULL;
}


Variable Documentation

Definition at line 54 of file pl_comp.c.

int datums_alloc [static]

Definition at line 42 of file pl_comp.c.

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

int datums_last = 0 [static]

Definition at line 45 of file pl_comp.c.

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

Initial value:
 {
            
    {NULL, 0}
}

Definition at line 80 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().

HTAB* plpgsql_HashTable = NULL [static]

Definition at line 60 of file pl_comp.c.

Definition at line 40 of file pl_comp.c.