Hive对execute和executeQuery的处理
我自己实现了一个SparkSQL的SQL Server服务,兼容了Hive的JDBC Driver,也就可通过beeline直接去连接,如果仔细看Java的JDBC标准,里面关于SQL的执行是有2类接口的:
execute和executeQuery,前者返回一个true/false,后者会封装成一个ResultSet,可获取对应的结果集。
按照正常理解来说,execute对应的场景是不关心结果集的情况,例如ddl语句,而executeQuery则是处理查询情况,需要对结果集进行处理。
因此在后台实现thrift 接口的时候,对于ddl类的操作,我直接将结果置空,且设置setHasResultSet为false,但是这样处理后,在beeline的客户端始终会出现这样的错误:
987541 [pool-28-thread-5] INFO - Processing EXECUTE_STATEMENT statement: EXECUTE_STATEMENT |
虽然结果没有问题,但是始终会有一个显示的错误,因为beeline后面使用的也是beeline的jdbc driver,因此我使用源码去调试的时候,发现了问题,在hive 的jdbc实现逻辑里面,executeQuery直接调用了execute:
@Override |
且这里有一个重点是如果返回是false,则会直接抛错:The query did not generate a result set!这个地方让我觉得有点郁闷,在我去看execute的时候发现client在调用thrift的ExecuteStatement接口执行SQL后会再去调用GetOperationStatus来获取当前执行的状态:
transportLock.lock(); |
这几行代码都在在一个类似while true的循环里面,直到整个操作结束,然后开始获取结果集,这里重点就来了:
// The query should be completed by now |
也就是如果这里的isHasResultSet是false,那么就意味着execute那就会直接抛出异常,也就意味着,对于后端的状态来说,isHasResultSet这个值必须返回是true,因此后端在进行thrift的结果集的封装的时候,需要做如下处理:
val operationHandle = new TOperationHandle |
正常来说这样设置就行了,也就是setHasResultSet=false代表没有返回集,setHasResultSetIsSet代表这个值被设置,但是实际发现这样并不行,因为setHasResultSetIsSet是和setHasResultSet关联一起的。
导致最后的解决方案是,如果是没有返回结果集的DDL执行,我得手动的生成一个类似这样的返回:
0: jdbc:hive2://127.0.0.1:xxx/fcbai> use default; |
这也算是Hive实现的一个不那么完美的地方吧。
扫码手机观看或分享: