• 论lightdb/postgresql中的search_path及实现兼容性管理


      上一篇介绍了lightdb/postgresql public、pg_catalog schema的区别及pg_namespace概念,因为最近几个版本开发下来,遇到了很多兼容性挑战。所以这一节来专门讨论一下search_path,以及它是如何实现版本隔离和理论上可实现的租户隔离(实际上,lightdb在22.1-22.2实现了,但是不够放心22.3临时取消了,22.4大概率会加回来,因为这涉及到database级别immutable,所以比较复杂)。

      search_path的用途是在语义分析的时候,确定函数、操作符、表等对象时让哪个命名空间中的生效。在Lightdb中,默认情况下,其取值为 "$user", public, lt_catalog。oracle模式,一般建议用户设置为"$user", public, lt_catalog, oracle。mysql模式则设置为"$user", public, lt_catalog, mysql。如果用户要添加一些额外的mysql/oracle兼容函数,可以考虑创建一个新的namepace,如$user_mysql_ext,然后在其中创建兼容函数,并添加到search_path的最后。这样当lightdb新版实现了兼容函数时,因为它会被添加到lt_catalog/mysql/oracle至少之一下,内置版本既能覆盖自定义版本,也不会带来额外的兼容性问题。可以从机制上很好的解决该兼容问题。

      虽然search_path能够解决该问题,但是由于它太灵活,一定要避免随意设置,比如避免设置同时包含oracle和mysql,当然lightdb在内部就进行了规避,如果是开源postgresql,这是需要注意的。

      对于oracle兼容,上述机制对自定义函数、存储过程、视图等都可以比较好的解决。但是对于oracle包(package),无论是内置包还是用户自定义包,事情要复杂一点。在lightdb中,oracle内置包按照schema存储,走search_path机制,自定义包是在lt_package中。包括集合类型、自定义类型、sys_refcursor、函数、过程等。

      null以及特殊的一些函数如substring负数索引等存在一词多义的情况是兼容的主要问题,如下:

    2022-11-14 20:04:19.330824T,DBeaver 22.0.2 - Metadata <lt_test>,zjh,lt_test,10.188.137.149(52068),client backend,PARSE,00000,2022-11-14 20:04:19 CST,0,180444,LOG:  duration: 0.636 ms  parse <unnamed>: SELECT t.oid,t.*,c.relkind,format_type(nullif(t.typbasetype, 0), t.typtypmod) as base_type_name, d.description
        FROM pg_catalog.pg_type t
        LEFT OUTER JOIN pg_catalog.pg_type et ON et.oid=t.typelem 
        LEFT OUTER JOIN pg_catalog.pg_class c ON c.oid=t.typrelid
        LEFT OUTER JOIN pg_catalog.pg_description d ON t.oid=d.objoid
        WHERE t.typname IS NOT NULL
        AND (c.relkind IS NULL OR c.relkind = 'c') AND (et.typcategory IS NULL OR et.typcategory <> 'C')

      因为不止postgres库会被第三方工具访问,业务库也可能会,如上所示,而且是三方初始化的一部分,无法修改SQL语句(通过rewrite插件也不行,因为不知道哪些是初始化的一部分,哪些不是)。所以还不能简单的将库的默认兼容改成oracle或mysql,否则就可能结果不正确。所以通过search_path执行是个正确的策略,不过幸好jdbc和libpq都可以通过option -c选项设置。

    jdbc.url=jdbc:postgresql://124.220.47.210:11345/defaultdb?options=-c%20search_path=\"$user\",public,oracle,lt_catalog%20-c%20statement_timeout=90000&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&lightdbSyntaxCompatibleType=oracle
      如果是mysql,上面的oracle改成mysql即可。

      对于is null,在oracle下如下:

    zjh@lt_test=# set lightdb_syntax_compatible_type = "Oracle";
    SET
    zjh@lt_test=# select '' is null;
     ?column? 
    ----------
     t
    (1 row)

      在pg/mysql模式下,如下:

    zjh@lt_test=# select '' is null;
     ?column? 
    ----------
     f
    (1 row)

      所以,可能就会出现不同的结果。

  • 相关阅读:
    利用VS的预生成事件获取SVN版本作为项目内部版本号
    静态构造函数到底执行了多少次?
    C#之自定义的implicit和explicit转换
    FineUI之使用SQL脚本从数据库表中生成相应的输入控件
    文件操作
    PHP中文件类型 文件属性 路径以及 文件相关的函数
    MySqli 中预处理类 stmt
    MySql 事务处理
    MySqli 执行多条SQL语句
    PHP与MySqli
  • 原文地址:https://www.cnblogs.com/lightdb/p/16634472.html
Copyright © 2020-2023  润新知