【SQL引擎 - analyze.cpp(四)】

SQL引擎 - analyze.cpp分析(四)

(一)SQL简要介绍


数据库的SQL引擎是数据库重要的子系统之一,它对上负责承接应用程序发送过来的SQL语句对下负责指挥执行器运行执行计划。其中优化器作为SQL引擎中最重要、最复杂的模块,被称为数据库的“大脑”,优化器产生的执行计划的优劣直接决定数据库的性能。

SQL引擎主要包括查询解析(parser)、查询分流(traffic cop)、查询优化(optimizer)、查询执行(executor)。parser源码目录为/src/common/backend/parser:
在这里插入图片描述

(二)transformStmt


/*
 * 说明:检查删除stmt是否为plan_table。
 * 参数:
 * @in relname:要删除的对象名称。
 * 如果对象名称为plan_table,则返回:true
 */
static bool checkDeleteStmtForPlanTable(const char* relname)
{
    OnlyDeleteFromPlanTable = false;
    const char* target_rel = V_PLAN_TABLE;
    Oid plan_table_data_oid = RelnameGetRelid(T_PLAN_TABLE_DATA);
    if (strcasecmp(relname, target_rel) == 0 && plan_table_data_oid != InvalidOid)
        return true;

    return false;
}
/*
 * 说明:make SessionIdExpr for WhereClause
 * 参数:
 * @in cur_location:当前位置
 * @out lexpr:左expr
 * @out rexpr:正确的expr
 * @out op_loc:操作位置
 * Return: void
 */
static void makeSessionIdExpr(Node** lexpr, Node** rexpr, int* cur_location, int* op_loc)
{
    /* 为session_id设置过滤条件 */
    char* lcolname = "session_id";
    ColumnRef* c = makeNode(ColumnRef);
    c->fields = list_make1(makeString(lcolname));
    c->location = *cur_location;

    *cur_location = *cur_location + strlen("session_id=");
    *op_loc = *cur_location - 1;

    char* s_id = (char*)palloc0(SESSION_ID_LEN);
    getSessionID(s_id,
        IS_THREAD_POOL_WORKER ? u_sess->proc_cxt.MyProcPort->SessionStartTime : t_thrd.proc_cxt.MyStartTime,
        IS_THREAD_POOL_WORKER ? u_sess->session_id : t_thrd.proc_cxt.MyProcPid);
    A_Const* n = makeNode(A_Const);
    n->val.type = T_String;
    n->val.val.str = s_id;
    n->location = *cur_location;

    *cur_location = *cur_location + strlen(s_id) + 3;

    *lexpr = (Node*)c;
    *rexpr = (Node*)n;
}

/*
 * 说明:make UserIdExpr for WhereClause。
 * 参数:
 * @in cur_location:当前位置
 * @out lexpr:左expr
 * @out rexpr:正确的expr
 * @out op_loc:操作位置
 * Return: void
 */
static void makeUserIdExpr(Node** lexpr, Node** rexpr, int* cur_location, int* op_loc)
{
    /* 对于过滤条件user_id */
    char* lcolname = "user_id";
    ColumnRef* c = makeNode(ColumnRef);
    c->fields = list_make1(makeString(lcolname));
    c->location = *cur_location;

    *cur_location = *cur_location + strlen("user_id=");
    *op_loc = *cur_location - 1;

    Oid user_id = GetCurrentUserId();
    A_Const* n = makeNode(A_Const);
    n->val.type = T_Integer;
    n->val.val.ival = user_id;
    n->location = *cur_location;

    *lexpr = (Node*)c;
    *rexpr = (Node*)n;
}

/*
 * 说明:为plan_table detele stmt创建包含SessionIdExpr和UserIdExpr的WhereClause节点
 * 参数:
 * @in cur_location:当前位置
 * @out where eclause:我们做的where eclause
 * Return: void
 */
static void makeNewWhereClause(Node** whereClause, int* cur_location)
{
    Node* lexpr = NULL;
    Node* rexpr = NULL;
    A_Expr* clause_1 = NULL;
    A_Expr* clause_2 = NULL;

    int op_loc = -1;
    int and_loc = -1;

    makeSessionIdExpr(&lexpr, &rexpr, cur_location, &op_loc);
    clause_1 = makeSimpleA_Expr(AEXPR_OP, "=", lexpr, rexpr, op_loc);

    and_loc = *cur_location;
    *cur_location = *cur_location + strlen("AND ");

    makeUserIdExpr(&lexpr, &rexpr, cur_location, &op_loc);
    clause_2 = makeSimpleA_Expr(AEXPR_OP, "=", lexpr, rexpr, op_loc);

    *whereClause = (Node*)makeA_Expr(AEXPR_AND, NIL, (Node*)clause_1, (Node*)clause_2, and_loc);
}

/*
 * 说明:为plan_table detele stmt添加WhereClause。
 * 参数:
 * @in pstate: ParseState.
 * @int stmt: delete stmt that user input.
 * 返回:删除testmt加上新的WhereClause
 */
static DeleteStmt* addWhereClauseForPlanTable(ParseState* pstate, DeleteStmt* stmt)
{
    int current_location = -1;

    DeleteStmt* new_stmt = (DeleteStmt*)copyObject(stmt);
    new_stmt->relation->relname = T_PLAN_TABLE_DATA;

    current_location = strlen("delete from plan_table_data where ");

    /* 创建一个新的WhereClause,其中包含session_id和user_id过滤器条件. */
    if (new_stmt->whereClause == NULL) {
        makeNewWhereClause(&new_stmt->whereClause, &current_location);
    } else {
        /* 在原来的WhereClause后面添加一个包含session_id和user_id的WhereClause过滤条件. */
        makeNewWhereClause(&new_stmt->whereClause, &current_location);

        new_stmt->whereClause = (Node*)makeA_Expr(AEXPR_AND, NIL, new_stmt->whereClause, stmt->whereClause, -1);
    }

    return new_stmt;
}

const void SendCommandIdForInsertCte(Query* qry, WithClause* withclause)
{
    ListCell* tl = NULL;

    /*
     * For a WITH query that deletes from a parent table in the
     * main query & inserts a row in the child table in the WITH query
     * we need to use command ID communication to remote nodes in order
     * to maintain global data visibility.
     * For example
     * CREATE TEMP TABLE parent ( id int, val text ) DISTRIBUTE BY REPLICATION;
     * CREATE TEMP TABLE child ( ) INHERITS ( parent ) DISTRIBUTE BY REPLICATION;
     * INSERT INTO parent VALUES ( 42, 'old' );
     * INSERT INTO child VALUES ( 42, 'older' );
     * WITH wcte AS ( INSERT INTO child VALUES ( 42, 'new' ) RETURNING id AS newid )
     * DELETE FROM parent USING wcte WHERE id = newid;
     * The last query gets translated into the following multi-statement
     * transaction on the primary datanode
     * (a) SELECT id, ctid FROM ONLY parent WHERE true
     * (b) START TRANSACTION ISOLATION LEVEL read committed READ WRITE
     * (c) INSERT INTO child (id, val) VALUES ($1, $2) RETURNING id -- (42, 'new')
     * (d) DELETE FROM ONLY parent parent WHERE (parent.ctid = $1)
     * (e) SELECT id, ctid FROM ONLY child parent WHERE true
     * (f) DELETE FROM ONLY child parent WHERE (parent.ctid = $1)
     * (g) COMMIT TRANSACTION
     * The command id of the select in step (e), should be such that
     * it does not see the insert of step (c)
     */
    if (IS_PGXC_COORDINATOR && !IsConnFromCoord()) {
        foreach (tl, withclause->ctes) {
            CommonTableExpr* cte = (CommonTableExpr*)lfirst(tl);
            if (IsA(cte->ctequery, InsertStmt)) {
                qry->has_to_save_cmd_id = true;
                SetSendCommandId(true);
                break;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值