Advertisement
Guest User

ClickHouseDatabaseMetadata.java (clickhouse-jdbc)

a guest
Mar 18th, 2020
262
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 37.97 KB | None | 0 0
  1. package ru.yandex.clickhouse;
  2.  
  3. import java.sql.Connection;
  4. import java.sql.DatabaseMetaData;
  5. import java.sql.ResultSet;
  6. import java.sql.RowIdLifetime;
  7. import java.sql.SQLException;
  8. import java.sql.Statement;
  9. import java.sql.Types;
  10. import java.util.ArrayList;
  11. import java.util.Arrays;
  12. import java.util.Iterator;
  13. import java.util.List;
  14.  
  15. import org.slf4j.Logger;
  16. import org.slf4j.LoggerFactory;
  17.  
  18. import ru.yandex.clickhouse.response.ClickHouseColumnInfo;
  19. import ru.yandex.clickhouse.response.ClickHouseResultBuilder;
  20. import ru.yandex.clickhouse.util.ClickHouseVersionNumberUtil;
  21.  
  22.  
  23. public class ClickHouseDatabaseMetadata implements DatabaseMetaData {
  24.  
  25.     static final String DEFAULT_CAT = "default";
  26.  
  27.     private static final Logger log = LoggerFactory.getLogger(ClickHouseDatabaseMetadata.class);
  28.  
  29.     private final String url;
  30.     private final ClickHouseConnection connection;
  31.  
  32.     public ClickHouseDatabaseMetadata(String url, ClickHouseConnection connection) {
  33.         this.url = url;
  34.         this.connection = connection;
  35.     }
  36.  
  37.     @Override
  38.     public boolean allProceduresAreCallable() throws SQLException {
  39.         return true;
  40.     }
  41.  
  42.     @Override
  43.     public boolean allTablesAreSelectable() throws SQLException {
  44.         return true;
  45.     }
  46.  
  47.     @Override
  48.     public String getURL() throws SQLException {
  49.         return url;
  50.     }
  51.  
  52.     @Override
  53.     public String getUserName() throws SQLException {
  54.         return null;
  55.     }
  56.  
  57.     @Override
  58.     public boolean isReadOnly() throws SQLException {
  59.         return true;
  60.     }
  61.  
  62.     @Override
  63.     public boolean nullsAreSortedHigh() throws SQLException {
  64.         return true;
  65.     }
  66.  
  67.     @Override
  68.     public boolean nullsAreSortedLow() throws SQLException {
  69.         return false;
  70.     }
  71.  
  72.     @Override
  73.     public boolean nullsAreSortedAtStart() throws SQLException {
  74.         return true;
  75.     }
  76.  
  77.     @Override
  78.     public boolean nullsAreSortedAtEnd() throws SQLException {
  79.         return false;
  80.     }
  81.  
  82.     @Override
  83.     public String getDatabaseProductName() throws SQLException {
  84.         return "ClickHouse";
  85.     }
  86.  
  87.     @Override
  88.     public String getDatabaseProductVersion() throws SQLException {
  89.         return connection.getServerVersion();
  90.     }
  91.  
  92.     @Override
  93.     public String getDriverName() throws SQLException {
  94.         return "ru.yandex.clickhouse-jdbc";
  95.     }
  96.  
  97.     @Override
  98.     public String getDriverVersion() throws SQLException {
  99.         String driverVersion = getClass().getPackage().getImplementationVersion();
  100.         return driverVersion != null ? driverVersion : "0.1";
  101.     }
  102.  
  103.     @Override
  104.     public int getDriverMajorVersion() {
  105.         String v;
  106.         try {
  107.             v = getDriverVersion();
  108.         } catch (SQLException sqle) {
  109.             log.warn("Error determining driver major version", sqle);
  110.             return 0;
  111.         }
  112.         return ClickHouseVersionNumberUtil.getMajorVersion(v);
  113.     }
  114.  
  115.     @Override
  116.     public int getDriverMinorVersion() {
  117.         String v;
  118.         try {
  119.             v = getDriverVersion();
  120.         } catch (SQLException sqle) {
  121.             log.warn("Error determining driver minor version", sqle);
  122.             return 0;
  123.         }
  124.         return ClickHouseVersionNumberUtil.getMinorVersion(v);
  125.     }
  126.  
  127.     @Override
  128.     public boolean usesLocalFiles() throws SQLException {
  129.         return false;
  130.     }
  131.  
  132.     @Override
  133.     public boolean usesLocalFilePerTable() throws SQLException {
  134.         return false;
  135.     }
  136.  
  137.     @Override
  138.     public boolean supportsMixedCaseIdentifiers() throws SQLException {
  139.         return true;
  140.     }
  141.  
  142.     @Override
  143.     public boolean storesUpperCaseIdentifiers() throws SQLException {
  144.         return false;
  145.     }
  146.  
  147.     @Override
  148.     public boolean storesLowerCaseIdentifiers() throws SQLException {
  149.         return false;
  150.     }
  151.  
  152.     @Override
  153.     public boolean storesMixedCaseIdentifiers() throws SQLException {
  154.         return true;
  155.     }
  156.  
  157.     @Override
  158.     public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
  159.         return true;
  160.     }
  161.  
  162.     @Override
  163.     public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
  164.         return false;
  165.     }
  166.  
  167.     @Override
  168.     public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
  169.         return false;
  170.     }
  171.  
  172.     @Override
  173.     public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
  174.         return true;
  175.     }
  176.  
  177.     @Override
  178.     public String getIdentifierQuoteString() throws SQLException {
  179.         return "`";
  180.     }
  181.  
  182.     @Override
  183.     public String getSQLKeywords() throws SQLException {
  184.         return "GLOBAL,ARRAY";
  185.     }
  186.  
  187.     @Override
  188.     public String getNumericFunctions() throws SQLException {
  189.         return "";
  190.     }
  191.  
  192.     @Override
  193.     public String getStringFunctions() throws SQLException {
  194.         return "";
  195.     }
  196.  
  197.     @Override
  198.     public String getSystemFunctions() throws SQLException {
  199.         return "";
  200.     }
  201.  
  202.     @Override
  203.     public String getTimeDateFunctions() throws SQLException {
  204.         return "";
  205.     }
  206.  
  207.     @Override
  208.     public String getSearchStringEscape() throws SQLException {
  209.         return "\\";
  210.     }
  211.  
  212.     @Override
  213.     public String getExtraNameCharacters() throws SQLException {
  214.         return "";
  215.     }
  216.  
  217.     @Override
  218.     public boolean supportsAlterTableWithAddColumn() throws SQLException {
  219.         return true;
  220.     }
  221.  
  222.     @Override
  223.     public boolean supportsAlterTableWithDropColumn() throws SQLException {
  224.         return true;
  225.     }
  226.  
  227.     @Override
  228.     public boolean supportsColumnAliasing() throws SQLException {
  229.         return true;
  230.     }
  231.  
  232.     @Override
  233.     public boolean nullPlusNonNullIsNull() throws SQLException {
  234.         return true;
  235.     }
  236.  
  237.     @Override
  238.     public boolean supportsConvert() throws SQLException {
  239.         return false;
  240.     }
  241.  
  242.     @Override
  243.     public boolean supportsConvert(int fromType, int toType) throws SQLException {
  244.         return false;
  245.     }
  246.  
  247.     @Override
  248.     public boolean supportsTableCorrelationNames() throws SQLException {
  249.         return false;
  250.     }
  251.  
  252.     @Override
  253.     public boolean supportsDifferentTableCorrelationNames() throws SQLException {
  254.         return false;
  255.     }
  256.  
  257.     @Override
  258.     public boolean supportsExpressionsInOrderBy() throws SQLException {
  259.         return true;
  260.     }
  261.  
  262.     @Override
  263.     public boolean supportsOrderByUnrelated() throws SQLException {
  264.         return true;
  265.     }
  266.  
  267.     @Override
  268.     public boolean supportsGroupBy() throws SQLException {
  269.         return true;
  270.     }
  271.  
  272.     @Override
  273.     public boolean supportsGroupByUnrelated() throws SQLException {
  274.         return true;
  275.     }
  276.  
  277.     @Override
  278.     public boolean supportsGroupByBeyondSelect() throws SQLException {
  279.         return true;
  280.     }
  281.  
  282.     @Override
  283.     public boolean supportsLikeEscapeClause() throws SQLException {
  284.         return true;
  285.     }
  286.  
  287.     @Override
  288.     public boolean supportsMultipleResultSets() throws SQLException {
  289.         return false;
  290.     }
  291.  
  292.     @Override
  293.     public boolean supportsMultipleTransactions() throws SQLException {
  294.         return false;
  295.     }
  296.  
  297.     @Override
  298.     public boolean supportsNonNullableColumns() throws SQLException {
  299.         return true;
  300.     }
  301.  
  302.     @Override
  303.     public boolean supportsMinimumSQLGrammar() throws SQLException {
  304.         return false;
  305.     }
  306.  
  307.     @Override
  308.     public boolean supportsCoreSQLGrammar() throws SQLException {
  309.         return false;
  310.     }
  311.  
  312.     @Override
  313.     public boolean supportsExtendedSQLGrammar() throws SQLException {
  314.         return false;
  315.     }
  316.  
  317.     @Override
  318.     public boolean supportsANSI92EntryLevelSQL() throws SQLException {
  319.         return false;
  320.     }
  321.  
  322.     @Override
  323.     public boolean supportsANSI92IntermediateSQL() throws SQLException {
  324.         return false;
  325.     }
  326.  
  327.     @Override
  328.     public boolean supportsANSI92FullSQL() throws SQLException {
  329.         return false;
  330.     }
  331.  
  332.     @Override
  333.     public boolean supportsIntegrityEnhancementFacility() throws SQLException {
  334.         return false;
  335.     }
  336.  
  337.     @Override
  338.     public boolean supportsOuterJoins() throws SQLException {
  339.         return true;
  340.     }
  341.  
  342.     @Override
  343.     public boolean supportsFullOuterJoins() throws SQLException {
  344.         return false;
  345.     }
  346.  
  347.     @Override
  348.     public boolean supportsLimitedOuterJoins() throws SQLException {
  349.         return true;
  350.     }
  351.  
  352.     @Override
  353.     public String getSchemaTerm() throws SQLException {
  354.         return "database";
  355.     }
  356.  
  357.     @Override
  358.     public String getProcedureTerm() throws SQLException {
  359.         return "procedure";
  360.     }
  361.  
  362.     @Override
  363.     public String getCatalogTerm() throws SQLException {
  364.         return "catalog";
  365.     }
  366.  
  367.     @Override
  368.     public boolean isCatalogAtStart() throws SQLException {
  369.         return false;
  370.     }
  371.  
  372.     @Override
  373.     public String getCatalogSeparator() throws SQLException {
  374.         return ".";
  375.     }
  376.  
  377.     @Override
  378.     public boolean supportsSchemasInDataManipulation() throws SQLException {
  379.         return true;
  380.     }
  381.  
  382.     @Override
  383.     public boolean supportsSchemasInProcedureCalls() throws SQLException {
  384.         return true;
  385.     }
  386.  
  387.     @Override
  388.     public boolean supportsSchemasInTableDefinitions() throws SQLException {
  389.         return true;
  390.     }
  391.  
  392.     @Override
  393.     public boolean supportsSchemasInIndexDefinitions() throws SQLException {
  394.         return true;
  395.     }
  396.  
  397.     @Override
  398.     public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException {
  399.         return true;
  400.     }
  401.  
  402.     @Override
  403.     public boolean supportsCatalogsInDataManipulation() throws SQLException {
  404.         return false;
  405.     }
  406.  
  407.     @Override
  408.     public boolean supportsCatalogsInProcedureCalls() throws SQLException {
  409.         return false;
  410.     }
  411.  
  412.     @Override
  413.     public boolean supportsCatalogsInTableDefinitions() throws SQLException {
  414.         return false;
  415.     }
  416.  
  417.     @Override
  418.     public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
  419.         return false;
  420.     }
  421.  
  422.     @Override
  423.     public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException {
  424.         return false;
  425.     }
  426.  
  427.     @Override
  428.     public boolean supportsPositionedDelete() throws SQLException {
  429.         return false;
  430.     }
  431.  
  432.     @Override
  433.     public boolean supportsPositionedUpdate() throws SQLException {
  434.         return false;
  435.     }
  436.  
  437.     @Override
  438.     public boolean supportsSelectForUpdate() throws SQLException {
  439.         return false;
  440.     }
  441.  
  442.     @Override
  443.     public boolean supportsStoredProcedures() throws SQLException {
  444.         return false;
  445.     }
  446.  
  447.     @Override
  448.     public boolean supportsSubqueriesInComparisons() throws SQLException {
  449.         return true;
  450.     }
  451.  
  452.     @Override
  453.     public boolean supportsSubqueriesInExists() throws SQLException {
  454.         return false;
  455.     }
  456.  
  457.     @Override
  458.     public boolean supportsSubqueriesInIns() throws SQLException {
  459.         return true;
  460.     }
  461.  
  462.     @Override
  463.     public boolean supportsSubqueriesInQuantifieds() throws SQLException {
  464.         return false;
  465.     }
  466.  
  467.     @Override
  468.     public boolean supportsCorrelatedSubqueries() throws SQLException {
  469.         return false;
  470.     }
  471.  
  472.     @Override
  473.     public boolean supportsUnion() throws SQLException {
  474.         return true;
  475.     }
  476.  
  477.     @Override
  478.     public boolean supportsUnionAll() throws SQLException {
  479.         return true;
  480.     }
  481.  
  482.     @Override
  483.     public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
  484.         return false;
  485.     }
  486.  
  487.     @Override
  488.     public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
  489.         return false;
  490.     }
  491.  
  492.     @Override
  493.     public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
  494.         return false;
  495.     }
  496.  
  497.     @Override
  498.     public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
  499.         return false;
  500.     }
  501.  
  502.     @Override
  503.     public int getMaxBinaryLiteralLength() throws SQLException {
  504.         return 0;
  505.     }
  506.  
  507.     @Override
  508.     public int getMaxCharLiteralLength() throws SQLException {
  509.         return 0;
  510.     }
  511.  
  512.     @Override
  513.     public int getMaxColumnNameLength() throws SQLException {
  514.         return 0;
  515.     }
  516.  
  517.     @Override
  518.     public int getMaxColumnsInGroupBy() throws SQLException {
  519.         return 0;
  520.     }
  521.  
  522.     @Override
  523.     public int getMaxColumnsInIndex() throws SQLException {
  524.         return 0;
  525.     }
  526.  
  527.     @Override
  528.     public int getMaxColumnsInOrderBy() throws SQLException {
  529.         return 0;
  530.     }
  531.  
  532.     @Override
  533.     public int getMaxColumnsInSelect() throws SQLException {
  534.         return 0;
  535.     }
  536.  
  537.     @Override
  538.     public int getMaxColumnsInTable() throws SQLException {
  539.         return 0;
  540.     }
  541.  
  542.     @Override
  543.     public int getMaxConnections() throws SQLException {
  544.         return 0;
  545.     }
  546.  
  547.     @Override
  548.     public int getMaxCursorNameLength() throws SQLException {
  549.         return 0;
  550.     }
  551.  
  552.     @Override
  553.     public int getMaxIndexLength() throws SQLException {
  554.         return 0;
  555.     }
  556.  
  557.     @Override
  558.     public int getMaxSchemaNameLength() throws SQLException {
  559.         return 0;
  560.     }
  561.  
  562.     @Override
  563.     public int getMaxProcedureNameLength() throws SQLException {
  564.         return 0;
  565.     }
  566.  
  567.     @Override
  568.     public int getMaxCatalogNameLength() throws SQLException {
  569.         return 0;
  570.     }
  571.  
  572.     @Override
  573.     public int getMaxRowSize() throws SQLException {
  574.         return 0;
  575.     }
  576.  
  577.     @Override
  578.     public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
  579.         return false;
  580.     }
  581.  
  582.     @Override
  583.     public int getMaxStatementLength() throws SQLException {
  584.         return 0;
  585.     }
  586.  
  587.     @Override
  588.     public int getMaxStatements() throws SQLException {
  589.         return 0;
  590.     }
  591.  
  592.     @Override
  593.     public int getMaxTableNameLength() throws SQLException {
  594.         return 0;
  595.     }
  596.  
  597.     @Override
  598.     public int getMaxTablesInSelect() throws SQLException {
  599.         return 0;
  600.     }
  601.  
  602.     @Override
  603.     public int getMaxUserNameLength() throws SQLException {
  604.         return 0;
  605.     }
  606.  
  607.     @Override
  608.     public int getDefaultTransactionIsolation() throws SQLException {
  609.         return Connection.TRANSACTION_NONE;
  610.     }
  611.  
  612.     @Override
  613.     public boolean supportsTransactions() throws SQLException {
  614.         return false;
  615.     }
  616.  
  617.     @Override
  618.     public boolean supportsTransactionIsolationLevel(int level) throws SQLException {
  619.         return level == Connection.TRANSACTION_NONE;
  620.     }
  621.  
  622.     @Override
  623.     public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException {
  624.         return false;
  625.     }
  626.  
  627.     @Override
  628.     public boolean supportsDataManipulationTransactionsOnly() throws SQLException {
  629.         return false;
  630.     }
  631.  
  632.     @Override
  633.     public boolean dataDefinitionCausesTransactionCommit() throws SQLException {
  634.         return false;
  635.     }
  636.  
  637.     @Override
  638.     public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
  639.         return false;
  640.     }
  641.  
  642.     private ResultSet request(String sql) throws SQLException {
  643.         Statement statement = connection.createStatement();
  644.         return statement.executeQuery(sql);
  645.     }
  646.  
  647.     @Override
  648.     public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException {
  649.         ClickHouseResultBuilder builder = ClickHouseResultBuilder.builder(9);
  650.         builder.names(
  651.                 "PROCEDURE_CAT",
  652.                 "PROCEDURE_SCHEM",
  653.                 "PROCEDURE_NAME",
  654.                 "RES_1",
  655.                 "RES_2",
  656.                 "RES_3",
  657.                 "REMARKS",
  658.                 "PROCEDURE_TYPE",
  659.                 "SPECIFIC_NAME"
  660.         );
  661.  
  662.         builder.types(
  663.                 "String",
  664.                 "String",
  665.                 "String",
  666.                 "String",
  667.                 "String",
  668.                 "String",
  669.                 "String",
  670.                 "UInt8",
  671.                 "String"
  672.         );
  673.  
  674.         return builder.build();
  675.     }
  676.  
  677.     @Override
  678.     public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException {
  679.         ClickHouseResultBuilder builder = ClickHouseResultBuilder.builder(20);
  680.         builder.names("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20");
  681.  
  682.         builder.types("UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32", "UInt32");
  683.  
  684.         return builder.build();
  685.     }
  686.  
  687.     @Override
  688.     public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException {
  689.         /*
  690.          TABLE_CAT String => table catalog (may be null)
  691.          TABLE_SCHEM String => table schema (may be null)
  692.          TABLE_NAME String => table name
  693.          TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
  694.          REMARKS String => explanatory comment on the table
  695.          TYPE_CAT String => the types catalog (may be null)
  696.          TYPE_SCHEM String => the types schema (may be null)
  697.          TYPE_NAME String => type name (may be null)
  698.          SELF_REFERENCING_COL_NAME String => name of the designated "identifier" column of a typed table (may be null)
  699.          REF_GENERATION String => specifies how values in SELF_REFERENCING_COL_NAME are created. Values are "SYSTEM", "USER", "DERIVED". (may be null)
  700.          */
  701.         String sql = "select " +
  702.                 "database, name, engine " +
  703.                 "from system.tables " +
  704.                 "where 1 = 1";
  705.         if (schemaPattern != null) {
  706.             sql += " and database like '" + schemaPattern + "'";
  707.         }
  708.         if (tableNamePattern != null) {
  709.             sql += " and name like '" + tableNamePattern + "'";
  710.         }
  711.         sql += " order by database, name";
  712.         ResultSet result = request(sql);
  713.  
  714.         ClickHouseResultBuilder builder = ClickHouseResultBuilder.builder(10);
  715.         builder.names("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE", "REMARKS", "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "SELF_REFERENCING_COL_NAME", "REF_GENERATION");
  716.         builder.types("String", "String", "String", "String", "String", "String", "String", "String", "String", "String");
  717.  
  718.         List typeList = types != null ? Arrays.asList(types) : null;
  719.         while (result.next()) {
  720.             List<String> row = new ArrayList<String>();
  721.             //row.add(DEFAULT_CAT);
  722.             row.add(null);
  723.             row.add(result.getString(1));
  724.             row.add(result.getString(2));
  725.             String type, e = result.getString(3).intern();
  726.             if (e == "View" || e == "MaterializedView" || e == "Merge" || e == "Distributed" || e == "Null") {
  727.                 type = "VIEW"; // some kind of view
  728.             } else if (e == "Set" || e == "Join" || e == "Buffer") {
  729.                 type = "OTHER"; // not a real table
  730.             } else {
  731.                 type = "TABLE";
  732.             }
  733.             row.add(type);
  734.             for (int i = 3; i < 9; i++) {
  735.                 row.add(null);
  736.             }
  737.             if (typeList == null || typeList.contains(type)) {
  738.                 builder.addRow(row);
  739.             }
  740.         }
  741.         result.close();
  742.         return builder.build();
  743.     }
  744.  
  745.     @Override
  746.     public ResultSet getSchemas() throws SQLException {
  747.         return getSchemas(null, null);
  748.     }
  749.  
  750.     @Override
  751.     public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException {
  752.         String sql = "select name as TABLE_SCHEM, '" +
  753.                 DEFAULT_CAT + "' as TABLE_CATALOG from system.databases";
  754.         if (catalog != null) {
  755.             sql += " where TABLE_CATALOG = '" + catalog + '\'';
  756.         }
  757.         if (schemaPattern != null) {
  758.             if (catalog != null) {
  759.                 sql += " and ";
  760.             } else {
  761.                 sql += " where ";
  762.             }
  763.             sql += "name LIKE '" + schemaPattern + '\'';
  764.         }
  765.         return request(sql);
  766.     }
  767.  
  768.     @Override
  769.     public ResultSet getCatalogs() throws SQLException {
  770.         ClickHouseResultBuilder builder = ClickHouseResultBuilder.builder(1);
  771.         builder.names("TABLE_CAT");
  772.         builder.types("String");
  773.  
  774.         builder.addRow(DEFAULT_CAT);
  775.         return builder.build();
  776.     }
  777.  
  778.     @Override
  779.     public ResultSet getTableTypes() throws SQLException {
  780.         ClickHouseResultBuilder builder = ClickHouseResultBuilder.builder(1);
  781.         builder.names("TABLE_TYPE");
  782.         builder.types("String");
  783.  
  784.         builder.addRow("TABLE");
  785.         builder.addRow("VIEW");
  786.         builder.addRow("OTHER");
  787.         return builder.build();
  788.     }
  789.  
  790.     private static void buildAndCondition(StringBuilder dest, List<String> conditions) {
  791.         Iterator<String> iter = conditions.iterator();
  792.         if (iter.hasNext()) {
  793.             String entry = iter.next();
  794.             dest.append(entry);
  795.         }
  796.         while (iter.hasNext()) {
  797.             String entry = iter.next();
  798.             dest.append(" AND ").append(entry);
  799.         }
  800.     }
  801.  
  802.     @Override
  803.     public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException {
  804.         StringBuilder query;
  805.         if (connection.getServerVersion().compareTo("1.1.54237") > 0) {
  806.             query = new StringBuilder(
  807.                 "SELECT database, table, name, type, default_kind as default_type, default_expression ");
  808.         } else {
  809.             query = new StringBuilder(
  810.                 "SELECT database, table, name, type, default_type, default_expression ");
  811.         }
  812.         query.append("FROM system.columns ");
  813.         List<String> predicates = new ArrayList<String>();
  814.         if (schemaPattern != null) {
  815.             predicates.add("database LIKE '" + schemaPattern + "' ");
  816.         }
  817.         if (tableNamePattern != null) {
  818.             predicates.add("table LIKE '" + tableNamePattern + "' ");
  819.         }
  820.         if (columnNamePattern != null) {
  821.             predicates.add("name LIKE '" + columnNamePattern + "' ");
  822.         }
  823.         if (!predicates.isEmpty()) {
  824.             query.append(" WHERE ");
  825.             buildAndCondition(query, predicates);
  826.         }
  827.         ClickHouseResultBuilder builder = getClickHouseResultBuilderForGetColumns();
  828.         ResultSet descTable = request(query.toString());
  829.         int colNum = 1;
  830.         while (descTable.next()) {
  831.             List<String> row = new ArrayList<String>();
  832.             //catalog name
  833.             row.add(DEFAULT_CAT);
  834.             //database name
  835.             row.add(descTable.getString("database"));
  836.             //table name
  837.             row.add(descTable.getString("table"));
  838.             //column name
  839.             ClickHouseColumnInfo columnInfo = ClickHouseColumnInfo.parse(
  840.                 descTable.getString("type"),
  841.                 descTable.getString("name"));
  842.             row.add(columnInfo.getColumnName());
  843.             //data type
  844.             row.add(String.valueOf(columnInfo.getClickHouseDataType().getSqlType()));
  845.             //type name
  846.             row.add(columnInfo.getCleanTypeName());
  847.             // column size / precision
  848.             row.add(String.valueOf(columnInfo.getPrecision()));
  849.             //buffer length
  850.             row.add("0");
  851.             // decimal digits
  852.             row.add(String.valueOf(columnInfo.getScale()));
  853.             // radix
  854.             row.add("10");
  855.             // nullable
  856.             row.add(columnInfo.isNullable()
  857.                 ? String.valueOf(columnNullable)
  858.                 : String.valueOf(columnNoNulls));
  859.             //remarks
  860.             row.add(null);
  861.  
  862.             // COLUMN_DEF
  863.             if ("DEFAULT".equals(descTable.getString("default_type"))) {
  864.                 row.add(descTable.getString("default_expression"));
  865.             } else {
  866.                 row.add(null);
  867.             }
  868.  
  869.             //"SQL_DATA_TYPE", unused per JavaDoc
  870.             row.add(null);
  871.             //"SQL_DATETIME_SUB", unused per JavaDoc
  872.             row.add(null);
  873.  
  874.             // char octet length
  875.             row.add("0");
  876.             // ordinal
  877.             row.add(String.valueOf(colNum));
  878.             colNum += 1;
  879.  
  880.             //IS_NULLABLE
  881.             row.add(columnInfo.isNullable()
  882.                 ? "YES"
  883.                 : "NO");
  884.             //"SCOPE_CATALOG",
  885.             row.add(null);
  886.             //"SCOPE_SCHEMA",
  887.             row.add(null);
  888.             //"SCOPE_TABLE",
  889.             row.add(null);
  890.             //"SOURCE_DATA_TYPE",
  891.             row.add(null);
  892.             //"IS_AUTOINCREMENT"
  893.             row.add("NO");
  894.             //"IS_GENERATEDCOLUMN"
  895.             row.add("NO");
  896.  
  897.             builder.addRow(row);
  898.         }
  899.         descTable.close();
  900.         return builder.build();
  901.     }
  902.  
  903.     private ClickHouseResultBuilder getClickHouseResultBuilderForGetColumns() {
  904.         ClickHouseResultBuilder builder = ClickHouseResultBuilder.builder(24);
  905.         builder.names(
  906.                 "TABLE_CAT",
  907.                 "TABLE_SCHEM",
  908.                 "TABLE_NAME",
  909.                 "COLUMN_NAME",
  910.                 "DATA_TYPE",
  911.                 "TYPE_NAME",
  912.                 "COLUMN_SIZE",
  913.                 "BUFFER_LENGTH",
  914.                 "DECIMAL_DIGITS",
  915.                 "NUM_PREC_RADIX",
  916.                 "NULLABLE",
  917.                 "REMARKS",
  918.                 "COLUMN_DEF",
  919.                 "SQL_DATA_TYPE",
  920.                 "SQL_DATETIME_SUB",
  921.                 "CHAR_OCTET_LENGTH",
  922.                 "ORDINAL_POSITION",
  923.                 "IS_NULLABLE",
  924.                 "SCOPE_CATALOG",
  925.                 "SCOPE_SCHEMA",
  926.                 "SCOPE_TABLE",
  927.                 "SOURCE_DATA_TYPE",
  928.                 "IS_AUTOINCREMENT",
  929.                 "IS_GENERATEDCOLUMN"
  930.         );
  931.         builder.types(
  932.                 "String",
  933.                 "String",
  934.                 "String",
  935.                 "String",
  936.                 "Int32",
  937.                 "String",
  938.                 "Int32",
  939.                 "Int32",
  940.                 "Int32",
  941.                 "Int32",
  942.                 "Int32",
  943.                 "String",
  944.                 "String",
  945.                 "Int32",
  946.                 "Int32",
  947.                 "Int32",
  948.                 "Int32",
  949.                 "String",
  950.                 "String",
  951.                 "String",
  952.                 "String",
  953.                 "Int32",
  954.                 "String",
  955.                 "String"
  956.         );
  957.         return builder;
  958.     }
  959.  
  960.     private ResultSet getEmptyResultSet() {
  961.         return ClickHouseResultBuilder.builder(1).names("some").types("String").build();
  962.     }
  963.  
  964.     @Override
  965.     public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException {
  966.         return getEmptyResultSet();
  967.     }
  968.  
  969.     @Override
  970.     public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException {
  971.         return getEmptyResultSet();
  972.     }
  973.  
  974.     @Override
  975.     public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException {
  976.         return getEmptyResultSet();
  977.     }
  978.  
  979.     @Override
  980.     public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException {
  981.         return getEmptyResultSet();
  982.     }
  983.  
  984.     @Override
  985.     public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException {
  986.         return getEmptyResultSet();
  987.     }
  988.  
  989.     @Override
  990.     public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException {
  991.         return getEmptyResultSet();
  992.     }
  993.  
  994.     @Override
  995.     public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException {
  996.         return getEmptyResultSet();
  997.     }
  998.  
  999.     @Override
  1000.     public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException {
  1001.         return getEmptyResultSet();
  1002.     }
  1003.  
  1004.     @Override
  1005.     public ResultSet getTypeInfo() throws SQLException {
  1006.         ClickHouseResultBuilder builder = ClickHouseResultBuilder.builder(18);
  1007.         builder.names(
  1008.                 "TYPE_NAME",
  1009.                 "DATA_TYPE",
  1010.                 "PRECISION",
  1011.                 "LITERAL_PREFIX",
  1012.                 "LITERAL_SUFFIX",
  1013.                 "CREATE_PARAMS",
  1014.                 "NULLABLE",
  1015.                 "CASE_SENSITIVE",
  1016.                 "SEARCHABLE",
  1017.                 "UNSIGNED_ATTRIBUTE",
  1018.                 "FIXED_PREC_SCALE",
  1019.                 "AUTO_INCREMENT",
  1020.                 "LOCAL_TYPE_NAME",
  1021.                 "MINIMUM_SCALE",
  1022.                 "MAXIMUM_SCALE",
  1023.                 "SQL_DATA_TYPE",
  1024.                 "SQL_DATETIME_SUB",
  1025.                 "NUM_PREC_RADIX"
  1026.         );
  1027.         builder.types(
  1028.                 "String",
  1029.                 "Int32",
  1030.                 "Int32",
  1031.                 "String",
  1032.                 "String",
  1033.                 "String",
  1034.                 "Int32",
  1035.                 "Int8",
  1036.                 "Int32",
  1037.                 "Int8",
  1038.                 "Int8",
  1039.                 "Int8",
  1040.                 "String",
  1041.                 "Int32",
  1042.                 "Int32",
  1043.                 "Int32",
  1044.                 "Int32",
  1045.                 "Int32"
  1046.         );
  1047.         builder.addRow(
  1048.                 "String", Types.VARCHAR,
  1049.                 null, // precision - todo
  1050.                 '\'', '\'', null,
  1051.                 typeNoNulls, true, typeSearchable,
  1052.                 true, // unsigned
  1053.                 true, // fixed precision (money)
  1054.                 false, //auto-incr
  1055.                 null,
  1056.                 null, null, // scale - should be fixed
  1057.                 null, null,
  1058.                 10
  1059.                 );
  1060.         int[] sizes = { 8, 16, 32, 64 };
  1061.         boolean[] signed = { true, false };
  1062.         for (int size : sizes) {
  1063.             for (boolean b: signed) {
  1064.                 String name = (b ? "" : "U") + "Int" + size;
  1065.                 builder.addRow(
  1066.                         name, (size <= 16 ? Types.INTEGER : Types.BIGINT),
  1067.                         null, // precision - todo
  1068.                         null, null, null,
  1069.                         typeNoNulls, true, typePredBasic,
  1070.                         !b, // unsigned
  1071.                         true, // fixed precision (money)
  1072.                         false, //auto-incr
  1073.                         null,
  1074.                         null, null, // scale - should be fixed
  1075.                         null, null,
  1076.                         10
  1077.                 );
  1078.             }
  1079.         }
  1080.         int[] floatSizes = { 32, 64 };
  1081.         for (int floatSize : floatSizes) {
  1082.             String name = "Float" + floatSize;
  1083.             builder.addRow(
  1084.                     name, Types.FLOAT,
  1085.                     null, // precision - todo
  1086.                     null, null, null,
  1087.                     typeNoNulls, true, typePredBasic,
  1088.                     false, // unsigned
  1089.                     true, // fixed precision (money)
  1090.                     false, //auto-incr
  1091.                     null,
  1092.                     null, null, // scale - should be fixed
  1093.                     null, null,
  1094.                     10
  1095.             );
  1096.         }
  1097.         builder.addRow(
  1098.                 "Date", Types.DATE,
  1099.                 null, // precision - todo
  1100.                 null, null, null,
  1101.                 typeNoNulls, true, typePredBasic,
  1102.                 false, // unsigned
  1103.                 true, // fixed precision (money)
  1104.                 false, //auto-incr
  1105.                 null,
  1106.                 null, null, // scale - should be fixed
  1107.                 null, null,
  1108.                 10
  1109.         );
  1110.         builder.addRow(
  1111.                 "DateTime", Types.TIMESTAMP,
  1112.                 null, // precision - todo
  1113.                 null, null, null,
  1114.                 typeNoNulls, true, typePredBasic,
  1115.                 false, // unsigned
  1116.                 true, // fixed precision (money)
  1117.                 false, //auto-incr
  1118.                 null,
  1119.                 null, null, // scale - should be fixed
  1120.                 null, null,
  1121.                 10
  1122.         );
  1123.         return builder.build();
  1124.     }
  1125.  
  1126.     @Override
  1127.     public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException {
  1128.         return getEmptyResultSet();
  1129.     }
  1130.  
  1131.     @Override
  1132.     public boolean supportsResultSetType(int type) throws SQLException {
  1133.         return ResultSet.TYPE_FORWARD_ONLY == type;
  1134.     }
  1135.  
  1136.     @Override
  1137.     public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException {
  1138.         return false;
  1139.     }
  1140.  
  1141.     @Override
  1142.     public boolean ownUpdatesAreVisible(int type) throws SQLException {
  1143.         return true;
  1144.     }
  1145.  
  1146.     @Override
  1147.     public boolean ownDeletesAreVisible(int type) throws SQLException {
  1148.         return true;
  1149.     }
  1150.  
  1151.     @Override
  1152.     public boolean ownInsertsAreVisible(int type) throws SQLException {
  1153.         return true;
  1154.     }
  1155.  
  1156.     @Override
  1157.     public boolean othersUpdatesAreVisible(int type) throws SQLException {
  1158.         return true;
  1159.     }
  1160.  
  1161.     @Override
  1162.     public boolean othersDeletesAreVisible(int type) throws SQLException {
  1163.         return true;
  1164.     }
  1165.  
  1166.     @Override
  1167.     public boolean othersInsertsAreVisible(int type) throws SQLException {
  1168.         return true;
  1169.     }
  1170.  
  1171.     @Override
  1172.     public boolean updatesAreDetected(int type) throws SQLException {
  1173.         return false;
  1174.     }
  1175.  
  1176.     @Override
  1177.     public boolean deletesAreDetected(int type) throws SQLException {
  1178.         return false;
  1179.     }
  1180.  
  1181.     @Override
  1182.     public boolean insertsAreDetected(int type) throws SQLException {
  1183.         return false;
  1184.     }
  1185.  
  1186.     @Override
  1187.     public boolean supportsBatchUpdates() throws SQLException {
  1188.         return true;
  1189.     }
  1190.  
  1191.     @Override
  1192.     public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException {
  1193.         return getEmptyResultSet();
  1194.     }
  1195.  
  1196.     @Override
  1197.     public Connection getConnection() throws SQLException {
  1198.         return connection;
  1199.     }
  1200.  
  1201.     @Override
  1202.     public boolean supportsSavepoints() throws SQLException {
  1203.         return false;
  1204.     }
  1205.  
  1206.     @Override
  1207.     public boolean supportsNamedParameters() throws SQLException {
  1208.         return false;
  1209.     }
  1210.  
  1211.     @Override
  1212.     public boolean supportsMultipleOpenResults() throws SQLException {
  1213.         return false;
  1214.     }
  1215.  
  1216.     @Override
  1217.     public boolean supportsGetGeneratedKeys() throws SQLException {
  1218.         return false;
  1219.     }
  1220.  
  1221.     @Override
  1222.     public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException {
  1223.         return getEmptyResultSet();
  1224.     }
  1225.  
  1226.     @Override
  1227.     public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException {
  1228.         return getEmptyResultSet();
  1229.     }
  1230.  
  1231.     @Override
  1232.     public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException {
  1233.         return getEmptyResultSet();
  1234.     }
  1235.  
  1236.     @Override
  1237.     public boolean supportsResultSetHoldability(int holdability) throws SQLException {
  1238.         return false;
  1239.     }
  1240.  
  1241.     @Override
  1242.     public int getResultSetHoldability() throws SQLException {
  1243.         return 0;
  1244.     }
  1245.  
  1246.     @Override
  1247.     public int getDatabaseMajorVersion() throws SQLException {
  1248.         return ClickHouseVersionNumberUtil.getMajorVersion(
  1249.             connection.getServerVersion());
  1250.     }
  1251.  
  1252.     @Override
  1253.     public int getDatabaseMinorVersion() throws SQLException {
  1254.         return ClickHouseVersionNumberUtil.getMinorVersion(
  1255.             connection.getServerVersion());
  1256.     }
  1257.  
  1258.     @Override
  1259.     public int getJDBCMajorVersion() throws SQLException {
  1260.         return 0;
  1261.     }
  1262.  
  1263.     @Override
  1264.     public int getJDBCMinorVersion() throws SQLException {
  1265.         return 1;
  1266.     }
  1267.  
  1268.     @Override
  1269.     public int getSQLStateType() throws SQLException {
  1270.         return sqlStateSQL;
  1271.     }
  1272.  
  1273.     @Override
  1274.     public boolean locatorsUpdateCopy() throws SQLException {
  1275.         return false;
  1276.     }
  1277.  
  1278.     @Override
  1279.     public boolean supportsStatementPooling() throws SQLException {
  1280.         return false;
  1281.     }
  1282.  
  1283.     @Override
  1284.     public RowIdLifetime getRowIdLifetime() throws SQLException {
  1285.         return RowIdLifetime.ROWID_UNSUPPORTED;
  1286.     }
  1287.  
  1288.     @Override
  1289.     public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException {
  1290.         return false;
  1291.     }
  1292.  
  1293.     @Override
  1294.     public boolean autoCommitFailureClosesAllResultSets() throws SQLException {
  1295.         return false;
  1296.     }
  1297.  
  1298.     @Override
  1299.     public ResultSet getClientInfoProperties() throws SQLException {
  1300.         return getEmptyResultSet();
  1301.     }
  1302.  
  1303.     @Override
  1304.     public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException {
  1305.         return getEmptyResultSet();
  1306.     }
  1307.  
  1308.     @Override
  1309.     public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException {
  1310.         return getEmptyResultSet();
  1311.     }
  1312.  
  1313.     @Override
  1314.     public <T> T unwrap(Class<T> iface) throws SQLException {
  1315.         if (iface.isAssignableFrom(getClass())) {
  1316.             return iface.cast(this);
  1317.         }
  1318.         throw new SQLException("Cannot unwrap to " + iface.getName());
  1319.     }
  1320.  
  1321.     @Override
  1322.     public boolean isWrapperFor(Class<?> iface) throws SQLException {
  1323.         return iface.isAssignableFrom(getClass());
  1324.     }
  1325.  
  1326.     public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException {
  1327.         return null;
  1328.     }
  1329.  
  1330.     public boolean generatedKeyAlwaysReturned() throws SQLException {
  1331.         return false;
  1332.     }
  1333.  
  1334. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement