<commit_before>#include "col-internal.h"
#include "parser/analyze.h"
#include "parser/walker.h"
#include "planner/planner-internal.h"
#include "types/datum.h"

static Datum
eval_const_expr(AstConstExpr *ast_const, PlannerState *state)
{
    DataType const_type;
    Datum result;

    const_type = expr_get_type((ColNode *) ast_const);
    result = datum_from_str(const_type, ast_const->value);
    pool_track_datum(state->plan_pool, result, const_type);
    return result;
}

static int
get_var_index_from_join(const char *var_name, AstJoinClause *join)
{
    ListCell *lc;
    int i;

    i = 0;
    foreach (lc, join->ref->cols)
    {
        AstColumnRef *col = (AstColumnRef *) lc_ptr(lc);
        AstVarExpr *var;

        ASSERT(col->expr->kind == AST_VAR_EXPR);
        var = (AstVarExpr *) col->expr;

        if (strcmp(var->name, var_name) == 0)
            return i;

        i++;
    }

    return -1;
}

static int
get_var_index_from_plist(const char *var_name, List *proj_list)
{
    ListCell *lc;
    int i;

    i = 0;
    foreach (lc, proj_list)
    {
        ExprVar *expr_var = (ExprVar *) lc_ptr(lc);

        if (strcmp(expr_var->name, var_name) == 0)
            return i;

        i++;
    }

    return -1;
}

/*
 * XXX: Terribly ugly. Should use a uniform interface for finding the index
 * associated with a given variable name.
 */
static ExprNode *
fix_qual_expr(ColNode *ast_qual, AstJoinClause *outer_rel,
              OpChainPlan *chain_plan, PlannerState *state)
{
    ExprNode *result;

    switch (ast_qual->kind)
    {
        case AST_CONST_EXPR:
            {
                AstConstExpr *ast_const = (AstConstExpr *) ast_qual;
                Datum const_val;
                ExprConst *expr_const;

                const_val = eval_const_expr(ast_const, state);
                expr_const = apr_pcalloc(state->plan_pool, sizeof(*expr_const));
                expr_const->expr.node.kind = EXPR_CONST;
                expr_const->expr.type = expr_get_type((ColNode *) ast_const);
                expr_const->value = const_val;
                result = (ExprNode *) expr_const;
            }
            break;

        case AST_OP_EXPR:
            {
                AstOpExpr *ast_op = (AstOpExpr *) ast_qual;
                ExprOp *expr_op;

                expr_op = apr_pcalloc(state->plan_pool, sizeof(*expr_op));
                expr_op->expr.node.kind = EXPR_OP;
                expr_op->expr.type = expr_get_type((ColNode *) ast_op);
                expr_op->op_kind = ast_op->op_kind;
                expr_op->lhs = fix_qual_expr(ast_op->lhs, outer_rel, chain_plan, state);
                expr_op->rhs = fix_qual_expr(ast_op->rhs, outer_rel, chain_plan, state);
                result = (ExprNode *) expr_op;
            }
            break;

        case AST_VAR_EXPR:
            {
                AstVarExpr *ast_var = (AstVarExpr *) ast_qual;
                int var_idx;
                bool is_outer = false;
                ExprVar *expr_var;

                /*
                 * If we haven't done projection yet, we need to look for
                 * variables in the delta table's join clause. Otherwise use
                 * the current projection list.
                 */
                if (state->current_plist == NULL)
                    var_idx = get_var_index_from_join(ast_var->name, chain_plan->delta_tbl);
                else
                    var_idx = get_var_index_from_plist(ast_var->name, state->current_plist);

                /*
                 * If the variable isn't in the projection list of the input
                 * to this operator, this must be a join and the variable is
                 * the scanned ("outer") relation.
                 */
                if (var_idx == -1 && outer_rel != NULL)
                {
                    is_outer = true;
                    var_idx = get_var_index_from_join(ast_var->name, outer_rel);
                }

                if (var_idx == -1)
                    ERROR("Failed to find variable %s", ast_var->name);

                expr_var = apr_pcalloc(state->plan_pool, sizeof(*expr_var));
                expr_var->expr.node.kind = EXPR_VAR;
                expr_var->expr.type = expr_get_type((ColNode *) ast_var);
                expr_var->attno = var_idx;
                expr_var->is_outer = is_outer;
                expr_var->name = apr_pstrdup(state->plan_pool, ast_var->name);
                result = (ExprNode *) expr_var;
            }
            break;

        default:
            ERROR("Unexpected expr node kind: %d", (int) ast_qual->kind);
    }

    return result;
}

typedef struct ProjListContext
{
    List *wip_plist;
    AstJoinClause *outer_rel;
    AstJoinClause *delta_tbl;
    PlannerState *state;
} ProjListContext;

static bool
make_proj_list_walker(ColNode *n, void *data)
{
    if (n->kind == AST_VAR_EXPR)
    {
        AstVarExpr *var = (AstVarExpr *) n;
        ProjListContext *cxt = (ProjListContext *) data;
        int var_idx;
        bool is_outer = false;

        if (cxt->state->current_plist == NULL)
            var_idx = get_var_index_from_join(var->name, cxt->delta_tbl);
        else
            var_idx = get_var_index_from_plist(var->name, cxt->state->current_plist);

        if (var_idx == -1 && cxt->outer_rel != NULL)
        {
            var_idx = get_var_index_from_join(var->name, cxt->outer_rel);
            is_outer = true;
        }

        if (var_idx != -1)
        {
            /* Don't add to proj list if it already contains this var */
            if (get_var_index_from_plist(var->name, cxt->wip_plist) == -1)
            {
                ExprVar *expr_var;

                expr_var = apr_pcalloc(cxt->state->plan_pool, sizeof(*expr_var));
                expr_var->expr.node.kind = EXPR_VAR;
                expr_var->expr.type = expr_get_type((ColNode *) var);
                expr_var->attno = var_idx;
                expr_var->is_outer = is_outer;
                expr_var->name = apr_pstrdup(cxt->state->plan_pool, var->name);

                list_append(cxt->wip_plist, expr_var);
            }<commit_msg>Code cleanup: reduce duplication.<commit_after>#include "col-internal.h"
#include "nodes/makefuncs.h"
#include "parser/analyze.h"
#include "parser/walker.h"
#include "planner/planner-internal.h"
#include "types/datum.h"

static Datum
eval_const_expr(AstConstExpr *ast_const, PlannerState *state)
{
    DataType const_type;
    Datum result;

    const_type = expr_get_type((ColNode *) ast_const);
    result = datum_from_str(const_type, ast_const->value);
    pool_track_datum(state->plan_pool, result, const_type);
    return result;
}

static int
get_var_index_from_join(const char *var_name, AstJoinClause *join)
{
    ListCell *lc;
    int i;

    i = 0;
    foreach (lc, join->ref->cols)
    {
        AstColumnRef *col = (AstColumnRef *) lc_ptr(lc);
        AstVarExpr *var;

        ASSERT(col->expr->kind == AST_VAR_EXPR);
        var = (AstVarExpr *) col->expr;

        if (strcmp(var->name, var_name) == 0)
            return i;

        i++;
    }

    return -1;
}

static int
get_var_index_from_plist(const char *var_name, List *proj_list)
{
    ListCell *lc;
    int i;

    i = 0;
    foreach (lc, proj_list)
    {
        ExprVar *expr_var = (ExprVar *) lc_ptr(lc);

        if (strcmp(expr_var->name, var_name) == 0)
            return i;

        i++;
    }

    return -1;
}

/*
 * XXX: Terribly ugly. Should use a uniform interface for finding the index
 * associated with a given variable name.
 */
static ExprNode *
fix_qual_expr(ColNode *ast_qual, AstJoinClause *outer_rel,
              OpChainPlan *chain_plan, PlannerState *state)
{
    ExprNode *result;

    switch (ast_qual->kind)
    {
        case AST_CONST_EXPR:
            {
                AstConstExpr *ast_const = (AstConstExpr *) ast_qual;
                Datum const_val;
                ExprConst *expr_const;

                const_val = eval_const_expr(ast_const, state);
                expr_const = apr_pcalloc(state->plan_pool, sizeof(*expr_const));
                expr_const->expr.node.kind = EXPR_CONST;
                expr_const->expr.type = expr_get_type((ColNode *) ast_const);
                expr_const->value = const_val;
                result = (ExprNode *) expr_const;
            }
            break;

        case AST_OP_EXPR:
            {
                AstOpExpr *ast_op = (AstOpExpr *) ast_qual;
                ExprOp *expr_op;

                expr_op = apr_pcalloc(state->plan_pool, sizeof(*expr_op));
                expr_op->expr.node.kind = EXPR_OP;
                expr_op->expr.type = expr_get_type((ColNode *) ast_op);
                expr_op->op_kind = ast_op->op_kind;
                expr_op->lhs = fix_qual_expr(ast_op->lhs, outer_rel, chain_plan, state);
                expr_op->rhs = fix_qual_expr(ast_op->rhs, outer_rel, chain_plan, state);
                result = (ExprNode *) expr_op;
            }
            break;

        case AST_VAR_EXPR:
            {
                AstVarExpr *ast_var = (AstVarExpr *) ast_qual;
                int var_idx;
                bool is_outer = false;
                DataType expr_type;

                /*
                 * If we haven't done projection yet, we need to look for
                 * variables in the delta table's join clause. Otherwise use
                 * the current projection list.
                 */
                if (state->current_plist == NULL)
                    var_idx = get_var_index_from_join(ast_var->name, chain_plan->delta_tbl);
                else
                    var_idx = get_var_index_from_plist(ast_var->name, state->current_plist);

                /*
                 * If the variable isn't in the projection list of the input
                 * to this operator, this must be a join and the variable is
                 * the scanned ("outer") relation.
                 */
                if (var_idx == -1 && outer_rel != NULL)
                {
                    is_outer = true;
                    var_idx = get_var_index_from_join(ast_var->name, outer_rel);
                }

                if (var_idx == -1)
                    ERROR("Failed to find variable %s", ast_var->name);

                expr_type = expr_get_type((ColNode *) ast_var);
                result = (ExprNode *) make_expr_var(expr_type,
                                                    var_idx, is_outer,
                                                    ast_var->name,
                                                    state->plan_pool);
            }
            break;

        default:
            ERROR("Unexpected expr node kind: %d", (int) ast_qual->kind);
    }

    return result;
}

typedef struct ProjListContext
{
    List *wip_plist;
    AstJoinClause *outer_rel;
    AstJoinClause *delta_tbl;
    PlannerState *state;
} ProjListContext;

static bool
make_proj_list_walker(ColNode *n, void *data)
{
    if (n->kind == AST_VAR_EXPR)
    {
        AstVarExpr *var = (AstVarExpr *) n;
        ProjListContext *cxt = (ProjListContext *) data;
        int var_idx;
        bool is_outer = false;

        if (cxt->state->current_plist == NULL)
            var_idx = get_var_index_from_join(var->name, cxt->delta_tbl);
        else
            var_idx = get_var_index_from_plist(var->name, cxt->state->current_plist);

        if (var_idx == -1 && cxt->outer_rel != NULL)
        {
            var_idx = get_var_index_from_join(var->name, cxt->outer_rel);
            is_outer = true;
        }

        if (var_idx != -1)
        {
            /* Don't add to proj list if it already contains this var */
            if (get_var_index_from_plist(var->name, cxt->wip_plist) == -1)
            {
                ExprVar *expr_var;

                expr_var = make_expr_var(expr_get_type((ColNode *) var),
                                         var_idx, is_outer, var->name,
                                         cxt->state->plan_pool);
                list_append(cxt->wip_plist, expr_var);
            }
{'fraction_non_alphanumeric': 0.1035453943008615, 'fraction_numerical': 0.0018223989396951624, 'mean_word_length': 1.727128981251412, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 116, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1660968', 'n_tokens_mistral': 3873, 'n_tokens_neox': 3666, 'n_words': 789}