/* -------------------------------- * ExecResetTupleTable * * This releases any resources (buffer pins, tupdesc refcounts) * held by the tuple table, and optionally releases the memory * occupied by the tuple table data structure. * It is expected that this routine be called by EndPlan(). * -------------------------------- */ void ExecResetTupleTable(List *tupleTable, /* tuple table */ bool shouldFree) /* true if we should free memory */ { ListCell *lc; foreach(lc, tupleTable) { TupleTableSlot *slot = lfirst_node(TupleTableSlot, lc); /* Always release resources and reset the slot to empty */ ExecClearTuple(slot); if (slot->tts_tupleDescriptor) { ReleaseTupleDesc(slot->tts_tupleDescriptor); slot->tts_tupleDescriptor = NULL; } /* If shouldFree, release memory occupied by the slot itself */ if (shouldFree) { if (!slot->tts_fixedTupleDescriptor) { if (slot->tts_values) pfree(slot->tts_values); if (slot->tts_isnull) pfree(slot->tts_isnull); } pfree(slot); } }
/* * CREATE COLLATION */ ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists) { char *collName; Oid collNamespace; AclResult aclresult; ListCell *pl; DefElem *fromEl = NULL; DefElem *localeEl = NULL; DefElem *lccollateEl = NULL; DefElem *lcctypeEl = NULL; DefElem *providerEl = NULL; DefElem *versionEl = NULL; char *collcollate = NULL; char *collctype = NULL; char *collproviderstr = NULL; int collencoding; char collprovider = 0; char *collversion = NULL; Oid newoid; ObjectAddress address; collNamespace = QualifiedNameGetCreationNamespace(names, &collName); aclresult = pg_namespace_aclcheck(collNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(collNamespace)); foreach(pl, parameters) { DefElem *defel = lfirst_node(DefElem, pl); DefElem **defelp; if (pg_strcasecmp(defel->defname, "from") == 0) defelp = &fromEl; else if (pg_strcasecmp(defel->defname, "locale") == 0) defelp = &localeEl; else if (pg_strcasecmp(defel->defname, "lc_collate") == 0) defelp = &lccollateEl; else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0) defelp = &lcctypeEl; else if (pg_strcasecmp(defel->defname, "provider") == 0) defelp = &providerEl; else if (pg_strcasecmp(defel->defname, "version") == 0) defelp = &versionEl; else { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("collation attribute \"%s\" not recognized", defel->defname), parser_errposition(pstate, defel->location))); break; } *defelp = defel; }
/* * get_actual_clauses * * Returns a list containing the bare clauses from 'restrictinfo_list'. * * This is only to be used in cases where none of the RestrictInfos can * be pseudoconstant clauses (for instance, it's OK on indexqual lists). */ List * get_actual_clauses(List *restrictinfo_list) { List *result = NIL; ListCell *l; foreach(l, restrictinfo_list) { RestrictInfo *rinfo = lfirst_node(RestrictInfo, l); Assert(!rinfo->pseudoconstant); result = lappend(result, rinfo->clause); }
/* * ExecInitRangeTable * Set up executor's range-table-related data * * We build an array from the range table list to allow faster lookup by RTI. * (The es_range_table field is now somewhat redundant, but we keep it to * avoid breaking external code unnecessarily.) * This is also a convenient place to set up the parallel es_relations array. */ void ExecInitRangeTable(EState *estate, List *rangeTable) { Index rti; ListCell *lc; /* Remember the range table List as-is */ estate->es_range_table = rangeTable; /* Set up the equivalent array representation */ estate->es_range_table_size = list_length(rangeTable); estate->es_range_table_array = (RangeTblEntry **) palloc(estate->es_range_table_size * sizeof(RangeTblEntry *)); rti = 0; foreach(lc, rangeTable) { estate->es_range_table_array[rti++] = lfirst_node(RangeTblEntry, lc); }
/* * DefineQueryRewrite * Create a rule * * This is essentially the same as DefineRule() except that the rule's * action and qual have already been passed through parse analysis. */ ObjectAddress DefineQueryRewrite(const char *rulename, Oid event_relid, Node *event_qual, CmdType event_type, bool is_instead, bool replace, List *action) { Relation event_relation; ListCell *l; Query *query; bool RelisBecomingView = false; Oid ruleId = InvalidOid; ObjectAddress address; /* * If we are installing an ON SELECT rule, we had better grab * AccessExclusiveLock to ensure no SELECTs are currently running on the * event relation. For other types of rules, it would be sufficient to * grab ShareRowExclusiveLock to lock out insert/update/delete actions and * to ensure that we lock out current CREATE RULE statements; but because * of race conditions in access to catalog entries, we can't do that yet. * * Note that this lock level should match the one used in DefineRule. */ event_relation = heap_open(event_relid, AccessExclusiveLock); /* * Verify relation is of a type that rules can sensibly be applied to. * Internal callers can target materialized views, but transformRuleStmt() * blocks them for users. Don't mention them in the error message. */ if (event_relation->rd_rel->relkind != RELKIND_RELATION && event_relation->rd_rel->relkind != RELKIND_MATVIEW && event_relation->rd_rel->relkind != RELKIND_VIEW && event_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table or view", RelationGetRelationName(event_relation)))); if (!allowSystemTableMods && IsSystemRelation(event_relation)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied: \"%s\" is a system catalog", RelationGetRelationName(event_relation)))); /* * Check user has permission to apply rules to this relation. */ if (!pg_class_ownercheck(event_relid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(event_relation->rd_rel->relkind), RelationGetRelationName(event_relation)); /* * No rule actions that modify OLD or NEW */ foreach(l, action) { query = lfirst_node(Query, l); if (query->resultRelation == 0) continue; /* Don't be fooled by INSERT/SELECT */ if (query != getInsertSelectQuery(query, NULL)) continue; if (query->resultRelation == PRS2_OLD_VARNO) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("rule actions on OLD are not implemented"), errhint("Use views or triggers instead."))); if (query->resultRelation == PRS2_NEW_VARNO) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("rule actions on NEW are not implemented"), errhint("Use triggers instead."))); }
/* * Transform the subscript expressions. */ foreach(idx, indirection) { A_Indices *ai = lfirst_node(A_Indices, idx); Node *subexpr; if (isSlice) { if (ai->lidx) { subexpr = transformExpr(pstate, ai->lidx, pstate->p_expr_kind); /* If it's not int4 already, try to coerce */ subexpr = coerce_to_target_type(pstate, subexpr, exprType(subexpr), INT4OID, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, -1); if (subexpr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("array subscript must have type integer"), parser_errposition(pstate, exprLocation(ai->lidx)))); } else if (!ai->is_slice) { /* Make a constant 1 */ subexpr = (Node *) makeConst(INT4OID, -1, InvalidOid, sizeof(int32), Int32GetDatum(1), false, true); /* pass by value */ } else { /* Slice with omitted lower bound, put NULL into the list */ subexpr = NULL; } lowerIndexpr = lappend(lowerIndexpr, subexpr); } else Assert(ai->lidx == NULL && !ai->is_slice); if (ai->uidx) { subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind); /* If it's not int4 already, try to coerce */ subexpr = coerce_to_target_type(pstate, subexpr, exprType(subexpr), INT4OID, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, -1); if (subexpr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("array subscript must have type integer"), parser_errposition(pstate, exprLocation(ai->uidx)))); } else { /* Slice with omitted upper bound, put NULL into the list */ Assert(isSlice && ai->is_slice); subexpr = NULL; } upperIndexpr = lappend(upperIndexpr, subexpr); }