标签
PostgreSQL , pg_plan_filter , HOOK , 成本过滤 , 语义过滤 , 防火墙
背景
SQL防火墙,或SQL过滤器,在一些特定的场合可能会比较有用。
例如限制某些用户执行可能会耗费很多资源的SQL,限制用户执行SELECT以外的SQL(尽管SELECT不能保证对数据不产生修改,例如SELECT FUNCTION)。
PostgreSQL 提供了一些HOOK可以用来开发此类功能插件。
planner_hook_type,在pg_plan_filter插件中,通过这个HOOK实现了COST和SELECT的限制。
限制用户只能执行COST低于N的SQL,或者限制用户只能执行SELECT。
static PlannedStmt *
limit_func(Query *parse, int cursorOptions, ParamListInfo boundParams)
{
PlannedStmt *result;
/* this way we can daisy chain planner hooks if necessary */
if (prev_planner_hook != NULL)
result = (*prev_planner_hook) (parse, cursorOptions, boundParams);
else
result = standard_planner(parse, cursorOptions, boundParams);
if(filter_select_only && parse->commandType != CMD_SELECT)
return result;
if (statement_cost_limit > 0.0 &&
result->planTree->total_cost > statement_cost_limit)
ereport(ERROR,
(errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
errmsg("plan cost limit exceeded"),
errhint("The plan for your query shows that it would probably "
"have an excessive run time. This may be due to a "
"logic error in the SQL, or it maybe just a very "
"costly query. Rewrite your query or increase the "
"configuration parameter "
"\"plan_filter.statement_cost_limit\".")));
return result;
}
pg_plan_filter用法
1、安装
git clone https://github.com/pgexperts/pg_plan_filter
cd pg_plan_filter/
USE_PGXS=1 make clean
USE_PGXS=1 make
USE_PGXS=1 make install
2、配置自动加载插件SO
vi $PGDATA/postgresql.conf
shared_preload_libraries = 'plan_filter' # 如果已有其他模块,追加即可。 a,b,c,...
重启PG
pg_ctl restart -m fast
3、配置用户级参数,设置用户的SQL过滤器
1、限制postgres用户,只能执行COST低于10000的SQL
alter role postgres set plan_filter.statement_cost_limit = 10000;
2、限制TEST用户只能执行SELECT语句。
alter role test set plan_filter.limit_select_only = true;
当用户重连数据库后,生效。