简单记录下碰到的一些问题

分析

  • arthas stack 查看调用
    对于hive 是类似的,我测试的是mysql 的
stack com.mysql.cj.jdbc.result.ResultSetImpl  getDate

效果

ffect(class count: 2 , method count: 4) cost in 329 ms, listenerId: 11
ts=2023-12-26 06:18:17;thread_name=e3 - 1a758fd6-4c6d-9baa-6d8f-31fa8220ee00:frag:0:0;id=c4;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@18b4aac2
    @com.mysql.cj.jdbc.result.ResultSetImpl.getDate()
        at org.apache.commons.dbcp2.DelegatingResultSet.getDate(DelegatingResultSet.java:682)
        at org.apache.commons.dbcp2.DelegatingResultSet.getDate(DelegatingResultSet.java:682)
        at com.dremio.exec.store.jdbc.JdbcRecordReader$DateCopier.copy(JdbcRecordReader.java:688)
        at com.dremio.exec.store.jdbc.JdbcRecordReader.next(JdbcRecordReader.java:291)
        at com.dremio.exec.store.CoercionReader.next(CoercionReader.java:187)
        at com.dremio.sabot.op.scan.ScanOperator.outputData(ScanOperator.java:365)
        at com.dremio.sabot.driver.SmartOp$SmartProducer.outputData(SmartOp.java:551)
        at com.dremio.sabot.driver.StraightPipe.pump(StraightPipe.java:56)
        at com.dremio.sabot.driver.Pipeline.doPump(Pipeline.java:124)
        at com.dremio.sabot.driver.Pipeline.pumpOnce(Pipeline.java:114)
        at com.dremio.sabot.exec.fragment.FragmentExecutor$DoAsPumper.run(FragmentExecutor.java:565)
        at com.dremio.sabot.exec.fragment.FragmentExecutor.run(FragmentExecutor.java:480)
        at com.dremio.sabot.exec.fragment.FragmentExecutor.access$1700(FragmentExecutor.java:109)
        at com.dremio.sabot.exec.fragment.FragmentExecutor$AsyncTaskImpl.run(FragmentExecutor.java:1016)
        at com.dremio.sabot.task.AsyncTaskWrapper.run(AsyncTaskWrapper.java:122)
        at com.dremio.sabot.task.slicing.SlicingThread.mainExecutionLoop(SlicingThread.java:249)
        at com.dremio.sabot.task.slicing.SlicingThread.run(SlicingThread.java:171)
 
ts=2023-12-26 06:57:01;thread_name=e6 - 1a7586c2-583b-6a25-56f0-01038d824a00:frag:0:0;id=c7;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@18b4aac2
    @com.mysql.cj.jdbc.result.ResultSetImpl.getDate()
        at org.apache.commons.dbcp2.DelegatingResultSet.getDate(DelegatingResultSet.java:682)
        at org.apache.commons.dbcp2.DelegatingResultSet.getDate(DelegatingResultSet.java:682)
        at com.dremio.exec.store.jdbc.JdbcRecordReader$DateCopier.copy(JdbcRecordReader.java:688)
        at com.dremio.exec.store.jdbc.JdbcRecordReader.next(JdbcRecordReader.java:291)
        at com.dremio.exec.store.CoercionReader.next(CoercionReader.java:187)
        at com.dremio.sabot.op.scan.ScanOperator.outputData(ScanOperator.java:365)
        at com.dremio.sabot.driver.SmartOp$SmartProducer.outputData(SmartOp.java:551)
        at com.dremio.sabot.driver.StraightPipe.pump(StraightPipe.java:56)
        at com.dremio.sabot.driver.Pipeline.doPump(Pipeline.java:124)
        at com.dremio.sabot.driver.Pipeline.pumpOnce(Pipeline.java:114)
        at com.dremio.sabot.exec.fragment.FragmentExecutor$DoAsPumper.run(FragmentExecutor.java:565)
        at com.dremio.sabot.exec.fragment.FragmentExecutor.run(FragmentExecutor.java:480)
        at com.dremio.sabot.exec.fragment.FragmentExecutor.access$1700(FragmentExecutor.java:109)
        at com.dremio.sabot.exec.fragment.FragmentExecutor$AsyncTaskImpl.run(FragmentExecutor.java:1016)
        at com.dremio.sabot.task.AsyncTaskWrapper.run(AsyncTaskWrapper.java:122)
        at com.dremio.sabot.task.slicing.SlicingThread.mainExecutionLoop(SlicingThread.java:249)
        at com.dremio.sabot.task.slicing.SlicingThread.run(SlicingThread.java:171)
类的反编译
jad com.dremio.exec.store.jdbc.JdbcRecordReader$DateCopier
效果

ClassLoader:                                                                                                                    
+-sun.misc.Launcher$AppClassLoader@18b4aac2                                                                                     
  +-sun.misc.Launcher$ExtClassLoader@5614c340                                                                                   
 
Location:                                                                                                                       
/opt/dremio/jars/dremio-ce-jdbc-plugin-24.3.0-202312190021150029-52db2faf.jar                                                   
 
        /*
         * Decompiled with CFR.
         */
        package com.dremio.exec.store.jdbc;
 
        import com.dremio.exec.store.jdbc.JdbcRecordReader;
        import java.sql.Date;
        import java.sql.ResultSet;
        import java.sql.SQLException;
        import java.util.Calendar;
        import java.util.TimeZone;
        import org.apache.arrow.vector.DateMilliVector;
 
        private static class JdbcRecordReader.DateCopier
        extends JdbcRecordReader.Copier<DateMilliVector> {
            private final Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
 
            JdbcRecordReader.DateCopier(int columnIndex, ResultSet result, DateMilliVector vector) {
/*683*/         super(columnIndex, result, vector);
            }
 
            @Override
            void copy(int index) throws SQLException {
               // 会传递calendar
                Date date = this.getResult().getDate(this.getColumnIndex(), this.calendar);
/*689*/         if (date != null) {
/*690*/             ((DateMilliVector)this.getValueVector()).setSafe(index, date.getTime());
                }
            }
        }
hive getdate 包含calendar 的处理
HiveBaseResultSet 类
效果
public Date getDate(int columnIndex, Calendar cal) throws SQLException {
    logger.trace("{}, {}", this.traceInfo(), columnIndex);
    throw new SQLException("Method not supported");
}
ts=2023-12-26 06:18:17;thread_name=e3 - 1a758fd6-4c6d-9baa-6d8f-31fa8220ee00:frag:0:0;id=c4;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@18b4aac2

已经很明显了,核心是dremio传递了Calendar,但是hive 的getdate 不支持Calendar,所以对于类型肯定就会有问题了

解决方法

  • 修改dremio
    不建议,侵入太大,而且会有影响
  • 直接修改hive jdbc 驱动
    对于getDate 包含Calendar 的处理,使用public Date getDate(int columnIndex) 的实现,忽略Calendar

说明

对于构建,如果不想自己完整编译,可以通过反编译,替换class 文件的模式(如果有源码不推荐这么玩,对于缺少源码的场景可以使用此方法)
实际一个修改的代码,参考下边的github

参考资料

https://github.com/apache/hive/blob/master/jdbc/src/java/org/apache/hive/jdbc/HiveBaseResultSet.java#L360
https://github.com/rongfengliang/inceptor-sdk-transwarp-fix