PLY库-实现最简单的sql语法的数据库
发布日期:2021-07-25 13:05:01
浏览次数:20
分类:技术文章
本文共 11182 字,大约阅读时间需要 37 分钟。
本文通过PLY实现一个简单的sql库
本文主要简述一下,有关语法解析的库的使用,并使用改实例编写一个简单的模仿最基本的sql语句的数据库,本文代码仅供示例参考。
语法解析与上下文
语法解析是一个比较大的内容,早起比较成熟的有lex与yacc,该工具相对比较成熟,详细的资料大家可以自行查阅资料,在编译中使用较多的是上下文无关文法主要的是BNF,大家有兴趣可查阅sql语句的,标准的sql的文法相对复杂,本文只是为了实现最基本的工作故只是做了最简单的解析。
示例代码
import ply.lex as leximport ply.yacc as yaccimport collectionstokens = ( 'LFPARENTH', 'RGPARENTH', 'TABLE', 'CREATE', 'INSERT', 'UPDATE', 'INTO', 'VALUES', 'SELECT', 'COLUMN', "COMMA", 'WHERE', 'FROM', 'AND', 'SET', 'EQUAL', 'STAR', "END")t_LFPARENTH = r'\('t_RGPARENTH = r'\)'t_SELECT = r'SELECT|select't_CREATE = r'CREATE|create't_INSERT = r'INSERT|insert't_UPDATE = r'UPDATE|update't_INTO = r'INTO|into't_VALUES = r'VALUES|values't_WHERE = r'WHERE|where't_FROM = r'FROM|from't_AND = r'AND|and't_SET = r'SET|set't_EQUAL = r'\='t_TABLE = r'TABLE|table't_COMMA = r','t_STAR = r'\*'t_END = r';'def t_COLUMN(t): r'[a-zA-Z0-9/.-]+' if t.value in ['FROM', 'from']: t.type = 'FROM' if t.value in ['CREATE', 'create']: t.type = 'CREATE' if t.value in ['TABLE', 'table']: t.type = 'TABLE' if t.value in ['INSERT', 'insert']: t.type = 'INSERT' if t.value in ['INTO', 'into']: t.type = 'INTO' if t.value in ['VALUES', 'values']: t.type = 'VALUES' if t.value in ['UPDATE', 'update']: t.type = 'UPDATE' if t.value in ['SET', 'set']: t.type = 'SET' if t.value in ['WHERE', 'where']: t.type = 'WHERE' if t.value in ['SELECT', 'select']: t.type = 'SELECT' if t.value in ['AND', 'and']: t.type = 'AND' return tdef t_newline(t): r'\n+' t.lexer.lineno += len(t.value)t_ignore = ' \t'def t_error(t): print("Illegal character {0}".format(t.value[0])) t.lexer.skip(1)lexer = lex.lex()datas = {}class Stack(object): def __init__(self): self.is_columns = False self._stack = [] def reset(self): self._stack = [] def append(self, value): self._stack.append(value) def __iter__(self): return iter(self._stack) def __len__(self): return len(self._stack) def __str__(self): print(self._stack) return "stack" def __getitem__(self, item): return self._stack[item] def __setslice__(self, i, j, sequence): return self._stack[i:j]stack = Stack()current_action = Nonecolumns_dict = {}condition_dict = {}def reset_action(): global current_action, stack, columns_dict, condition_dict current_action = None stack.reset() columns_dict = {} condition_dict = {}class Select(object): def __init__(self): self.values = [] self.table = None def set_table(self, table): self.table = table return table in datas def add_stack(self, stack): [self.add_values(v) for v in stack if v not in self.values] def add_values(self, value): self.values.append(value) def action(self): """展示数据""" if self.table not in datas: print("table {0} not exists") return table = datas[self.table] if self.values: for v in self.values: if v in table: print(" {0} = {1}".format(v, table[v])) else: print(" {0} not in table {1}".format(v, self.table)) else: for v in table: print(" {0} = {1}".format(v, table[v]))class Create(object): def __init__(self): self.values = [] self.table = None def set_table(self, table): self.table = table return table not in datas def add_stack(self, stack): [self.add_values(v) for v in stack if v not in self.values] def add_values(self, value): self.values.append(value) def action(self): datas[self.table] = collections.OrderedDict() for v in self.values: datas[self.table][v] = [] print("create : ", datas)class Insert(object): def __init__(self): self.values = [] self.columns = set() self.table = None self._stack = None def set_table(self, table): self.table = table return table not in datas def add_stack(self, stack): # 判断是否输入的sql 为 insert into table(c1, c2, c3) values(1,2,3) self._stack = stack def action(self): table = datas[self.table] if self._stack.is_columns: if len(self._stack) and len(self._stack) % 2 == 0: index = int(len(self._stack) / 2) if index != len(table.keys()): print("error default columns") return for i in range(index): if self._stack[i] in table: table[self._stack[i]].append(self._stack[i + index]) else: print(" error columns and values not equal") return else: if len(table.keys()) != len(self._stack): print("input values len {0} not equal table columes len {1}". format(len(self._stack), len(table.keys()))) return t_index = 0 for v in table.keys(): table[v].append(self._stack[t_index]) t_index += 1 print("insert : ", datas)class Update(object): def __init__(self): self.values = [] self.table = None self.condition_dict = {} self.columns_dict = {} self.index_list = None def set_table(self, table): self.table = table return table not in datas def add_stack(self, condition, colums): self.condition_dict = condition self.columns_dict = colums def check_dict_key(self, val_dict, table): for key in val_dict.keys(): if key not in table: return False return True def find_keys(self, val_dict, table): keys = [key for key in val_dict] values = [val_dict[key] for key in val_dict] self.index_list = [] print(keys) print(table) result_list = [] if keys: first_line = table[keys[0]] for i in range(len(first_line)): detail_value = [] for key in keys: detail_value.append(table[key][i]) result_list.append(detail_value) print(values) print(result_list) for index, v in enumerate(result_list): if v == values: self.index_list.append(index) print(self.index_list) return self.index_list def action(self): table = datas[self.table] if not (self.check_dict_key(self.condition_dict, table) and\ self.check_dict_key(self.columns_dict, table)): print(" error found keys ") return index_list = self.find_keys(self.condition_dict, table) if not index_list: print(" update condition not found") return for k in self.columns_dict: for index in index_list: table[k][index] = self.columns_dict[k]def p_statement_expr(t): '''expressions : expression | expressions expression''' if current_action: current_action.action() reset_action()def p_expression_start(t): '''expression : exp_select | exp_create | exp_insert | exp_update'''def p_expression_select(t): '''exp_select : SELECT columns FROM COLUMN END | SELECT STAR FROM COLUMN END''' print(t[1], t[2]) global current_action current_action = Select() if not current_action.set_table(t[4]): print("{0} table not exists".format(t[4])) return if not t[2]: current_action.add_stack(stack)def p_expression_create(t): '''exp_create : CREATE TABLE COLUMN LFPARENTH columns RGPARENTH END''' print(t[1]) global current_action current_action = Create() if not current_action.set_table(t[3]): print("{0} table already exists".format(t[3])) return # 处理参数 current_action.add_stack(stack)def p_expression_insert(t): '''exp_insert : INSERT INTO COLUMN exp_insert_end''' print(t[1]) global current_action current_action = Insert() if current_action.set_table(t[3]): print("{0} table not exists".format(t[3])) reset_action() return # 处理insert的参数 current_action.add_stack(stack)def p_expression_update(t): '''exp_update : UPDATE COLUMN SET exp_update_colums WHERE exp_update_condition END''' print(t[1]) global current_action current_action = Update() if current_action.set_table(t[2]): print("{0} table not exists".format(t[2])) return print(condition_dict, columns_dict) current_action.add_stack(condition_dict, columns_dict)def p_expression_update_columns(t): '''exp_update_colums : COLUMN EQUAL COLUMN | COLUMN EQUAL COLUMN COMMA exp_update_colums''' columns_dict[t[1]] = t[3]def p_expression_update_condition(t): '''exp_update_condition : COLUMN EQUAL COLUMN | COLUMN EQUAL COLUMN AND exp_update_condition''' condition_dict[t[1]] = t[3]def p_expresssion_insert_end(t): '''exp_insert_end : VALUES LFPARENTH columns RGPARENTH END | LFPARENTH columns RGPARENTH VALUES LFPARENTH columns RGPARENTH END''' if len(t) == 9: stack.is_columns = Truedef p_expression_columns(t): '''columns : COLUMN | COLUMN COMMA columns''' stack.append(t[1])def p_error(p): if p: print("Syntax error at {0}".format(p.value)) else: print("Syntax error at EOF")while True: data = input("sql>") yacc.yacc() yacc.parse(data)
运行该示例代码如下;
sql>create table t1 (line1, line2, line3);createcreate : {'t1': OrderedDict([('line3', []), ('line2', []), ('line1', [])])}sql>insert into t1 values(1,2,3);insertinsert : {'t1': OrderedDict([('line3', ['3']), ('line2', ['2']), ('line1', ['1'])])}sql>insert into t1 values(1,2,32);insertinsert : {'t1': OrderedDict([('line3', ['3', '32']), ('line2', ['2', '2']), ('line1', ['1', '1'])])}sql>insert into t1 values(1,23, 33);insertinsert : {'t1': OrderedDict([('line3', ['3', '32', '33']), ('line2', ['2', '2', '23']), ('line1', ['1', '1', '1'])])}sql>insert into t1 values(1,2, 43);insertinsert : {'t1': OrderedDict([('line3', ['3', '32', '33', '43']), ('line2', ['2', '2', '23', '2']), ('line1', ['1', '1', '1', '1'])])}sql>update t1 set line1=0, line2=0 where line1=1 and line2=2;update{'line2': '2', 'line1': '1'} {'line2': '0', 'line1': '0'}['line2', 'line1']OrderedDict([('line3', ['3', '32', '33', '43']), ('line2', ['2', '2', '23', '2']), ('line1', ['1', '1', '1', '1'])])['2', '1'][['2', '1'], ['2', '1'], ['23', '1'], ['2', '1']][0, 1, 3]sql>select * from t1;select * line3 = ['3', '32', '33', '43'] line2 = ['0', '0', '23', '0'] line1 = ['0', '0', '1', '0']sql>select line1, line2 from t1;select None line2 = ['0', '0', '23', '0'] line1 = ['0', '0', '1', '0']sql>
本文仅仅是支持简单的语法,基本的select 语法也没有支持where条件语句,update的操作支持多条件多行的更改,创建表的语句create也并没有支持字段属性,所有的数据都是存储在python的字典中。
总结
本文只是作为在sql语法与编译器相关的一些基本的原理的知识的梳理,展示的脚本也仅仅是作为演示使用,大家有兴趣可自行学习库。由于本人才疏学浅,如有错误请批评指正。
转载地址:https://blog.csdn.net/qq_33339479/article/details/96435808 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
逛到本站,mark一下
[***.202.152.39]2024年04月12日 03时06分48秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
服务器端开发经验总结 Linux C语言
2019-04-27
将网站程序放在tmpfs下
2019-04-27
使用Nginx的proxy_cache缓存功能取代Squid
2019-04-27
nginx 反向代理,动静态请求分离,proxy_cache缓存及缓存清除
2019-04-27
nginx 的proxy_cache才是王道
2019-04-27
Nginx proxy_cache 使用示例
2019-04-27
Nginx源代码分析 - 日志处理
2019-04-27
使Apache实现gzip压缩
2019-04-27
Memcached在大型网站中应用
2019-04-27
Hadoop简要介绍
2019-04-27
squid中的X-Cache和X-Cache-Lookup的意义
2019-04-27
squid 优化指南
2019-04-27
编程方式刷新Squid缓存服务器的五种方法
2019-04-27
centos vnc配置笔记
2019-04-27
Linux服务器网络开发模型
2019-04-27
nginx虚拟目录设置 alias 和 root
2019-04-27
理解http响应头中的Date和Age
2019-04-27
四层和七层负载均衡的区别
2019-04-27
设置Squid Cache_mem大小
2019-04-27
squid日志文件太大,怎样处理?
2019-04-27