pl_comp.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,081 行 · 第 1/4 页

C
2,081
字号
				if (rettypeid == VOIDOID ||					rettypeid == RECORDOID)					 /* okay */ ;				else if (rettypeid == TRIGGEROID)					ereport(ERROR,							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),							 errmsg("trigger functions can only be called as triggers")));				else					ereport(ERROR,							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),							 errmsg("plpgsql functions cannot return type %s",									format_type_be(rettypeid))));			}			if (typeStruct->typrelid != InvalidOid ||				rettypeid == RECORDOID)				function->fn_retistuple = true;			else			{				function->fn_retbyval = typeStruct->typbyval;				function->fn_rettyplen = typeStruct->typlen;				function->fn_rettypioparam = getTypeIOParam(typeTup);				fmgr_info(typeStruct->typinput, &(function->fn_retinput));				/*				 * install $0 reference, but only for polymorphic return				 * types, and not when the return is specified through an				 * output parameter.				 */				if (IsPolymorphicType(procStruct->prorettype) &&					num_out_args == 0)				{					(void) plpgsql_build_variable("$0", 0,												  build_datatype(typeTup, -1),												  true);				}			}			ReleaseSysCache(typeTup);			break;		case T_TRIGGER:			/* Trigger procedure's return type is unknown yet */			function->fn_rettype = InvalidOid;			function->fn_retbyval = false;			function->fn_retistuple = true;			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;			/* tg_table_name is now preferred to tg_relname */			var = plpgsql_build_variable("tg_table_name", 0,										 plpgsql_build_datatype(NAMEOID, -1),										 true);			function->tg_table_name_varno = var->dno;			/* add variable tg_table_schema */			var = plpgsql_build_variable("tg_table_schema", 0,										 plpgsql_build_datatype(NAMEOID, -1),										 true);			function->tg_table_schema_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;	/*	 * 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);}/* ---------- * plpgsql_parse_word		The scanner calls this to postparse *				any single word not found by a *				keyword rule. * ---------- */intplpgsql_parse_word(const 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	 * (XXX this sucks, it should be a regular variable in the namestack)	 */	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, NULL, NULL);	pfree(cp[0]);	if (nse != NULL)	{		switch (nse->itemtype)		{			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.	 */	return T_WORD;}/* ---------- * plpgsql_parse_dblword		Same lookup for two words *					separated by a dot. * ---------- */intplpgsql_parse_dblword(const char *word){	PLpgSQL_nsitem *ns;	char	   *cp[2];	int			nnames;	/* Do case conversion and word separation */	plpgsql_convert_ident(word, cp, 2);	/*	 * Do a lookup on the compiler's namestack	 */	ns = plpgsql_ns_lookup(cp[0], cp[1], NULL, &nnames);	if (ns == NULL)	{		pfree(cp[0]);		pfree(cp[1]);		return T_ERROR;	}	switch (ns->itemtype)	{		case PLPGSQL_NSTYPE_VAR:			/* Block-qualified reference to scalar variable. */			plpgsql_yylval.scalar = plpgsql_Datums[ns->itemno];			pfree(cp[0]);			pfree(cp[1]);			return T_SCALAR;		case PLPGSQL_NSTYPE_REC:			if (nnames == 1)			{				/*				 * 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;			}			else			{				/* Block-qualified reference to record variable. */				plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);				pfree(cp[0]);				pfree(cp[1]);				return T_RECORD;			}		case PLPGSQL_NSTYPE_ROW:			if (nnames == 1)			{				/*				 * 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])));			}			else			{				/* Block-qualified reference to row variable. */				plpgsql_yylval.row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);				pfree(cp[0]);				pfree(cp[1]);				return T_ROW;			}		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(const char *word){	PLpgSQL_nsitem *ns;	char	   *cp[3];	int			nnames;	/* Do case conversion and word separation */	plpgsql_convert_ident(word, cp, 3);	/*	 * Do a lookup on the compiler's namestack.	 * Must find a qualified reference.	 */	ns = plpgsql_ns_lookup(cp[0], cp[1], cp[2], &nnames);	if (ns == NULL || nnames != 2)	{		pfree(cp[0]);		pfree(cp[1]);		pfree(cp[2]);		return T_ERROR;	}	switch (ns->itemtype)	{		case PLPGSQL_NSTYPE_REC:			{				/*				 * words 1/2 are a record name, so third 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[2]);				new->recparentno = ns->itemno;				plpgsql_adddatum((PLpgSQL_datum *) new);				plpgsql_yylval.scalar = (PLpgSQL_datum *) new;				pfree(cp[0]);				pfree(cp[1]);				pfree(cp[2]);				return T_SCALAR;			}		case PLPGSQL_NSTYPE_ROW:			{				/*				 * words 1/2 are a row name, so third 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[2]) == 0)					{						plpgsql_yylval.scalar = plpgsql_Datums[row->varnos[i]];

⌨️ 快捷键说明

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