Compute information about EEOP_*_FETCHSOME at expression init time.
authorAndres Freund <andres@anarazel.de>
Fri, 16 Nov 2018 06:00:30 +0000 (22:00 -0800)
committerAndres Freund <andres@anarazel.de>
Fri, 16 Nov 2018 06:00:30 +0000 (22:00 -0800)
Previously this information was computed when JIT compiling an
expression.  But the information is useful for assertions in the
non-JIT case too (for assertions), therefore it makes sense to move
it.

This will, in a followup commit, allow to treat different slot types
differently. E.g. for virtual slots there's no need to generate a JIT
function to deform the slot.

Author: Andres Freund
Discussion: https://postgr.es/m/20181105210039.hh4vvi4vwoq5ba2q@alap3.anarazel.de

src/backend/executor/execExpr.c
src/backend/jit/llvm/llvmjit_expr.c
src/include/executor/execExpr.h

index cd5ee91cd435db556b34f94ef1feaa70b3b5d66b..d64dab43b8df70c3f62e4a3d009766de8874b18f 100644 (file)
@@ -65,6 +65,7 @@ static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args,
 static void ExecInitExprSlots(ExprState *state, Node *node);
 static void ExecPushExprSlots(ExprState *state, LastAttnumInfo *info);
 static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info);
+static void ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op);
 static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable,
                                        ExprState *state);
 static void ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
@@ -2288,21 +2289,30 @@ ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
        {
                scratch.opcode = EEOP_INNER_FETCHSOME;
                scratch.d.fetch.last_var = info->last_inner;
+               scratch.d.fetch.fixed = false;
+               scratch.d.fetch.kind = NULL;
                scratch.d.fetch.known_desc = NULL;
+               ExecComputeSlotInfo(state, &scratch);
                ExprEvalPushStep(state, &scratch);
        }
        if (info->last_outer > 0)
        {
                scratch.opcode = EEOP_OUTER_FETCHSOME;
                scratch.d.fetch.last_var = info->last_outer;
+               scratch.d.fetch.fixed = false;
+               scratch.d.fetch.kind = NULL;
                scratch.d.fetch.known_desc = NULL;
+               ExecComputeSlotInfo(state, &scratch);
                ExprEvalPushStep(state, &scratch);
        }
        if (info->last_scan > 0)
        {
                scratch.opcode = EEOP_SCAN_FETCHSOME;
                scratch.d.fetch.last_var = info->last_scan;
+               scratch.d.fetch.fixed = false;
+               scratch.d.fetch.kind = NULL;
                scratch.d.fetch.known_desc = NULL;
+               ExecComputeSlotInfo(state, &scratch);
                ExprEvalPushStep(state, &scratch);
        }
 }
@@ -2355,6 +2365,94 @@ get_last_attnums_walker(Node *node, LastAttnumInfo *info)
                                                                  (void *) info);
 }
 
+/*
+ * Compute additional information for EEOP_*_FETCHSOME ops.
+ *
+ * The goal is to determine whether a slot is 'fixed', that is, every
+ * evaluation of the the expression will have the same type of slot, with an
+ * equivalent descriptor.
+ */
+static void
+ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
+{
+       PlanState *parent = state->parent;
+       TupleDesc       desc = NULL;
+       const TupleTableSlotOps *tts_ops = NULL;
+       bool isfixed = false;
+
+       if (op->d.fetch.known_desc != NULL)
+       {
+               desc = op->d.fetch.known_desc;
+               tts_ops = op->d.fetch.kind;
+               isfixed = op->d.fetch.kind != NULL;
+       }
+       else if (!parent)
+       {
+               isfixed = false;
+       }
+       else if (op->opcode == EEOP_INNER_FETCHSOME)
+       {
+               PlanState  *is = innerPlanState(parent);
+
+               if (parent->inneropsset && !parent->inneropsfixed)
+               {
+                       isfixed = false;
+               }
+               else if (parent->inneropsset && parent->innerops)
+               {
+                       isfixed = true;
+                       tts_ops = parent->innerops;
+               }
+               else if (is)
+               {
+                       tts_ops = ExecGetResultSlotOps(is, &isfixed);
+                       desc = ExecGetResultType(is);
+               }
+       }
+       else if (op->opcode == EEOP_OUTER_FETCHSOME)
+       {
+               PlanState  *os = outerPlanState(parent);
+
+               if (parent->outeropsset && !parent->outeropsfixed)
+               {
+                       isfixed = false;
+               }
+               else if (parent->outeropsset && parent->outerops)
+               {
+                       isfixed = true;
+                       tts_ops = parent->outerops;
+               }
+               else if (os)
+               {
+                       tts_ops = ExecGetResultSlotOps(os, &isfixed);
+                       desc = ExecGetResultType(os);
+               }
+       }
+       else if (op->opcode == EEOP_SCAN_FETCHSOME)
+       {
+               desc = parent->scandesc;
+
+               if (parent && parent->scanops)
+                       tts_ops = parent->scanops;
+
+               if (parent->scanopsset)
+                       isfixed = parent->scanopsfixed;
+       }
+
+       if (isfixed && desc != NULL && tts_ops != NULL)
+       {
+               op->d.fetch.fixed = true;
+               op->d.fetch.kind = tts_ops;
+               op->d.fetch.known_desc = desc;
+       }
+       else
+       {
+               op->d.fetch.fixed = false;
+               op->d.fetch.kind = NULL;
+               op->d.fetch.known_desc = NULL;
+       }
+}
+
 /*
  * Prepare step for the evaluation of a whole-row variable.
  * The caller still has to push the step.
@@ -3255,12 +3353,18 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
        /* push deform steps */
        scratch.opcode = EEOP_INNER_FETCHSOME;
        scratch.d.fetch.last_var = maxatt;
+       scratch.d.fetch.fixed = false;
        scratch.d.fetch.known_desc = ldesc;
+       scratch.d.fetch.kind = lops;
+       ExecComputeSlotInfo(state, &scratch);
        ExprEvalPushStep(state, &scratch);
 
        scratch.opcode = EEOP_OUTER_FETCHSOME;
        scratch.d.fetch.last_var = maxatt;
+       scratch.d.fetch.fixed = false;
        scratch.d.fetch.known_desc = rdesc;
+       scratch.d.fetch.kind = rops;
+       ExecComputeSlotInfo(state, &scratch);
        ExprEvalPushStep(state, &scratch);
 
        /*
index 0dbc1e41062def6c2928aca102d5d8db5ae1a6a7..be9b2aecffe0103ce74def93e80e3dc0caa6a210 100644 (file)
@@ -276,6 +276,8 @@ llvm_compile_expr(ExprState *state)
                                        LLVMValueRef v_slot;
                                        LLVMBasicBlockRef b_fetch;
                                        LLVMValueRef v_nvalid;
+                                       LLVMValueRef l_jit_deform = NULL;
+                                       const TupleTableSlotOps *tts_ops = NULL;
 
                                        b_fetch = l_bb_before_v(opblocks[i + 1],
                                                                                        "op.%d.fetch", i);
@@ -283,40 +285,22 @@ llvm_compile_expr(ExprState *state)
                                        if (op->d.fetch.known_desc)
                                                desc = op->d.fetch.known_desc;
 
-                                       if (opcode == EEOP_INNER_FETCHSOME)
-                                       {
-                                               PlanState  *is = innerPlanState(parent);
+                                       if (op->d.fetch.fixed)
+                                               tts_ops = op->d.fetch.kind;
 
+                                       if (opcode == EEOP_INNER_FETCHSOME)
                                                v_slot = v_innerslot;
-
-                                               if (!desc &&
-                                                       is &&
-                                                       is->ps_ResultTupleSlot &&
-                                                       TTS_FIXED(is->ps_ResultTupleSlot))
-                                                       desc = is->ps_ResultTupleSlot->tts_tupleDescriptor;
-                                       }
                                        else if (opcode == EEOP_OUTER_FETCHSOME)
-                                       {
-                                               PlanState  *os = outerPlanState(parent);
-
                                                v_slot = v_outerslot;
-
-                                               if (!desc &&
-                                                       os &&
-                                                       os->ps_ResultTupleSlot &&
-                                                       TTS_FIXED(os->ps_ResultTupleSlot))
-                                                       desc = os->ps_ResultTupleSlot->tts_tupleDescriptor;
-                                       }
                                        else
-                                       {
                                                v_slot = v_scanslot;
-                                               if (!desc && parent)
-                                                       desc = parent->scandesc;
-                                       }
 
                                        /*
                                         * Check if all required attributes are available, or
                                         * whether deforming is required.
+                                        *
+                                        * TODO: skip nvalid check if slot is fixed and known to
+                                        * be a virtual slot.
                                         */
                                        v_nvalid =
                                                l_load_struct_gep(b, v_slot,
@@ -336,19 +320,21 @@ llvm_compile_expr(ExprState *state)
                                         * function specific to tupledesc and the exact number of
                                         * to-be-extracted attributes.
                                         */
-                                       if (desc && (context->base.flags & PGJIT_DEFORM))
+                                       if (tts_ops && desc && (context->base.flags & PGJIT_DEFORM))
                                        {
-                                               LLVMValueRef params[1];
-                                               LLVMValueRef l_jit_deform;
-
                                                l_jit_deform =
                                                        slot_compile_deform(context, desc,
                                                                                                op->d.fetch.last_var);
+                                       }
+
+                                       if (l_jit_deform)
+                                       {
+                                               LLVMValueRef params[1];
+
                                                params[0] = v_slot;
 
                                                LLVMBuildCall(b, l_jit_deform,
                                                                          params, lengthof(params), "");
-
                                        }
                                        else
                                        {
index ac53935d700b686debea905894da4b93e0991dec..194bf46e0f570c596ab82ddd2fef967560787884 100644 (file)
@@ -262,7 +262,12 @@ typedef struct ExprEvalStep
                {
                        /* attribute number up to which to fetch (inclusive) */
                        int                     last_var;
+                       /* will the type of slot be the same for every invocation */
+                       bool            fixed;
+                       /* tuple descriptor, if known */
                        TupleDesc       known_desc;
+                       /* type of slot, can only be relied upon if fixed is set */
+                       const TupleTableSlotOps *kind;
                }                       fetch;
 
                /* for EEOP_INNER/OUTER/SCAN_[SYS]VAR[_FIRST] */