PostgreSQL SQL filter (SQL 成本 语义过滤器) - SQL成本防火墙

less than 1 minute read

背景

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;  

当用户重连数据库后,生效。

参考

《PostgreSQL SQL防火墙》

https://github.com/pgexperts/pg_plan_filter

Flag Counter

digoal’s 大量PostgreSQL文章入口