📄 pl_comp.c
字号:
/********************************************************************** * pl_comp.c - Compiler part of the PL/pgSQL * procedural language * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.7 1999/05/25 16:15:17 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"#include "executor/spi.h"#include "commands/trigger.h"#include "utils/elog.h"#include "utils/builtins.h"#include "fmgr.h"#include "access/heapam.h"#include "utils/syscache.h"#include "utils/catcache.h"#include "catalog/catname.h"#include "catalog/pg_proc.h"#include "catalog/pg_type.h"#include "catalog/pg_class.h"#include "catalog/pg_attribute.h"#include "catalog/pg_attrdef.h"/* ---------- * Variables in the parser that shouldn't go into plpgsql.h * ---------- */extern PLPGSQL_YYSTYPE plpgsql_yylval;extern int plpgsql_yylineno;extern char plpgsql_yytext[];void plpgsql_yyerror(const char *s);/* ---------- * Our own local and global variables * ---------- */static int datums_alloc;int plpgsql_nDatums;PLpgSQL_datum **plpgsql_Datums;static int datums_last = 0;int plpgsql_error_lineno;char *plpgsql_error_funcname;int plpgsql_DumpExecTree = 0;PLpgSQL_function *plpgsql_curr_compile;/* ---------- * Local function declarations * ---------- */static char *xlateSqlType(char *name);/* ---------- * plpgsql_compile Given a pg_proc's oid, make * an execution tree for it. * ---------- */PLpgSQL_function *plpgsql_compile(Oid fn_oid, int functype){ int parse_rc; HeapTuple procTup; Form_pg_proc procStruct; HeapTuple typeTup; Form_pg_type typeStruct; char *proc_source; PLpgSQL_function *function; PLpgSQL_var *var; PLpgSQL_row *row; PLpgSQL_rec *rec; int i; int arg_varnos[MAXFMGRARGS]; /* ---------- * Initialize the compiler * ---------- */ plpgsql_ns_init(); plpgsql_ns_push(NULL); plpgsql_DumpExecTree = 0; datums_alloc = 128; plpgsql_nDatums = 0; plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc); datums_last = 0; /* ---------- * Lookup the pg_proc tuple by Oid * ---------- */ procTup = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(fn_oid), 0, 0, 0); if (!HeapTupleIsValid(procTup)) elog(ERROR, "plpgsql: cache lookup from pg_proc failed"); /* ---------- * Setup the scanner input and error info * ---------- */ procStruct = (Form_pg_proc) GETSTRUCT(procTup); proc_source = textout(&(procStruct->prosrc)); plpgsql_setinput(proc_source, functype); plpgsql_error_funcname = nameout(&(procStruct->proname)); plpgsql_error_lineno = 0; /* ---------- * Create the new function node * ---------- */ function = malloc(sizeof(PLpgSQL_function)); memset(function, 0, sizeof(PLpgSQL_function)); plpgsql_curr_compile = function; function->fn_functype = functype; function->fn_oid = fn_oid; function->fn_name = strdup(nameout(&(procStruct->proname))); switch (functype) { case T_FUNCTION: /* ---------- * Normal function has a defined returntype * ---------- */ function->fn_rettype = procStruct->prorettype; function->fn_retset = procStruct->proretset; /* ---------- * Lookup the functions return type * ---------- */ typeTup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(procStruct->prorettype), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) { plpgsql_comperrinfo(); elog(ERROR, "cache lookup for return type %u failed", procStruct->prorettype); } typeStruct = (Form_pg_type) GETSTRUCT(typeTup); if (typeStruct->typrelid != InvalidOid) function->fn_retistuple = true; else { function->fn_retbyval = typeStruct->typbyval; function->fn_rettyplen = typeStruct->typlen; fmgr_info(typeStruct->typinput, &(function->fn_retinput)); } /* ---------- * Create the variables for the procedures parameters * ---------- */ for (i = 0; i < procStruct->pronargs; i++) { char buf[256]; /* ---------- * Get the parameters type * ---------- */ typeTup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(procStruct->proargtypes[i]), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) { plpgsql_comperrinfo(); elog(ERROR, "cache lookup for argument type %u failed", procStruct->proargtypes[i]); } typeStruct = (Form_pg_type) GETSTRUCT(typeTup); if (typeStruct->typrelid != InvalidOid) { /* ---------- * For tuple type parameters, we set up a record * of that type * ---------- */ sprintf(buf, "%s%%rowtype", nameout(&(typeStruct->typname))); if (plpgsql_parse_wordrowtype(buf) != T_ROW) { plpgsql_comperrinfo(); elog(ERROR, "cannot get tuple struct of argument %d", i + 1); } row = plpgsql_yylval.row; sprintf(buf, "$%d", i + 1); row->refname = strdup(buf); plpgsql_adddatum((PLpgSQL_datum *) row); plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, row->rowno, buf); arg_varnos[i] = row->rowno; } else { /* ---------- * Normal parameters get a var node * ---------- */ var = malloc(sizeof(PLpgSQL_var)); memset(var, 0, sizeof(PLpgSQL_var)); var->datatype = malloc(sizeof(PLpgSQL_type)); memset(var->datatype, 0, sizeof(PLpgSQL_type)); sprintf(buf, "$%d", i + 1); var->dtype = PLPGSQL_DTYPE_VAR; var->refname = strdup(buf); var->lineno = 0; var->datatype->typname = strdup(nameout(&(typeStruct->typname))); var->datatype->typoid = procStruct->proargtypes[i]; fmgr_info(typeStruct->typinput, &(var->datatype->typinput)); var->datatype->typbyval = typeStruct->typbyval; var->datatype->atttypmod = -1; var->isconst = true; var->notnull = false; var->default_val = NULL; plpgsql_adddatum((PLpgSQL_datum *) var); plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, buf); arg_varnos[i] = var->varno; } } break; case T_TRIGGER: /* ---------- * Trigger procedures return type is unknown yet * ---------- */ function->fn_rettype = InvalidOid; function->fn_retbyval = false; function->fn_retistuple = true; function->fn_retset = false; /* ---------- * Add the record for referencing NEW * ---------- */ rec = malloc(sizeof(PLpgSQL_rec)); memset(rec, 0, sizeof(PLpgSQL_rec)); rec->dtype = PLPGSQL_DTYPE_REC; rec->refname = strdup("new"); 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 = malloc(sizeof(PLpgSQL_rec)); memset(rec, 0, sizeof(PLpgSQL_rec)); rec->dtype = PLPGSQL_DTYPE_REC; rec->refname = strdup("old"); 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 = malloc(sizeof(PLpgSQL_var)); memset(var, 0, sizeof(PLpgSQL_var)); var->dtype = PLPGSQL_DTYPE_VAR; var->refname = strdup("tg_name"); var->lineno = 0; plpgsql_parse_word("name"); var->datatype = plpgsql_yylval.dtype; var->isconst = false; var->notnull = false; var->default_val = NULL; plpgsql_adddatum((PLpgSQL_datum *) var); plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); function->tg_name_varno = var->varno; /* ---------- * Add the variable tg_when * ---------- */ var = malloc(sizeof(PLpgSQL_var)); memset(var, 0, sizeof(PLpgSQL_var)); var->dtype = PLPGSQL_DTYPE_VAR; var->refname = strdup("tg_when"); var->lineno = 0; plpgsql_parse_word("text"); var->datatype = plpgsql_yylval.dtype; var->isconst = false; var->notnull = false; var->default_val = NULL; plpgsql_adddatum((PLpgSQL_datum *) var); plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); function->tg_when_varno = var->varno; /* ---------- * Add the variable tg_level * ---------- */ var = malloc(sizeof(PLpgSQL_var)); memset(var, 0, sizeof(PLpgSQL_var)); var->dtype = PLPGSQL_DTYPE_VAR; var->refname = strdup("tg_level"); var->lineno = 0; plpgsql_parse_word("text"); var->datatype = plpgsql_yylval.dtype; var->isconst = false; var->notnull = false; var->default_val = NULL; plpgsql_adddatum((PLpgSQL_datum *) var); plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); function->tg_level_varno = var->varno; /* ---------- * Add the variable tg_op * ---------- */ var = malloc(sizeof(PLpgSQL_var)); memset(var, 0, sizeof(PLpgSQL_var)); var->dtype = PLPGSQL_DTYPE_VAR; var->refname = strdup("tg_op"); var->lineno = 0; plpgsql_parse_word("text"); var->datatype = plpgsql_yylval.dtype; var->isconst = false; var->notnull = false; var->default_val = NULL; plpgsql_adddatum((PLpgSQL_datum *) var); plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); function->tg_op_varno = var->varno; /* ---------- * Add the variable tg_relid * ---------- */ var = malloc(sizeof(PLpgSQL_var)); memset(var, 0, sizeof(PLpgSQL_var)); var->dtype = PLPGSQL_DTYPE_VAR; var->refname = strdup("tg_relid"); var->lineno = 0; plpgsql_parse_word("oid"); var->datatype = plpgsql_yylval.dtype; var->isconst = false; var->notnull = false; var->default_val = NULL; plpgsql_adddatum((PLpgSQL_datum *) var); plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); function->tg_relid_varno = var->varno; /* ---------- * Add the variable tg_relname * ---------- */ var = malloc(sizeof(PLpgSQL_var)); memset(var, 0, sizeof(PLpgSQL_var)); var->dtype = PLPGSQL_DTYPE_VAR; var->refname = strdup("tg_relname"); var->lineno = 0; plpgsql_parse_word("name"); var->datatype = plpgsql_yylval.dtype; var->isconst = false; var->notnull = false; var->default_val = NULL; plpgsql_adddatum((PLpgSQL_datum *) var); plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); function->tg_relname_varno = var->varno; /* ---------- * Add the variable tg_nargs * ---------- */ var = malloc(sizeof(PLpgSQL_var)); memset(var, 0, sizeof(PLpgSQL_var)); var->dtype = PLPGSQL_DTYPE_VAR; var->refname = strdup("tg_nargs"); var->lineno = 0; plpgsql_parse_word("int4"); var->datatype = plpgsql_yylval.dtype; var->isconst = false; var->notnull = false; var->default_val = NULL; plpgsql_adddatum((PLpgSQL_datum *) var); plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); function->tg_nargs_varno = var->varno; break; default: elog(ERROR, "unknown function type %u in plpgsql_compile()", functype); break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -