think-orm icon indicating copy to clipboard operation
think-orm copied to clipboard

pgsql数据库多schema支持问题

Open ZhouSiliang opened this issue 1 year ago • 0 comments

根据文档所述,在使用pgsql之前需要导入/db/connector/pgsql.sql文件(postgres12以上版本,则使用 /db/connector/pgsql12.sql),查看源码后发现存在以a_schema_name+a_table_name双参数获取表数据的table_msg函数,以及重载后单入参a_table_name的table_msg函数。 但是重载后单入参a_table_name的table_msg函数只获取public模式下的表数据。但查看/db/connector/Pgsql.php源代码第63行 $sql = 'select fields_name as "field",fields_type as "type",fields_not_null as "null",fields_key_name as "key",fields_default as "default",fields_default as "extra" from table_msg(\'' . $tableName . '\');'; 发现该处仅使用了单入参a_table_name的table_msg函数进行获取,top-think/think-orm是否可以针对pgsql支持schema多模式。 因为top-think/think-orm仅支持public单模式,如果强行使用多模式,会导致无法获取非public模式表数据,以及无法更改表数据等问题,我尝试将pgsql.sql文件里的单入参table_msg函数:

---重载一个函数
CREATE OR REPLACE FUNCTION "public"."table_msg" (a_table_name varchar) RETURNS SETOF "public"."tablestruct" AS
$body$
DECLARE
    v_ret tablestruct;
BEGIN
    FOR v_ret IN SELECT * FROM table_msg('public',a_table_name) LOOP
        RETURN NEXT v_ret;
    END LOOP;
    RETURN;
END;
$body$
LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;

COMMENT ON FUNCTION "public"."table_msg"(a_table_name varchar)
IS '获得表信息';

修改为:

---重载一个函数
CREATE OR REPLACE FUNCTION "public"."table_msg" (a_table_name varchar) RETURNS SETOF "public"."tablestruct" AS
$body$
DECLARE
    v_ret tablestruct;
    v_schema varchar;
    v_table varchar;
BEGIN
    IF position('.' IN a_table_name) > 0 THEN
        v_schema := split_part(a_table_name, '.', 1);
        v_table := split_part(a_table_name, '.', 2);
    ELSE
        v_schema := 'public'; -- 默认模式为 public
        v_table := a_table_name;
    END IF;

    FOR v_ret IN SELECT * FROM table_msg(v_schema,v_table) LOOP
        RETURN NEXT v_ret;
    END LOOP;
    RETURN;
END;
$body$
LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;

COMMENT ON FUNCTION "public"."table_msg"(a_table_name varchar)
IS '获得表信息';

上述改动将支持多schema方案,当需要使用多schema,可以将Model的表名进行调整: protected $name = 'schema.表名'; 如果不进行改动,仍然默认为public模式

ZhouSiliang avatar Jun 04 '24 03:06 ZhouSiliang