pl_funcs.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:15k
- /**********************************************************************
- * 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
- * ----------
- */
- void
- plpgsql_dstring_init(PLpgSQL_dstring * ds)
- {
- ds->value = palloc(ds->alloc = 512);
- ds->used = 0;
- }
- /* ----------
- * plpgsql_dstring_free Dynamic string destruction
- * ----------
- */
- void
- plpgsql_dstring_free(PLpgSQL_dstring * ds)
- {
- pfree(ds->value);
- }
- /* ----------
- * plpgsql_dstring_append Dynamic string extending
- * ----------
- */
- void
- plpgsql_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
- * ----------
- */
- void
- plpgsql_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.
- * ----------
- */
- bool
- plpgsql_ns_setlocal(bool flag)
- {
- bool oldstate;
- oldstate = ns_localmode;
- ns_localmode = flag;
- return oldstate;
- }
- /* ----------
- * plpgsql_ns_push Enter a new namestack level
- * ----------
- */
- void
- plpgsql_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
- * ----------
- */
- void
- plpgsql_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
- * ----------
- */
- void
- plpgsql_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
- * ----------
- */
- void
- plpgsql_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 = ' ';
- 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 void
- dump_ind()
- {
- int i;
- for (i = 0; i < dump_indent; i++)
- printf(" ");
- }
- static void
- dump_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 %dn", stmt->cmd_type);
- break;
- }
- }
- static void
- dump_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 -- %sn", name);
- }
- static void
- dump_assign(PLpgSQL_stmt_assign * stmt)
- {
- dump_ind();
- printf("ASSIGN var %d := ", stmt->varno);
- dump_expr(stmt->expr);
- printf("n");
- }
- static void
- dump_if(PLpgSQL_stmt_if * stmt)
- {
- int i;
- dump_ind();
- printf("IF ");
- dump_expr(stmt->cond);
- printf(" THENn");
- 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(" ELSEn");
- 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(" ENDIFn");
- }
- static void
- dump_loop(PLpgSQL_stmt_loop * stmt)
- {
- int i;
- dump_ind();
- printf("LOOPn");
- 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(" ENDLOOPn");
- }
- static void
- dump_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(" ENDWHILEn");
- }
- static void
- dump_fori(PLpgSQL_stmt_fori * stmt)
- {
- int i;
- dump_ind();
- printf("FORI %s %sn", 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(" ENDFORIn");
- }
- static void
- dump_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(" ENDFORSn");
- }
- static void
- dump_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 %sn", stmt->rec->recno, stmt->rec->refname);
- }
- if (stmt->row != NULL)
- {
- dump_ind();
- printf(" target = %d %sn", stmt->row->rowno, stmt->row->refname);
- }
- dump_indent -= 2;
- }
- static void
- dump_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 void
- dump_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 void
- dump_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 void
- dump_execsql(PLpgSQL_stmt_execsql * stmt)
- {
- dump_ind();
- printf("EXECSQL ");
- dump_expr(stmt->sqlstmt);
- printf("n");
- }
- static void
- dump_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("'");
- }
- void
- plpgsql_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 %dn",
- 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 %sn", ((PLpgSQL_rec *) d)->refname);
- break;
- case PLPGSQL_DTYPE_RECFIELD:
- printf("RECFIELD %-16s of REC %dn", ((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 %dn", 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 %snn", func->fn_name);
- }