⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pl_comp.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
		default:			elog(ERROR, "unrecognized ttype: %d", dtype->ttype);			result = NULL;		/* keep compiler quiet */			break;	}	return result;}/* * Build a row-variable data structure given the pg_class OID. */static PLpgSQL_row *build_row_from_class(Oid classOid){	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, or composite type entries */	if (classStruct->relkind != RELKIND_RELATION &&		classStruct->relkind != RELKIND_SEQUENCE &&		classStruct->relkind != RELKIND_VIEW &&		classStruct->relkind != RELKIND_COMPOSITE_TYPE)		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),										 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 'b':				/* base type */		case 'd':				/* domain */			typ->ttype = PLPGSQL_TTYPE_SCALAR;			break;		case 'c':				/* composite, ie, rowtype */			Assert(OidIsValid(typeStruct->typrelid));			typ->ttype = PLPGSQL_TTYPE_ROW;			break;		case 'p':				/* 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		Put all datum entries created *					since the last call into the *					finishing code block so the *					block knows which variables to *					reinitialize when entered. * ---------- */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:					argtypes[i] = INT4OID;					break;				case ANYARRAYOID:					argtypes[i] = INT4ARRAYOID;					break;				default:					break;			}		}	}}static voiddelete_function(PLpgSQL_function *func){	/* remove function from hash table */	plpgsql_HashTableDelete(func);	/* release the function's storage */	MemoryContextDelete(func->fn_cxt);	/*	 * Caller should be sure not to use passed-in pointer, as it now points to	 * pfree'd storage	 */}/* 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;	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");}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -