delete 语句解析与执行

mac2026-04-11  3

代码传送门:

 3.1.2 参考代码(解析)

 3.2.3 参考代码(执行)


3.1 delete 语句的解析

3.1.1 

解析 sql 语句需要了解一些分词器和解析器

简要流程:

匹配 delete :使用 matchToken(TOKEN_RESERVED_WORD, "delete") 匹配获取表名:使用 if 判断是否是 TOKEN_WORD 类型,如果是,获得表名;给字符串指针开空间的时候可以使用 new_id_name() 函数匹配 where : matchToken(TOKEN_RESERVED_WORD,"where") ,注意不是所有 delete 语句都伴随一个 where 表达式使用 parseExpressionRD() 获取值(或者表达式),并包裹在 SRA_t 中( SRA_SELECT类型),作为 sql_stmt_delete->where 的值。(语句若不伴随 where 则仅需构造SRA_TABLE ,具体实现可参考 exp_01_stmt_parser/exp_01_03_select.cpp)创建 sql_stmt_delete 类型的指针,分配内存空间并对各字段进行赋值,返回该指针

常用函数:

push_back(elem); //向 vector 尾部加入数据Expression *Parser::parseExpressionRD(); //递归下降法解析表达式 详情看src/parser/parser.cpp 中SRA_t *SRATable(TableReference_t *ref); // SRA_TABLE 构造函数SRA_t *SRASelect(SRA_t *sra, Expression *cond); // SRA_SELECT 构造函数void SRA_print(SRA_t *sra); //输出 SRA_t 中的数据(调试用)

 3.1.2 参考代码 

#include <dongmensql/sqlstatement.h> #include <parser/StatementParser.h> /** * 在现有实现基础上,实现delete from子句 * * 支持的delete语法: * * DELETE FROM <table_nbame> * WHERE <logical_expr> * * 解析获得 sql_stmt_delete 结构 */ sql_stmt_delete *DeleteParser::parse_sql_stmt_delete(){ char *tableName; SRA_t *where; Token *token = this->parseNextToken(); if (!this->matchToken( TOKEN_RESERVED_WORD, "delete")) { return NULL; } token = this->parseNextToken(); if (token->type == TOKEN_WORD) { tableName = new_id_name(); strcpy(tableName, token->text); } else { strcpy(this->parserMessage, "invalid sql: missing table name."); return NULL; } token = this->parseEatAndNextToken(); // where 语句 where = SRATable(TableReference_make(tableName, nullptr)); if(this->matchToken(TOKEN_RESERVED_WORD, "where")){ /*解析where子句中的条件表达式*/ Expression *whereExpr = this->parseExpressionRD(); if (this->parserStateType == PARSER_WRONG) { return NULL; } where = SRASelect(where, whereExpr); } //进行赋值 sql_stmt_delete *sqlStmtDelete = (sql_stmt_delete *)calloc(1, sizeof(sql_stmt_delete)); sqlStmtDelete->tableName = tableName; sqlStmtDelete->where = where; return sqlStmtDelete; };

 

3.2 delete 语句执行

3.2.1 物理操作

首先创建一个表扫描计划,然后用 Scan 类中的 next() 函数迭代数据库数据条目,对满足条件的条目进行修改。

Scan 类中有针对不同的物理计划的虚拟函数:

class Scan { public: DongmenDB *m_db; Transaction *m_tx; virtual int beforeFirst()=0; virtual int next()=0; virtual int close()=0; virtual variant *getValueByIndex(int index)=0; virtual int getIntByIndex(int index)=0; virtual string getStringByIndex(int index)=0; virtual int getInt(string tableName, string fieldName) = 0; virtual variant* getValue(string fieldName)=0; virtual string getString(string tableName, string fieldName)=0; virtual int hasField(string tableName,string fieldName)=0; virtual FieldInfo * getField(string tableName, string fieldName)=0; virtual vector<char*> getFieldsName(string tableName)=0; virtual int setInt(string tableName, string fieldName, int value)=0; virtual int setString(string tableName, string fieldName, string value)=0; virtual int deleteRecord()=0; virtual int insertRecord()=0; virtual int getRID(RecordID *recordID)=0; virtual int moveTo(RecordID *recordID)=0; Expression * evaluateExpression(Expression *expr, Scan* scan, variant *var); };

3.2.2 实现

函数的具体实现在 src/physicalplan/ 下 Scan 的多个子类中

主要思路:

使用 SRA_t 类型的 where 构造执行计划( Scan 对象);遍历计划在遍历计划过程的循环中,调用 scan->deleteRecord() 删除记录在循环中更新删除的记录条数,作为最终的返回值。

 3.2.3 参考代码

#include <physicalplan/ExecutionPlan.h> #include <physicalplan/TableScan.h> #include <physicalplan/Select.h> #include <physicalplan/Project.h> #include <physicalplan/Join.h> /*执行delete语句的物理计划,返回删除的记录条数 * 返回大于等于0的值,表示删除的记录条数; * 返回小于0的值,表示删除过程中出现错误。 * */ int ExecutionPlan::executeDelete(DongmenDB *db, sql_stmt_delete *sqlStmtDelete, Transaction *tx){ /*删除语句以select的物理操作为基础实现。 * 1. 使用 sql_stmt_delete 的条件参数,调用 physical_scan_select_create 创建select的物理计划并初始化; * 2. 执行 select 的物理计划,完成 delete 操作 * */ int count = 0; Scan* scan = generateScan(db, sqlStmtDelete->where, tx); scan->beforeFirst(); while(scan->next()) { scan->deleteRecord(); count++; } scan->close(); return count; };

 

 指导文档由山东科技大学各位老师完成。

最新回复(0)