精华内容
下载资源
问答
  • 语法树学习笔记——数据库实现原理.doc
  • 本人在学习的过程中,自己总结了一下。经典的SQL数据库语法大全.数据库的基本语法,数据的常用关键字等等。希望能对朋友们有所帮助。
  • sql抽象语法树 我已经订阅了jOOQ竞争数据库抽象工具的各种用户组。 其中之一是ActiveJDBC ,这是Active Record设计模式的Java实现。 它的维护者Igor Polevoy最近声称: SQL注入是一个Web应用程序问题,与ORM没有...

    sql抽象语法树

    我已经订阅了jOOQ竞争数据库抽象工具的各种用户组。 其中之一是ActiveJDBC ,这是Active Record设计模式的Java实现。 它的维护者Igor Polevoy最近声称:

    SQL注入是一个Web应用程序问题,与ORM没有直接关系。 ActiveJDBC将处理传递给它的任何SQL。

    (请参阅此处的讨论: https : //groups.google.com/d/topic/activejdbc-group/5D2jhWuW4Sg/discussion


    是真的吗 数据库抽象层是否应该将SQL注入预防委托给客户端应用程序?  

    SQL注入背景

    SQL注入是我们大多数开发人员在职业生涯中不得不一次或多次处理的问题。 维基百科很好地解释了这个问题 给定以下一段Java代码(或任何其他语言):

    statement = "SELECT * FROM users WHERE name = '" + userName + "';"

    假设“ userName”是从HTTP请求中获取的变量。 盲目粘贴HTTP请求参数可以让攻击变得简单,如下所示:

    -- attacker sends this code in the userName field:
    userName = "a';DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't"
    
    -- resulting in the following statement:
    statement = "SELECT * FROM users WHERE name = 'a';"
              + "DROP TABLE users;" +
              + "SELECT * FROM userinfo WHERE 't' = 't';"

    这不是发生在你身上吗?

    也许不会。 但是问题经常在Stack Overflow上看到。 搜索“ SQL注入”时有2000多个结果: http : //stackoverflow.com/search?q= sql+injection。 因此,即使您知道如何预防,您团队中的某人也可能不会。 好的但是 …

    如果500个语句中的一个语句被某个忽略了这种威胁的程序员糟糕地写了,那还不那么糟糕吗?

    再想一想。 您是否听说过称为sqlmap的工具? 根据注入问题的严重程度,此工具将在几秒钟/几分钟/几小时内找到应用程序中任何有问题的页面。 不仅如此,一旦发现有问题的页面,它就能从数据库中提取所有类型的数据。 我的意思是所有数据。 多种sqlmap功能:

    • 支持枚举用户,密码哈希,特权,角色,数据库,表和列
    • 支持搜索特定数据库名称,所有数据库中的特定表或所有数据库表中的特定列 例如,这对于识别包含自定义应用程序凭据的表很有用,其中相关列的名称包含诸如name和pass之类的字符串。
    • 当数据库软件是MySQL,PostgreSQL或Microsoft SQL Server时,支持从数据库服务器基础文件系统下载和上传任何文件
    • 当数据库软件为MySQL,PostgreSQL或Microsoft SQL Server时,支持在数据库操作系统底层操作系统上执行任意命令并检索其标准输出


    是! 如果您遭受SQL注入不安全代码的困扰,在某些情况下攻击者可以抢占您的服务器! 在我们公司中,我们已经在沙盒环境中针对某些已知漏洞的开源博客软件尝试了sqlmap。 我们已经成功地立即占领了服务器,而没有编写任何一行SQL  

    数据库抽象和SQL注入

    好吧,现在我引起了您的注意,让我们再考虑一下Igor Polevoy所说的话:

    SQL注入是一个Web应用程序问题,与ORM没有直接关系。 ActiveJDBC将处理传递给它的任何SQL。

    是的,他可能是正确的。 鉴于ActiveJDBC是JDBC的瘦身包装,因此可以进行一些不错的CRUD简化,例如(从其网站获取):

    List<Employee> people =
    Employee.where("department = ? and hire_date > ? ", "IT", hireDate)
            .offset(21)
            .limit(10)
            .orderBy("hire_date asc");

    您发现SQL注入的风险了吗? 对。 即使它为基础的PreparedStatement使用绑定值,此工具也像JDBC一样不安全。 如果小心,可以避免SQL注入。 或者,您可以开始串联字符串。 但是您必须意识到这一点! jOOQ如何处理此类情况? jOOQ手册介绍了如何显式或隐式处理绑定值 这里有些例子:

    // Implicitly creating a bind value for "Poe"
    create.select()
          .from(T_AUTHOR)
          .where(LAST_NAME.equal("Poe"));
    
    // Explicitly creating a (named) bind value for "Poe"
    create.select()
          .from(T_AUTHOR)
          .where(LAST_NAME.equal(param("lastName", "Poe")));
    
    // Explicitly inlining "Poe" in the generated SQL string
    create.select()
          .from(T_AUTHOR)
          .where(LAST_NAME.equal(inline("Poe")));

    上面的例子将产生

    SELECT * FROM T_AUTHOR WHERE LAST_NAME = ?
    SELECT * FROM T_AUTHOR WHERE LAST_NAME = ?
    SELECT * FROM T_AUTHOR WHERE LAST_NAME = 'Poe'

    在内联“ Poe”的情况下,转义由jOOQ处理,以防止语法错误和SQL注入。 但是jOOQ还支持在生成SQL中直接注入SQL字符串 例如:

    // Inject plain SQL into jOOQ
    create.select()
          .from(T_AUTHOR)
          .where("LAST_NAME = 'Poe'");

    在这种情况下,SQL注入可能与JDBC一样发生  

    结论

    本质上,伊戈尔是对的。 (客户端)应用程序开发人员的责任是意识到由其代码创建SQL注入问题。 但是,如果建立在JDBC之上的数据库抽象框架可以在其API中尽可能避免SQL注入,那就更好了。 从SQL注入的角度来看,数据库抽象框架可以分为三类:

    • 简单的实用程序 这些包括Spring的JdbcTemplateApache的DbUtils 它们实际上只是通过便利性(更少的异常处理,更少的冗长性,更简单的变量绑定,更简单的数据提取)增强了JDBC API。 当然,这些工具不会阻止SQL注入
    • 完整SQL抽象 这些包括jOOQJaQuQueryDSLJPA的CriteriaQuery等。 它们的正常操作模式将始终在生成SQL中呈现绑定值。 在大多数情况下,这可以防止SQL注入。
    • 其他的 许多其他框架(包括ActiveJDBCHibernate )主要基于(SQL或HQL)字符串操作。 尽管它们抽象了许多与SQL有关的内容,但它们根本不会阻止SQL注入。

    因此,当您在Java应用程序中选择任何SQL抽象工具时,请注意SQL注入的严重性。 并且要注意一个事实,无论您的工具是否可以帮助您防止它!

    参考:来自JAVA,SQL和JOOQ博客的JCG合作伙伴 Lukas Eder的数据库抽象和SQL注入


    翻译自: https://www.javacodegeeks.com/2012/07/database-abstraction-and-sql-injection.html

    sql抽象语法树

    展开全文
  • 前言:本篇主要讲解怎么画查询语法树并对其优化,因为我在之前学的时候,在网上其实没怎么找到详细地教程,还是自己一点一点扣书扣出来的,所以想写一篇具体来描述一下这类题的方法技巧。 如题,这是东华大学一年的...

    前言:本篇主要讲解怎么画查询语法树并对其优化,因为我在之前学的时候,在网上其实没怎么找到详细地教程,还是自己一点一点扣书扣出来的,所以想写一篇具体来描述一下这类题的方法技巧。

    如题,这是东华大学一年的考研题目:

    我们来解决第二问的前提是先写出它的关系表达式:

    这一步没什么技巧,学过关系代数就很简单,我们主要讲解如何画查询语法树:

    第一步:转化关系表达式:就是将原来的三个表的自然连接转成笛卡尔积形式,在中间再加一个投影和选择即可;L就是指笛卡尔积里的所有属性,选择就是将这三个表连接起来的相同的属性,也比较简单,对照写出来即可;

    第二步:画出原始的优化树,这个画出来很简单,就是把刚刚转化的关系表达式化成这样的形式:

    最重要的第三步!优化!书上写的原则有很多,但其实只要记住该在哪投影,哪选择即可:

    我先把图贴出来:

    首先先看最上边,就是先写一个投影一个选择,投影投的就是咱们最后要的什么,选择就是右子树和左子树最后的连接,我们看右子树是Bike,那上面的选择操作一定就是

    这样我们上面的树就写好了。

    然后我们来到右子树,如果我们的条件是有在Bike里体现的,那一定就是加上Π和,如果我们没有这方面的条件,那就只加一个Π就行,而很明显,在Bike里我们是有条件的,所以就搞成:

    这样即可,就是我要用Bname来筛选出来,但我最后只要Bid就行了;下面的都是这个意思:

     

    这也是同理,我们要清楚的就是,条件是什么,我最后要什么就够了,这就是优化过程;

    要注意一点的是这一点:

    这一步要判断好,这一步输出的可就直接给上边的树了,要确认好上面的树需要什么;

     

    然后就结束啦!其实很简单的,主要是分清条件是什么,每一步只需要什么。

     

     

    展开全文
  • 数据库SQL语法详解

    2012-01-21 20:07:02
    数据库SQL语法详解,对于学习数据库技术开发的比较有用。
  • 语法树遍历

    2015-11-14 10:42:12
    尝试设计翻译方法。假定对程序片段已得到语法树,如 if (a > b) b = a; 已得到语法树 编写程序,遍历语法树,执行代码,得到正确结果。
  • OceanBase是阿里巴巴集团自主研发的可扩展的关系型数据库,实现了跨行跨表的事务,支持数千亿条记录、数百TB数据上的SQL操作。在阿里巴巴集团下,OceanBase数据库支持了多个重要业务的数据存储,包括收藏夹、直通车...


    OceanBase
    是阿里巴巴集团自主研发的可扩展的关系型数据库,实现了跨行跨表的事务,支持数千亿条记录、数百TB数据上的SQL操作。在阿里巴巴集团下,OceanBase数据库支持了多个重要业务的数据存储,包括收藏夹、直通车报表、天猫评价等。截止到2013年4月份,OceanBase线上业务的数据量已经超过一千亿条。

    看起来挺厉害的,今天我们来研究下它的源代码。关于OceanBase的架构描述有很多文档,这篇笔记也不打算涉及这些东西,只讨论OceanBase的SQL编译部分的代码。

    OceanBase是一个开源的数据库,托管在github上,点击下载。本文讨论的源码路径对应为:oceanbase_0.3/src/sql。最新的版本为0.4,本文讨论的代码基于0.3版本的OceanBase.目前OceanBase的能解析的SQL还比较少,包括Select,Insert,Update,Delete,Show,Explain等.

    选择OceanBase 0.3 版本进行学习,基于几个原因:

    • OceanBase 的高质量,高可读性
    • OceanBase 版本低,没有历史负担
    • OceanBase SQL解析相对简单,更容易窥见全貌,利于理解设计开发中要解决的主要问题。
    • 与其他数据库的SQL解析部分进行对比,深入理解问题本质

    该部分主要功能包括了,SQL语句解析,逻辑计划的生成,物理操作符运算等。

    入口:ObSql类

    本部分的入口函数在ob_sql.h中,调用函数ObSql::direct_execute可以直接执行SQL语句,并返回结果集ObResultSet。函数stmt_prepare用于解析要预编译的SQL语句,stmt_execute则用于执行Prepare过的SQL语句。

     class ObSql
        {
          public:
            ObSql(){}
            ~ObSql(){}
            int direct_execute(const common::ObString &stmt, ObResultSet &result)
            int stmt_prepare(const common::ObString &stmt, ObStmtPrepareResult &result);
            int stmt_execute(const uint64_t stmt_id, const common::ObArray<common::ObObj> params, ObResultSet &result);
            int stmt_close(const uint64_t stmt_id);
        };


    在0.4版本中,direct_execute,stmt_prepare,stmt_execute等函数都被声明为static函数,意味着调用SQL语句执行时可以直接ObSql::direct_execute可以执行SQL语句,而不必再先定义一个ObSql对象。OceanBase还有年轻,还存在不足,我们阅读源码时应该带着批判思考的精神
    直接进入direct_execute函数,可以看到整个执行的过程,函数中有很多的if,else语句,主要是因为OceanBase有一个编码规范要求:一个函数只能有一个返回出口.按单出口的规范写代码会使得写代码的思路非常清晰,不容易出现内存泄露等问题,在大型项目中还是应该尽量保持函数单出口.当然,我觉得保持一个函数功能简洁、简单易懂也是非常重要的。

    在你阅读源码的过程中,遇到的大部分函数都会是这个样.刨去其他干扰信息,结合注释,可以看到,SQL执行分为5个步骤:

    1. 初始化
      parse_init(&parse_res)
    2. 解析SQL语法树
      parse_sql(&parse_res, stmt.ptr(), static_cast<size_t>(stmt.length()));
    3. 制定逻辑计划
      resolve(&logical_plan, parse_res.result_tree_)
      ObMultiPlan* multi_plan = static_cast<ObMultiPlan*>(logical_plan.plan_tree_);
    4. 生成物理计划:
      trans.add_logical_plans(multi_plan);
      physical_plan = trans.get_physical_plan(0)
    5. 执行物理计划:
      exec_plan->open()

    初始化仅仅是初始化一个缓冲区,可以略过来研究后面关键的4步。

    解析SQL语法树

    像PostgreSQL,MySQl等一样,OceanBase采用lex和yacc系的词法和语法解析工具生成语法树。GNU下的词法和语法工具为Flex和Bison.Flex利用正则表达式识别SQL语句中的所有词语,Bison则根据类似BNF的语法规则识别SQL语义,从而构建语法树。不熟悉Flex与Bison的同学推荐阅读《FLEX与BISON》(貌似我也没找到其他类似的书籍,^_^),里面也有专门的一章讲述利用Flex与Bison实现一个简单的SQL分析器。

    OceanBase的SQL语法树与PostgreSQL更为相似,但是设计上也有很多区别。

    节点设计

    语法树由一系列的节点串连而成。我选取较为简单的Update语句作为示例,下面是一个例句:
    Update student set sex="M" where name="小明";
    其SQL语法树可以表示为:

    |--Update Stmt
    |--Table:student
    |--TargeList:
    |--sex = "M"
    |--Qualifications:
    |--name="小明"

    语法解析的作用就是如何用数据结构来表示上面这棵语法树。不同的数据库有不同的方案。为加强对比,我选取了PostgreSQL,RedBase与OceanBase作为参照。

    PostgreSQL语法树的节点设计

    PostgreSQL中每一种语法都会有一个对应的结构体,比如更新语句Update对应的结构体为UpdateStmt:

      typedef struct UpdateStmt
    {
        NodeTag        type;           /* 枚举类型 */
        RangeVar   *relation;        /* 要更新的关系 */
        List       *targetList;        /* 要更新的项 */
        Node       *whereClause;    /* 更新条件 */
        List       *fromClause;        /* optional from clause for more tables */
        List       *returningList;    /* 返回的表达式列表 */
        WithClause *withClause;        /* WITH clause */
    } UpdateStmt;


    其中type是个枚举值,表示结构体的类型,在UpdateStmt中为T_UpdateStmt。其他字段分别对应UPdate语句的各个部分,该结构体可以支持更复杂的Update语句。
    PostgreSQL中还有一个基础的结构体:

    typedef struct Node
    {
        NodeTag        type;
    } Node;


    用于语法解析的结构体都可以强制转换成Node * 类型。PostgreSQL中传递语法结构体是都会转化成Node *类型,只有在需要明确类型的时候根据type枚举值转换成需要的类型。Node *的作用有的类似于void * ,但是更利于调试。我们也可以简单的认为:诸如UpdateStmt的语法解析结构体们都继承自Node

    由于每个语法对应一个结构体,因此在PostgreSQL中存在很多类似的结构体,包括SelectStmt,InsertStmt,DeleteStmt等。最终这些结构体还会被统一转换成Query结构体。即Query是统一的语法树结构体。
    在PostgreSQL中,示例中的SQL语法树可表示为:

    |--UpdateStmt
    |--type: T_UpdateStmt
    |--relation: student
    |--targetList:
    |--targest[0]:
    |--name: sex
    |--val: "M"
    |--whereClause:
    |--expr: =
    |--left: name
    |--right: "小明"

    RedBase的语法树的节点设计

    RedBase是斯坦福的数据库系统实现这门课程(cs346)的一个项目。RedBase比起PostgreSQL,OceanBase这样的复杂数据库而言,十分的简单。但是其语法树的节点设计与其他数据库不同,因此提出来做对比。
    typedef struct node{
       NODEKIND kind;/*枚举类型*/
    
       union{
          /* SM component nodes */
          /* create table node */
          struct{
             char *relname;
             struct node *attrlist;
          } CREATETABLE;
    
         /*此处省略n多个结构体...*/
    
          /* QL component nodes */
          /* query node */
          ...
    
          /* update node */
          struct{
             char *relname;                 /* 关系名 */
             struct node *relattr;          /* 属性 */
             struct node *relorvalue;       /* 修改后值 */
             struct node *conditionlist;    /* 条件列表 */
          } UPDATE;
    
         /*此处省略n多个结构体...*/
       } u;
    } NODE;


    RedBase数据库的语法树结构体只有一个,就是NODE,但是这个NODE结构体的声明有150多行(^-^).NODE包括一个枚举类型,作用于PostgreSQL中的type一样。所有的语法结构如UPDATE,SELECT,CREATETABLE等构成巨大的联合体。针对Update语句的结构体包括了关系名,属性,修改后的值,条件列表等字段,显然这种设计只能支持简单的Update语句。
    RedBase采用“巨型”联合体取代PostgreSQL中的多个结构体,免去了类型转换(语法结构体到Node*的转换)。如果把PostgreSQL语法树节点看成是“继承”结构,那么RedBase的语法树节点可以看成是“组合”结构。
    在RedBase中,示例中的SQL语法树可表示为:

    |--NODE:
    |--kind: N_UPDATE
    |--u:UPDATE
    |--relname: student
    |--relattr:
    |--kind: N_RELATTR
    |--u:RELATTR
    |--relname: (null)
    |--attrname: sex
    |--relorvalue:
    |--kind: N_RELATTR_OR_VALUE
    |--u:RELATTR_OR_VALUE
    |--relattr: (null)
    |--value:
    |--kind:N_VALUE
    |--u:VALUE
    |--sval = "M"
    |--conditionlist:
    |--kind:N_LIST
    |--u: LIST
    |--next: (null)
    |--curr:
    |--kind: N_CONDITION
    |--u: CONDITION
    |--lhsRelattr:
    |--kind: N_RELATTR
    |--u:RELATTR
    |--relname: (null)
    |--attrname: name
    |--op:
    |--kind: N_EQ
    |--rhsRelattr:(null)
    |--rhsValue:
    |--kind:N_VALUE
    |--u:VALUE
    |--sval = "M"

    OceanBase的语法树的节点设计

    OceanBase 的语法树节点结构体也只有一个,该结构体包括一个枚举类型变量type_,和PostgreSQL与RedBase一样,代表该结构体对应的类型。还有两组属性,对应终止符节点,只能使用vakue_和str_value_两个字段,分别对应64位整形值和字符串值;非终止符节点使用最后两个字段,num_child_表示子节点的个数,children_指向子节点数组的首地址。

    typedef struct _ParseNode
    {
      ObItemType   type_;
    
      /* 终止符节点的真实的值 */
      int64_t      value_;
      const char*  str_value_;
    
      /* 非终止符节点的孩子节点*/
      int32_t      num_child_; /*孩子节点的个数*/
      struct _ParseNode** children_; 
    
      // BuildPlanFunc m_fnBuildPlan;
    } ParseNode;


    对应一个节点而言,要么是终止符节点要么是非终止符节点,它只会使用两组属性中的一组。int,long,float,double,string等都是终止符类型,可以看出int,long都是用64位整形int64表示。float,double,string则用char *字符串表示。终止符的num_child_为0,children_为null.

    PostgreSQL的子节点都是有名字的子节点,可以使用名字进行访问,如在PostgreSQL中,Update语句的where条件可以通过 updatestmt.whereClause 来访问 。 但在OceanBase中不行 , 所有的子节点都是匿名的 , 只能通过下标来访问。

    打个比方,在PostgreSQL和RedBase中,孩子是有名字的,可以叫小明、小红等,根据名字你大概可以知道这个孩子是男是女;但是在OceanBase家,他们分别叫老大,老二,老三,听名字完全听不出是男是女的。OceanBase家有点不讲究^-^。

    可以在运行时查看语法树的结构,也可以在代码中可以推各个子节点代表的类型,但是不如PostgreSQL和RedBase方便。在sql_parser.y文件中,定义了SQL的语法规则,同时也规定了各种类型的子节点的结构。

    update_stmt: 
        UPDATE relation_factor SET update_asgn_list opt_where
        {
          ParseNode* assign_list = merge_tree(result->malloc_pool_, T_ASSIGN_LIST, $4);
          $$ = new_non_terminal_node(result->malloc_pool_, T_UPDATE, 3, $2, assign_list, $5);
        }
      ;


    从上述代码可以看出,Update语法结构体中有3个子节点,第一个表示表名,第二个表示要更新列表项,第三个表示更新的条件语句。
    示例中的Update语句在OceanBase中可以表示为如下形式:

    |--ParseNode
    |--type: T_UPDATE
    |--num_child: 3
    |--children[0]:
    |--type: T_IDENT
    |--str_value: student
    |--children[1]:
    |--type: T_ASSIGN_LIST
    |--num_child:1
    |--children[0]:
    |--type: T_ASSIGN_ITEM
    |--children[0]:
    |--type: T_IDENT
    |--str_value: sex
    |children[1]:
    |--type: T_EXPR
    |--children[0]:
    |--type: T_STRING
    |--str_value: "M"
    |--children[2]:
    |--type: T_OP_EQ
    |--num_child: 2
    |--children[0]:
    |--type: T_IDENT
    |--str_value: name
    |--children[1]:
    |--type: T_IDENT
    |--str_value: "小明"

    OceanBase中采用的这种方式缺点很明显,就是使用这些结构体时必须要仔细辨别各个子节点代表的意义,否则容易出错。优点同样也很明显,可以非常灵活的构建出语法树。

    语法树的节点的设计,主要是为了解决如何表达语法结构。不同的数据库有不同的具体实现。OceanBase采用终止符和非终止符分类,使用OceanBase的设计极具灵活性,但使用时需要仔细验证,避免出错。

    构建语法树

    SQL的语法规则很多 , SELECT , INSERT , UPDATE , DELETE , CREATE TABLE 等 dml , ddl 等语句都有对应的语法树。在上一节节中我们已经看到了UPDATE语句在内存中的语法树形状。本节需要些Flex和Bison的基础知识,如果之前没有接触过Flex与Bison的话,可以阅读《Flex与Bison中文版》或者GNU Bison 2.1 中文手册
    SQL全称为结构化查询语言,有独立于各数据库厂家的SQL标准,各数据库基本上都会大体上遵循该标准。像PostgreSQL数据库兼容某些版本的SQL标准,同时也有些自己独有的语句。每个数据库都有自己的擅长之处,这些细微的区别有时候就体现在查询语言的细微区别上。OceanBase在0.3版本仅支持有限的几条SQL语句,按照其官方的介绍,其目标之一是兼容MySQL的语法,让我们拭目以待。

    词法分析

    利用Flex进行词法分析是构建语法树的第一个。Flex源文件包含3部分:选项定义、词法规则、代码部分。选项定义部分定义了该词法分析器使用的特性和一些自定义的函数。词法规则部分为匹配语法+匹配动作。匹配语法为正则表达式,flex从上往下按顺序对每个规则进行匹配,一旦匹配成功则执行该项后面大括号内对应的动作代码;代码部分则是C语言代码。

    OceanBase的词法文件为sql_parser.l。其中定义了一些函数,选取部分来看。

    下面这两个函数可以使得OceanBase支持转义字符,包括:\b,\f,\n,\r,\t.

    inline unsigned char escaped_char(unsigned char c);
    
    /* quote_type: 0 - single quotes; 1 - double quotation marks */
    int64_t parse_string(const char* src, char* dest, int64_t len, int quote_type);


    OceanBase中的字符串用双引号括起来的表示,而且需要进行转义处理。

    \"(\\.|\"\"|[^"\\\n])*\" {
      ParseNode* node = NULL;
      malloc_new_node(node, ((ParseResult*)yyextra)->malloc_pool_, T_IDENT, 0);
      yylval->node = node;
      char* src = yytext+1;
      int len = strlen(src) - 1; //remove last quote charactor
      char* dest = (char*) parse_malloc(len + 1, ((ParseResult*)yyextra)->malloc_pool_);
      check_value(dest);
      node->str_value_ = dest;
      node->value_ = parse_string(src, dest, len, 1);/*字符串转义处理*/
      return NAME;
    }


    当匹配到NULL时,返回的值类型不能为NULL,因为NULL是c语言的保留字,所以需要换成其他名字,此处将NULL的类型定义为NULLX。

    NULL   {
      /* yylval->node = new_node(((ParseResult*)yyextra)->malloc_pool_, T_NULL, 0); */
      malloc_new_node(yylval->node, ((ParseResult*)yyextra)->malloc_pool_, T_NULL, 0);
      return NULLX;
    }


    再来看关系符号的规则代码,每个符号分别返回一个值。

    "||" {return CNNOP;}
    "=" {return COMP_EQ;}
    ">=" {return COMP_GE;}
    ">" {return COMP_GT;}
    "<=" {return COMP_LE;}
    "<" {return COMP_LT;}
    "!="|"<>" {return COMP_NE;}


    在《Flex与Bison》一书中,作者让所有关系符号返回同一个值,通过yylval的成员值来标记不同符号。代码类型如下这段。

    "=" { yylval.subtok = EXPR_EQ; return COMPARISON; }
    "<=>"   { yylval.subtok = EXPR_COMP; return COMPARISON; }
    ">="    { yylval.subtok = EXPR_GE; return COMPARISON; }
    ">" { yylval.subtok = EXPR_GT; return COMPARISON; }
    "<="    { yylval.subtok = EXPR_LE; return COMPARISON; }
    "<" { yylval.subtok = EXPR_LT; return COMPARISON; }
    "!="    |
    "<>"    { yylval.subtok = EXPR_NE; return COMPARISON; }


    虽然都能完成相同的功能,但是从个人喜好来讲,我更喜欢OceanBase这种做法,因为够直接。

    整数的值保留在node->value_中返回,为long long 类型 ( 64位 ) 。 而浮点数的值字面值则保存在node->str_value_ 中。

    接下来,看日期时间的提取。

    Date{whitespace}?'[0-9]{4}(-[0-9]{2}){2}' {
      int year, month, day;
      struct  tm time;
      int ret = 0;
    
      /* ParseNode* node = new_node(((ParseResult*)yyextra)->malloc_pool_, T_DATE, 0); */
      ParseNode* node = NULL;
      malloc_new_node(node, ((ParseResult*)yyextra)->malloc_pool_, T_DATE, 0);
      char* dest = strchr(yytext, '\'');
      dest =  parse_strdup(dest + 1, ((ParseResult*)yyextra)->malloc_pool_); // skip left quote
      check_value(dest);
      size_t len = strlen(dest);
      dest[len - 1] = '\0'; //remove final '
    
      node->str_value_ = dest;//字面值
    
      ret = sscanf(dest, "%4d-%2d-%2d", &year, &month, &day);
      assert(ret == 3);
    
      memset(&time, 0, sizeof(struct tm));
      time.tm_year = year - 1900;
      time.tm_mon = month - 1;
      time.tm_mday = day;
      time.tm_hour = 0;
      time.tm_min = 0;
      time.tm_sec = 0;
      time.tm_isdst = -1;
    
      node->value_ = mktime(&time) * 1000000L;//转成微秒
      yylval->node = node;
      return DATE_VALUE;
    }


    从表达式中可以看到,OceanBase支持直接传入日期时间,OceanBase也支持Time和Timestamp类型。具体如下表:

    类型 格式(不区分大小写) 表达式
    Date Date 'YYYY-MM-DD' Date{whitespace}?'[0-9]{4}(-[0-9]{2}){2}'
    Time Time 'HH:MI:SS.FF'或Time 'HH:MI:SS Time{whitespace}?'[0-9]{2}(:[0-9]{2}){2}[.][0-9]{1,6}',Time{whitespace}?'[0-9]{2}(:[0-9]{2}){2}[.]?'
    Timestamp Timestamp 'YYYY-MM-DD HH:MI:SS.FF'或 Timestamp 'YYYY-MM-DD HH:MI:SS' Timestamp{whitespace}?'[0-9]{4}(-[0-9]{2}){2}[ ][0-9]{2}(:[0-9]{2}){2}[.][0-9]{1,6}',Timestamp{whitespace}?'[0-9]{4}(-[0-9]{2}){2}[ ][0-9]{2}(:[0-9]{2}){2}[.]?'

    如下是一个使用日期的示例:

    select id,name from student where createtime <= date '2014-09-12';

    语法树中存在日期类型的节点,其str_value_存储时间的字面值,value_存储该时间与基准时间(1970年1月1日0时0分0秒)之差的毫秒值。

    OceanBase通过拓展标准的SQL语法支持直接在SQL语句中写入时间 ,在词法分析阶段就识别到时间类型,而 PostgreSQL 是在语法分析阶段才会识别时间 。 相比而言 , OceanBase 这种方式更直观,方便。

    在0.4版本的OceanBase中,增加了预编译的功能,需要识别占位符"?",系统变量和用户变量。对应性质如下:

    名称 表达式 动作代码返回值
    占位符(?) "?" QUESTIONMARK
    系统变量(system_variable) (@@[A-Za-z_][A_Za-z0-9_]*) SYSTEM_VARIABLE
    用户变量(temp_variable) (@[A-Za-z_][A_Za-z0-9_]*) TEMP_VARIABLE

    语法分析

    OceanBase的SQL语法文件为sql_parser.y。.y语法文件最终由Bison转为可编译的.c文件。其结构与Flex的.l文件类似,分为选项部分,规则部分和代码部分。下面的代码都是去掉了关联的动作代码的规则语法,这样有助于更专注的理解语法的实现。

    select语法

    在SQL的语句语法中,最复杂的语法莫过于Select语句。我们先来看其在OceanBase中的语法。一个select语句可以使带括号的select语句,也可以使不带括号的select语句:

    select_stmt: 
        select_no_parens    %prec UMINUS    /* 不到括号的select语句 */
      | select_with_parens    %prec UMINUS  /* 带括号的select语句 */
      ;


    %prec用于交换左右两个标记的优先级和结合性。即select_no_parens与UMINUS互换优先级和结核性,select_with_parens 与UMINUS互换优先级和结核性。UMINUS的定义为%right UMINUS。所有上面两句的结果是select_no_parens和select_with_parens都变成了右结合。

    带括号的select语句可以是只带一个括号,也可以带多对括号:

    select_with_parens:
        '(' select_no_parens ')'      /*只带一个括号*/
      | '(' select_with_parens ')'    /*带多对括号*/
      ;


    不带括号的select语句包括简单的select,带order by排序,带order by排序和limit限制的select语句3种:

    select_no_parens:
        simple_select              
      | select_clause order_by
      | select_clause opt_order_by select_limit
      ;


    select子句包括简单slect和带括号的select:

    select_clause:
        simple_select                 
      | select_with_parens           
      ;


    为什么不包括不带括号的select,暂时没想通。

    简单select语句包括我们常见的select 语句,但没有order by和limit选项;同时还包括UNION,INTERSECT,EXCEPT三种运算:

    simple_select: 
        SELECT opt_distinct select_expr_list 
        FROM from_list
        opt_where opt_groupby opt_having
      | select_clause UNION opt_distinct select_clause
      | select_clause INTERSECT opt_distinct select_clause
      | select_clause EXCEPT opt_distinct select_clause
      ;


    select语句的定义相对其他语句很复杂,而且上面这段代码还没有包括无表的select和for update的select。(这两项在0.4版本的OceanBase中已经实现)。

    下面这段是从PostgreSQL9.2.3中截取的Select语法:

    SelectStmt: select_no_parens      %prec UMINUS
          | select_with_parens    %prec UMINUS
        ;
    
    select_with_parens:
          '(' select_no_parens ')'       
          | '(' select_with_parens ')'   
        ;
    select_no_parens:
          simple_select           
          | select_clause sort_clause
          | select_clause opt_sort_clause for_locking_clause opt_select_limit
          | select_clause opt_sort_clause select_limit opt_for_locking_clause
          | with_clause select_clause
          | with_clause select_clause sort_clause
          | with_clause select_clause opt_sort_clause for_locking_clause opt_select_limit
          | with_clause select_clause opt_sort_clause select_limit opt_for_locking_clause
        ;
    
    select_clause:
          simple_select             
          | select_with_parens      
        ;
    simple_select:
          SELECT opt_distinct target_list
          into_clause from_clause where_clause
          group_clause having_clause window_clause
          | values_clause             
          | TABLE relation_expr
          | select_clause UNION opt_all select_clause
          | select_clause INTERSECT opt_all select_clause
          | select_clause EXCEPT opt_all select_clause
        ;


    不知道你是不是有种似曾相识的感觉。没错,在这里,OceanBase借鉴了PostgreSQL的语法分析方式。PostgreSQL号称世界上最优秀的开源数据库,绝非浪得虚名。

    update语法

    为保证示例的完整性,我们在来分析下update的语法。

    /*0.3版本的OceanBase*/
    update_stmt: 
        UPDATE relation_factor SET update_asgn_list opt_where
      ;
    
    update_asgn_list: 
        update_asgn_factor
      | update_asgn_list ',' update_asgn_factor
      ;
    
    update_asgn_factor:
        NAME COMP_EQ expr
      ;


    上面为0.3版本中的update的语法,支持常见的update的SQL语句,如果将它和0.4版本的update的语法相比,就会发现:0.4版本的update在set时可以使用保留关键字作为列名,支持hint语法,支持when子句。随着OceanBase逐渐完善,其解析的语法也必然会越来越复杂。在学习的时候,从一个简单的版本开始,由易到难,就显得很重要。

    /*0.4版本的OceanBase*/
    update_stmt:
        UPDATE opt_hint relation_factor SET update_asgn_list opt_where opt_when
      ;
    update_asgn_factor:
        column_name COMP_EQ expr
      ;
    column_name:
        NAME
      | unreserved_keyword
      ;
    opt_when:
        /* EMPTY */
      | WHEN expr
      ;


    除了select,比较复杂还有create table,alter table,expr等。本节最后只讨论表达式的语法问题。其他的不再讨论。

    表达式语法

    expression 是指表达列名或者是一个能够给出真假的布尔表达式。如
    a+3 > b
    a is not null
    等等。表达式最常出现在where子句中,用于过滤数据行。

    表达式的语法之所以复杂,是因为表达式可以嵌套多个子表达式,多个子表达式出现后可能会出现语法上的歧义。BETWEEN ... AND 用于测试给的表达式是否在给定的范围内,这个操作符中的AND 与逻辑与的AND有歧义。需要使用%prec来改变其优先级和结合性,该方法能奏效,但是PostgreSQL和OceanBase都选择从语法树规则上完全消除该歧义。

    OceanBase中表达式有3种类型,分别为expr , arith_expr , simple_expr。其中

    • expr :expr为表达式的核心,是不受约束的表达式,可以直接用于where,having等子句中。
    • arith_expr :arith_expr是可以用于between ... and之间的表达式,是受约束的表达式。因此arith_expr是expr的一个真子集。
    • simple_expr :simple_expr是简单表达式,不能直接进行自我递归的表达式。是expr和aritharith_expr的共有的部分。
    expr_const:
        STRING 
      | DATE_VALUE 
      | INTNUM 
      | APPROXNUM 
      | BOOL 
      | NULLX 
      | QUESTIONMARK 
      | TEMP_VARIABLE 
      | SYSTEM_VARIABLE 
      | SESSION_ALIAS '.' column_name 
      ;
    
    simple_expr:
        column_ref
      | expr_const
      | '(' expr ')'
      | '(' expr_list ',' expr ')'
      | case_expr
      | func_expr
      | when_func
      | select_with_parens        %prec UMINUS
      | EXISTS select_with_parens
      ;
    
    /* used by the expression that use range value, e.g. between and */
    arith_expr:
        simple_expr   
      | '+' arith_expr %prec UMINUS
      | '-' arith_expr %prec UMINUS
      | arith_expr '+' arith_expr 
      | arith_expr '-' arith_expr 
      | arith_expr '*' arith_expr 
      | arith_expr '/' arith_expr 
      | arith_expr '%' arith_expr 
      | arith_expr '^' arith_expr 
      | arith_expr MOD arith_expr 
    
    expr:
        simple_expr   
      | '+' expr %prec UMINUS
      | '-' expr %prec UMINUS
      | expr '+' expr 
      | expr '-' expr 
      | expr '*' expr 
      | expr '/' expr 
      | expr '%' expr 
      | expr '^' expr 
      | expr MOD expr 
      | expr COMP_LE expr 
      | expr COMP_LT expr 
      | expr COMP_EQ expr 
      | expr COMP_GE expr 
      | expr COMP_GT expr 
      | expr COMP_NE expr 
      | expr LIKE expr 
      | expr NOT LIKE expr 
      | expr AND expr %prec AND
      | expr OR expr %prec OR
      | NOT expr
      | expr IS NULLX
      | expr IS NOT NULLX
      | expr IS BOOL
      | expr IS NOT BOOL
      | expr IS UNKNOWN
      | expr IS NOT UNKNOWN
      | expr BETWEEN arith_expr AND arith_expr        %prec BETWEEN
      | expr NOT BETWEEN arith_expr AND arith_expr      %prec BETWEEN
      | expr IN in_expr
      | expr NOT IN in_expr
      | expr CNNOP expr
      ;


    simple_expr为简单表达式,并不是说它很简单,因为simple_expr也包含了select_with_parens(带括号的select语句)等语句,只能说simple_expr不能像arith_expr和expr等一样递归调用。

    expr:expr BETWEEN arith_expr AND arith_expr        %prec BETWEEN
      | expr NOT BETWEEN arith_expr AND arith_expr      %prec BETWEEN
      ;


    arith_expr用于between ... and 之间,只包含了算术表达式,没有is,like 以及比较关系表达式。

    expr,arith_expr,simple_expr实际上等同于PostgreSQL中的a_expr,b_expr,c_expr。

    总之,在语法树规则和词法分析方面,OceanBase大量的借鉴了PostgreSQL。

    节点的创建

    确定了节点的结构和语法树的形状,就到了实际创建语法树的过程。通常,1条SQL语句的语法树存在多个节点,数据库中要高效的执行多条语句,就会遇到大量的节点创建问题。如果每次创建都调用new/malloc等系统函数必然会浪费大量的时,而且还会造成内存碎片。这种问题常常会出现在现实中,各个数据库都有自己不同的解决办法,但基本原理是一次性向系统申请较大的内存,然后在需要的时候自行分配。
    接下来我将对比PostgreSQL,RedBase,OceanBase 3个数据库是各自如何解决这一问题的。

    PostgreSQL创建语法树节点

    PostgreSQL使用两个宏完成节点的创建,即makeNode和newNode.

    #define makeNode(_type_)  ((_type_ *) newNode(sizeof(_type_),T_##_type_))
    
    /* 针对gcc版本的newNode */#define newNode(size, tag) \
    ({    Node *_result; \
        AssertMacro((size) >= sizeof(Node));/* 检测申请的内存大小,>>=sizeof(Node) */ \
        _result = (Node *) palloc0fast(size); /* 申请内存 */ \
        _result->type = (tag); /*设置TypeTag */ \
        _result; /*返回值*/\
    })
    
    #define palloc0fast(sz) \
        ( MemSetTest(0, sz) ? \
            MemoryContextAllocZeroAligned(CurrentMemoryContext, sz) : \
            MemoryContextAllocZero(CurrentMemoryContext, sz) )


    注意:要避免直接使用newNode来创建节点,因为节点的大小在不同的环境下可能是不同的。使用makeNode即可,如:
    Stmt *s = makeNode(Stmt);

    我们知道,PostgreSQL中继承自NODE*的结构体们各自大小不一,都大于等于NODE 的大小。newNode中使用palloc0fast申请内存,它仍然是个宏,最终调用的是PostgreSQL中的MemoryContextAllocZeroAligned或者MemoryContextAllocZero函数,这两个函数来自PostgreSQL中内存管理模块--内存上下文,该模块能够很好的应对内存碎片,向数据库进程提供缓冲区管理。

    RedBase创建语法树节点

    RedBase没有提供向PostgreSQL一样复杂的内存管理机制,而是采用简单的方法来解决频繁创建节点的问题。因为RedBase中语法树的节点都是NODE类型的,所有RedBase使用一个NODE的数组来作为缓冲区,默认最大值为100,超过这个值就会创建出错,并最终退出程序。如果你的SQL语句需要的节点超过100,需要在编译之前修改最大节点数目MAXNODE以适应需求。

    #define MAXNODE        100 //最大节点数目
    
    static NODE nodepool[MAXNODE];
    static int nodeptr = 0;
    
    /*
     * newnode: allocates a new node of the specified kind and returns a pointer
     * to it on success.  Returns NULL on error.
     */
    NODE *newnode(NODEKIND kind)
    {
        NODE *n;
    
        /* if we've used up all of the nodes then error */
        if(nodeptr == MAXNODE){
        fprintf(stderr, "out of memory\n");
        exit(1);
        }
    
        /* get the next node */
        n = nodepool + nodeptr;
        ++nodeptr;
    
        /* initialize the `kind' field */
        n -> kind = kind;
        return n;
    }


    OceanBase创建语法树节点

    OceanBase创建语法树节点的方式与PostgreSQL类似,上层调用,底层有负责内存池管理的模块来负责真正的创建,不过不是内存上下文,而是一个类ObStringBuf.

    OceanBase的new_node函数申请内存时调用的是parse_malloc函数,该函数专用于语法树结构体的创建,从obStringBuf中获取内存,直到obStringBuf线程退出时才会真正释放这些内存。

    大型的数据库都会有专门的内存管理模块来负责语法程序运行过程中的内存申请和释放,小型的数据库则结合自身特点,量身定制轻量的内存管理机制。目的都只有一个:降低频繁创建和销毁语法树节点的开销

    总结

    SQL的执行包括了解析语法树,制定逻辑查询计划,执行物理查询计划等步骤。通过对比3个不同的数据库的源代码,得出在解析语法树中遇到的一些共性问题:

    • 如何表示一个语法树的节点
    • 利用Bison定义语法树的结构时的一些难点,如select,expr等
    • 如何降低频繁创建和销毁语法树节点的开销

    如果你要自己来写一个SQL解析程序的话,这些问题同样难以避免。


    欢迎光临我的网站----我的博客园----我的CSDN
    如果阅读本文过程中有任何问题,请联系作者,转载请注明出处!


    展开全文
  • 【SQL】SQL语法树

    万次阅读 2018-04-08 22:32:57
    1. 为什么会出现SQL语法树? 假设有一个SQL语句 select name,age,count(name) as count_name, count(id) as count_id from mytable where id = ? and name = ? 这是一条sql语句,如果你想运行这个语句(下面写...

    在这里插入图片描述

    1. 为什么会出现SQL语法树?

    假设有一个SQL语句

    select name,age,count(name) as count_name,
    count(id) as count_id from  mytable where id = ?  and name = ?
    

    这是一条sql语句,如果你想运行这个语句(下面写伪代码,具体实现肯定不是这样的但是这是人实现的思想)
    1.找到数据库表mytable这里要获取表名简单一个if判断
    2.假设里面有1000条数据,那么我们先获取1000条

    id name 	age  	sex  	birthday
    1	梁川川  	23  	男		2015-04-08
    2	梁川川1  23  	男		2015-04-08
    3	梁川川2  23  	男		2015-04-08
    。。。。。
    

    3.然后根据语句获取我们需要的列,根据name,age,count(name) as count_name,count(id) as count_id获得id name age,这里我们可能需要些很多if去判断

    id name 	age  	
    1	梁川川  	23  	
    2	梁川川1  23  	
    3	梁川川2  23  	
    。。。。。
    

    4.然后开始过滤 ,后面的就不说了

    对于这个问题,开始的设想比较简单,大致过程是:把Sql语句中不相同的关键字和函数名替换掉,如Oracle中的To_Date换成SqlServer的Convert,就可以在SqlServer上执行了.对一些简单的Sql语句这样确实可以,可是对复杂的应用来说,Sql语句可能多层嵌套,函数也有多层嵌套,如果只是简单的替换,代码中必然会有无数的if else,并且出错后的修改和调试几乎是不可能的。

    通过对Oracle和SqlServer两种数据库的Sql语法的研究比较,认为必须采用语法分析,把Sql语句解析为一棵语法树,然后再按照语法的转换规则把sql语句转换到SqlServer上可执行的语句。

    例如一个Select语句的结构如下
      
    这里写图片描述

    从这张结构图中可以看到,Sql语句可能出现非常复杂的组合结构,如果不使用语法树表示,很难实现不同数据库平台的转换。

    案例2

    一则简单的例子
    如果我们需要让计算机帮忙算一下 「1加2再乘以3」 的结果,该怎么表达呢?
    现在我们大多数的现代编程语言,都是使用「中缀表达式」的方式来编写运算,比如JavaScript:

    (1 + 2) * 3
    

    而FORTH语言则使用「后缀表达式」,这基本上与日语中的语序是一致的:

    1 2 + 3 *
    

    LISP语言使用的「前缀表达式」:

    ( * (+ 1 2) 3)
    

    我们再看一下这三种表达式的语法树:

    这里写图片描述

    可以看出,对于这三种简单的语言,它们只是在这个语法树上按不同的规则遍历而已。三者的代码看起来差别很大,但实际上所用的树结构是相同的。

    总结:

    1. 一条sql语句能否在不同的语言和数据库执行,首先都要生成语法树
    2. 语法树是运行的前提,(还记得数据结构中的二叉树吗)

    2.有了Sql语法树,我们可以做什么?

    看到这里你可能会问,知道语法是又有什么用呢?跟我日常编写代码貌似半毛钱关系都没有。其实语法树还是很有用的,想一下如果想做「语法高亮」、「关键字匹配」、「作用域判断」、以及「代码压缩」等等,都是最好把代码解构成语法树之后再去各种操作,当然仅仅解构还不够,还需要提供各种函数去遍历与修改语法树。

    展开全文
  • 数据库树查询

    千次阅读 2015-02-01 22:26:14
    其中有一个是对数据的校验,而这些数据在数据库里是以的形式存在!没有问别人之前我是打算以循环的方式来做,周日花了整整一下午把数据表研究了一番发现不是我想象的那么简单,我先把这个要求简单的描述一下: ...
  • layui学习:数据库输出

    千次阅读 2018-05-26 11:30:34
    所用材料: 1、TP5框架 2、mysql 3、layui第一步:创建数据库 laytree表数据库字段介绍如下: 1、id:这个不用说了,索引字段 2、name:node名称 3、pid:父id (根字段的父id设置为0) 4、path:我这里放的...
  • 数据库B索引的工作原理

    千次阅读 2019-01-09 16:14:06
    什么是B? B是一种数据结构,它按排序顺序在其节点中存储数据。我们可以如下表示样本B。 样本B ...B存储数据,使得每个节点...为什么索引在数据库中使用? 想象一下,您需要在文件中存储一个数字列表,...
  • 查询优化一般算法和语法树,对提高关系运算的理解有很大帮助!
  • 关系代数优化(语法树优化)

    千次阅读 多人点赞 2020-05-07 19:53:40
    数据库 – 关系代数优化 关系代数优化是指通过对关系代数表达式的等价变换操作来提高数据库的查询效率。 关系代数有5大基本操作:包括并( Union,U ),差 (Difference , - ),笛卡尔积( X ),投影( project,∏),...
  • 数据库高级(oracle) 1、sql基础 1.1 sql语言:structure query language DDL:(data define language) create \drop\alter\truncate(截断) ddl默认自带事务,自动提交 DML:(DATA MANAGEMENT LANGUAG.....
  • DruidSQL解析引擎主要分为三个部分,AST抽象语法树,词法解析,语法解析。 AST抽象语法树,语法解析的结果,由众多AST语法对象组成一颗树,而词法分析就是解析出一个一个关键字,作为语法解析的输入。 Druid SQL...
  • MySQL数据库面试题(2020最新版)

    万次阅读 多人点赞 2020-03-10 17:20:40
    文章目录数据库基础知识为什么要使用数据库什么是SQL?什么是MySQL?数据库三大范式是什么mysql有关权限的表都有哪几个MySQL的binlog有有几种录入格式?分别有什么区别?数据类型mysql有哪些数据类型引擎MySQL存储...
  • 数据库》查询优化

    万次阅读 多人点赞 2014-03-08 11:33:42
    查询的启发式优化 典型的启发式规则: 1.选择运算应尽可能先做。在优化策略中这是最重要、最基本的一条 2.把投影运算和选择运算同时进行 如有若干投影和选择运算,并且它们都对同一个关系操作,则可以在扫描此...
  • 二、 Hive语法树的生成

    千次阅读 2016-03-17 09:20:30
    HiveQL是一个非标准的sql...ANTLR(ANother Tool for Language Recognition)是一款功能强大的语言构建工具,提供了词法分析、语法分析等功能。用户编写语言的词法规则和语法规则,然后通过antlr提供的运行时库将语言转
  • 一、什么是数据库 数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。 每个数据库都有一个或多个不同的API用于创建,访问,管理,搜索和复制所保存的数据。 通常使用关系型数据库管理系统(RDBMS)来...
  • sql 解析,编译,ast 抽象语法树

    万次阅读 2018-03-06 01:35:35
    `),中文是抽象语法树。在不说子查询之类的情况下,这个AST也不会太复杂,毕竟where后面的情况比起编译原理里的程序语言来说情况还是要少得多的。以上述的sql为例,这里解析出来的Where结构是这样的: & sqlparser ....
  • 最近应业务需求,公司需要把数据库从oracle数据迁移到postgresql库,以下简称pg库。代码逻辑是适用的,但是因为oracle语法比较随意,而pg库语法比较严格,这就涉及到整理哪些是oracle语法,以及替代函数等,现总结...
  • 数据库题目~查询,优化查询

    千次阅读 2020-04-27 21:54:13
  • 语法特征之模式对象管理 一、状态与模式 1.1状态 达梦的数据库状态分为三种:配置(MOUNT)、打开(OPEN)和挂起(SUSPEND)。 数据库状态 是否允许访问数据库对象 数据库模式修改、控制文件维护、归档配置 磁盘...
  • 形结构在实际中应用很多,但在数据库中一般也是设计为表格,如何读取,子孙节点,或者是祖先节点?在Oracle中使用start with connect by prior select * from tablename start with cond1connect by cond2where ...
  • SQL查询提交给数据库系统的时候,一个查询优化器的软件模块将对查询... 这些数据结构包括:二叉树,2-3,散列表 数据库的索引包含的数据量比一次能够调入内存的数据量大。 所以数据库的索引的数据只能放在磁盘...
  • 1.1. Sql语法树 ast 如下图锁死1 2. SQL语句解析的思路和过程3 2.1. lexer作为一个工具,完成了对SQL字符串的切割,将语句转化成一个tokens数组。3 2.2. Parser完成了SQL解析的后序部分:使用一个lexer对象...
  • 数据库

    千次阅读 2010-04-20 13:30:00
    数据库编程总结 收藏 此文于2010-04-12被推荐到CSDN首页此文于2010-04-16被推荐到CSDN首页如何被推荐?数据库编程总结当前各种主流数据库有很多,包括Oracle, MS SQL Server, Sybase, Informix, MySQL, DB2, ...
  • 把Sql语句解析为一棵语法树 相关

    万次阅读 2012-07-03 13:49:37
    》》 http://www.bianceng.cn/Sql%20server/sql99.htm 》》http://www.open-open.com/doc/view/ab3fcde50b4a429faa0c4365760c73dd

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 83,728
精华内容 33,491
关键字:

数据库语法树