public ArrowReader getStatistics()

in java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcConnection.java [149:301]


  public ArrowReader getStatistics(
      String catalogPattern, String dbSchemaPattern, String tableNamePattern, boolean approximate)
      throws AdbcException {
    if (tableNamePattern == null) {
      throw AdbcException.notImplemented(
          JdbcDriverUtil.prefixExceptionMessage("getStatistics: must supply table name"));
    }

    try (final VectorSchemaRoot root =
            VectorSchemaRoot.create(StandardSchemas.GET_STATISTICS_SCHEMA, allocator);
        ResultSet rs =
            connection
                .getMetaData()
                .getIndexInfo(
                    catalogPattern,
                    dbSchemaPattern,
                    tableNamePattern, /*unique*/
                    false,
                    approximate)) {
      // Build up the statistics in-memory and then return a constant reader.
      // We have to read and sort the data first because the ordering is not by the catalog/etc.

      // {catalog: {schema: {index_name: statistic}}}
      Map<String, Map<String, Map<String, Statistic>>> allStatistics = new HashMap<>();

      while (rs.next()) {
        @Nullable String catalog = rs.getString(1);
        String schema = rs.getString(2);
        String table = rs.getString(3);
        String index = rs.getString(6);
        short statisticType = rs.getShort(7);
        String column = rs.getString(9);
        long cardinality = rs.getLong(11);

        if (table == null || column == null) {
          throw new AdbcException(
              JdbcDriverUtil.prefixExceptionMessage("JDBC driver returned null table/column name"),
              null,
              AdbcStatusCode.INTERNAL,
              null,
              0);
        }

        if (!allStatistics.containsKey(catalog)) {
          allStatistics.put(catalog, new HashMap<>());
        }

        Map<String, Map<String, Statistic>> catalogStats = allStatistics.get(catalog);
        if (!catalogStats.containsKey(schema)) {
          catalogStats.put(schema, new HashMap<>());
        }

        Map<String, Statistic> schemaStats = catalogStats.get(schema);
        Statistic statistic = schemaStats.getOrDefault(index, new Statistic(table, column));
        assert statistic != null; // for checker-framework
        if (schemaStats.containsKey(index)) {
          // Multi-column index, ignore it
          statistic.multiColumn = true;
          continue;
        }

        statistic.column = column;
        statistic.table = table;
        statistic.key =
            statisticType == DatabaseMetaData.tableIndexStatistic
                ? StandardStatistics.ROW_COUNT.getKey()
                : StandardStatistics.DISTINCT_COUNT.getKey();
        statistic.value = cardinality;
        schemaStats.put(index, statistic);
      }

      VarCharVector catalogNames = (VarCharVector) root.getVector(0);
      ListVector catalogDbSchemas = (ListVector) root.getVector(1);
      StructVector dbSchemas = (StructVector) catalogDbSchemas.getDataVector();
      VarCharVector dbSchemaNames = (VarCharVector) dbSchemas.getVectorById(0);
      ListVector dbSchemaStatistics = (ListVector) dbSchemas.getVectorById(1);
      StructVector statistics = (StructVector) dbSchemaStatistics.getDataVector();
      VarCharVector tableNames = (VarCharVector) statistics.getVectorById(0);
      VarCharVector columnNames = (VarCharVector) statistics.getVectorById(1);
      SmallIntVector statisticKeys = (SmallIntVector) statistics.getVectorById(2);
      DenseUnionVector statisticValues = (DenseUnionVector) statistics.getVectorById(3);
      BitVector statisticIsApproximate = (BitVector) statistics.getVectorById(4);

      // Build up the Arrow result
      Text text = new Text();
      NullableBigIntHolder holder = new NullableBigIntHolder();
      int catalogIndex = 0;
      int schemaIndex = 0;
      int statisticIndex = 0;
      for (String catalog : allStatistics.keySet()) {
        Map<String, Map<String, Statistic>> schemas = allStatistics.get(catalog);

        if (catalog == null) {
          catalogNames.setNull(catalogIndex);
        } else {
          text.set(catalog);
          catalogNames.setSafe(catalogIndex, text);
        }
        catalogDbSchemas.startNewValue(catalogIndex);

        int schemaCount = 0;
        for (String schema : schemas.keySet()) {
          if (schema == null) {
            dbSchemaNames.setNull(schemaIndex);
          } else {
            text.set(schema);
            dbSchemaNames.setSafe(schemaIndex, text);
          }

          dbSchemaStatistics.startNewValue(schemaIndex);

          Map<String, Statistic> indices = schemas.get(schema);
          int statisticCount = 0;
          for (Statistic statistic : indices.values()) {
            if (statistic.multiColumn) {
              continue;
            }

            text.set(statistic.table);
            tableNames.setSafe(statisticIndex, text);
            if (statistic.column == null) {
              columnNames.setNull(statisticIndex);
            } else {
              text.set(statistic.column);
              columnNames.setSafe(statisticIndex, text);
            }
            statisticKeys.setSafe(statisticIndex, statistic.key);
            statisticValues.setTypeId(statisticIndex, (byte) 0);
            holder.isSet = 1;
            holder.value = statistic.value;
            statisticValues.setSafe(statisticIndex, holder);
            statisticIsApproximate.setSafe(statisticIndex, approximate ? 1 : 0);

            statistics.setIndexDefined(statisticIndex++);
            statisticCount++;
          }

          dbSchemaStatistics.endValue(schemaIndex, statisticCount);

          dbSchemas.setIndexDefined(schemaIndex++);
          schemaCount++;
        }

        catalogDbSchemas.endValue(catalogIndex, schemaCount);
        catalogIndex++;
      }
      root.setRowCount(catalogIndex);

      return RootArrowReader.fromRoot(allocator, root);
    } catch (SQLException e) {
      throw JdbcDriverUtil.fromSqlException(e);
    }
  }