pl_comp.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,081 行 · 第 1/4 页
C
2,081 行
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; HeapTuple typeTup; 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. Ensure we scan all levels. */ old_nsstate = plpgsql_ns_setlocal(false); nse = plpgsql_ns_lookup(cp[0], NULL, NULL, 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 shell types and complex types. */ typeTup = LookupTypeName(NULL, makeTypeName(cp[0]), NULL); if (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] = '%'; pfree(cp[2]); /* * Do a lookup on the compiler's namestack. Ensure we scan all levels. * We don't need to check number of names matched, because we will only * consider scalar variables. */ old_nsstate = plpgsql_ns_setlocal(false); nse = plpgsql_ns_lookup(cp[0], cp[1], NULL, NULL); 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; 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 * ---------- */intplpgsql_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[4]; 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 */ /* We convert %type to .type momentarily to keep converter happy */ i = strlen(word) - 5; Assert(word[i] == '%'); word[i] = '.'; plpgsql_convert_ident(word, cp, 4); word[i] = '%'; pfree(cp[3]); relvar = makeRangeVar(cp[0], cp[1]); 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 */ attrtup = SearchSysCacheAttName(classOid, cp[2]); 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. * ---------- */intplpgsql_parse_dblwordrowtype(char *word){ Oid classOid; char *cp[3]; 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) - 8; Assert(word[i] == '%'); word[i] = '.'; plpgsql_convert_ident(word, cp, 3); word[i] = '%'; /* Lookup the relation */ relvar = makeRangeVar(cp[0], cp[1]); classOid = RangeVarGetRelid(relvar, true); if (!OidIsValid(classOid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s.%s\" does not exist", cp[0], cp[1]))); /* 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; default: elog(ERROR, "unrecognized ttype: %d", dtype->ttype); result = NULL; /* keep compiler quiet */ break; } return result;}/* * Build a row-variable data structure given the pg_class OID. */static PLpgSQL_row *build_row_from_class(Oid classOid){ PLpgSQL_row *row; Relation rel; Form_pg_class classStruct; const char *relname; int i; /* * Open the relation to get info. */ rel = relation_open(classOid, AccessShareLock); classStruct = RelationGetForm(rel); relname = RelationGetRelationName(rel); /* accept relation, sequence, view, or composite type entries */ if (classStruct->relkind != RELKIND_RELATION && classStruct->relkind != RELKIND_SEQUENCE && classStruct->relkind != RELKIND_VIEW && classStruct->relkind != RELKIND_COMPOSITE_TYPE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("relation \"%s\" is not a table", relname))); /* * Create a row datum entry and all the required variables that it will * point to. */ row = palloc0(sizeof(PLpgSQL_row)); row->dtype = PLPGSQL_DTYPE_ROW; row->rowtupdesc = CreateTupleDescCopy(RelationGetDescr(rel)); row->nfields = classStruct->relnatts; row->fieldnames = palloc(sizeof(char *) * row->nfields); row->varnos = palloc(sizeof(int) * row->nfields); for (i = 0; i < row->nfields; i++) { Form_pg_attribute attrStruct; /* * Get the attribute and check for dropped column */ attrStruct = row->rowtupdesc->attrs[i];
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?