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 + -
显示快捷键?