/* * Extract a string value (otherwise uninterpreted) from a DefElem. */ char * defGetString(DefElem *def) { if (def->arg == NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s requires a parameter", def->defname))); switch (nodeTag(def->arg)) { case T_Integer: { char *str = palloc(32); snprintf(str, 32, "%ld", (long) intVal(def->arg)); return str; } case T_Float: /* * T_Float values are kept in string form, so this type cheat * works (and doesn't risk losing precision) */ return strVal(def->arg); case T_String: return strVal(def->arg); case T_TypeName: return TypeNameToString((TypeName *) def->arg); case T_List: return NameListToString((List *) def->arg); default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg)); } return NULL; /* keep compiler quiet */ }
/* * Serializes a given plan node for hashing and matching. * The serialized plan is palloc'd in the current memory context. */ static workfile_set_plan * workfile_mgr_serialize_plan(PlanState *ps) { Assert(ps); Plan *plan = ps->plan; workfile_set_plan *splan = NULL; splan = (workfile_set_plan *) palloc0(sizeof(workfile_set_plan)); Assert(nodeTag(plan) >= T_Plan && nodeTag(plan) < T_PlanInvalItem); /* serialize plan, without outputting the variable fields */ outfast_workfile_mgr_init(ps->state->es_range_table); char *serialized_plan = NULL; int plan_len = 0; PG_TRY(); { serialized_plan = nodeToBinaryStringFast(plan, &plan_len); Assert(plan_len > 0); } PG_CATCH(); { outfast_workfile_mgr_end(); PG_RE_THROW(); } PG_END_TRY(); outfast_workfile_mgr_end(); Assert(serialized_plan); splan->serialized_plan = serialized_plan; splan->serialized_plan_len = plan_len; return splan; }
/* * ExecRecScan * * In order to fetch our initial tuple, we need to utilize the standard SeqScan fetch * method. The problem is, those parameters are static methods located in another file. * Our solution is to utilize another function that we place in nodeSeqScan.c, which will * then redirect themselves back here to ExecRecommend. It's pretty roundabout, but our * hands are a little tied. This messes with existing code the least. * * As before, we have a failsafe to make sure we're using SeqScan. */ TupleTableSlot * ExecRecScan(RecScanState *node) { switch(nodeTag(node->subscan)) { case T_SeqScanState: return ExecSeqRecScan(node); default: elog(ERROR, "invalid RecScan subscan type: %d", (int) nodeTag(node->subscan)); } return NULL; /* keep compiler quiet */ }
/* * ExecRecRestrPos * * This decides what kind of RestrPos method to use. We should only be * considering a SeqScan; we built in a failsafe, though anything else * should be impossible due to how we handled the planning. */ void ExecRecRestrPos(RecScanState *node) { switch (nodeTag(node->subscan)) { case T_SeqScanState: ExecSeqRestrPos((SeqScanState *) node->subscan); break; default: elog(ERROR, "invalid RecScan subscan type: %d", (int) nodeTag(node->subscan)); break; } }
/* * As for pljavaCheckExtension, livecheck == null when called from _PG_init * (when the real questions are whether PL/Java itself is being loaded, from * what path, and whether or not as an extension). When livecheck is not null, * PL/Java is already alive and the caller wants to know if an extension is * being created for some other reason. That wouldn't even involve this * function, except for the need to work around creating_extension visibility * on Windows. So if livecheck isn't null, this function only needs to proceed * as far as the CREATING_EXTENSION_HACK and then return. */ static void checkLoadPath( bool *livecheck) { List *l; Node *ut; LoadStmt *ls; #ifndef CREATING_EXTENSION_HACK if ( NULL != livecheck ) return; #endif if ( NULL == ActivePortal ) return; l = ActivePortal->stmts; if ( NULL == l ) return; if ( 1 < list_length( l) ) elog(DEBUG2, "ActivePortal lists %d statements", list_length( l)); ut = (Node *)linitial(l); if ( NULL == ut ) { elog(DEBUG2, "got null for first statement from ActivePortal"); return; } if ( T_LoadStmt != nodeTag(ut) ) #ifdef CREATING_EXTENSION_HACK if ( T_CreateExtensionStmt == nodeTag(ut) ) { if ( NULL != livecheck ) { *livecheck = true; return; } getExtensionLoadPath(); if ( NULL != pljavaLoadPath ) pljavaLoadingAsExtension = true; } #endif return; if ( NULL != livecheck ) return; ls = (LoadStmt *)ut; if ( NULL == ls->filename ) { elog(DEBUG2, "got null for a LOAD statement's filename"); return; } pljavaLoadPath = (char const *)MemoryContextStrdup(TopMemoryContext, ls->filename); }
/* * ExecRecMarkPos * * This decides what kind of MarkPos method to use. We should only be * considering a SeqScan; we built in a failsafe, though anything else * should be impossible due to how we handled the planning. */ void ExecRecMarkPos(RecScanState *node) { switch (nodeTag(node->subscan)) { case T_SeqScanState: ExecSeqMarkPos((SeqScanState *) node->subscan); break; default: /* don't make hard error unless caller asks to restore... */ elog(DEBUG2, "invalid RecScan subscan type: %d", (int) nodeTag(node->subscan)); break; } }
/* * Extract a TypeName from a DefElem. * * Note: we do not accept a List arg here, because the parser will only * return a bare List when the name looks like an operator name. */ TypeName * defGetTypeName(DefElem *def) { if (def->arg == NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s requires a parameter", def->defname))); switch (nodeTag(def->arg)) { case T_TypeName: return (TypeName *) def->arg; case T_String: { /* Allow quoted typename for backwards compatibility */ TypeName *n = makeNode(TypeName); n->names = list_make1(def->arg); n->typmod = -1; return n; } default: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("argument of %s must be a type name", def->defname))); } return NULL; /* keep compiler quiet */ }
/* * Extract an int64 value from a DefElem. */ int64 defGetInt64(DefElem *def) { if (def->arg == NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s requires a numeric value", def->defname))); switch (nodeTag(def->arg)) { case T_Integer: return (int64) intVal(def->arg); case T_Float: /* * Values too large for int4 will be represented as Float * constants by the lexer. Accept these if they are valid int8 * strings. */ return DatumGetInt64(DirectFunctionCall1(int8in, CStringGetDatum(strVal(def->arg)))); default: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s requires a numeric value", def->defname))); } return 0; /* keep compiler quiet */ }
/* * add_base_rels_to_query * * Scan the query's jointree and create baserel RelOptInfos for all * the base relations (ie, table, subquery, and function RTEs) * appearing in the jointree. * * The initial invocation must pass root->parse->jointree as the value of * jtnode. Internally, the function recurses through the jointree. * * At the end of this process, there should be one baserel RelOptInfo for * every non-join RTE that is used in the query. Therefore, this routine * is the only place that should call build_simple_rel with reloptkind * RELOPT_BASEREL. (Note: build_simple_rel recurses internally to build * "other rel" RelOptInfos for the members of any appendrels we find here.) */ void add_base_rels_to_query(PlannerInfo *root, Node *jtnode) { if (jtnode == NULL) return; if (IsA(jtnode, RangeTblRef)) { int varno = ((RangeTblRef *) jtnode)->rtindex; (void) build_simple_rel(root, varno, RELOPT_BASEREL); } else if (IsA(jtnode, FromExpr)) { FromExpr *f = (FromExpr *) jtnode; ListCell *l; foreach(l, f->fromlist) add_base_rels_to_query(root, lfirst(l)); } else if (IsA(jtnode, JoinExpr)) { JoinExpr *j = (JoinExpr *) jtnode; add_base_rels_to_query(root, j->larg); add_base_rels_to_query(root, j->rarg); } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(jtnode)); }
static Query * _copyQuery(Query *from) { Query *newnode = makeNode(Query); newnode->commandType = from->commandType; newnode->resultRelation = from->resultRelation; newnode->into = from->into; newnode->isPortal = from->isPortal; Node_Copy(from, newnode, rtable); if (from->utilityStmt && nodeTag(from->utilityStmt) == T_NotifyStmt) { NotifyStmt *from_notify = (NotifyStmt*)from->utilityStmt; NotifyStmt *n = makeNode(NotifyStmt); int length = strlen(from_notify->relname); n->relname = palloc(length + 1); strcpy(n->relname,from_notify->relname); newnode->utilityStmt = (Node*)n; } if (from->uniqueFlag) { newnode->uniqueFlag = (char*)palloc(strlen(from->uniqueFlag)+1); strcpy(newnode->uniqueFlag, from->uniqueFlag); } else newnode->uniqueFlag = NULL; Node_Copy(from, newnode, sortClause); Node_Copy(from, newnode, targetList); Node_Copy(from, newnode, qual); return newnode; }
/* * Extract a possibly-qualified name (as a List of Strings) from a DefElem. */ List * defGetQualifiedName(DefElem *def) { if (def->arg == NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s requires a parameter", def->defname))); switch (nodeTag(def->arg)) { case T_TypeName: return ((TypeName *) def->arg)->names; case T_List: return (List *) def->arg; case T_String: /* Allow quoted name for backwards compatibility */ return list_make1(def->arg); default: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("argument of %s must be a name", def->defname))); } return NIL; /* keep compiler quiet */ }
/* * pxf_make_expression_items_list * * Given a scan node qual list, find the filters that are eligible to be used * by PXF, construct an expressions list, which consists of OpExpr or BoolExpr nodes * and return it to the caller. * * Basically this function just transforms expression tree to Reversed Polish Notation list. * * */ static List * pxf_make_expression_items_list(List *quals, Node *parent, int *logicalOpsNum) { ExpressionItem *expressionItem = NULL; List *result = NIL; ListCell *lc = NULL; ListCell *ilc = NULL; if (list_length(quals) == 0) return NIL; foreach (lc, quals) { Node *node = (Node *) lfirst(lc); NodeTag tag = nodeTag(node); expressionItem = (ExpressionItem *) palloc0(sizeof(ExpressionItem)); expressionItem->node = node; expressionItem->parent = parent; expressionItem->processed = false; switch (tag) { case T_OpExpr: case T_NullTest: { result = lappend(result, expressionItem); break; } case T_BoolExpr: { (*logicalOpsNum)++; BoolExpr *expr = (BoolExpr *) node; List *inner_result = pxf_make_expression_items_list(expr->args, node, logicalOpsNum); result = list_concat(result, inner_result); int childNodesNum = 0; /* Find number of child nodes on first level*/ foreach (ilc, inner_result) { ExpressionItem *ei = (ExpressionItem *) lfirst(ilc); if (!ei->processed && ei->parent == node) { ei->processed = true; childNodesNum++; } } for (int i = 0; i < childNodesNum - 1; i++) { result = lappend(result, expressionItem); } break; } default: elog(DEBUG1, "pxf_make_expression_items_list: unsupported node tag %d", tag); break; }
/* * Look up file set the cache given a certain PlanState. * Return NULL if not found. */ static workfile_set * workfile_mgr_lookup_set(PlanState *ps) { Assert(NULL != ps); Assert(NULL != workfile_mgr_cache); Assert(NULL != ps->plan); Assert(nodeTag(ps->plan) >= T_Plan && nodeTag(ps->plan) < T_PlanInvalItem); /* Create parameter info for the populate function */ workset_info set_info; set_info.dir_path = NULL; set_info.operator_work_mem = get_operator_work_mem(ps); set_info.on_disk = false; CacheEntry *localEntry = acquire_entry_retry(workfile_mgr_cache, &set_info); Assert(localEntry != NULL); workfile_set *local_work_set = (workfile_set *) CACHE_ENTRY_PAYLOAD(localEntry); /* Populate the rest of the entries needed for look-up * Allocate the serialized plan in the TopMemoryContext since this memory * context is still available when calling the transaction callback at the * time when the transaction aborts. */ MemoryContext oldcxt = MemoryContextSwitchTo(TopMemoryContext); workfile_set_plan *s_plan = workfile_mgr_serialize_plan(ps); MemoryContextSwitchTo(oldcxt); Assert(s_plan != NULL); local_work_set->set_plan = s_plan; local_work_set->key = workfile_mgr_hash_key(s_plan); CacheEntry *cachedEntry = Cache_Lookup(workfile_mgr_cache, localEntry); /* Release local entry and free up plan memory. We don't need it anymore */ Cache_Release(workfile_mgr_cache, localEntry); workfile_set *work_set = NULL; if (NULL != cachedEntry) { work_set = (workfile_set *) CACHE_ENTRY_PAYLOAD(cachedEntry); } return work_set; }
/* * pxf_make_filter_list * * Given a scan node qual list, find the filters that are eligible to be used * by PXF, construct a PxfFilterDesc list that describes the filter information, * and return it to the caller. * * Caller is responsible for pfreeing the returned PxfFilterDesc List. */ static List * pxf_make_filter_list(List *quals) { List *result = NIL; ListCell *lc = NULL; if (list_length(quals) == 0) return NIL; /* * Iterate over all implicitly ANDed qualifiers and add the ones * that are supported for push-down into the result filter list. */ foreach (lc, quals) { Node *node = (Node *) lfirst(lc); NodeTag tag = nodeTag(node); switch (tag) { case T_OpExpr: { OpExpr *expr = (OpExpr *) node; PxfFilterDesc *filter; filter = (PxfFilterDesc *) palloc0(sizeof(PxfFilterDesc)); elog(DEBUG5, "pxf_make_filter_list: node tag %d (T_OpExpr)", tag); if (opexpr_to_pxffilter(expr, filter)) result = lappend(result, filter); else pfree(filter); break; } case T_BoolExpr: { BoolExpr *expr = (BoolExpr *) node; BoolExprType boolType = expr->boolop; elog(DEBUG5, "pxf_make_filter_list: node tag %d (T_BoolExpr), bool node type %d %s", tag, boolType, boolType==AND_EXPR ? "(AND_EXPR)" : ""); /* only AND_EXPR is supported */ if (expr->boolop == AND_EXPR) { List *inner_result = pxf_make_filter_list(expr->args); elog(DEBUG5, "pxf_make_filter_list: inner result size %d", list_length(inner_result)); result = list_concat(result, inner_result); } break; } default: /* expression not supported. ignore */ elog(DEBUG5, "pxf_make_filter_list: unsupported node tag %d", tag); break; } }
/* * oidparse - get OID from IConst/FConst node */ Oid oidparse(Node *node) { switch (nodeTag(node)) { case T_Integer: return intVal(node); case T_Float: /* * Values too large for int4 will be represented as Float * constants by the lexer. Accept these if they are valid OID * strings. */ return oidin_subr(strVal(node), NULL); default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); } return InvalidOid; /* keep compiler quiet */ }
/* * Extract a type length indicator (either absolute bytes, or * -1 for "variable") from a DefElem. */ int defGetTypeLength(DefElem *def) { if (def->arg == NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s requires a parameter", def->defname))); switch (nodeTag(def->arg)) { case T_Integer: return intVal(def->arg); case T_Float: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s requires an integer value", def->defname))); break; case T_String: if (pg_strcasecmp(strVal(def->arg), "variable") == 0) return -1; /* variable length */ break; case T_TypeName: /* cope if grammar chooses to believe "variable" is a typename */ if (pg_strcasecmp(TypeNameToString((TypeName *) def->arg), "variable") == 0) return -1; /* variable length */ break; case T_List: /* must be an operator name */ break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg)); } ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid argument for %s: \"%s\"", def->defname, defGetString(def)))); return 0; /* keep compiler quiet */ }
/* * Extract a boolean value from a DefElem. */ bool defGetBoolean(DefElem *def) { /* * If no parameter given, assume "true" is meant. */ if (def->arg == NULL) return true; /* * Allow 0, 1, "true", "false", "on", "off" */ switch (nodeTag(def->arg)) { case T_Integer: switch (intVal(def->arg)) { case 0: return false; case 1: return true; default: /* otherwise, error out below */ break; } break; default: { char *sval = defGetString(def); /* * The set of strings accepted here should match up with the * grammar's opt_boolean production. */ if (pg_strcasecmp(sval, "true") == 0) return true; if (pg_strcasecmp(sval, "false") == 0) return false; if (pg_strcasecmp(sval, "on") == 0) return true; if (pg_strcasecmp(sval, "off") == 0) return false; } break; } ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s requires a Boolean value", def->defname))); return false; /* keep compiler quiet */ }
/* * ExecEndRecScan * * Ends the SeqScan and then does some additional things. */ void ExecEndRecScan(RecScanState *node) { /* End the normal scan. */ switch(nodeTag(node->subscan)) { case T_SeqScanState: ExecEndSeqScan((SeqScanState *) node->subscan); break; default: elog(ERROR, "invalid RecScan subscan type: %d", (int) nodeTag(node->subscan)); break; } /* Now for extra stuff. */ if (node->itemList) pfree(node->itemList); if (node->fullItemList) pfree(node->fullItemList); if (node->userFeatures) pfree(node->userFeatures); if (node->base_slot) FreeTupleDesc(node->base_slot); }
static void dbrestrict_utility(Node *parsetree, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) { /* Do our custom process on drop database */ switch (nodeTag(parsetree)) { case T_DropdbStmt: { DropdbStmt *stmt = (DropdbStmt *) parsetree; char *username = GetUserNameFromId(GetUserId(), false); /* * Check that only the authorized superuser foo can * drop the database undroppable_foodb. */ if (strcmp(stmt->dbname, hook_dbname) == 0 && strcmp(username, hook_username) != 0) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Only super-superuser \"%s\" can drop database \"%s\"", hook_username, hook_dbname))); break; } default: break; } /* * Fallback to normal process, be it the previous hook loaded * or the in-core code path if the previous hook does not exist. */ if (prev_utility_hook) (*prev_utility_hook) (parsetree, queryString, context, params, dest, completionTag); else standard_ProcessUtility(parsetree, queryString, context, params, dest, completionTag); }
static void MMProcessUtility(Node *parsetree, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) { bool skipCommand; switch (nodeTag(parsetree)) { case T_TransactionStmt: case T_PlannedStmt: case T_ClosePortalStmt: case T_FetchStmt: case T_DoStmt: case T_CopyStmt: case T_PrepareStmt: case T_ExecuteStmt: case T_NotifyStmt: case T_ListenStmt: case T_UnlistenStmt: case T_LoadStmt: case T_VariableSetStmt: case T_VariableShowStmt: skipCommand = true; break; default: skipCommand = false; break; } if (skipCommand || IsTransactionBlock()) { if (PreviousProcessUtilityHook != NULL) { PreviousProcessUtilityHook(parsetree, queryString, context, params, dest, completionTag); } else { standard_ProcessUtility(parsetree, queryString, context, params, dest, completionTag); } if (!skipCommand) { MMIsDistributedTrans = false; } } else { MMBroadcastUtilityStmt(queryString, false); } }
/* * IsBlockingOperator * Return true when the given plan node is a blocking operator. */ static bool IsBlockingOperator(Node *node) { switch(nodeTag(node)) { case T_BitmapIndexScan: case T_Hash: case T_Sort: return true; case T_Material: return IsMaterialBlockingOperator((Material *)node); case T_Agg: return IsAggBlockingOperator((Agg *)node); default: return false; } }
/* * Extract an int32 value from a DefElem. */ int32 defGetInt32(DefElem *def) { if (def->arg == NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s requires an integer value", def->defname))); switch (nodeTag(def->arg)) { case T_Integer: return (int32) intVal(def->arg); default: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s requires an integer value", def->defname))); } return 0; /* keep compiler quiet */ }
/* * add_vars_to_targetlist * For each variable appearing in the list, add it to the owning * relation's targetlist if not already present, and mark the variable * as being needed for the indicated join (or for final output if * where_needed includes "relation 0"). * * The list may also contain PlaceHolderVars. These don't necessarily * have a single owning relation; we keep their attr_needed info in * root->placeholder_list instead. */ void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed) { ListCell *temp; Assert(!bms_is_empty(where_needed)); foreach(temp, vars) { Node *node = (Node *) lfirst(temp); if (IsA(node, Var)) { Var *var = (Var *) node; RelOptInfo *rel = find_base_rel(root, var->varno); int attno = var->varattno; Assert(attno >= rel->min_attr && attno <= rel->max_attr); attno -= rel->min_attr; if (rel->attr_needed[attno] == NULL) { /* Variable not yet requested, so add to reltargetlist */ /* XXX is copyObject necessary here? */ rel->reltargetlist = lappend(rel->reltargetlist, copyObject(var)); } rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno], where_needed); } else if (IsA(node, PlaceHolderVar)) { PlaceHolderVar *phv = (PlaceHolderVar *) node; PlaceHolderInfo *phinfo = find_placeholder_info(root, phv); phinfo->ph_needed = bms_add_members(phinfo->ph_needed, where_needed); } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node)); }
/* * Extract a numeric value (actually double) from a DefElem. */ double defGetNumeric(DefElem *def) { if (def->arg == NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s requires a numeric value", def->defname))); switch (nodeTag(def->arg)) { case T_Integer: return (double) intVal(def->arg); case T_Float: return floatVal(def->arg); default: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s requires a numeric value", def->defname))); } return 0; /* keep compiler quiet */ }
/* * Prepare targetlist SRF function call for execution. * * This is used by nodeProjectSet.c. */ SetExprState * ExecInitFunctionResultSet(Expr *expr, ExprContext *econtext, PlanState *parent) { SetExprState *state = makeNode(SetExprState); state->funcReturnsSet = true; state->expr = expr; state->func.fn_oid = InvalidOid; /* * Initialize metadata. The expression node could be either a FuncExpr or * an OpExpr. */ if (IsA(expr, FuncExpr)) { FuncExpr *func = (FuncExpr *) expr; state->args = ExecInitExprList(func->args, parent); init_sexpr(func->funcid, func->inputcollid, expr, state, parent, econtext->ecxt_per_query_memory, true, true); } else if (IsA(expr, OpExpr)) { OpExpr *op = (OpExpr *) expr; state->args = ExecInitExprList(op->args, parent); init_sexpr(op->opfuncid, op->inputcollid, expr, state, parent, econtext->ecxt_per_query_memory, true, true); } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); /* shouldn't get here unless the selected function returns set */ Assert(state->func.fn_retset); return state; }
/* * ExecScanReScan * * This must be called within the ReScan function of any plan node type * that uses ExecScan(). */ void ExecScanReScan(ScanState *node) { EState *estate = node->ps.state; /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */ if (estate->es_epqScanDone != NULL) { Index scanrelid = ((Scan *) node->ps.plan)->scanrelid; if (scanrelid > 0) estate->es_epqScanDone[scanrelid - 1] = false; else { Bitmapset *relids; int rtindex = -1; /* * If an FDW or custom scan provider has replaced the join with a * scan, there are multiple RTIs; reset the epqScanDone flag for * all of them. */ if (IsA(node->ps.plan, ForeignScan)) relids = ((ForeignScan *) node->ps.plan)->fs_relids; else if (IsA(node->ps.plan, CustomScan)) relids = ((CustomScan *) node->ps.plan)->custom_relids; else elog(ERROR, "unexpected scan node: %d", (int) nodeTag(node->ps.plan)); while ((rtindex = bms_next_member(relids, rtindex)) >= 0) { Assert(rtindex > 0); estate->es_epqScanDone[rtindex - 1] = false; } } } }
/* * CStoreProcessUtility is the hook for handling utility commands. This function * intercepts "COPY cstore_table FROM" statements, and redirectes execution to * CopyIntoCStoreTable function. For all other utility statements, the function * calls the previous utility hook or the standard utility command. */ static void CStoreProcessUtility(Node *parseTree, const char *queryString, ProcessUtilityContext context, ParamListInfo paramListInfo, DestReceiver *destReceiver, char *completionTag) { bool copyIntoCStoreTable = false; /* check if the statement is a "COPY cstore_table FROM ..." statement */ if (nodeTag(parseTree) == T_CopyStmt) { CopyStmt *copyStatement = (CopyStmt *) parseTree; if (copyStatement->is_from && CStoreTable(copyStatement->relation)) { copyIntoCStoreTable = true; } } if (copyIntoCStoreTable) { uint64 processed = CopyIntoCStoreTable((CopyStmt *) parseTree, queryString); if (completionTag != NULL) { snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "COPY " UINT64_FORMAT, processed); } } else if (PreviousProcessUtilityHook != NULL) { PreviousProcessUtilityHook(parseTree, queryString, context, paramListInfo, destReceiver, completionTag); } else { standard_ProcessUtility(parseTree, queryString, context, paramListInfo, destReceiver, completionTag); } }
void DMLUtils::PrepareUpdateState(ModifyTablePlanState *info, ModifyTableState *mt_plan_state) { // Should be only one sub plan which is a SeqScan assert(mt_plan_state->mt_nplans == 1); assert(mt_plan_state->mt_plans != nullptr); // Get the first sub plan state PlanState *sub_planstate = mt_plan_state->mt_plans[0]; assert(sub_planstate); auto child_tag = nodeTag(sub_planstate->plan); if (child_tag == T_SeqScan || child_tag == T_IndexScan || child_tag == T_IndexOnlyScan || child_tag == T_BitmapHeapScan) { // Sub plan is a Scan of any type LOG_TRACE("Child of Update is %u ", child_tag); // Extract the projection info from the underlying scan // and put it in our update node auto scan_state = reinterpret_cast<ScanState *>(sub_planstate); auto child_planstate = (AbstractScanPlanState *)PreparePlanState(nullptr, sub_planstate, true); child_planstate->proj = BuildProjectInfo(scan_state->ps.ps_ProjInfo, info->table_nattrs); info->mt_plans = (AbstractPlanState **)palloc(sizeof(AbstractPlanState *) * mt_plan_state->mt_nplans); info->mt_plans[0] = child_planstate; } else { LOG_ERROR("Unsupported sub plan type of Update : %u ", child_tag); } }
static void pxf_free_expression_items_list(List *expressionItems, bool freeBoolExprNodes) { ExpressionItem *expressionItem = NULL; int previousLength; while (list_length(expressionItems) > 0) { expressionItem = (ExpressionItem *) lfirst(list_head(expressionItems)); if (freeBoolExprNodes && nodeTag(expressionItem->node) == T_BoolExpr) { pfree((BoolExpr *)expressionItem->node); } pfree(expressionItem); /* to avoid freeing already freed items - delete all occurrences of current expression*/ previousLength = expressionItems->length + 1; while (expressionItems != NULL && previousLength > expressionItems->length) { previousLength = expressionItems->length; expressionItems = list_delete_ptr(expressionItems, expressionItem); } } }
/* * ExecIndexBuildScanKeys * Build the index scan keys from the index qualification expressions * * The index quals are passed to the index AM in the form of a ScanKey array. * This routine sets up the ScanKeys, fills in all constant fields of the * ScanKeys, and prepares information about the keys that have non-constant * comparison values. We divide index qual expressions into five types: * * 1. Simple operator with constant comparison value ("indexkey op constant"). * For these, we just fill in a ScanKey containing the constant value. * * 2. Simple operator with non-constant value ("indexkey op expression"). * For these, we create a ScanKey with everything filled in except the * expression value, and set up an IndexRuntimeKeyInfo struct to drive * evaluation of the expression at the right times. * * 3. RowCompareExpr ("(indexkey, indexkey, ...) op (expr, expr, ...)"). * For these, we create a header ScanKey plus a subsidiary ScanKey array, * as specified in access/skey.h. The elements of the row comparison * can have either constant or non-constant comparison values. * * 4. ScalarArrayOpExpr ("indexkey op ANY (array-expression)"). For these, * we create a ScanKey with everything filled in except the comparison value, * and set up an IndexArrayKeyInfo struct to drive processing of the qual. * (Note that we treat all array-expressions as requiring runtime evaluation, * even if they happen to be constants.) * * 5. NullTest ("indexkey IS NULL/IS NOT NULL"). We just fill in the * ScanKey properly. * * This code is also used to prepare ORDER BY expressions for amcanorderbyop * indexes. The behavior is exactly the same, except that we have to look up * the operator differently. Note that only cases 1 and 2 are currently * possible for ORDER BY. * * Input params are: * * planstate: executor state node we are working for * index: the index we are building scan keys for * scanrelid: varno of the index's relation within current query * quals: indexquals (or indexorderbys) expressions * isorderby: true if processing ORDER BY exprs, false if processing quals * *runtimeKeys: ptr to pre-existing IndexRuntimeKeyInfos, or NULL if none * *numRuntimeKeys: number of pre-existing runtime keys * * Output params are: * * *scanKeys: receives ptr to array of ScanKeys * *numScanKeys: receives number of scankeys * *runtimeKeys: receives ptr to array of IndexRuntimeKeyInfos, or NULL if none * *numRuntimeKeys: receives number of runtime keys * *arrayKeys: receives ptr to array of IndexArrayKeyInfos, or NULL if none * *numArrayKeys: receives number of array keys * * Caller may pass NULL for arrayKeys and numArrayKeys to indicate that * ScalarArrayOpExpr quals are not supported. */ void ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid, List *quals, bool isorderby, ScanKey *scanKeys, int *numScanKeys, IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys, IndexArrayKeyInfo **arrayKeys, int *numArrayKeys) { ListCell *qual_cell; ScanKey scan_keys; IndexRuntimeKeyInfo *runtime_keys; IndexArrayKeyInfo *array_keys; int n_scan_keys; int n_runtime_keys; int max_runtime_keys; int n_array_keys; int j; /* Allocate array for ScanKey structs: one per qual */ n_scan_keys = list_length(quals); scan_keys = (ScanKey) palloc(n_scan_keys * sizeof(ScanKeyData)); /* * runtime_keys array is dynamically resized as needed. We handle it this * way so that the same runtime keys array can be shared between * indexquals and indexorderbys, which will be processed in separate calls * of this function. Caller must be sure to pass in NULL/0 for first * call. */ runtime_keys = *runtimeKeys; n_runtime_keys = max_runtime_keys = *numRuntimeKeys; /* Allocate array_keys as large as it could possibly need to be */ array_keys = (IndexArrayKeyInfo *) palloc0(n_scan_keys * sizeof(IndexArrayKeyInfo)); n_array_keys = 0; /* * for each opclause in the given qual, convert the opclause into a single * scan key */ j = 0; foreach(qual_cell, quals) { Expr *clause = (Expr *) lfirst(qual_cell); ScanKey this_scan_key = &scan_keys[j++]; Oid opno; /* operator's OID */ RegProcedure opfuncid; /* operator proc id used in scan */ Oid opfamily; /* opfamily of index column */ int op_strategy; /* operator's strategy number */ Oid op_lefttype; /* operator's declared input types */ Oid op_righttype; Expr *leftop; /* expr on lhs of operator */ Expr *rightop; /* expr on rhs ... */ AttrNumber varattno; /* att number used in scan */ if (IsA(clause, OpExpr)) { /* indexkey op const or indexkey op expression */ int flags = 0; Datum scanvalue; opno = ((OpExpr *) clause)->opno; opfuncid = ((OpExpr *) clause)->opfuncid; /* * leftop should be the index key Var, possibly relabeled */ leftop = (Expr *) get_leftop(clause); if (leftop && IsA(leftop, RelabelType)) leftop = ((RelabelType *) leftop)->arg; Assert(leftop != NULL); if (!(IsA(leftop, Var) && ((Var *) leftop)->varno == scanrelid)) elog(ERROR, "indexqual doesn't have key on left side"); varattno = ((Var *) leftop)->varattno; if (varattno < 1 || varattno > index->rd_index->indnatts) elog(ERROR, "bogus index qualification"); /* * We have to look up the operator's strategy number. This * provides a cross-check that the operator does match the index. */ opfamily = index->rd_opfamily[varattno - 1]; get_op_opfamily_properties(opno, opfamily, isorderby, &op_strategy, &op_lefttype, &op_righttype); if (isorderby) flags |= SK_ORDER_BY; /* * rightop is the constant or variable comparison value */ rightop = (Expr *) get_rightop(clause); if (rightop && IsA(rightop, RelabelType)) rightop = ((RelabelType *) rightop)->arg; Assert(rightop != NULL); if (IsA(rightop, Const)) { /* OK, simple constant comparison value */ scanvalue = ((Const *) rightop)->constvalue; if (((Const *) rightop)->constisnull) flags |= SK_ISNULL; } else { /* Need to treat this one as a runtime key */ if (n_runtime_keys >= max_runtime_keys) { if (max_runtime_keys == 0) { max_runtime_keys = 8; runtime_keys = (IndexRuntimeKeyInfo *) palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo)); } else { max_runtime_keys *= 2; runtime_keys = (IndexRuntimeKeyInfo *) repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo)); } } runtime_keys[n_runtime_keys].scan_key = this_scan_key; runtime_keys[n_runtime_keys].key_expr = ExecInitExpr(rightop, planstate); runtime_keys[n_runtime_keys].key_toastable = TypeIsToastable(op_righttype); n_runtime_keys++; scanvalue = (Datum) 0; } /* * initialize the scan key's fields appropriately */ ScanKeyEntryInitialize(this_scan_key, flags, varattno, /* attribute number to scan */ op_strategy, /* op's strategy */ op_righttype, /* strategy subtype */ ((OpExpr *) clause)->inputcollid, /* collation */ opfuncid, /* reg proc to use */ scanvalue); /* constant */ } else if (IsA(clause, RowCompareExpr)) { /* (indexkey, indexkey, ...) op (expression, expression, ...) */ RowCompareExpr *rc = (RowCompareExpr *) clause; ListCell *largs_cell = list_head(rc->largs); ListCell *rargs_cell = list_head(rc->rargs); ListCell *opnos_cell = list_head(rc->opnos); ListCell *collids_cell = list_head(rc->inputcollids); ScanKey first_sub_key; int n_sub_key; Assert(!isorderby); first_sub_key = (ScanKey) palloc(list_length(rc->opnos) * sizeof(ScanKeyData)); n_sub_key = 0; /* Scan RowCompare columns and generate subsidiary ScanKey items */ while (opnos_cell != NULL) { ScanKey this_sub_key = &first_sub_key[n_sub_key]; int flags = SK_ROW_MEMBER; Datum scanvalue; Oid inputcollation; /* * leftop should be the index key Var, possibly relabeled */ leftop = (Expr *) lfirst(largs_cell); largs_cell = lnext(largs_cell); if (leftop && IsA(leftop, RelabelType)) leftop = ((RelabelType *) leftop)->arg; Assert(leftop != NULL); if (!(IsA(leftop, Var) && ((Var *) leftop)->varno == scanrelid)) elog(ERROR, "indexqual doesn't have key on left side"); varattno = ((Var *) leftop)->varattno; /* * We have to look up the operator's associated btree support * function */ opno = lfirst_oid(opnos_cell); opnos_cell = lnext(opnos_cell); if (index->rd_rel->relam != BTREE_AM_OID || varattno < 1 || varattno > index->rd_index->indnatts) elog(ERROR, "bogus RowCompare index qualification"); opfamily = index->rd_opfamily[varattno - 1]; get_op_opfamily_properties(opno, opfamily, isorderby, &op_strategy, &op_lefttype, &op_righttype); if (op_strategy != rc->rctype) elog(ERROR, "RowCompare index qualification contains wrong operator"); opfuncid = get_opfamily_proc(opfamily, op_lefttype, op_righttype, BTORDER_PROC); inputcollation = lfirst_oid(collids_cell); collids_cell = lnext(collids_cell); /* * rightop is the constant or variable comparison value */ rightop = (Expr *) lfirst(rargs_cell); rargs_cell = lnext(rargs_cell); if (rightop && IsA(rightop, RelabelType)) rightop = ((RelabelType *) rightop)->arg; Assert(rightop != NULL); if (IsA(rightop, Const)) { /* OK, simple constant comparison value */ scanvalue = ((Const *) rightop)->constvalue; if (((Const *) rightop)->constisnull) flags |= SK_ISNULL; } else { /* Need to treat this one as a runtime key */ if (n_runtime_keys >= max_runtime_keys) { if (max_runtime_keys == 0) { max_runtime_keys = 8; runtime_keys = (IndexRuntimeKeyInfo *) palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo)); } else { max_runtime_keys *= 2; runtime_keys = (IndexRuntimeKeyInfo *) repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo)); } } runtime_keys[n_runtime_keys].scan_key = this_sub_key; runtime_keys[n_runtime_keys].key_expr = ExecInitExpr(rightop, planstate); runtime_keys[n_runtime_keys].key_toastable = TypeIsToastable(op_righttype); n_runtime_keys++; scanvalue = (Datum) 0; } /* * initialize the subsidiary scan key's fields appropriately */ ScanKeyEntryInitialize(this_sub_key, flags, varattno, /* attribute number */ op_strategy, /* op's strategy */ op_righttype, /* strategy subtype */ inputcollation, /* collation */ opfuncid, /* reg proc to use */ scanvalue); /* constant */ n_sub_key++; } /* Mark the last subsidiary scankey correctly */ first_sub_key[n_sub_key - 1].sk_flags |= SK_ROW_END; /* * We don't use ScanKeyEntryInitialize for the header because it * isn't going to contain a valid sk_func pointer. */ MemSet(this_scan_key, 0, sizeof(ScanKeyData)); this_scan_key->sk_flags = SK_ROW_HEADER; this_scan_key->sk_attno = first_sub_key->sk_attno; this_scan_key->sk_strategy = rc->rctype; /* sk_subtype, sk_collation, sk_func not used in a header */ this_scan_key->sk_argument = PointerGetDatum(first_sub_key); } else if (IsA(clause, ScalarArrayOpExpr)) { /* indexkey op ANY (array-expression) */ ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; Assert(!isorderby); Assert(saop->useOr); opno = saop->opno; opfuncid = saop->opfuncid; /* * leftop should be the index key Var, possibly relabeled */ leftop = (Expr *) linitial(saop->args); if (leftop && IsA(leftop, RelabelType)) leftop = ((RelabelType *) leftop)->arg; Assert(leftop != NULL); if (!(IsA(leftop, Var) && ((Var *) leftop)->varno == scanrelid)) elog(ERROR, "indexqual doesn't have key on left side"); varattno = ((Var *) leftop)->varattno; if (varattno < 1 || varattno > index->rd_index->indnatts) elog(ERROR, "bogus index qualification"); /* * We have to look up the operator's strategy number. This * provides a cross-check that the operator does match the index. */ opfamily = index->rd_opfamily[varattno - 1]; get_op_opfamily_properties(opno, opfamily, isorderby, &op_strategy, &op_lefttype, &op_righttype); /* * rightop is the constant or variable array value */ rightop = (Expr *) lsecond(saop->args); if (rightop && IsA(rightop, RelabelType)) rightop = ((RelabelType *) rightop)->arg; Assert(rightop != NULL); array_keys[n_array_keys].scan_key = this_scan_key; array_keys[n_array_keys].array_expr = ExecInitExpr(rightop, planstate); /* the remaining fields were zeroed by palloc0 */ n_array_keys++; /* * initialize the scan key's fields appropriately */ ScanKeyEntryInitialize(this_scan_key, 0, /* flags */ varattno, /* attribute number to scan */ op_strategy, /* op's strategy */ op_righttype, /* strategy subtype */ saop->inputcollid, /* collation */ opfuncid, /* reg proc to use */ (Datum) 0); /* constant */ } else if (IsA(clause, NullTest)) { /* indexkey IS NULL or indexkey IS NOT NULL */ NullTest *ntest = (NullTest *) clause; int flags; Assert(!isorderby); /* * argument should be the index key Var, possibly relabeled */ leftop = ntest->arg; if (leftop && IsA(leftop, RelabelType)) leftop = ((RelabelType *) leftop)->arg; Assert(leftop != NULL); if (!(IsA(leftop, Var) && ((Var *) leftop)->varno == scanrelid)) elog(ERROR, "NullTest indexqual has wrong key"); varattno = ((Var *) leftop)->varattno; /* * initialize the scan key's fields appropriately */ switch (ntest->nulltesttype) { case IS_NULL: flags = SK_ISNULL | SK_SEARCHNULL; break; case IS_NOT_NULL: flags = SK_ISNULL | SK_SEARCHNOTNULL; break; default: elog(ERROR, "unrecognized nulltesttype: %d", (int) ntest->nulltesttype); flags = 0; /* keep compiler quiet */ break; } ScanKeyEntryInitialize(this_scan_key, flags, varattno, /* attribute number to scan */ InvalidStrategy, /* no strategy */ InvalidOid, /* no strategy subtype */ InvalidOid, /* no collation */ InvalidOid, /* no reg proc for this */ (Datum) 0); /* constant */ } else elog(ERROR, "unsupported indexqual type: %d", (int) nodeTag(clause)); }