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

📄 pl_comp.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
			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("You probably want to use TG_NARGS and TG_ARGV instead.")));			/* Add the record for referencing NEW */			rec = palloc0(sizeof(PLpgSQL_rec));			rec->dtype = PLPGSQL_DTYPE_REC;			rec->refname = pstrdup("new");			rec->tup = NULL;			rec->tupdesc = NULL;			rec->freetup = false;			plpgsql_adddatum((PLpgSQL_datum *) rec);			plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, rec->refname);			function->new_varno = rec->recno;			/* Add the record for referencing OLD */			rec = palloc0(sizeof(PLpgSQL_rec));			rec->dtype = PLPGSQL_DTYPE_REC;			rec->refname = pstrdup("old");			rec->tup = NULL;			rec->tupdesc = NULL;			rec->freetup = false;			plpgsql_adddatum((PLpgSQL_datum *) rec);			plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, rec->refname);			function->old_varno = rec->recno;			/* Add the variable tg_name */			var = plpgsql_build_variable("tg_name", 0,										 plpgsql_build_datatype(NAMEOID, -1),										 true);			function->tg_name_varno = var->dno;			/* Add the variable tg_when */			var = plpgsql_build_variable("tg_when", 0,										 plpgsql_build_datatype(TEXTOID, -1),										 true);			function->tg_when_varno = var->dno;			/* Add the variable tg_level */			var = plpgsql_build_variable("tg_level", 0,										 plpgsql_build_datatype(TEXTOID, -1),										 true);			function->tg_level_varno = var->dno;			/* Add the variable tg_op */			var = plpgsql_build_variable("tg_op", 0,										 plpgsql_build_datatype(TEXTOID, -1),										 true);			function->tg_op_varno = var->dno;			/* Add the variable tg_relid */			var = plpgsql_build_variable("tg_relid", 0,										 plpgsql_build_datatype(OIDOID, -1),										 true);			function->tg_relid_varno = var->dno;			/* Add the variable tg_relname */			var = plpgsql_build_variable("tg_relname", 0,										 plpgsql_build_datatype(NAMEOID, -1),										 true);			function->tg_relname_varno = var->dno;			/* Add the variable tg_nargs */			var = plpgsql_build_variable("tg_nargs", 0,										 plpgsql_build_datatype(INT4OID, -1),										 true);			function->tg_nargs_varno = var->dno;			break;		default:			elog(ERROR, "unrecognized function typecode: %u", functype);			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),								 true);	function->found_varno = var->dno;	/*	 * Forget about the above created variables	 */	plpgsql_add_initdatums(NULL);	/*	 * 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_yylval.program;	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.  However, 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 (num_out_args > 0 || function->fn_rettype == VOIDOID ||		function->fn_retset)	{		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);		}	}	/*	 * 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_error_lineno = 0;	plpgsql_check_syntax = false;	MemoryContextSwitchTo(compile_tmp_cxt);	compile_tmp_cxt = NULL;	return function;}/* * error context callback to let us supply a call-stack traceback. If * we are validating, the function source is passed as an * argument. This function is public only for the sake of an assertion * in gram.y */voidplpgsql_compile_error_callback(void *arg){	if (arg)	{		/*		 * Try to convert syntax error position to reference text of original		 * CREATE FUNCTION 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("compile of PL/pgSQL function \"%s\" near line %d",				   plpgsql_error_funcname, plpgsql_error_lineno);}/* * Fetch info about the argument types, names, and IN/OUT modes from the * pg_proc tuple.  Return value is the number of arguments. * Other results are palloc'd. */static intfetchArgInfo(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames,			 char **p_argmodes){	Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);	Datum		proallargtypes;	Datum		proargmodes;	Datum		proargnames;	bool		isNull;	ArrayType  *arr;	int			numargs;	Datum	   *elems;	int			nelems;	int			i;	/* First discover the total number of parameters and get their types */	proallargtypes = SysCacheGetAttr(PROCOID, procTup,									 Anum_pg_proc_proallargtypes,									 &isNull);	if (!isNull)	{		/*		 * We expect the arrays to be 1-D arrays of the right types; verify		 * that.  For the OID and char arrays, we don't need to use		 * deconstruct_array() since the array data is just going to look like		 * a C array of values.		 */		arr = DatumGetArrayTypeP(proallargtypes);		/* ensure not toasted */		numargs = ARR_DIMS(arr)[0];		if (ARR_NDIM(arr) != 1 ||			numargs < 0 ||			ARR_ELEMTYPE(arr) != OIDOID)			elog(ERROR, "proallargtypes is not a 1-D Oid array");		Assert(numargs >= procStruct->pronargs);		*p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));		memcpy(*p_argtypes, ARR_DATA_PTR(arr),			   numargs * sizeof(Oid));	}	else	{		/* If no proallargtypes, use proargtypes */		numargs = procStruct->proargtypes.dim1;		Assert(numargs == procStruct->pronargs);		*p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));		memcpy(*p_argtypes, procStruct->proargtypes.values,			   numargs * sizeof(Oid));	}	/* Get argument names, if available */	proargnames = SysCacheGetAttr(PROCOID, procTup,								  Anum_pg_proc_proargnames,								  &isNull);	if (isNull)		*p_argnames = NULL;	else	{		deconstruct_array(DatumGetArrayTypeP(proargnames),						  TEXTOID, -1, false, 'i',						  &elems, &nelems);		if (nelems != numargs)	/* should not happen */			elog(ERROR, "proargnames must have the same number of elements as the function has arguments");		*p_argnames = (char **) palloc(sizeof(char *) * numargs);		for (i = 0; i < numargs; i++)			(*p_argnames)[i] = DatumGetCString(DirectFunctionCall1(textout,																   elems[i]));	}	/* Get argument modes, if available */	proargmodes = SysCacheGetAttr(PROCOID, procTup,								  Anum_pg_proc_proargmodes,								  &isNull);	if (isNull)		*p_argmodes = NULL;	else	{		arr = DatumGetArrayTypeP(proargmodes);	/* ensure not toasted */		if (ARR_NDIM(arr) != 1 ||			ARR_DIMS(arr)[0] != numargs ||			ARR_ELEMTYPE(arr) != CHAROID)			elog(ERROR, "proargmodes is not a 1-D char array");		*p_argmodes = (char *) palloc(numargs * sizeof(char));		memcpy(*p_argmodes, ARR_DATA_PTR(arr),			   numargs * sizeof(char));	}	return numargs;}/* ---------- * plpgsql_parse_word		The scanner calls this to postparse *				any single word not found by a *				keyword rule. * ---------- */intplpgsql_parse_word(char *word){	PLpgSQL_nsitem *nse;	char	   *cp[1];	/* Do case conversion and word separation */	plpgsql_convert_ident(word, cp, 1);	/*	 * Recognize tg_argv when compiling triggers	 */	if (plpgsql_curr_compile->fn_functype == T_TRIGGER)	{		if (strcmp(cp[0], "tg_argv") == 0)		{			bool		save_spacescanned = plpgsql_SpaceScanned;			PLpgSQL_trigarg *trigarg;			trigarg = palloc0(sizeof(PLpgSQL_trigarg));			trigarg->dtype = PLPGSQL_DTYPE_TRIGARG;			if (plpgsql_yylex() != '[')				plpgsql_yyerror("expected \"[\"");			trigarg->argnum = plpgsql_read_expression(']', "]");			plpgsql_adddatum((PLpgSQL_datum *) trigarg);			plpgsql_yylval.scalar = (PLpgSQL_datum *) trigarg;			plpgsql_SpaceScanned = save_spacescanned;			pfree(cp[0]);			return T_SCALAR;		}	}	/*	 * Do a lookup on the compiler's namestack	 */	nse = plpgsql_ns_lookup(cp[0], NULL);	if (nse != NULL)	{		pfree(cp[0]);		switch (nse->itemtype)		{			case PLPGSQL_NSTYPE_LABEL:				return T_LABEL;			case PLPGSQL_NSTYPE_VAR:				plpgsql_yylval.scalar = plpgsql_Datums[nse->itemno];				return T_SCALAR;			case PLPGSQL_NSTYPE_REC:				plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]);				return T_RECORD;			case PLPGSQL_NSTYPE_ROW:				plpgsql_yylval.row = (PLpgSQL_row *) (plpgsql_Datums[nse->itemno]);				return T_ROW;			default:				return T_ERROR;		}	}	/*	 * Nothing found - up to now it's a word without any special meaning for	 * us.	 */	pfree(cp[0]);	return T_WORD;}/* ---------- * plpgsql_parse_dblword		Same lookup for two words *					separated by a dot. * ---------- */intplpgsql_parse_dblword(char *word){	PLpgSQL_nsitem *ns;	char	   *cp[2];	/* Do case conversion and word separation */	plpgsql_convert_ident(word, cp, 2);	/*	 * Lookup the first word	 */	ns = plpgsql_ns_lookup(cp[0], NULL);	if (ns == NULL)	{		pfree(cp[0]);		pfree(cp[1]);		return T_ERROR;	}	switch (ns->itemtype)	{		case PLPGSQL_NSTYPE_LABEL:			/*			 * First word is a label, so second word could be a variable,			 * record or row in that bodies namestack. Anything else could			 * only be something in a query given to the SPI manager and			 * T_ERROR will get eaten up by the collector routines.			 */			ns = plpgsql_ns_lookup(cp[1], cp[0]);			pfree(cp[0]);			pfree(cp[1]);			if (ns == NULL)				return T_ERROR;			switch (ns->itemtype)			{				case PLPGSQL_NSTYPE_VAR:					plpgsql_yylval.scalar = plpgsql_Datums[ns->itemno];					return T_SCALAR;				case PLPGSQL_NSTYPE_REC:					plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);					return T_RECORD;				case PLPGSQL_NSTYPE_ROW:					plpgsql_yylval.row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);					return T_ROW;				default:					return T_ERROR;			}			break;		case PLPGSQL_NSTYPE_REC:			{				/*				 * First word is a record name, so second word must be a field				 * in this record.				 */				PLpgSQL_recfield *new;				new = palloc(sizeof(PLpgSQL_recfield));				new->dtype = PLPGSQL_DTYPE_RECFIELD;				new->fieldname = pstrdup(cp[1]);				new->recparentno = ns->itemno;				plpgsql_adddatum((PLpgSQL_datum *) new);				plpgsql_yylval.scalar = (PLpgSQL_datum *) new;				pfree(cp[0]);				pfree(cp[1]);				return T_SCALAR;			}		case PLPGSQL_NSTYPE_ROW:			{				/*				 * First word is a row name, so second word must 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], cp[1]) == 0)					{						plpgsql_yylval.scalar = plpgsql_Datums[row->varnos[i]];						pfree(cp[0]);						pfree(cp[1]);						return T_SCALAR;					}				}				ereport(ERROR,						(errcode(ERRCODE_UNDEFINED_COLUMN),						 errmsg("row \"%s\" has no field \"%s\"",								cp[0], cp[1])));			}		default:			break;	}	pfree(cp[0]);	pfree(cp[1]);	return T_ERROR;}/* ---------- * plpgsql_parse_tripword		Same lookup for three words *					separated by dots. * ---------- */intplpgsql_parse_tripword(char *word){	PLpgSQL_nsitem *ns;	char	   *cp[3];	/* Do case conversion and word separation */	plpgsql_convert_ident(word, cp, 3);	/*	 * Lookup the first word - it must be a label	 */	ns = plpgsql_ns_lookup(cp[0], NULL);	if (ns == NULL)	{		pfree(cp[0]);		pfree(cp[1]);		pfree(cp[2]);		return T_ERROR;	}	if (ns->itemtype != PLPGSQL_NSTYPE_LABEL)	{		pfree(cp[0]);		pfree(cp[1]);		pfree(cp[2]);		return T_ERROR;	}	/*	 * First word is a label, so second word could be a record or row	 */	ns = plpgsql_ns_lookup(cp[1], cp[0]);	if (ns == NULL)	{		pfree(cp[0]);		pfree(cp[1]);		pfree(cp[2]);		return T_ERROR;	}	switch (ns->itemtype)	{

⌨️ 快捷键说明

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