pl_comp.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,081 行 · 第 1/4 页
C
2,081 行
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), 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;}/* * Build a row-variable data structure given the component variables. */static PLpgSQL_row *build_row_from_vars(PLpgSQL_variable **vars, int numvars){ 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; switch (var->dtype) { case PLPGSQL_DTYPE_VAR: typoid = ((PLpgSQL_var *) var)->datatype->typoid; typmod = ((PLpgSQL_var *) var)->datatype->atttypmod; 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; } 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); } return row;}/* ---------- * plpgsql_parse_datatype Scanner found something that should * be a datatype name. * ---------- */PLpgSQL_type *plpgsql_parse_datatype(const char *string){ Oid type_id; int32 typmod; /* Let the main parser try to parse it under standard SQL rules */ parseTypeString(string, &type_id, &typmod); /* Okay, build a PLpgSQL_type data structure for it */ return plpgsql_build_datatype(type_id, typmod);}/* * plpgsql_build_datatype * Build PLpgSQL_type struct given type OID and typmod. */PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod){ HeapTuple typeTup; PLpgSQL_type *typ; typeTup = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeOid), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) elog(ERROR, "cache lookup failed for type %u", typeOid); typ = build_datatype(typeTup, typmod); ReleaseSysCache(typeTup); return typ;}/* * Utility subroutine to make a PLpgSQL_type struct given a pg_type entry */static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod){ 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: 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); fmgr_info(typeStruct->typinput, &(typ->typinput)); typ->atttypmod = typmod; return typ;}/* * plpgsql_parse_err_condition * Generate PLpgSQL_condition entry(s) for an exception condition name * * This has to be able to return a list because there are some duplicate * names in the table of error code names. */PLpgSQL_condition *plpgsql_parse_err_condition(char *condname){ 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;}/* ---------- * plpgsql_adddatum Add a variable, record or row * to the compiler's datum list. * ---------- */voidplpgsql_adddatum(PLpgSQL_datum *new){ if (plpgsql_nDatums == datums_alloc) { datums_alloc *= 2; plpgsql_Datums = repalloc(plpgsql_Datums, sizeof(PLpgSQL_datum *) * datums_alloc); } new->dno = plpgsql_nDatums; plpgsql_Datums[plpgsql_nDatums++] = new;}/* ---------- * plpgsql_add_initdatums Make an array of the datum numbers of * all the simple VAR datums created since the last call * to this function. * * If varnos is NULL, we just forget any datum entries created since the * last call. * * This is used around a DECLARE section to create a list of the VARs * that have to be initialized at block entry. Note that VARs can also * be created elsewhere than DECLARE, eg by a FOR-loop, but it is then * the responsibility of special-purpose code to initialize them. * ---------- */intplpgsql_add_initdatums(int **varnos){ 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;}/* * Compute the hashkey for a given function invocation * * The hashkey is returned into the caller-provided storage at *hashkey. */static voidcompute_function_hashkey(FunctionCallInfo fcinfo, Form_pg_proc procStruct, PLpgSQL_func_hashkey *hashkey, bool forValidator){ /* 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; /* * 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 (CALLED_AS_TRIGGER(fcinfo) && !forValidator) { TriggerData *trigdata = (TriggerData *) fcinfo->context; hashkey->trigrelOid = RelationGetRelid(trigdata->tg_relation); } 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)); }}/* * This is the same as the standard resolve_polymorphic_argtypes() function, * but with a special case for validation: assume that polymorphic arguments * are integer or integer-array. Also, we go ahead and report the error * if we can't resolve the types. */static voidplpgsql_resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes, Node *call_expr, bool forValidator, const char *proname){ 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; default: break; } } }}/* * delete_function - clean up as much as possible of a stale function cache * * We can't release the PLpgSQL_function struct itself, because of the * possibility that there are fn_extra pointers to it. We can release * the subsidiary storage, but only if there are no active evaluations * in progress. Otherwise we'll just leak that storage. Since the * case would only occur if a pg_proc update is detected during a nested * recursive call on the function, a leak seems acceptable. * * Note that this can be called more than once if there are multiple fn_extra * pointers to the same function cache. Hence be careful not to do things * twice. */static voiddelete_function(PLpgSQL_function *func){ /* 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 && func->fn_cxt) { MemoryContextDelete(func->fn_cxt); func->fn_cxt = NULL; }}/* exported so we can call it from plpgsql_init() */voidplpgsql_HashTableInit(void){ 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 PLpgSQL_function *plpgsql_HashTableLookup(PLpgSQL_func_hashkey *func_key){ 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 voidplpgsql_HashTableInsert(PLpgSQL_function *function, PLpgSQL_func_hashkey *func_key){ 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 voidplpgsql_HashTableDelete(PLpgSQL_function *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;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?