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

📄 pl_comp.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 3 页
字号:
		ReleaseSysCache(classtup);		pfree(cp[0]);		pfree(cp[1]);		return T_ERROR;	}	attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);	typetup = SearchSysCache(TYPEOID,							 ObjectIdGetDatum(attrStruct->atttypid),							 0, 0, 0);	if (!HeapTupleIsValid(typetup))		elog(ERROR, "cache lookup failed for type %u", attrStruct->atttypid);	/*	 * Found that - build a compiler type struct and return it	 */	plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod);	ReleaseSysCache(classtup);	ReleaseSysCache(attrtup);	ReleaseSysCache(typetup);	pfree(cp[0]);	pfree(cp[1]);	return T_DTYPE;}/* ---------- * plpgsql_parse_tripwordtype		Same lookup for word.word.word%TYPE * ---------- */#define TYPE_JUNK_LEN	5intplpgsql_parse_tripwordtype(char *word){	Oid			classOid;	HeapTuple	classtup;	Form_pg_class classStruct;	HeapTuple	attrtup;	Form_pg_attribute attrStruct;	HeapTuple	typetup;	char	   *cp[2];	char	   *colname[1];	int			qualified_att_len;	int			numdots = 0;	int			i;	RangeVar   *relvar;	/* Do case conversion and word separation */	qualified_att_len = strlen(word) - TYPE_JUNK_LEN;	Assert(word[qualified_att_len] == '%');	for (i = 0; i < qualified_att_len; i++)	{		if (word[i] == '.' && ++numdots == 2)		{			cp[0] = (char *) palloc((i + 1) * sizeof(char));			memset(cp[0], 0, (i + 1) * sizeof(char));			memcpy(cp[0], word, i * sizeof(char));			/*			 * qualified_att_len - one based position + 1 (null			 * terminator)			 */			cp[1] = (char *) palloc((qualified_att_len - i) * sizeof(char));			memset(cp[1], 0, (qualified_att_len - i) * sizeof(char));			memcpy(cp[1], &word[i + 1], (qualified_att_len - i - 1) * sizeof(char));			break;		}	}	relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp[0], "plpgsql_parse_tripwordtype"));	classOid = RangeVarGetRelid(relvar, true);	if (!OidIsValid(classOid))	{		pfree(cp[0]);		pfree(cp[1]);		return T_ERROR;	}	classtup = SearchSysCache(RELOID,							  ObjectIdGetDatum(classOid),							  0, 0, 0);	if (!HeapTupleIsValid(classtup))	{		pfree(cp[0]);		pfree(cp[1]);		return T_ERROR;	}	/*	 * It must be a relation, sequence, view, or type	 */	classStruct = (Form_pg_class) GETSTRUCT(classtup);	if (classStruct->relkind != RELKIND_RELATION &&		classStruct->relkind != RELKIND_SEQUENCE &&		classStruct->relkind != RELKIND_VIEW &&		classStruct->relkind != RELKIND_COMPOSITE_TYPE)	{		ReleaseSysCache(classtup);		pfree(cp[0]);		pfree(cp[1]);		return T_ERROR;	}	/*	 * Fetch the named table field and it's type	 */	plpgsql_convert_ident(cp[1], colname, 1);	attrtup = SearchSysCacheAttName(classOid, colname[0]);	pfree(colname[0]);	if (!HeapTupleIsValid(attrtup))	{		ReleaseSysCache(classtup);		pfree(cp[0]);		pfree(cp[1]);		return T_ERROR;	}	attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);	typetup = SearchSysCache(TYPEOID,							 ObjectIdGetDatum(attrStruct->atttypid),							 0, 0, 0);	if (!HeapTupleIsValid(typetup))		elog(ERROR, "cache lookup failed for type %u", attrStruct->atttypid);	/*	 * Found that - build a compiler type struct and return it	 */	plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod);	ReleaseSysCache(classtup);	ReleaseSysCache(attrtup);	ReleaseSysCache(typetup);	pfree(cp[0]);	pfree(cp[1]);	return T_DTYPE;}/* ---------- * plpgsql_parse_wordrowtype		Scanner found word%ROWTYPE. *					So word must be a table name. * ---------- */intplpgsql_parse_wordrowtype(char *word){	Oid			classOid;	char	   *cp[2];	int			i;	/* Do case conversion and word separation */	/* We convert %rowtype to .rowtype momentarily to keep converter happy */	i = strlen(word) - 8;	Assert(word[i] == '%');	word[i] = '.';	plpgsql_convert_ident(word, cp, 2);	word[i] = '%';	/* Lookup the relation */	classOid = RelnameGetRelid(cp[0]);	if (!OidIsValid(classOid))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_TABLE),				 errmsg("relation \"%s\" does not exist", cp[0])));	/*	 * Build and return the complete row definition	 */	plpgsql_yylval.row = plpgsql_build_rowtype(classOid);	plpgsql_adddatum((PLpgSQL_datum *) plpgsql_yylval.row);	pfree(cp[0]);	pfree(cp[1]);	return T_ROW;}/* ---------- * plpgsql_parse_dblwordrowtype		Scanner found word.word%ROWTYPE. *			So word must be namespace qualified a table name. * ---------- */#define ROWTYPE_JUNK_LEN	8intplpgsql_parse_dblwordrowtype(char *word){	Oid			classOid;	char	   *cp;	int			i;	RangeVar   *relvar;	/* Do case conversion and word separation */	/* We convert %rowtype to .rowtype momentarily to keep converter happy */	i = strlen(word) - ROWTYPE_JUNK_LEN;	Assert(word[i] == '%');	cp = (char *) palloc((i + 1) * sizeof(char));	memset(cp, 0, (i + 1) * sizeof(char));	memcpy(cp, word, i * sizeof(char));	/* Lookup the relation */	relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp, "plpgsql_parse_dblwordrowtype"));	classOid = RangeVarGetRelid(relvar, true);	if (!OidIsValid(classOid))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_TABLE),				 errmsg("relation \"%s\" does not exist", cp)));	/*	 * Build and return the complete row definition	 */	plpgsql_yylval.row = plpgsql_build_rowtype(classOid);	plpgsql_adddatum((PLpgSQL_datum *) plpgsql_yylval.row);	pfree(cp);	return T_ROW;}/* * Build a rowtype data structure given the pg_class OID. */PLpgSQL_row *plpgsql_build_rowtype(Oid classOid){	PLpgSQL_row *row;	Relation	rel;	Form_pg_class classStruct;	const char *relname;	int			i;	MemoryContext oldcxt;	/*	 * 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 = malloc(sizeof(PLpgSQL_row));	memset(row, 0, sizeof(PLpgSQL_row));	row->dtype = PLPGSQL_DTYPE_ROW;	/*	 * This is a bit ugly --- need a permanent copy of the rel's tupdesc.	 * Someday all these mallocs should go away in favor of a per-function	 * memory context ...	 */	oldcxt = MemoryContextSwitchTo(TopMemoryContext);	row->rowtupdesc = CreateTupleDescCopy(RelationGetDescr(rel));	MemoryContextSwitchTo(oldcxt);	row->nfields = classStruct->relnatts;	row->fieldnames = malloc(sizeof(char *) * row->nfields);	row->varnos = malloc(sizeof(int) * row->nfields);	for (i = 0; i < row->nfields; i++)	{		Form_pg_attribute attrStruct;		/*		 * Get the attribute and check for dropped column		 */		attrStruct = RelationGetDescr(rel)->attrs[i];		if (!attrStruct->attisdropped)		{			const char *attname;			HeapTuple	typetup;			PLpgSQL_var *var;			attname = NameStr(attrStruct->attname);			typetup = SearchSysCache(TYPEOID,									 ObjectIdGetDatum(attrStruct->atttypid),									 0, 0, 0);			if (!HeapTupleIsValid(typetup))				elog(ERROR, "cache lookup failed for type %u",					 attrStruct->atttypid);			/*			 * 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 = malloc(sizeof(PLpgSQL_var));			MemSet(var, 0, sizeof(PLpgSQL_var));			var->dtype = PLPGSQL_DTYPE_VAR;			var->refname = malloc(strlen(relname) + strlen(attname) + 2);			strcpy(var->refname, relname);			strcat(var->refname, ".");			strcat(var->refname, attname);			var->datatype = build_datatype(typetup, attrStruct->atttypmod);			var->isconst = false;			var->notnull = false;			var->default_val = NULL;			var->value = (Datum) 0;			var->isnull = true;			var->freeval = false;			plpgsql_adddatum((PLpgSQL_datum *) var);			/*			 * Add the variable to the row.			 */			row->fieldnames[i] = strdup(attname);			row->varnos[i] = var->varno;			ReleaseSysCache(typetup);		}		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;}/* ---------- * plpgsql_parse_datatype			Scanner found something that should *					be a datatype name. * ---------- */PLpgSQL_type *plpgsql_parse_datatype(char *string){	Oid			type_id;	int32		typmod;	HeapTuple	typeTup;	PLpgSQL_type *typ;	/* 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 */	typeTup = SearchSysCache(TYPEOID,							 ObjectIdGetDatum(type_id),							 0, 0, 0);	if (!HeapTupleIsValid(typeTup))		elog(ERROR, "cache lookup failed for type %u", type_id);	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;	typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));	typ->typname = strdup(NameStr(typeStruct->typname));	typ->typoid = HeapTupleGetOid(typeTup);	typ->typlen = typeStruct->typlen;	typ->typbyval = typeStruct->typbyval;	typ->typrelid = typeStruct->typrelid;	typ->typelem = typeStruct->typelem;	perm_fmgr_info(typeStruct->typinput, &(typ->typinput));	typ->atttypmod = typmod;	return typ;}/* ---------- * plpgsql_adddatum			Add a variable, record or row *					to the compilers 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 *) malloc(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;}/* --------- * plpgsql_yyerror			Handle parser error * --------- */voidplpgsql_yyerror(const char *s){	plpgsql_error_lineno = plpgsql_scanner_lineno();	ereport(ERROR,			(errcode(ERRCODE_SYNTAX_ERROR),	/* translator: first %s is a phrase like "syntax error" */			 errmsg("%s at or near \"%s\"", s, plpgsql_yytext)));}/* * 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){	int			i;	/* 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 */	if (CALLED_AS_TRIGGER(fcinfo))	{		TriggerData *trigdata = (TriggerData *) fcinfo->context;		hashkey->trigrelOid = RelationGetRelid(trigdata->tg_relation);	}	/* get the argument types */	for (i = 0; i < procStruct->pronargs; i++)	{		Oid			argtypeid = procStruct->proargtypes[i];		/*		 * Check for polymorphic arguments. If found, use the actual		 * parameter type from the caller's FuncExpr node, if we have one.		 *		 * We can support arguments of type ANY the same way as normal		 * polymorphic arguments.		 */		if (argtypeid == ANYARRAYOID || argtypeid == ANYELEMENTOID ||			argtypeid == ANYOID)		{			argtypeid = get_fn_expr_argtype(fcinfo->flinfo, i);			if (!OidIsValid(argtypeid))				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("could not determine actual argument "								"type for polymorphic function \"%s\"",								NameStr(procStruct->proname))));		}		hashkey->argtypes[i] = argtypeid;	}}/* exported so we can call it from plpgsql_init() */voidplpgsql_HashTableInit(void){	HASHCTL		ctl;	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 (PLpgSQL_function *) 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 (hentry == NULL)		ereport(ERROR,				(errcode(ERRCODE_OUT_OF_MEMORY),				 errmsg("out of memory")));	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 + -