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

📄 pl_funcs.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
字号:
/********************************************************************** * pl_funcs.c		- Misc functins for the PL/pgSQL *			  procedural language * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.5 1999/05/25 16:15:18 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 <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include <ctype.h>#include "plpgsql.h"#include "pl.tab.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 = 0;}/* ---------- * plpgsql_dstring_free			Dynamic string destruction * ---------- */voidplpgsql_dstring_free(PLpgSQL_dstring * ds){	pfree(ds->value);}/* ---------- * plpgsql_dstring_append		Dynamic string extending * ---------- */voidplpgsql_dstring_append(PLpgSQL_dstring * ds, char *str){	int			len = strlen(str);	if (ds->used + len + 1 > ds->alloc)	{		ds->alloc *= 2;		ds->value = repalloc(ds->value, ds->alloc);	}	strcpy(&(ds->value[ds->used]), str);	ds->used += len;}/* ---------- * 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;	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(){	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, char *name){	PLpgSQL_ns *ns = ns_current;	PLpgSQL_nsitem *nse;	if (name == NULL)		name = "";	name = plpgsql_tolower(name);	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 in the current namespace only	 * ----------	 */	/* ----------	 * 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, 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;			}		}	}	elog(ERROR, "there is no variable '%s' in the current block", oldname);}/* ---------- * plpgsql_tolower			Translate a string to lower case *					but honor "" escaping. * ---------- */char *plpgsql_tolower(char *s){	char	   *ret;	char	   *cp;	ret = palloc(strlen(s) + 1);	cp = ret;	while (*s)	{		if (*s == '"')		{			s++;			while (*s)			{				if (*s == '"')					break;				*cp++ = *s++;			}			if (*s != '"')			{				plpgsql_comperrinfo();				elog(ERROR, "unterminated \"");			}			s++;		}		else		{			if (isupper(*s))				*cp++ = tolower(*s++);			else				*cp++ = *s++;		}	}	*cp = '\0';	return ret;}/********************************************************************** * 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_raise(PLpgSQL_stmt_raise * stmt);static void dump_execsql(PLpgSQL_stmt_execsql * stmt);static void dump_expr(PLpgSQL_expr * expr);static voiddump_ind(){	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);			break;		case PLPGSQL_STMT_LOOP:			dump_loop((PLpgSQL_stmt_loop *) stmt);			break;		case PLPGSQL_STMT_WHILE:			dump_while((PLpgSQL_stmt_while *) stmt);			break;		case PLPGSQL_STMT_FORI:			dump_fori((PLpgSQL_stmt_fori *) stmt);			break;		case PLPGSQL_STMT_FORS:			dump_fors((PLpgSQL_stmt_fors *) stmt);			break;		case PLPGSQL_STMT_SELECT:			dump_select((PLpgSQL_stmt_select *) stmt);			break;		case PLPGSQL_STMT_EXIT:			dump_exit((PLpgSQL_stmt_exit *) stmt);			break;		case PLPGSQL_STMT_RETURN:			dump_return((PLpgSQL_stmt_return *) stmt);			break;		case PLPGSQL_STMT_RAISE:			dump_raise((PLpgSQL_stmt_raise *) stmt);			break;		case PLPGSQL_STMT_EXECSQL:			dump_execsql((PLpgSQL_stmt_execsql *) stmt);			break;		default:			elog(ERROR, "plpgsql_dump: unknown cmd_type %d\n", stmt->cmd_type);			break;	}}static voiddump_block(PLpgSQL_stmt_block * block){	int			i;	char	   *name;	if (block->label == NULL)		name = "*unnamed*";	else		name = block->label;	dump_ind();	printf("BLOCK <<%s>>\n", name);	dump_indent += 2;	for (i = 0; i < block->body->stmts_used; i++)		dump_stmt((PLpgSQL_stmt *) (block->body->stmts[i]));	dump_indent -= 2;	dump_ind();	printf("    END -- %s\n", name);}static voiddump_assign(PLpgSQL_stmt_assign * stmt){	dump_ind();	printf("ASSIGN var %d := ", stmt->varno);	dump_expr(stmt->expr);	printf("\n");}static voiddump_if(PLpgSQL_stmt_if * stmt){	int			i;	dump_ind();	printf("IF ");	dump_expr(stmt->cond);	printf(" THEN\n");	dump_indent += 2;	for (i = 0; i < stmt->true_body->stmts_used; i++)		dump_stmt((PLpgSQL_stmt *) (stmt->true_body->stmts[i]));	dump_indent -= 2;	dump_ind();	printf("    ELSE\n");	dump_indent += 2;	for (i = 0; i < stmt->false_body->stmts_used; i++)		dump_stmt((PLpgSQL_stmt *) (stmt->false_body->stmts[i]));	dump_indent -= 2;	dump_ind();	printf("    ENDIF\n");}static voiddump_loop(PLpgSQL_stmt_loop * stmt){	int			i;	dump_ind();	printf("LOOP\n");	dump_indent += 2;	for (i = 0; i < stmt->body->stmts_used; i++)		dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));	dump_indent -= 2;	dump_ind();	printf("    ENDLOOP\n");}static voiddump_while(PLpgSQL_stmt_while * stmt){	int			i;	dump_ind();	printf("WHILE ");	dump_expr(stmt->cond);	printf("\n");	dump_indent += 2;	for (i = 0; i < stmt->body->stmts_used; i++)		dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));	dump_indent -= 2;	dump_ind();	printf("    ENDWHILE\n");}static voiddump_fori(PLpgSQL_stmt_fori * stmt){	int			i;	dump_ind();	printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL");	dump_indent += 2;	dump_ind();	printf("    lower = ");	dump_expr(stmt->lower);	printf("\n");	dump_ind();	printf("    upper = ");	dump_expr(stmt->upper);	printf("\n");	for (i = 0; i < stmt->body->stmts_used; i++)		dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));	dump_indent -= 2;	dump_ind();	printf("    ENDFORI\n");}static voiddump_fors(PLpgSQL_stmt_fors * stmt){	int			i;	dump_ind();	printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);	dump_expr(stmt->query);	printf("\n");	dump_indent += 2;	for (i = 0; i < stmt->body->stmts_used; i++)		dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));	dump_indent -= 2;	dump_ind();	printf("    ENDFORS\n");}static voiddump_select(PLpgSQL_stmt_select * stmt){	dump_ind();	printf("SELECT ");	dump_expr(stmt->query);	printf("\n");	dump_indent += 2;	if (stmt->rec != NULL)	{		dump_ind();		printf("    target = %d %s\n", stmt->rec->recno, stmt->rec->refname);	}	if (stmt->row != NULL)	{		dump_ind();		printf("    target = %d %s\n", stmt->row->rowno, stmt->row->refname);	}	dump_indent -= 2;}static voiddump_exit(PLpgSQL_stmt_exit * stmt){	dump_ind();	printf("EXIT lbl='%s'", stmt->label);	if (stmt->cond != NULL)	{		printf(" WHEN ");		dump_expr(stmt->cond);	}	printf("\n");}static voiddump_return(PLpgSQL_stmt_return * stmt){	dump_ind();	printf("RETURN ");	if (stmt->retrecno >= 0)		printf("record %d", stmt->retrecno);	else	{		if (stmt->expr == NULL)			printf("NULL");		else			dump_expr(stmt->expr);	}	printf("\n");}static voiddump_raise(PLpgSQL_stmt_raise * stmt){	int			i;	dump_ind();	printf("RAISE '%s'", stmt->message);	for (i = 0; i < stmt->nparams; i++)		printf(" %d", stmt->params[i]);	printf("\n");}static voiddump_execsql(PLpgSQL_stmt_execsql * stmt){	dump_ind();	printf("EXECSQL ");	dump_expr(stmt->sqlstmt);	printf("\n");}static voiddump_expr(PLpgSQL_expr * expr){	int			i;	printf("'%s", expr->query);	if (expr->nparams > 0)	{		printf(" {");		for (i = 0; i < expr->nparams; i++)		{			if (i > 0)				printf(", ");			printf("$%d=%d", i + 1, expr->params[i]);		}		printf("}");	}	printf("'");}voidplpgsql_dumptree(PLpgSQL_function * func){	int			i;	PLpgSQL_datum *d;	printf("\nExecution tree of successfully compiled PL/pgSQL function %s:\n",		   func->fn_name);	printf("\nFunctions data area:\n");	for (i = 0; i < func->ndatums; i++)	{		d = func->datums[i];		printf("    entry %d: ", i);		switch (d->dtype)		{			case PLPGSQL_DTYPE_VAR:				{					PLpgSQL_var *var = (PLpgSQL_var *) d;					printf("VAR %-16s type %s (typoid %u) atttypmod %d\n",						   var->refname, var->datatype->typname,						   var->datatype->typoid,						   var->datatype->atttypmod);				}				break;			case PLPGSQL_DTYPE_ROW:				{					PLpgSQL_row *row = (PLpgSQL_row *) d;					int			i;					printf("ROW %-16s fields", row->refname);					for (i = 0; i < row->nfields; i++)					{						printf(" %s=var %d", row->fieldnames[i],							   row->varnos[i]);					}					printf("\n");				}				break;			case PLPGSQL_DTYPE_REC:				printf("REC %s\n", ((PLpgSQL_rec *) d)->refname);				break;			case PLPGSQL_DTYPE_RECFIELD:				printf("RECFIELD %-16s of REC %d\n", ((PLpgSQL_recfield *) d)->fieldname, ((PLpgSQL_recfield *) d)->recno);				break;			case PLPGSQL_DTYPE_TRIGARG:				printf("TRIGARG ");				dump_expr(((PLpgSQL_trigarg *) d)->argnum);				printf("\n");				break;			default:				printf("??? unknown data type %d\n", d->dtype);		}	}	printf("\nFunctions statements:\n");	dump_indent = 0;	printf("%3d:", func->action->lineno);	dump_block(func->action);	printf("\nEnd of execution tree of function %s\n\n", func->fn_name);}

⌨️ 快捷键说明

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