在Greenplum中,对于任意一个SQL,我们想获取这个SQL执行后的字段名是比较难的。
比方说在写一个通用工具的时候,使用copy命令将一个SQL导出成文本,但是每个字段的名称导出的文本中却没有,如果使用自己解析SQL的话就太复杂了
如果我们想取得这些字段名的话,不真正执行sql,因为在生成执行计划的时候已经,我知道的有以下几种方法:
1.使用JDBC,prepareStatement先生成执行计划,然后获取字段名:
PreparedStatement pstmt = conn.prepareStatement("select * from gp_segment_configuration a");
ResultSetMetaData metaData=pstmt.getMetaData();
for(int i=1;i<=metaData.getColumnCount();i++){
System.out.println(metaData.getColumnName(i)+" \t\t :"+metaData.getColumnTypeName(i));
}
ps:不止是JDBC,其他的客户端接口估计都会有这种接口将字段给取出来。看了jdbc的源码,在获取metaData信息的时候,是直接跟数据库交互,然后将这些信息接收过来的。对于其他的,应该都是有定义好的接口的,这个需要自己去挖掘。
2.explain 如果加上verbose会将整个解析后的语法数打印出来。如下:
aligputf8=# explain verbose select * from cxfa;
QUERY PLAN
----------------------------------------------------------------
{MOTION
:motionID 1
:motionType 1
:sendToSecondary false
:sendSorted false
:numInputSegs 3
:inputSegIdx <>
:numHashSegs 0
:hashSegIdx
:hashExpr <>
:hashDataTypes <>
:numOutputSegs 1
:outputSegIdx -1
:numSortCols 0
:sortColIdx
:sortOperators
:plan_node_id 1
:plan_parent_node_id -1
:startup_cost 0.00
:total_cost 0.00
:plan_rows 1
:plan_width 36
其中最上层的targetlist就是 SQL要返回的字段列表。
:targetlist (
{TARGETENTRY
:expr
{VAR
:varno 1
:varattno 1
:vartype 23
:vartypmod -1
:varlevelsup 0
:varnoold 1
:varoattno 1
}
:resno 1
:resname a
:ressortgroupref 0
:resorigtbl 28569230
:resorigcol 1
:resjunk false
}
{TARGETENTRY
:expr
{VAR
:varno 1
:varattno 2
:vartype 25
:vartypmod -1
:varlevelsup 0
:varnoold 1
:varoattno 2
}
:resno 2
:resname b
:ressortgroupref 0
:resorigtbl 28569230
:resorigcol 2
:resjunk false
}
)
这样,我们能不能利用这个写一个函数,来将这个字段名给取出来呢,如果直接解析这个语法树还是比较麻烦的。我们发现,字段名前面都有一个 :resname开头,我们可以遍历这个数,把“ :resname”开头的都给找出来,就是字段名了。
函数的代码如下:
CREATE or replace FUNCTION public.get_sql_column_name(sqlori text)
RETURNS setof text
AS $
sql_ori=sqlori.strip().lower()
if not sql_ori.startswith('select'):
return ['SQL is not Select SQL,Please check!']
retext=[]
sql="explain verbose " + sql_ori
#plpy.info(sql)
rv = plpy.execute(sql)
for i in rv:
if i['QUERY PLAN'].startswith(" :resname"):
retext.append(i['QUERY PLAN'].replace(" :resname",''))
return retext;
$ LANGUAGE plpythonu;
执行效果如下:
aligputf8=# select get_sql_column_name('select * from cxfa');
get_sql_column_name
---------------------
a
b
(2 rows)
Time: 32.037 ms
aligputf8=# select get_sql_column_name(pg_get_viewdef('pg_partitions'));
get_sql_column_name
----------------------------
schemaname
tablename
partitionschemaname
partitiontablename
partitionname
parentpartitiontablename
parentpartitionname
partitiontype
partitionlevel
partitionrank
partitionposition
partitionlistvalues
partitionrangestart
partitionstartinclusive
partitionrangeend
partitionendinclusive
partitioneveryclause
partitionisdefault
partitionboundary
(19 rows)
Time: 44.404 ms