📄 pl_comp.c
字号:
var->dtype = PLPGSQL_DTYPE_VAR; var->refname = strdup("tg_relname"); var->lineno = 0; var->datatype = plpgsql_parse_datatype("name"); 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; var->datatype = plpgsql_parse_datatype("int4"); 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, "unrecognized function typecode: %u", functype); break; } /* * Create the magic FOUND variable. */ var = malloc(sizeof(PLpgSQL_var)); memset(var, 0, sizeof(PLpgSQL_var)); var->dtype = PLPGSQL_DTYPE_VAR; var->refname = strdup("found"); var->lineno = 0; var->datatype = plpgsql_parse_datatype("bool"); 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->found_varno = var->varno; /* * Forget about the above created variables */ plpgsql_add_initdatums(NULL); /* * Now parse the functions text */ parse_rc = plpgsql_yyparse(); if (parse_rc != 0) elog(ERROR, "plpgsql parser returned %d", parse_rc); plpgsql_scanner_finish(); /* * If that was successful, complete the functions info. */ function->fn_nargs = procStruct->pronargs; for (i = 0; i < function->fn_nargs; i++) function->fn_argvarnos[i] = arg_varnos[i]; function->ndatums = plpgsql_nDatums; function->datums = malloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums); for (i = 0; i < plpgsql_nDatums; i++) function->datums[i] = plpgsql_Datums[i]; function->action = plpgsql_yylval.program; /* 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; return function;}/* * error context callback to let us supply a call-stack traceback */static voidplpgsql_compile_error_callback(void *arg){ 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(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 */ if (plpgsql_curr_compile->fn_functype == T_TRIGGER) { if (strcmp(cp[0], "tg_argv") == 0) { int save_spacescanned = plpgsql_SpaceScanned; PLpgSQL_trigarg *trigarg; trigarg = malloc(sizeof(PLpgSQL_trigarg)); memset(trigarg, 0, 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.variable = (PLpgSQL_datum *) trigarg; plpgsql_SpaceScanned = save_spacescanned; pfree(cp[0]); return T_VARIABLE; } } /* * Do a lookup on the compilers namestack */ nse = plpgsql_ns_lookup(cp[0], NULL); if (nse != NULL) { pfree(cp[0]); switch (nse->itemtype) { case PLPGSQL_NSTYPE_LABEL: return T_LABEL; case PLPGSQL_NSTYPE_VAR: plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[nse->itemno]); return T_VARIABLE; 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. */ pfree(cp[0]); return T_WORD;}/* ---------- * plpgsql_parse_dblword Same lookup for two words * separated by a dot. * ---------- */intplpgsql_parse_dblword(char *word){ PLpgSQL_nsitem *ns; char *cp[2]; /* Do case conversion and word separation */ plpgsql_convert_ident(word, cp, 2); /* * Lookup the first word */ ns = plpgsql_ns_lookup(cp[0], NULL); if (ns == NULL) { pfree(cp[0]); pfree(cp[1]); return T_ERROR; } switch (ns->itemtype) { case PLPGSQL_NSTYPE_LABEL: /* * First word is a label, so second word could be a variable, * record or row in that bodies namestack. Anything else could * only be something in a query given to the SPI manager and * T_ERROR will get eaten up by the collector routines. */ ns = plpgsql_ns_lookup(cp[1], cp[0]); pfree(cp[0]); pfree(cp[1]); if (ns == NULL) return T_ERROR; switch (ns->itemtype) { case PLPGSQL_NSTYPE_VAR: plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[ns->itemno]); return T_VARIABLE; case PLPGSQL_NSTYPE_REC: plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]); return T_RECORD; case PLPGSQL_NSTYPE_ROW: plpgsql_yylval.row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]); return T_ROW; default: return T_ERROR; } break; case PLPGSQL_NSTYPE_REC: { /* * First word is a record name, so second word must be a * field in this record. */ PLpgSQL_recfield *new; new = malloc(sizeof(PLpgSQL_recfield)); new->dtype = PLPGSQL_DTYPE_RECFIELD; new->fieldname = strdup(cp[1]); new->recparentno = ns->itemno; plpgsql_adddatum((PLpgSQL_datum *) new); plpgsql_yylval.variable = (PLpgSQL_datum *) new; pfree(cp[0]); pfree(cp[1]); return T_VARIABLE; } case PLPGSQL_NSTYPE_ROW: { /* * 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.var = (PLpgSQL_var *) (plpgsql_Datums[row->varnos[i]]); pfree(cp[0]); pfree(cp[1]); return T_VARIABLE; } } ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("row \"%s\" has no field \"%s\"", cp[0], cp[1]))); } 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(char *word){ PLpgSQL_nsitem *ns; char *cp[3]; /* Do case conversion and word separation */ plpgsql_convert_ident(word, cp, 3); /* * Lookup the first word - it must be a label */ ns = plpgsql_ns_lookup(cp[0], NULL); if (ns == NULL) { pfree(cp[0]); pfree(cp[1]); pfree(cp[2]); return T_ERROR; } if (ns->itemtype != PLPGSQL_NSTYPE_LABEL) { pfree(cp[0]); pfree(cp[1]); pfree(cp[2]); return T_ERROR; } /* * First word is a label, so second word could be a record or row */ ns = plpgsql_ns_lookup(cp[1], cp[0]); if (ns == NULL) { pfree(cp[0]); pfree(cp[1]); pfree(cp[2]); return T_ERROR; } switch (ns->itemtype) { case PLPGSQL_NSTYPE_REC: { /* * This word is a record name, so third word must be a * field in this record. */ PLpgSQL_recfield *new; new = malloc(sizeof(PLpgSQL_recfield)); new->dtype = PLPGSQL_DTYPE_RECFIELD; new->fieldname = strdup(cp[2]); new->recparentno = ns->itemno; plpgsql_adddatum((PLpgSQL_datum *) new); plpgsql_yylval.variable = (PLpgSQL_datum *) new; pfree(cp[0]); pfree(cp[1]); pfree(cp[2]); return T_VARIABLE; } case PLPGSQL_NSTYPE_ROW: { /* * This word is 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.var = (PLpgSQL_var *) (plpgsql_Datums[row->varnos[i]]); pfree(cp[0]); pfree(cp[1]); pfree(cp[2]); return T_VARIABLE; } } ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("row \"%s.%s\" has no field \"%s\"", cp[0], cp[1], cp[2]))); } default: break; } pfree(cp[0]); pfree(cp[1]); pfree(cp[2]); return T_ERROR;}/* ---------- * plpgsql_parse_wordtype The scanner found word%TYPE. word can be * a variable name or a basetype. * ---------- */intplpgsql_parse_wordtype(char *word){ PLpgSQL_nsitem *nse; bool old_nsstate; Oid typeOid; char *cp[2]; int i; /* Do case conversion and word separation */ /* We convert %type to .type momentarily to keep converter happy */ i = strlen(word) - 5; Assert(word[i] == '%'); word[i] = '.'; plpgsql_convert_ident(word, cp, 2); word[i] = '%'; pfree(cp[1]); /* * Do a lookup on the compilers namestack. But ensure it moves up to * the toplevel. */ old_nsstate = plpgsql_ns_setlocal(false); nse = plpgsql_ns_lookup(cp[0], NULL); plpgsql_ns_setlocal(old_nsstate); if (nse != NULL) { pfree(cp[0]); switch (nse->itemtype) { case PLPGSQL_NSTYPE_VAR: plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; return T_DTYPE; default: return T_ERROR; } } /* * Word wasn't found on the namestack. Try to find a data type with * that name, but ignore pg_type entries that are in fact class types. */ typeOid = LookupTypeName(makeTypeName(cp[0])); if (OidIsValid(typeOid)) { HeapTuple typeTup; typeTup = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeOid), 0, 0, 0); if (HeapTupleIsValid(typeTup)) { Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); if (!typeStruct->typisdefined || typeStruct->typrelid != InvalidOid) { ReleaseSysCache(typeTup); pfree(cp[0]); return T_ERROR; } plpgsql_yylval.dtype = build_datatype(typeTup, -1); ReleaseSysCache(typeTup); pfree(cp[0]); return T_DTYPE; } } /* * Nothing found - up to now it's a word without any special meaning * for us. */ pfree(cp[0]); return T_ERROR;}/* ---------- * plpgsql_parse_dblwordtype Same lookup for word.word%TYPE * ---------- */intplpgsql_parse_dblwordtype(char *word){ PLpgSQL_nsitem *nse; bool old_nsstate; Oid classOid; HeapTuple classtup; Form_pg_class classStruct; HeapTuple attrtup; Form_pg_attribute attrStruct; HeapTuple typetup; char *cp[3]; int i; /* Do case conversion and word separation */ /* We convert %type to .type momentarily to keep converter happy */ i = strlen(word) - 5; Assert(word[i] == '%'); word[i] = '.'; plpgsql_convert_ident(word, cp, 3); word[i] = '%'; pfree(cp[2]); /* * Lookup the first word */ nse = plpgsql_ns_lookup(cp[0], NULL); /* * If this is a label lookup the second word in that labels namestack * level */ if (nse != NULL) { if (nse->itemtype == PLPGSQL_NSTYPE_LABEL) { old_nsstate = plpgsql_ns_setlocal(false); nse = plpgsql_ns_lookup(cp[1], cp[0]); plpgsql_ns_setlocal(old_nsstate); pfree(cp[0]); pfree(cp[1]); if (nse != NULL) { switch (nse->itemtype) { case PLPGSQL_NSTYPE_VAR: plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; return T_DTYPE; default: return T_ERROR; } } return T_ERROR; } pfree(cp[0]); pfree(cp[1]); return T_ERROR; } /* * First word could also be a table name */ classOid = RelnameGetRelid(cp[0]); if (!OidIsValid(classOid)) { pfree(cp[0]); pfree(cp[1]); return T_ERROR; } classtup = SearchSysCache(RELOID, ObjectIdGetDatum(classOid), 0, 0, 0); if (!HeapTupleIsValid(classtup)) { pfree(cp[0]); pfree(cp[1]); return T_ERROR; } /* * It must be a relation, sequence, view, or type */ classStruct = (Form_pg_class) GETSTRUCT(classtup); if (classStruct->relkind != RELKIND_RELATION && classStruct->relkind != RELKIND_SEQUENCE && classStruct->relkind != RELKIND_VIEW && classStruct->relkind != RELKIND_COMPOSITE_TYPE) { ReleaseSysCache(classtup); pfree(cp[0]); pfree(cp[1]); return T_ERROR; } /* * Fetch the named table field and it's type */ attrtup = SearchSysCacheAttName(classOid, cp[1]); if (!HeapTupleIsValid(attrtup)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -