📄 pl_comp.c
字号:
case PLPGSQL_NSTYPE_REC: { /* * This word is a record name, so third word must be a field * in this record. */ PLpgSQL_recfield *new; new = palloc(sizeof(PLpgSQL_recfield)); new->dtype = PLPGSQL_DTYPE_RECFIELD; new->fieldname = pstrdup(cp[2]); new->recparentno = ns->itemno; plpgsql_adddatum((PLpgSQL_datum *) new); plpgsql_yylval.scalar = (PLpgSQL_datum *) new; pfree(cp[0]); pfree(cp[1]); pfree(cp[2]); return T_SCALAR; } 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.scalar = plpgsql_Datums[row->varnos[i]]; pfree(cp[0]); pfree(cp[1]); pfree(cp[2]); return T_SCALAR; } } 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 compiler's 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; /* XXX perhaps allow REC here? */ 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 = NULL; HeapTuple attrtup = NULL; HeapTuple typetup = NULL; Form_pg_class classStruct; Form_pg_attribute attrStruct; char *cp[3]; int i; MemoryContext oldCxt; int result = T_ERROR; /* Avoid memory leaks in the long-term function context */ oldCxt = MemoryContextSwitchTo(compile_tmp_cxt); /* 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] = '%'; /* * Lookup the first word */ nse = plpgsql_ns_lookup(cp[0], NULL); /* * If this is a label lookup the second word in that label's 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); if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_VAR) { plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; result = T_DTYPE; } } /* Return T_ERROR if not found, otherwise T_DTYPE */ goto done; } /* * First word could also be a table name */ classOid = RelnameGetRelid(cp[0]); if (!OidIsValid(classOid)) goto done; classtup = SearchSysCache(RELOID, ObjectIdGetDatum(classOid), 0, 0, 0); if (!HeapTupleIsValid(classtup)) goto done; classStruct = (Form_pg_class) GETSTRUCT(classtup); /* * It must be a relation, sequence, view, or type */ if (classStruct->relkind != RELKIND_RELATION && classStruct->relkind != RELKIND_SEQUENCE && classStruct->relkind != RELKIND_VIEW && classStruct->relkind != RELKIND_COMPOSITE_TYPE) goto done; /* * Fetch the named table field and its type */ attrtup = SearchSysCacheAttName(classOid, cp[1]); if (!HeapTupleIsValid(attrtup)) goto done; attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup); typetup = SearchSysCache(TYPEOID, ObjectIdGetDatum(attrStruct->atttypid), 0, 0, 0); if (!HeapTupleIsValid(typetup)) elog(ERROR, "cache lookup failed for type %u", attrStruct->atttypid); /* * Found that - build a compiler type struct in the caller's cxt and * return it */ MemoryContextSwitchTo(oldCxt); plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod); MemoryContextSwitchTo(compile_tmp_cxt); result = T_DTYPE;done: if (HeapTupleIsValid(classtup)) ReleaseSysCache(classtup); if (HeapTupleIsValid(attrtup)) ReleaseSysCache(attrtup); if (HeapTupleIsValid(typetup)) ReleaseSysCache(typetup); MemoryContextSwitchTo(oldCxt); return result;}/* ---------- * plpgsql_parse_tripwordtype Same lookup for word.word.word%TYPE * ---------- */#define TYPE_JUNK_LEN 5intplpgsql_parse_tripwordtype(char *word){ Oid classOid; HeapTuple classtup = NULL; HeapTuple attrtup = NULL; HeapTuple typetup = NULL; Form_pg_class classStruct; Form_pg_attribute attrStruct; char *cp[2]; char *colname[1]; int qualified_att_len; int numdots = 0; int i; RangeVar *relvar; MemoryContext oldCxt; int result = T_ERROR; /* Avoid memory leaks in the long-term function context */ oldCxt = MemoryContextSwitchTo(compile_tmp_cxt); /* Do case conversion and word separation */ qualified_att_len = strlen(word) - TYPE_JUNK_LEN; Assert(word[qualified_att_len] == '%'); for (i = 0; i < qualified_att_len; i++) { if (word[i] == '.' && ++numdots == 2) break; } cp[0] = (char *) palloc((i + 1) * sizeof(char)); memcpy(cp[0], word, i * sizeof(char)); cp[0][i] = '\0'; /* * qualified_att_len - one based position + 1 (null terminator) */ cp[1] = (char *) palloc((qualified_att_len - i) * sizeof(char)); memcpy(cp[1], &word[i + 1], (qualified_att_len - i - 1) * sizeof(char)); cp[1][qualified_att_len - i - 1] = '\0'; relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp[0], "plpgsql_parse_tripwordtype")); classOid = RangeVarGetRelid(relvar, true); if (!OidIsValid(classOid)) goto done; classtup = SearchSysCache(RELOID, ObjectIdGetDatum(classOid), 0, 0, 0); if (!HeapTupleIsValid(classtup)) goto done; classStruct = (Form_pg_class) GETSTRUCT(classtup); /* * It must be a relation, sequence, view, or type */ if (classStruct->relkind != RELKIND_RELATION && classStruct->relkind != RELKIND_SEQUENCE && classStruct->relkind != RELKIND_VIEW && classStruct->relkind != RELKIND_COMPOSITE_TYPE) goto done; /* * Fetch the named table field and its type */ plpgsql_convert_ident(cp[1], colname, 1); attrtup = SearchSysCacheAttName(classOid, colname[0]); if (!HeapTupleIsValid(attrtup)) goto done; attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup); typetup = SearchSysCache(TYPEOID, ObjectIdGetDatum(attrStruct->atttypid), 0, 0, 0); if (!HeapTupleIsValid(typetup)) elog(ERROR, "cache lookup failed for type %u", attrStruct->atttypid); /* * Found that - build a compiler type struct in the caller's cxt and * return it */ MemoryContextSwitchTo(oldCxt); plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod); MemoryContextSwitchTo(compile_tmp_cxt); result = T_DTYPE;done: if (HeapTupleIsValid(classtup)) ReleaseSysCache(classtup); if (HeapTupleIsValid(attrtup)) ReleaseSysCache(attrtup); if (HeapTupleIsValid(typetup)) ReleaseSysCache(typetup); MemoryContextSwitchTo(oldCxt); return result;}/* ---------- * plpgsql_parse_wordrowtype Scanner found word%ROWTYPE. * So word must be a table name. * ---------- */intplpgsql_parse_wordrowtype(char *word){ Oid classOid; char *cp[2]; int i; /* Do case conversion and word separation */ /* We convert %rowtype to .rowtype momentarily to keep converter happy */ i = strlen(word) - 8; Assert(word[i] == '%'); word[i] = '.'; plpgsql_convert_ident(word, cp, 2); word[i] = '%'; /* Lookup the relation */ classOid = RelnameGetRelid(cp[0]); if (!OidIsValid(classOid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s\" does not exist", cp[0]))); /* * Build and return the row type struct */ plpgsql_yylval.dtype = plpgsql_build_datatype(get_rel_type_id(classOid), -1); pfree(cp[0]); pfree(cp[1]); return T_DTYPE;}/* ---------- * plpgsql_parse_dblwordrowtype Scanner found word.word%ROWTYPE. * So word must be a namespace qualified table name. * ---------- */#define ROWTYPE_JUNK_LEN 8intplpgsql_parse_dblwordrowtype(char *word){ Oid classOid; char *cp; int i; RangeVar *relvar; MemoryContext oldCxt; /* Avoid memory leaks in long-term function context */ oldCxt = MemoryContextSwitchTo(compile_tmp_cxt); /* Do case conversion and word separation */ /* We convert %rowtype to .rowtype momentarily to keep converter happy */ i = strlen(word) - ROWTYPE_JUNK_LEN; Assert(word[i] == '%'); word[i] = '\0'; cp = pstrdup(word); word[i] = '%'; /* Lookup the relation */ relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp, "plpgsql_parse_dblwordrowtype")); classOid = RangeVarGetRelid(relvar, true); if (!OidIsValid(classOid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s\" does not exist", cp))); /* Build and return the row type struct */ plpgsql_yylval.dtype = plpgsql_build_datatype(get_rel_type_id(classOid), -1); MemoryContextSwitchTo(oldCxt); return T_DTYPE;}/* * plpgsql_build_variable - build a datum-array entry of a given * datatype * * The returned struct may be a PLpgSQL_var, PLpgSQL_row, or * PLpgSQL_rec depending on the given datatype, and is allocated via * palloc. The struct is automatically added to the current datum * array, and optionally to the current namespace. */PLpgSQL_variable *plpgsql_build_variable(const char *refname, int lineno, PLpgSQL_type *dtype, bool add2namespace){ PLpgSQL_variable *result; switch (dtype->ttype) { case PLPGSQL_TTYPE_SCALAR: { /* Ordinary scalar datatype */ PLpgSQL_var *var; var = palloc0(sizeof(PLpgSQL_var)); var->dtype = PLPGSQL_DTYPE_VAR; var->refname = pstrdup(refname); var->lineno = lineno; var->datatype = dtype; /* other fields might be filled by caller */ /* preset to NULL */ var->value = 0; var->isnull = true; var->freeval = false; plpgsql_adddatum((PLpgSQL_datum *) var); if (add2namespace) plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, refname); result = (PLpgSQL_variable *) var; break; } case PLPGSQL_TTYPE_ROW: { /* Composite type -- build a row variable */ PLpgSQL_row *row; row = build_row_from_class(dtype->typrelid); row->dtype = PLPGSQL_DTYPE_ROW; row->refname = pstrdup(refname); row->lineno = lineno; plpgsql_adddatum((PLpgSQL_datum *) row); if (add2namespace) plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, row->rowno, refname); result = (PLpgSQL_variable *) row; break; } case PLPGSQL_TTYPE_REC: { /* * "record" type -- build a variable-contents record variable */ PLpgSQL_rec *rec; rec = palloc0(sizeof(PLpgSQL_rec)); rec->dtype = PLPGSQL_DTYPE_REC; rec->refname = pstrdup(refname); rec->lineno = lineno; plpgsql_adddatum((PLpgSQL_datum *) rec); if (add2namespace) plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, refname); result = (PLpgSQL_variable *) rec; break; } case PLPGSQL_TTYPE_PSEUDO: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("variable \"%s\" has pseudo-type %s", refname, format_type_be(dtype->typoid)))); result = NULL; /* keep compiler quiet */ break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -