lt_sql_inspect
模块提供两个功能:SQL 最佳实践和 SQL 拦截。
该功能将提供用于规范 SQL 编写的规则。
具体而言,它分为两部分:LightDB DDL 规范检查和 LightDB DML 规范检查。
lightdb_best_practice_mode
(String
)
lightdb_best_practice_mode 用于指定用于检查 SQL 的规则。
目前支持以下规则:keyword_not_allowed,bad_datatype,must_have_pk,must_have_gmt,no_more_100cols,no_paging。 默认值为: must_have_pk.
可以在单个会话中更改此设置。
lightdb_best_practice_level
(String
)
lightdb_best_practice_level 用于指定检查失败时的消息级别。
它用于 SQL 最佳实践和 SQL 拦截。
可以在单个会话中更改此设置。
在使用 DDL 语句时,LightDB 会首先检查您的语句是否符合规范。
目前,有五个检查:关键字检查(包括表名、字段名、库名和索引名)、字段类型检查(float、double、text、real、uuid、bytea、boolean、bit、character)、表是否必须包含主键、表是否包含创建时间和最后修改时间字段,以及操作的列数不超过 100。DDL 语句规范支持:
CREATE DATABASE... CREATE TABLE... CREATE INDEX... ALTER TABLE...
关键字列表可以参考 "www.light-pg.com/docs/current/sql-keywords-appendix.html"
当您使用非标准语句时,将直接报告警告或错误。 例如:
create database text; WARNING: LightDB DDL check warn! 不允许使用关键字 [db name]:text create table text(id int); WARNING: LightDB DDL check warn! 不允许使用关键字 [table name]:text WARNING: LightDB DDL check warn! 不允许使用关键字 [column name]:id WARNING: LightDB DDL check warn! 必须包含主键! WARNING: LightDB DDL check warn! 必须包含 gmt_create 或 gmt_modified 字段!
在这里,'text' 是一个非标准的数据库名称,因此报告了一个警告。 在创建表时,表名不是标准的,列名不是标准的,不包含主键,不包含创建时间和最后修改时间的字段,所以会发出警告。当然,还有 100 个操作列的上限,这里未列出。
默认情况下,DDL 语法检查未启用,有两种方法可以启用它。 全局修改方式是通过修改配置文件:
lightdb_best_practice_level = 'warn' lightdb_best_practice_mode = 'all'
lightdb_best_practice_level 的值为 'warn' 表示错误级别为警告。'error' 表示错误。当检测到非标准语句时,直接报告错误:
create database text; ERROR: LightDB DDL check error! 不允许使用关键字 [db name]:text
如果 lightdb_best_practice_mode 配置为 'all',则表示同时检查 5 种类型。当然,您可以随意组合要配置的检查,例如:
lightdb_best_practice_mode = 'keyword_not_allowed,must_have_pk'
上述配置表示仅检查关键字和主键。
另一种配置方法是会话级别修改:
set lightdb_best_practice_level to 'warn'; set lightdb_best_practice_mode to 'all';
这里有五种完全开放的方式,还有另一种方式:
set lightdb_best_practice_mode to 'keyword_not_allowed,bad_datatype,must_have_pk,must_have_gmt,no_more_100cols';
在使用 DML 语句时,LightDB 会首先检查您的语句是否符合规范。
目前,只有一个检查,即无分页检查: 当用户 SQL 没有指定查询条件或分页时,提醒用户。 下面详细描述了这些检查的用法。
no_paging check
。
在以下场景中需要检查:
查询语句没有 where
条件、没有 limit
或没有 offset
。
更新语句没有 where
条件。
删除语句没有 where
条件。
如何使用它?需要在配置文件中配置 lightdb_best_practice_level
和 lightdb_best_practice_mode
。
默认情况下,DML 语法检查未启用。 全局修改方式是通过修改配置文件:
lightdb_best_practice_level = 'error' lightdb_best_practice_mode = 'all'
lightdb_best_practice_level 的值为 'warn' 表示错误级别为警告。'error' 表示错误。当检测到非标准语句时,直接报告错误:
select * from table1; ERROR: LightDB DML check error! select 语句中缺少 where/limit/offset 子句!
如果 lightdb_best_practice_mode 配置为 'all',则表示同时检查所有类型。当然,您可以随意组合要配置的检查,例如:
lightdb_best_practice_mode = 'no_paging'
此功能将拦截与 lt_sql_inspect.secure_mode 中指定规则匹配的风险 SQL。
仅操作指定数据库的 SQL 将被阻止,使用 lt_sql_inspect.secure_enable_db 指定数据库。
您可以通过 lt_sql_inspect.secure_enable_time 定义时间段,在此时间段内才会拦截 SQL。时间段仅限于一天内。
lightdb_best_practice_level 控制拦截 SQL 时的日志级别,默认为 'warn'。 lightdb_best_practice_level 的值为 'warn' 表示错误级别为警告。'error' 表示错误。
详细规则请参阅 lt_sql_inspect.secure_mode。
lt_sql_inspect.secure_mode
(String
)
lt_sql_inspect.secure_mode 指定了一些 SQL 执行规则,例如拦截符合条件的 SQL。 您可以指定多个规则,用逗号分隔。 支持以下规则:select_without_where、update_without_where、delete_without_where、no_paging、high_risk_ddl。
可以在单个会话中更改此设置。
select_without_where:阻止仅查询一个表且没有 where 条件、没有 limit 和没有 offset 的 select 查询。
update_without_where:阻止仅查询一个表且没有 where 条件、没有 limit 和没有 offset 的 update 查询。
delete_without_where:阻止仅查询一个表且没有 where 条件、没有 limit 和没有 offset 的 delete 查询。
no_paging:相当于同时使用 select_without_where、update_without_where 和 delete_without_where。
high_risk_ddl:阻止以下 ddl:drop table、truncate table、alter table add/drop column、alter table add/drop Constraint、alter table modify column(null/not null, default/no default, type)。
lt_sql_inspect.secure_enable_time
(String
)
lt_sql_inspect.secure_enable_time 指定时间段,在此时间段内才会拦截 SQL。
格式为 'start_time - end_time'(例如:'09:00 - 18:00')。
此参数只能在 lightdb.conf
文件或服务器命令行中设置,并可重新加载。
lt_sql_inspect.secure_db
(String
)
lt_sql_inspect.secure_enable_db 指定数据库,仅在这些数据库上才会拦截 SQL。
您可以指定多个数据库,用逗号分隔。
此参数只能在 lightdb.conf
文件或服务器命令行中设置,并可重新加载。
如果一个DQL仅涉及一个表,且没有where、limit和offset语句,则会被阻塞。
查询pg_catalog、lt_catalog或ltcluster方案下的表时,SQL将不会被阻塞。 需要注意的是,当lightdb_best_practice_level设置为error时,查询其他模式下符合要求的表(包括扩展创建的表)将会报错。
lightdb@lt_test=# set lt_sql_inspect.secure_mode=select_without_where; SET lightdb@lt_test=# select * from t1; ERROR: lt_sql_inspect: SQL cannot execute, because a full table scan or modification may be performed on the table "t1" lightdb@lt_test=# select * from (select * from t1); ERROR: lt_sql_inspect: SQL cannot execute, because a full table scan or modification may be performed on the table "t1" lightdb@lt_test=# select * from t1 limit 1; key1 | key2 ------+------ (0 rows) lightdb@lt_test=# select * from t1 offset 1; key1 | key2 ------+------ (0 rows)
涉及多个表的DQL不会被阻塞。
lightdb@lt_test=# select * from t1, t2; key1 | key2 | key1 ------+------+------ (0 rows)
这同样适用于视图,就像适用于子查询一样。
lightdb@lt_test=# create view t1_v as select * from t1; CREATE VIEW lightdb@lt_test=# select * from t1_v; ERROR: lt_sql_inspect: SQL cannot execute, because a full table scan or modification may be performed on the table "t1" lightdb@lt_test=# select * from t1_v where key1=1; key1 | key2 ------+------ (0 rows)
与select_without_where类似,但针对update语句。
lightdb@lt_test=# set lt_sql_inspect.secure_mode = 'update_without_where'; SET lightdb@lt_test=# update t1 set key1=1; ERROR: lt_sql_inspect: SQL cannot execute, because a full table scan or modification may be performed on the table "t1" lightdb@lt_test=# update t1 set key1=1 limit 1; UPDATE 0 lightdb@lt_test=# update t1 set key1=1 offset 1; UPDATE 0 lightdb@lt_test=# update t1 set key1=1 from t2 ; UPDATE 0 lightdb@lt_test=# update t1 set key1=1 from t2 where t1.key1=t2.key1; UPDATE 0
与select_without_where类似,但针对delete语句。
lightdb@lt_test=# set lt_sql_inspect.secure_mode = 'delete_without_where'; SET lightdb@lt_test=# delete from t1 ; ERROR: lt_sql_inspect: SQL cannot execute, because a full table scan or modification may be performed on the table "t1" lightdb@lt_test=# delete from t1 where key1=1; DELETE 0 lightdb@lt_test=# delete from t1 limit 1; DELETE 0 lightdb@lt_test=# delete from t1 offset 1; DELETE 0 lightdb@lt_test=# delete from t1 using t2; DELETE 0 lightdb@lt_test=# delete from t1 using t2 where t1.key1=t2.key1; DELETE 0
等价于同时使用select_without_where、update_without_where和delete_without_where。
lightdb@lt_test=# set lt_sql_inspect.secure_mode=no_paging; SET lightdb@lt_test=# ERROR: lt_sql_inspect: SQL cannot execute, because a full table scan or modification may be performed on the table "t1" lightdb@lt_test=# update t1 set key1=1; ERROR: lt_sql_inspect: SQL cannot execute, because a full table scan or modification may be performed on the table "t1" lightdb@lt_test=# delete from t1 ; ERROR: lt_sql_inspect: SQL cannot execute, because a full table scan or modification may be performed on the table "t1"
目前以下DDL将被视为高风险DDL,并将被拦截。
DROP TABLE
lightdb@lt_test=# set lt_sql_inspect.secure_mode = high_risk_ddl; 设置 lightdb@lt_test=# drop table t1; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL
TRUNCATE TABLE
lightdb@lt_test=# set lt_sql_inspect.secure_mode = high_risk_ddl; 设置 lightdb@lt_test=# truncate table t1; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL
ALTER TABLE ADD COLUMN
lightdb@lt_test=# set lt_sql_inspect.secure_mode = high_risk_ddl; 设置 lightdb@lt_test=# alter table t1 add column key3 int; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL
ALTER TABLE DROP COLUMN
lightdb@lt_test=# set lt_sql_inspect.secure_mode = high_risk_ddl; 设置 lightdb@lt_test=# alter table t1 drop column key1; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL
ALTER TABLE ADD CONSTRAINT
lightdb@lt_test=# set lt_sql_inspect.secure_mode = high_risk_ddl; 设置 lightdb@lt_test=# alter table t1 add constraint t_uq unique(key1); 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL
ALTER TABLE DROP CONSTRAINT
lightdb@lt_test=# set lt_sql_inspect.secure_mode = high_risk_ddl; 设置 lightdb@lt_test=# alter table t1 drop constraint t_uq; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL
ALTER TABLE MODIFY/ALTER COLUMN(仅以下示例中的类型将被阻止,包括null/not-null,default/non-default,以及type)。
lightdb@lt_test=# set lt_sql_inspect.secure_mode = high_risk_ddl; 设置 lightdb@lt_test=# alter table t1 modify key2 bigint; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL lightdb@lt_test=# lightdb@lt_test=# alter table t1 alter key2 type text; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL lightdb@lt_test=# lightdb@lt_test=# alter table t1 modify key2 null; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL lightdb@lt_test=# lightdb@lt_test=# alter table t1 alter key2 drop not null; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL lightdb@lt_test=# lightdb@lt_test=# alter table t1 modify key2 not null; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL lightdb@lt_test=# lightdb@lt_test=# alter table t1 alter key2 set not null; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL lightdb@lt_test=# lightdb@lt_test=# alter table t1 modify key2 default 10; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL lightdb@lt_test=# lightdb@lt_test=# alter table t1 alter key2 set default 10; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL lightdb@lt_test=# lightdb@lt_test=# alter table t1 alter key2 drop default; 错误: lt_sql_inspect: SQL无法执行,因为它是高风险DDL lightdb@lt_test=#