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

📄 pl_funcs.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/********************************************************************** * pl_funcs.c		- Misc functions for the PL/pgSQL *			  procedural language * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.46.2.1 2005/11/22 18:23:30 momjian Exp $ * *	  This software is copyrighted by Jan Wieck - Hamburg. * *	  The author hereby grants permission  to  use,  copy,	modify, *	  distribute,  and	license this software and its documentation *	  for any purpose, provided that existing copyright notices are *	  retained	in	all  copies  and  that	this notice is included *	  verbatim in any distributions. No written agreement, license, *	  or  royalty  fee	is required for any of the authorized uses. *	  Modifications to this software may be  copyrighted  by  their *	  author  and  need  not  follow  the licensing terms described *	  here, provided that the new terms are  clearly  indicated  on *	  the first page of each file where they apply. * *	  IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY *	  PARTY  FOR  DIRECT,	INDIRECT,	SPECIAL,   INCIDENTAL,	 OR *	  CONSEQUENTIAL   DAMAGES  ARISING	OUT  OF  THE  USE  OF  THIS *	  SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN *	  IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH *	  DAMAGE. * *	  THE  AUTHOR  AND	DISTRIBUTORS  SPECIFICALLY	 DISCLAIM	ANY *	  WARRANTIES,  INCLUDING,  BUT	NOT  LIMITED  TO,  THE	IMPLIED *	  WARRANTIES  OF  MERCHANTABILITY,	FITNESS  FOR  A  PARTICULAR *	  PURPOSE,	AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON *	  AN "AS IS" BASIS, AND THE AUTHOR	AND  DISTRIBUTORS  HAVE  NO *	  OBLIGATION   TO	PROVIDE   MAINTENANCE,	 SUPPORT,  UPDATES, *	  ENHANCEMENTS, OR MODIFICATIONS. * **********************************************************************/#include "plpgsql.h"#include "pl.tab.h"#include <ctype.h>#include "parser/scansup.h"/* ---------- * Local variables for the namestack handling * ---------- */static PLpgSQL_ns *ns_current = NULL;static bool ns_localmode = false;/* ---------- * plpgsql_dstring_init			Dynamic string initialization * ---------- */voidplpgsql_dstring_init(PLpgSQL_dstring *ds){	ds->value = palloc(ds->alloc = 512);	ds->used = 1;	ds->value[0] = '\0';}/* ---------- * plpgsql_dstring_free			Dynamic string destruction * ---------- */voidplpgsql_dstring_free(PLpgSQL_dstring *ds){	pfree(ds->value);}static voidplpgsql_dstring_expand(PLpgSQL_dstring *ds, int needed){	/* Don't allow truncating the string */	Assert(needed > ds->alloc);	Assert(ds->used <= ds->alloc);	/* Might have to double more than once, if needed is large */	do	{		ds->alloc *= 2;	} while (needed > ds->alloc);	ds->value = repalloc(ds->value, ds->alloc);}/* ---------- * plpgsql_dstring_append		Dynamic string extending * ---------- */voidplpgsql_dstring_append(PLpgSQL_dstring *ds, const char *str){	int			len = strlen(str);	int			needed = ds->used + len;	if (needed > ds->alloc)		plpgsql_dstring_expand(ds, needed);	memcpy(&(ds->value[ds->used - 1]), str, len);	ds->used += len;	ds->value[ds->used - 1] = '\0';}/* ---------- * plpgsql_dstring_append_char	Append a single character *								to a dynamic string * ---------- */voidplpgsql_dstring_append_char(PLpgSQL_dstring *ds, char c){	if (ds->used == ds->alloc)		plpgsql_dstring_expand(ds, ds->used + 1);	ds->value[ds->used - 1] = c;	ds->value[ds->used] = '\0';	ds->used++;}/* ---------- * plpgsql_dstring_get			Dynamic string get value * ---------- */char *plpgsql_dstring_get(PLpgSQL_dstring *ds){	return ds->value;}/* ---------- * plpgsql_ns_init			Initialize the namestack * ---------- */voidplpgsql_ns_init(void){	ns_current = NULL;	ns_localmode = false;}/* ---------- * plpgsql_ns_setlocal			Tell plpgsql_ns_lookup to or to *					not look into the current level *					only. * ---------- */boolplpgsql_ns_setlocal(bool flag){	bool		oldstate;	oldstate = ns_localmode;	ns_localmode = flag;	return oldstate;}/* ---------- * plpgsql_ns_push			Enter a new namestack level * ---------- */voidplpgsql_ns_push(char *label){	PLpgSQL_ns *new;	if (label == NULL)		label = "";	new = palloc(sizeof(PLpgSQL_ns));	memset(new, 0, sizeof(PLpgSQL_ns));	new->upper = ns_current;	ns_current = new;	plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, 0, label);}/* ---------- * plpgsql_ns_pop			Return to the previous level * ---------- */voidplpgsql_ns_pop(void){	int			i;	PLpgSQL_ns *old;	old = ns_current;	ns_current = old->upper;	for (i = 0; i < old->items_used; i++)		pfree(old->items[i]);	pfree(old->items);	pfree(old);}/* ---------- * plpgsql_ns_additem			Add an item to the current *					namestack level * ---------- */voidplpgsql_ns_additem(int itemtype, int itemno, const char *name){	PLpgSQL_ns *ns = ns_current;	PLpgSQL_nsitem *nse;	Assert(name != NULL);	if (ns->items_used == ns->items_alloc)	{		if (ns->items_alloc == 0)		{			ns->items_alloc = 32;			ns->items = palloc(sizeof(PLpgSQL_nsitem *) * ns->items_alloc);		}		else		{			ns->items_alloc *= 2;			ns->items = repalloc(ns->items,								 sizeof(PLpgSQL_nsitem *) * ns->items_alloc);		}	}	nse = palloc(sizeof(PLpgSQL_nsitem) + strlen(name));	nse->itemtype = itemtype;	nse->itemno = itemno;	strcpy(nse->name, name);	ns->items[ns->items_used++] = nse;}/* ---------- * plpgsql_ns_lookup			Lookup for a word in the namestack * ---------- */PLpgSQL_nsitem *plpgsql_ns_lookup(char *name, char *label){	PLpgSQL_ns *ns;	int			i;	/*	 * If a label is specified, lookup only in that	 */	if (label != NULL)	{		for (ns = ns_current; ns != NULL; ns = ns->upper)		{			if (!strcmp(ns->items[0]->name, label))			{				for (i = 1; i < ns->items_used; i++)				{					if (!strcmp(ns->items[i]->name, name))						return ns->items[i];				}				return NULL;	/* name not found in specified label */			}		}		return NULL;			/* label not found */	}	/*	 * No label given, lookup for visible labels ignoring localmode	 */	for (ns = ns_current; ns != NULL; ns = ns->upper)	{		if (!strcmp(ns->items[0]->name, name))			return ns->items[0];	}	/*	 * Finally lookup name in the namestack	 */	for (ns = ns_current; ns != NULL; ns = ns->upper)	{		for (i = 1; i < ns->items_used; i++)		{			if (!strcmp(ns->items[i]->name, name))				return ns->items[i];		}		if (ns_localmode)			return NULL;		/* name not found in current namespace */	}	return NULL;}/* ---------- * plpgsql_ns_rename			Rename a namespace entry * ---------- */voidplpgsql_ns_rename(char *oldname, char *newname){	PLpgSQL_ns *ns;	PLpgSQL_nsitem *newitem;	int			i;	/*	 * Lookup name in the namestack; do the lookup in the current namespace	 * only.	 */	for (ns = ns_current; ns != NULL; ns = ns->upper)	{		for (i = 1; i < ns->items_used; i++)		{			if (!strcmp(ns->items[i]->name, oldname))			{				newitem = palloc(sizeof(PLpgSQL_nsitem) + strlen(newname));				newitem->itemtype = ns->items[i]->itemtype;				newitem->itemno = ns->items[i]->itemno;				strcpy(newitem->name, newname);				pfree(oldname);				pfree(newname);				pfree(ns->items[i]);				ns->items[i] = newitem;				return;			}		}	}	ereport(ERROR,			(errcode(ERRCODE_UNDEFINED_OBJECT),			 errmsg("there is no variable \"%s\" in the current block",					oldname)));}/* ---------- * plpgsql_convert_ident * * Convert a possibly-qualified identifier to internal form: handle * double quotes, translate to lower case where not inside quotes, * truncate to NAMEDATALEN. * * There may be several identifiers separated by dots and optional * whitespace.	Each one is converted to a separate palloc'd string. * The caller passes the expected number of identifiers, as well as * a char* array to hold them.	It is an error if we find the wrong * number of identifiers (cf grammar processing of fori_varname). * * NOTE: the input string has already been accepted by the flex lexer, * so we don't need a heckuva lot of error checking here. * ---------- */voidplpgsql_convert_ident(const char *s, char **output, int numidents){	const char *sstart = s;	int			identctr = 0;	/* Outer loop over identifiers */	while (*s)	{		char	   *curident;		char	   *cp;		/* Process current identifier */		if (*s == '"')		{			/* Quoted identifier: copy, collapsing out doubled quotes */			curident = palloc(strlen(s) + 1);	/* surely enough room */			cp = curident;			s++;			while (*s)			{				if (*s == '"')				{					if (s[1] != '"')						break;					s++;				}				*cp++ = *s++;			}			if (*s != '"')		/* should not happen if lexer checked */				ereport(ERROR,						(errcode(ERRCODE_SYNTAX_ERROR),						 errmsg("unterminated \" in name: %s", sstart)));			s++;			*cp = '\0';			/* Truncate to NAMEDATALEN */			truncate_identifier(curident, cp - curident, false);		}		else		{			/* Normal identifier: extends till dot or whitespace */			const char *thisstart = s;			while (*s && *s != '.' && !isspace((unsigned char) *s))				s++;			/* Downcase and truncate to NAMEDATALEN */			curident = downcase_truncate_identifier(thisstart, s - thisstart,													false);		}		/* Pass ident to caller */		if (identctr < numidents)			output[identctr++] = curident;		else			ereport(ERROR,					(errcode(ERRCODE_SYNTAX_ERROR),					 errmsg("qualified identifier cannot be used here: %s",							sstart)));		/* If not done, skip whitespace, dot, whitespace */		if (*s)		{			while (*s && isspace((unsigned char) *s))				s++;			if (*s++ != '.')				elog(ERROR, "expected dot between identifiers: %s", sstart);			while (*s && isspace((unsigned char) *s))				s++;			if (*s == '\0')				elog(ERROR, "expected another identifier: %s", sstart);		}	}	if (identctr != numidents)		elog(ERROR, "improperly qualified identifier: %s",			 sstart);}/* * Statement type as a string, for use in error messages etc. */const char *plpgsql_stmt_typename(PLpgSQL_stmt *stmt){	switch (stmt->cmd_type)	{		case PLPGSQL_STMT_BLOCK:			return "block variables initialization";		case PLPGSQL_STMT_ASSIGN:			return "assignment";		case PLPGSQL_STMT_IF:			return "if";		case PLPGSQL_STMT_LOOP:			return "loop";		case PLPGSQL_STMT_WHILE:			return "while";		case PLPGSQL_STMT_FORI:			return "for with integer loopvar";		case PLPGSQL_STMT_FORS:			return "for over select rows";		case PLPGSQL_STMT_SELECT:			return "select into variables";		case PLPGSQL_STMT_EXIT:			return "exit";		case PLPGSQL_STMT_RETURN:			return "return";		case PLPGSQL_STMT_RETURN_NEXT:			return "return next";		case PLPGSQL_STMT_RAISE:			return "raise";		case PLPGSQL_STMT_EXECSQL:			return "SQL statement";		case PLPGSQL_STMT_DYNEXECUTE:			return "execute statement";		case PLPGSQL_STMT_DYNFORS:			return "for over execute statement";		case PLPGSQL_STMT_GETDIAG:			return "get diagnostics";		case PLPGSQL_STMT_OPEN:			return "open";		case PLPGSQL_STMT_FETCH:			return "fetch";		case PLPGSQL_STMT_CLOSE:			return "close";		case PLPGSQL_STMT_PERFORM:			return "perform";	}	return "unknown";}/********************************************************************** * Debug functions for analyzing the compiled code **********************************************************************/static int	dump_indent;static void dump_ind();static void dump_stmt(PLpgSQL_stmt *stmt);static void dump_block(PLpgSQL_stmt_block *block);static void dump_assign(PLpgSQL_stmt_assign *stmt);static void dump_if(PLpgSQL_stmt_if *stmt);static void dump_loop(PLpgSQL_stmt_loop *stmt);static void dump_while(PLpgSQL_stmt_while *stmt);static void dump_fori(PLpgSQL_stmt_fori *stmt);static void dump_fors(PLpgSQL_stmt_fors *stmt);static void dump_select(PLpgSQL_stmt_select *stmt);static void dump_exit(PLpgSQL_stmt_exit *stmt);static void dump_return(PLpgSQL_stmt_return *stmt);static void dump_return_next(PLpgSQL_stmt_return_next *stmt);static void dump_raise(PLpgSQL_stmt_raise *stmt);static void dump_execsql(PLpgSQL_stmt_execsql *stmt);static void dump_dynexecute(PLpgSQL_stmt_dynexecute *stmt);static void dump_dynfors(PLpgSQL_stmt_dynfors *stmt);static void dump_getdiag(PLpgSQL_stmt_getdiag *stmt);static void dump_open(PLpgSQL_stmt_open *stmt);static void dump_fetch(PLpgSQL_stmt_fetch *stmt);static void dump_close(PLpgSQL_stmt_close *stmt);static void dump_perform(PLpgSQL_stmt_perform *stmt);static void dump_expr(PLpgSQL_expr *expr);static voiddump_ind(void){	int			i;	for (i = 0; i < dump_indent; i++)		printf(" ");}static voiddump_stmt(PLpgSQL_stmt *stmt){	printf("%3d:", stmt->lineno);	switch (stmt->cmd_type)	{		case PLPGSQL_STMT_BLOCK:			dump_block((PLpgSQL_stmt_block *) stmt);			break;		case PLPGSQL_STMT_ASSIGN:			dump_assign((PLpgSQL_stmt_assign *) stmt);			break;		case PLPGSQL_STMT_IF:			dump_if((PLpgSQL_stmt_if *) stmt);

⌨️ 快捷键说明

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