📄 pl_comp.c
字号:
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. * ---------- */ typeXlated = xlateSqlType(cp); typeTup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(typeXlated), 0, 0, 0); if (HeapTupleIsValid(typeTup)) { PLpgSQL_type *typ; typeStruct = (Form_pg_type) GETSTRUCT(typeTup); if (typeStruct->typrelid != InvalidOid) { pfree(cp); return T_ERROR; } typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type)); typ->typname = strdup(nameout(&(typeStruct->typname))); typ->typoid = typeTup->t_data->t_oid; fmgr_info(typeStruct->typinput, &(typ->typinput)); typ->typbyval = typeStruct->typbyval; typ->atttypmod = -1; plpgsql_yylval.dtype = typ; pfree(cp); return T_DTYPE; } /* ---------- * Nothing found - up to now it's a word without any * special meaning for us. * ---------- */ pfree(cp); return T_ERROR;}/* ---------- * plpgsql_parse_dblwordtype Same lookup for word.word%TYPE * ---------- */intplpgsql_parse_dblwordtype(char *string){ char *word1; char *word2; PLpgSQL_nsitem *nse; bool old_nsstate; HeapTuple classtup; Form_pg_class classStruct; HeapTuple attrtup; Form_pg_attribute attrStruct; HeapTuple typetup; Form_pg_type typeStruct; PLpgSQL_type *typ; /* ---------- * Convert to lower case and separate the words * ---------- */ word1 = plpgsql_tolower(string); word2 = strchr(word1, '.'); *word2++ = '\0'; *(strchr(word2, '%')) = '\0'; /* ---------- * Lookup the first word * ---------- */ nse = plpgsql_ns_lookup(word1, 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(word2, word1); plpgsql_ns_setlocal(old_nsstate); pfree(word1); 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(word1); return T_ERROR; } /* ---------- * First word could also be a table name * ---------- */ classtup = SearchSysCacheTuple(RELNAME, PointerGetDatum(word1), 0, 0, 0); if (!HeapTupleIsValid(classtup)) { pfree(word1); return T_ERROR; } /* ---------- * It must be a (shared) relation class * ---------- */ classStruct = (Form_pg_class) GETSTRUCT(classtup); if (classStruct->relkind != 'r' && classStruct->relkind != 's') { pfree(word1); return T_ERROR; } /* ---------- * Fetch the named table field and it's type * ---------- */ attrtup = SearchSysCacheTuple(ATTNAME, ObjectIdGetDatum(classtup->t_data->t_oid), PointerGetDatum(word2), 0, 0); if (!HeapTupleIsValid(attrtup)) { pfree(word1); return T_ERROR; } attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup); typetup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(attrStruct->atttypid), 0, 0, 0); if (!HeapTupleIsValid(typetup)) { plpgsql_comperrinfo(); elog(ERROR, "cache lookup for type %u of %s.%s failed", attrStruct->atttypid, word1, word2); } /* ---------- * Found that - build a compiler type struct and return it * ---------- */ typeStruct = (Form_pg_type) GETSTRUCT(typetup); typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type)); typ->typname = strdup(nameout(&(typeStruct->typname))); typ->typoid = typetup->t_data->t_oid; fmgr_info(typeStruct->typinput, &(typ->typinput)); typ->typbyval = typeStruct->typbyval; typ->atttypmod = attrStruct->atttypmod; plpgsql_yylval.dtype = typ; pfree(word1); return T_DTYPE;}/* ---------- * plpgsql_parse_wordrowtype Scanner found word%ROWTYPE. * So word must be a table name. * ---------- */intplpgsql_parse_wordrowtype(char *string){ HeapTuple classtup; Form_pg_class classStruct; HeapTuple typetup; Form_pg_type typeStruct; HeapTuple attrtup; Form_pg_attribute attrStruct; char *word1; char *cp; int i; PLpgSQL_row *row; PLpgSQL_var *var; /* ---------- * Get the word in lower case and fetch the pg_class tuple. * ---------- */ word1 = plpgsql_tolower(string); cp = strchr(word1, '%'); *cp = '\0'; classtup = SearchSysCacheTuple(RELNAME, PointerGetDatum(word1), 0, 0, 0); if (!HeapTupleIsValid(classtup)) { plpgsql_comperrinfo(); elog(ERROR, "%s: no such class", word1); } classStruct = (Form_pg_class) GETSTRUCT(classtup); if (classStruct->relkind != 'r' && classStruct->relkind != 's') { plpgsql_comperrinfo(); elog(ERROR, "%s isn't a table", word1); } /* ---------- * Fetch the tables pg_type tuple too * ---------- */ typetup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(word1), 0, 0, 0); if (!HeapTupleIsValid(typetup)) { plpgsql_comperrinfo(); elog(ERROR, "cache lookup for %s in pg_type failed", word1); } /* ---------- * Create a row datum entry and all the required variables * that it will point to. * ---------- */ row = malloc(sizeof(PLpgSQL_row)); memset(row, 0, sizeof(PLpgSQL_row)); row->dtype = PLPGSQL_DTYPE_ROW; row->nfields = classStruct->relnatts; row->rowtypeclass = typetup->t_data->t_oid; row->fieldnames = malloc(sizeof(char *) * row->nfields); row->varnos = malloc(sizeof(int) * row->nfields); for (i = 0; i < row->nfields; i++) { /* ---------- * Get the attribute and it's type * ---------- */ attrtup = SearchSysCacheTuple(ATTNUM, ObjectIdGetDatum(classtup->t_data->t_oid), (Datum) (i + 1), 0, 0); if (!HeapTupleIsValid(attrtup)) { plpgsql_comperrinfo(); elog(ERROR, "cache lookup for attribute %d of class %s failed", i + 1, word1); } attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup); typetup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(attrStruct->atttypid), 0, 0, 0); if (!HeapTupleIsValid(typetup)) { plpgsql_comperrinfo(); elog(ERROR, "cache lookup for type %u of %s.%s failed", attrStruct->atttypid, word1, nameout(&(attrStruct->attname))); } typeStruct = (Form_pg_type) GETSTRUCT(typetup); cp = strdup(nameout(&(attrStruct->attname))); /* ---------- * Create the internal variable * We know if the table definitions contain a default value * or if the field is declared in the table as NOT NULL. But * it's possible to create a table field as NOT NULL without * a default value and that would lead to problems later when * initializing the variables due to entering a block at * execution time. Thus we ignore this information for now. * ---------- */ var = malloc(sizeof(PLpgSQL_var)); var->dtype = PLPGSQL_DTYPE_VAR; var->refname = malloc(strlen(word1) + strlen(cp) + 2); strcpy(var->refname, word1); strcat(var->refname, "."); strcat(var->refname, cp); var->datatype = malloc(sizeof(PLpgSQL_type)); var->datatype->typname = strdup(nameout(&(typeStruct->typname))); var->datatype->typoid = typetup->t_data->t_oid; fmgr_info(typeStruct->typinput, &(var->datatype->typinput)); var->datatype->typbyval = typeStruct->typbyval; var->datatype->atttypmod = attrStruct->atttypmod; var->isconst = false; var->notnull = false; var->default_val = NULL; var->value = (Datum) 0; var->isnull = true; var->shouldfree = false; plpgsql_adddatum((PLpgSQL_datum *) var); /* ---------- * Add the variable to the row. * ---------- */ row->fieldnames[i] = cp; row->varnos[i] = var->varno; } /* ---------- * Return the complete row definition * ---------- */ plpgsql_yylval.row = row; return T_ROW;}/* ---------- * plpgsql_adddatum Add a variable, record or row * to the compilers datum list. * ---------- */voidplpgsql_adddatum(PLpgSQL_datum * new){ if (plpgsql_nDatums == datums_alloc) { datums_alloc *= 2; plpgsql_Datums = repalloc(plpgsql_Datums, sizeof(PLpgSQL_datum *) * datums_alloc); } new->dno = plpgsql_nDatums; plpgsql_Datums[plpgsql_nDatums++] = new;}/* ---------- * plpgsql_add_initdatums Put all datum entries created * since the last call into the * finishing code block so the * block knows which variables to * reinitialize when entered. * ---------- */intplpgsql_add_initdatums(int **varnos){ int i; int n = 0; for (i = datums_last; i < plpgsql_nDatums; i++) { switch (plpgsql_Datums[i]->dtype) { case PLPGSQL_DTYPE_VAR: n++; break; default: break; } } if (varnos != NULL) { *varnos = (int *) malloc(sizeof(int) * n); n = 0; for (i = datums_last; i < plpgsql_nDatums; i++) { switch (plpgsql_Datums[i]->dtype) { case PLPGSQL_DTYPE_VAR: (*varnos)[n++] = plpgsql_Datums[i]->dno; default: break; } } } datums_last = plpgsql_nDatums; return n;}/* ---------- * plpgsql_comperrinfo Called before elog(ERROR, ...) * during compile. * ---------- */voidplpgsql_comperrinfo(){ elog(NOTICE, "plpgsql: ERROR during compile of %s near line %d", plpgsql_error_funcname, plpgsql_error_lineno);}/* --------- * plpgsql_yyerror Handle parser error * --------- */voidplpgsql_yyerror(const char *s){ plpgsql_error_lineno = plpgsql_yylineno; plpgsql_comperrinfo(); elog(ERROR, "%s at or near \"%s\"", s, plpgsql_yytext);}/* ---------- * xlateSqlType() * Convert alternate type names to internal Postgres types. * * Stolen from backend's main parser * ---------- */static char *xlateSqlType(char *name){ if (!strcasecmp(name, "int") || !strcasecmp(name, "integer")) return "int4"; else if (!strcasecmp(name, "smallint")) return "int2"; else if (!strcasecmp(name, "real") || !strcasecmp(name, "float")) return "float8"; else if (!strcasecmp(name, "interval")) return "timespan"; else if (!strcasecmp(name, "boolean")) return "bool"; else return name;} /* xlateSqlType() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -