This is an automated email from the ASF dual-hosted git repository. isapego pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push: new eb77c8a IGNITE-13908: ODBC nullability info for columns eb77c8a is described below commit eb77c8af710995237e69c8946e2fc5fa20d7c7a1 Author: Igor Sapego <isap...@apache.org> AuthorDate: Fri Dec 25 16:03:49 2020 +0300 IGNITE-13908: ODBC nullability info for columns This closes #8610 --- .../processors/odbc/odbc/OdbcColumnMeta.java | 39 ++++++++++--------- .../odbc/odbc/OdbcConnectionContext.java | 6 ++- .../processors/odbc/odbc/OdbcMessageParser.java | 4 +- .../processors/odbc/odbc/OdbcRequestHandler.java | 7 +++- .../processors/odbc/odbc/OdbcResultSet.java | 2 +- .../internal/processors/odbc/odbc/OdbcUtils.java | 7 +--- .../processors/query/GridQueryFieldMetadata.java | 9 +++++ .../processors/query/h2/H2SqlFieldMetadata.java | 11 +++++- .../internal/processors/query/h2/H2Utils.java | 7 +++- .../cpp/odbc-test/src/attributes_test.cpp | 24 ++++++++++++ .../cpp/odbc-test/src/meta_queries_test.cpp | 44 +++++++++++----------- .../odbc/include/ignite/odbc/meta/column_meta.h | 41 +++++++++++++++++++- .../odbc/include/ignite/odbc/protocol_version.h | 3 ++ .../platforms/cpp/odbc/src/meta/column_meta.cpp | 28 +++++++++++++- .../platforms/cpp/odbc/src/protocol_version.cpp | 6 ++- 15 files changed, 179 insertions(+), 59 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcColumnMeta.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcColumnMeta.java index a8f749e..58ae98f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcColumnMeta.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcColumnMeta.java @@ -35,19 +35,19 @@ public class OdbcColumnMeta { private final String tableName; /** Column name. */ - public final String columnName; + private final String columnName; /** Data type. */ private final Class<?> dataType; /** Precision. */ - public final int precision; + private final int precision; /** Scale. */ - public final int scale; + private final int scale; - /** Client version. */ - private final ClientListenerProtocolVersion ver; + /** Nullability. See {@link java.sql.ResultSetMetaData#isNullable(int)} for more info. */ + private final int nullability; /** * @param schemaName Cache name. @@ -56,30 +56,30 @@ public class OdbcColumnMeta { * @param dataType Data type. * @param precision Precision. * @param scale Scale. - * @param ver Client version. + * @param nullability Nullability. */ public OdbcColumnMeta(String schemaName, String tableName, String columnName, Class<?> dataType, - int precision, int scale, ClientListenerProtocolVersion ver) { + int precision, int scale, int nullability) { this.schemaName = OdbcUtils.addQuotationMarksIfNeeded(schemaName); this.tableName = tableName; this.columnName = columnName; this.dataType = dataType; this.precision = precision; this.scale = scale; - this.ver = ver; + this.nullability = nullability; } /** + * Constructor for result set column. * @param info Field metadata. - * @param ver Client version. */ - public OdbcColumnMeta(GridQueryFieldMetadata info, ClientListenerProtocolVersion ver) { - this.schemaName = OdbcUtils.addQuotationMarksIfNeeded(info.schemaName()); - this.tableName = info.typeName(); - this.columnName = info.fieldName(); - this.precision = info.precision(); - this.scale = info.scale(); - this.ver = ver; + public OdbcColumnMeta(GridQueryFieldMetadata info) { + schemaName = OdbcUtils.addQuotationMarksIfNeeded(info.schemaName()); + tableName = info.typeName(); + columnName = info.fieldName(); + precision = info.precision(); + scale = info.scale(); + nullability = info.nullability(); Class<?> type; @@ -123,8 +123,9 @@ public class OdbcColumnMeta { * Write in a binary format. * * @param writer Binary writer. + * @param ver Client version. */ - public void write(BinaryRawWriter writer) { + public void write(BinaryRawWriter writer, ClientListenerProtocolVersion ver) { writer.writeString(schemaName); writer.writeString(tableName); writer.writeString(columnName); @@ -137,6 +138,10 @@ public class OdbcColumnMeta { writer.writeInt(precision); writer.writeInt(scale); } + + if (ver.compareTo(OdbcConnectionContext.VER_2_8_0) >= 0) { + writer.writeByte((byte)nullability); + } } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcConnectionContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcConnectionContext.java index 74def0d..5b78b6e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcConnectionContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcConnectionContext.java @@ -56,8 +56,11 @@ public class OdbcConnectionContext extends ClientListenerAbstractConnectionConte /** Version 2.7.0: added precision and scale. */ public static final ClientListenerProtocolVersion VER_2_7_0 = ClientListenerProtocolVersion.create(2, 7, 0); + /** Version 2.8.0: added column nullability info. */ + public static final ClientListenerProtocolVersion VER_2_8_0 = ClientListenerProtocolVersion.create(2, 8, 0); + /** Current version. */ - private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_7_0; + private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_8_0; /** Supported versions. */ private static final Set<ClientListenerProtocolVersion> SUPPORTED_VERS = new HashSet<>(); @@ -79,6 +82,7 @@ public class OdbcConnectionContext extends ClientListenerAbstractConnectionConte static { SUPPORTED_VERS.add(CURRENT_VER); + SUPPORTED_VERS.add(VER_2_7_0); SUPPORTED_VERS.add(VER_2_5_0); SUPPORTED_VERS.add(VER_2_3_0); SUPPORTED_VERS.add(VER_2_3_2); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcMessageParser.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcMessageParser.java index 33f1c4b..2d0d2d4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcMessageParser.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcMessageParser.java @@ -419,13 +419,13 @@ public class OdbcMessageParser implements ClientListenerMessageParser { * @param writer Writer. * @param meta Metadata */ - private static void writeResultsetMeta(BinaryWriterExImpl writer, Collection<OdbcColumnMeta> meta) { + private void writeResultsetMeta(BinaryWriterExImpl writer, Collection<OdbcColumnMeta> meta) { assert meta != null; writer.writeInt(meta.size()); for (OdbcColumnMeta columnMeta : meta) - columnMeta.write(writer); + columnMeta.write(writer, ver); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java index a21caeb..8cc24a1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java @@ -69,6 +69,8 @@ import org.apache.ignite.transactions.TransactionMixedModeException; import org.apache.ignite.transactions.TransactionSerializationException; import org.apache.ignite.transactions.TransactionUnsupportedConcurrencyException; +import static java.sql.ResultSetMetaData.columnNoNulls; +import static java.sql.ResultSetMetaData.columnNullable; import static org.apache.ignite.internal.processors.odbc.odbc.OdbcRequest.META_COLS; import static org.apache.ignite.internal.processors.odbc.odbc.OdbcRequest.META_PARAMS; import static org.apache.ignite.internal.processors.odbc.odbc.OdbcRequest.META_RESULTSET; @@ -696,7 +698,8 @@ public class OdbcRequestHandler implements ClientListenerRequestHandler { GridQueryProperty prop = table.property(field.getKey()); OdbcColumnMeta columnMeta = new OdbcColumnMeta(table.schemaName(), table.tableName(), - field.getKey(), field.getValue(), prop.precision(), prop.scale(), ver); + field.getKey(), field.getValue(), prop.precision(), prop.scale(), + prop.notNull() ? columnNoNulls : columnNullable); if (!meta.contains(columnMeta)) meta.add(columnMeta); @@ -802,7 +805,7 @@ public class OdbcRequestHandler implements ClientListenerRequestHandler { SqlFieldsQueryEx qry = makeQuery(schema, sql); List<GridQueryFieldMetadata> columns = ctx.query().getIndexing().resultMetaData(schema, qry); - Collection<OdbcColumnMeta> meta = OdbcUtils.convertMetadata(columns, ver); + Collection<OdbcColumnMeta> meta = OdbcUtils.convertMetadata(columns); OdbcQueryGetResultsetMetaResult res = new OdbcQueryGetResultsetMetaResult(meta); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcResultSet.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcResultSet.java index 1eba63d..879acde 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcResultSet.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcResultSet.java @@ -54,7 +54,7 @@ public class OdbcResultSet { if (this.cursor.isQuery()) { iter = this.cursor.iterator(); - meta = OdbcUtils.convertMetadata(this.cursor.fieldsMeta(), ver); + meta = OdbcUtils.convertMetadata(this.cursor.fieldsMeta()); } else { iter = null; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcUtils.java index 80fab2e..926524a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcUtils.java @@ -25,7 +25,6 @@ import org.apache.ignite.IgniteException; import org.apache.ignite.cache.query.QueryCursor; import org.apache.ignite.internal.processors.cache.QueryCursorImpl; import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; -import org.apache.ignite.internal.processors.odbc.ClientListenerProtocolVersion; import org.apache.ignite.internal.processors.odbc.SqlListenerDataTypes; import org.apache.ignite.internal.processors.odbc.SqlListenerUtils; import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata; @@ -252,16 +251,14 @@ public class OdbcUtils { * {@link OdbcColumnMeta}. * * @param meta Internal query field metadata. - * @param ver Client version. * @return Odbc query field metadata. */ - public static Collection<OdbcColumnMeta> convertMetadata(Collection<GridQueryFieldMetadata> meta, - ClientListenerProtocolVersion ver) { + public static Collection<OdbcColumnMeta> convertMetadata(Collection<GridQueryFieldMetadata> meta) { List<OdbcColumnMeta> res = new ArrayList<>(); if (meta != null) { for (GridQueryFieldMetadata info : meta) - res.add(new OdbcColumnMeta(info, ver)); + res.add(new OdbcColumnMeta(info)); } return res; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryFieldMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryFieldMetadata.java index f9df499..3c28e38 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryFieldMetadata.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryFieldMetadata.java @@ -65,4 +65,13 @@ public interface GridQueryFieldMetadata extends Externalizable { * @return Field scale. */ public int scale(); + + /** + * Gets field nullability. + * + * See {@link java.sql.ResultSetMetaData#isNullable(int)} for more info. + * + * @return Field nullability. + */ + public int nullability(); } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2SqlFieldMetadata.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2SqlFieldMetadata.java index a42771e..08cf1b3 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2SqlFieldMetadata.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2SqlFieldMetadata.java @@ -51,6 +51,9 @@ public class H2SqlFieldMetadata implements GridQueryFieldMetadata { /** Scale. */ private int scale; + /** Nullability. See {@link java.sql.ResultSetMetaData#isNullable(int)} */ + private int nullability; + /** * Required by {@link Externalizable}. */ @@ -67,7 +70,7 @@ public class H2SqlFieldMetadata implements GridQueryFieldMetadata { * @param scale Scale. */ H2SqlFieldMetadata(@Nullable String schemaName, @Nullable String typeName, String name, String type, - int precision, int scale) { + int precision, int scale, int nullability) { assert name != null && type != null : schemaName + " | " + typeName + " | " + name + " | " + type; this.schemaName = schemaName; @@ -76,6 +79,7 @@ public class H2SqlFieldMetadata implements GridQueryFieldMetadata { this.type = type; this.precision = precision; this.scale = scale; + this.nullability = nullability; } /** {@inheritDoc} */ @@ -109,6 +113,11 @@ public class H2SqlFieldMetadata implements GridQueryFieldMetadata { } /** {@inheritDoc} */ + @Override public int nullability() { + return nullability; + } + + /** {@inheritDoc} */ @Override public void writeExternal(ObjectOutput out) throws IOException { U.writeString(out, schemaName); U.writeString(out, typeName); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java index f766de9..e55e6ef 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java @@ -105,6 +105,7 @@ import org.h2.value.ValueUuid; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static java.sql.ResultSetMetaData.columnNullableUnknown; import static org.apache.ignite.internal.processors.query.QueryUtils.KEY_COL; import static org.apache.ignite.internal.processors.query.QueryUtils.KEY_FIELD_NAME; import static org.apache.ignite.internal.processors.query.QueryUtils.VAL_FIELD_NAME; @@ -136,7 +137,8 @@ public class H2Utils { /** Dummy metadata for update result. */ public static final List<GridQueryFieldMetadata> UPDATE_RESULT_META = - Collections.singletonList(new H2SqlFieldMetadata(null, null, "UPDATED", Long.class.getName(), -1, -1)); + Collections.singletonList(new H2SqlFieldMetadata(null, null, "UPDATED", Long.class.getName(), -1, -1, + columnNullableUnknown)); /** Spatial index class name. */ private static final String SPATIAL_IDX_CLS = @@ -375,11 +377,12 @@ public class H2Utils { String type = rsMeta.getColumnClassName(i); int precision = rsMeta.getPrecision(i); int scale = rsMeta.getScale(i); + int nullability = rsMeta.isNullable(i); if (type == null) // Expression always returns NULL. type = Void.class.getName(); - meta.add(new H2SqlFieldMetadata(schemaName, typeName, name, type, precision, scale)); + meta.add(new H2SqlFieldMetadata(schemaName, typeName, name, type, precision, scale, nullability)); } return meta; diff --git a/modules/platforms/cpp/odbc-test/src/attributes_test.cpp b/modules/platforms/cpp/odbc-test/src/attributes_test.cpp index 278a066..8d6f6e3 100644 --- a/modules/platforms/cpp/odbc-test/src/attributes_test.cpp +++ b/modules/platforms/cpp/odbc-test/src/attributes_test.cpp @@ -116,6 +116,30 @@ BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_2_3_2) InsertTestBatch(11, 20, 9); } +BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_2_5_0) +{ + Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache;PROTOCOL_VERSION=2.5.0"); + + InsertTestStrings(10, false); + InsertTestBatch(11, 20, 9); +} + +BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_2_7_0) +{ + Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache;PROTOCOL_VERSION=2.7.0"); + + InsertTestStrings(10, false); + InsertTestBatch(11, 20, 9); +} + +BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_2_8_0) +{ + Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache;PROTOCOL_VERSION=2.8.0"); + + InsertTestStrings(10, false); + InsertTestBatch(11, 20, 9); +} + BOOST_AUTO_TEST_CASE(TestConnectionRangeBegin) { Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110..11115;SCHEMA=cache"); diff --git a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp index 05a0e46..696c878 100644 --- a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp +++ b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp @@ -189,7 +189,7 @@ struct MetaQueriesTestSuiteFixture : public odbc::OdbcTestSuite " dec3 decimal," " char1 char(3)," " char2 char(42)," - " char3 char," + " char3 char not null," " vchar varchar" ")"); @@ -218,14 +218,14 @@ struct MetaQueriesTestSuiteFixture : public odbc::OdbcTestSuite BOOST_CHECK_EQUAL(columnCount, 8); - CheckColumnMetaWithSQLDescribeCol(stmt, 1, "ID", SQL_INTEGER, 10, 0, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLDescribeCol(stmt, 2, "DEC1", SQL_DECIMAL, 3, 0, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLDescribeCol(stmt, 3, "DEC2", SQL_DECIMAL, 42, 12, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLDescribeCol(stmt, 4, "DEC3", SQL_DECIMAL, 65535, 32767, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLDescribeCol(stmt, 5, "CHAR1", SQL_VARCHAR, 3, 0, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLDescribeCol(stmt, 6, "CHAR2", SQL_VARCHAR, 42, 0, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLDescribeCol(stmt, 7, "CHAR3", SQL_VARCHAR, 2147483647, 0, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLDescribeCol(stmt, 8, "VCHAR", SQL_VARCHAR, 2147483647, 0, SQL_NULLABLE_UNKNOWN); + CheckColumnMetaWithSQLDescribeCol(stmt, 1, "ID", SQL_INTEGER, 10, 0, SQL_NULLABLE); + CheckColumnMetaWithSQLDescribeCol(stmt, 2, "DEC1", SQL_DECIMAL, 3, 0, SQL_NULLABLE); + CheckColumnMetaWithSQLDescribeCol(stmt, 3, "DEC2", SQL_DECIMAL, 42, 12, SQL_NULLABLE); + CheckColumnMetaWithSQLDescribeCol(stmt, 4, "DEC3", SQL_DECIMAL, 65535, 32767, SQL_NULLABLE); + CheckColumnMetaWithSQLDescribeCol(stmt, 5, "CHAR1", SQL_VARCHAR, 3, 0, SQL_NULLABLE); + CheckColumnMetaWithSQLDescribeCol(stmt, 6, "CHAR2", SQL_VARCHAR, 42, 0, SQL_NULLABLE); + CheckColumnMetaWithSQLDescribeCol(stmt, 7, "CHAR3", SQL_VARCHAR, 2147483647, 0, SQL_NO_NULLS); + CheckColumnMetaWithSQLDescribeCol(stmt, 8, "VCHAR", SQL_VARCHAR, 2147483647, 0, SQL_NULLABLE); } /** @@ -298,7 +298,7 @@ struct MetaQueriesTestSuiteFixture : public odbc::OdbcTestSuite " dec3 decimal," " char1 char(3)," " char2 char(42)," - " char3 char," + " char3 char not null," " vchar varchar" ")"); @@ -327,14 +327,14 @@ struct MetaQueriesTestSuiteFixture : public odbc::OdbcTestSuite BOOST_CHECK_EQUAL(columnCount, 8); - CheckColumnMetaWithSQLColAttribute(stmt, 1, "ID", SQL_INTEGER, 10, 0, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLColAttribute(stmt, 2, "DEC1", SQL_DECIMAL, 3, 0, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLColAttribute(stmt, 3, "DEC2", SQL_DECIMAL, 42, 12, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLColAttribute(stmt, 4, "DEC3", SQL_DECIMAL, 65535, 32767, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLColAttribute(stmt, 5, "CHAR1", SQL_VARCHAR, 3, 0, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLColAttribute(stmt, 6, "CHAR2", SQL_VARCHAR, 42, 0, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLColAttribute(stmt, 7, "CHAR3", SQL_VARCHAR, 2147483647, 0, SQL_NULLABLE_UNKNOWN); - CheckColumnMetaWithSQLColAttribute(stmt, 8, "VCHAR", SQL_VARCHAR, 2147483647, 0, SQL_NULLABLE_UNKNOWN); + CheckColumnMetaWithSQLColAttribute(stmt, 1, "ID", SQL_INTEGER, 10, 0, SQL_NULLABLE); + CheckColumnMetaWithSQLColAttribute(stmt, 2, "DEC1", SQL_DECIMAL, 3, 0, SQL_NULLABLE); + CheckColumnMetaWithSQLColAttribute(stmt, 3, "DEC2", SQL_DECIMAL, 42, 12, SQL_NULLABLE); + CheckColumnMetaWithSQLColAttribute(stmt, 4, "DEC3", SQL_DECIMAL, 65535, 32767, SQL_NULLABLE); + CheckColumnMetaWithSQLColAttribute(stmt, 5, "CHAR1", SQL_VARCHAR, 3, 0, SQL_NULLABLE); + CheckColumnMetaWithSQLColAttribute(stmt, 6, "CHAR2", SQL_VARCHAR, 42, 0, SQL_NULLABLE); + CheckColumnMetaWithSQLColAttribute(stmt, 7, "CHAR3", SQL_VARCHAR, 2147483647, 0, SQL_NO_NULLS); + CheckColumnMetaWithSQLColAttribute(stmt, 8, "VCHAR", SQL_VARCHAR, 2147483647, 0, SQL_NULLABLE); } /** @@ -883,7 +883,7 @@ BOOST_AUTO_TEST_CASE(TestSQLNumResultColsAfterSQLPrepare) * 2. Connect to node using ODBC. * 3. Create table with decimal and char columns with specified size and scale. * 4. Prepare statement. - * 5. Check presicion and scale of every column using SQLDescribeCol. + * 5. Check precision and scale of every column using SQLDescribeCol. */ BOOST_AUTO_TEST_CASE(TestSQLDescribeColPrecisionAndScaleAfterPrepare) { @@ -897,7 +897,7 @@ BOOST_AUTO_TEST_CASE(TestSQLDescribeColPrecisionAndScaleAfterPrepare) * 2. Connect to node using ODBC. * 3. Create table with decimal and char columns with specified size and scale. * 4. Execute statement. - * 5. Check presicion and scale of every column using SQLDescribeCol. */ + * 5. Check precision and scale of every column using SQLDescribeCol. */ BOOST_AUTO_TEST_CASE(TestSQLDescribeColPrecisionAndScaleAfterExec) { CheckSQLDescribeColPrecisionAndScale(&OdbcTestSuite::ExecQuery); @@ -910,7 +910,7 @@ BOOST_AUTO_TEST_CASE(TestSQLDescribeColPrecisionAndScaleAfterExec) * 2. Connect to node using ODBC. * 3. Create table with decimal and char columns with specified size and scale. * 4. Prepare statement. - * 5. Check presicion and scale of every column using SQLColAttribute. + * 5. Check precision and scale of every column using SQLColAttribute. */ BOOST_AUTO_TEST_CASE(TestSQLColAttributePrecisionAndScaleAfterPrepare) { @@ -924,7 +924,7 @@ BOOST_AUTO_TEST_CASE(TestSQLColAttributePrecisionAndScaleAfterPrepare) * 2. Connect to node using ODBC. * 3. Create table with decimal and char columns with specified size and scale. * 4. Execute statement. - * 5. Check presicion and scale of every column using SQLColAttribute. */ + * 5. Check precision and scale of every column using SQLColAttribute. */ BOOST_AUTO_TEST_CASE(TestSQLColAttributePrecisionAndScaleAfterExec) { CheckSQLColAttributePrecisionAndScale(&OdbcTestSuite::ExecQuery); diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/meta/column_meta.h b/modules/platforms/cpp/odbc/include/ignite/odbc/meta/column_meta.h index c4aeae0..5144fa3 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/meta/column_meta.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/meta/column_meta.h @@ -33,6 +33,29 @@ namespace ignite { namespace meta { + /** + * Nullability type. + */ + struct Nullability + { + enum Type + { + NO_NULL = 0, + + NULLABLE = 1, + + NULLABILITY_UNKNOWN = 2 + }; + + /** + * Convert to SQL constant. + * + * @param nullability Nullability. + * @return SQL constant. + */ + static SqlLen ToSql(int32_t nullability); + }; + using namespace ignite::odbc; /** @@ -69,7 +92,7 @@ namespace ignite ColumnMeta(const std::string& schemaName, const std::string& tableName, const std::string& columnName, int8_t dataType) : schemaName(schemaName), tableName(tableName), columnName(columnName), dataType(dataType), - precision(-1), scale(-1) + precision(-1), scale(-1), nullability(Nullability::NULLABILITY_UNKNOWN) { // No-op. } @@ -91,7 +114,8 @@ namespace ignite columnName(other.columnName), dataType(other.dataType), precision(other.precision), - scale(other.scale) + scale(other.scale), + nullability(other.nullability) { // No-op. } @@ -107,6 +131,7 @@ namespace ignite dataType = other.dataType; precision = other.precision; scale = other.scale; + nullability = other.nullability; return *this; } @@ -173,6 +198,15 @@ namespace ignite } /** + * Get column nullability. + * @return Column nullability. + */ + int32_t GetNullability() const + { + return nullability; + } + + /** * Try to get attribute of a string type. * * @param fieldId Field ID. @@ -208,6 +242,9 @@ namespace ignite /** Column scale. */ int32_t scale; + + /** Column nullability. */ + int32_t nullability; }; /** Column metadata vector alias. */ diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/protocol_version.h b/modules/platforms/cpp/odbc/include/ignite/odbc/protocol_version.h index 1a722e3..f4c0e92 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/protocol_version.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/protocol_version.h @@ -49,6 +49,9 @@ namespace ignite /** Version 2.7.0: added fields precision and scale. */ static const ProtocolVersion VERSION_2_7_0; + /** Version 2.8.0: added column nullability info. */ + static const ProtocolVersion VERSION_2_8_0; + typedef std::set<ProtocolVersion> VersionSet; /** diff --git a/modules/platforms/cpp/odbc/src/meta/column_meta.cpp b/modules/platforms/cpp/odbc/src/meta/column_meta.cpp index 203b4ad..0270888 100644 --- a/modules/platforms/cpp/odbc/src/meta/column_meta.cpp +++ b/modules/platforms/cpp/odbc/src/meta/column_meta.cpp @@ -74,6 +74,27 @@ namespace ignite #undef DBG_STR_CASE + SqlLen Nullability::ToSql(int32_t nullability) + { + switch (nullability) + { + case Nullability::NO_NULL: + return SQL_NO_NULLS; + + case Nullability::NULLABLE: + return SQL_NULLABLE; + + case Nullability::NULLABILITY_UNKNOWN: + return SQL_NULLABLE_UNKNOWN; + + default: + break; + } + + assert(false); + return SQL_NULLABLE_UNKNOWN; + } + void ColumnMeta::Read(ignite::impl::binary::BinaryReaderImpl& reader, const ProtocolVersion& ver) { utility::ReadString(reader, schemaName); @@ -87,6 +108,9 @@ namespace ignite precision = reader.ReadInt32(); scale = reader.ReadInt32(); } + + if (ver >= ProtocolVersion::VERSION_2_8_0) + nullability = reader.ReadInt8(); } bool ColumnMeta::GetAttribute(uint16_t fieldId, std::string& value) const @@ -235,7 +259,7 @@ namespace ignite case SQL_DESC_NULLABLE: { - value = type_traits::BinaryTypeNullability(dataType); + value = Nullability::ToSql(nullability); break; } @@ -312,7 +336,7 @@ namespace ignite } void ReadColumnMetaVector(ignite::impl::binary::BinaryReaderImpl& reader, ColumnMetaVector& meta, - const ProtocolVersion& ver) + const ProtocolVersion& ver) { int32_t metaNum = reader.ReadInt32(); diff --git a/modules/platforms/cpp/odbc/src/protocol_version.cpp b/modules/platforms/cpp/odbc/src/protocol_version.cpp index 01937e2..a073ab2 100644 --- a/modules/platforms/cpp/odbc/src/protocol_version.cpp +++ b/modules/platforms/cpp/odbc/src/protocol_version.cpp @@ -32,6 +32,7 @@ namespace ignite const ProtocolVersion ProtocolVersion::VERSION_2_3_2(2, 3, 2); const ProtocolVersion ProtocolVersion::VERSION_2_5_0(2, 5, 0); const ProtocolVersion ProtocolVersion::VERSION_2_7_0(2, 7, 0); + const ProtocolVersion ProtocolVersion::VERSION_2_8_0(2, 8, 0); ProtocolVersion::VersionSet::value_type supportedArray[] = { ProtocolVersion::VERSION_2_1_0, @@ -39,7 +40,8 @@ namespace ignite ProtocolVersion::VERSION_2_3_0, ProtocolVersion::VERSION_2_3_2, ProtocolVersion::VERSION_2_5_0, - ProtocolVersion::VERSION_2_7_0 + ProtocolVersion::VERSION_2_7_0, + ProtocolVersion::VERSION_2_8_0 }; const ProtocolVersion::VersionSet ProtocolVersion::supported(supportedArray, @@ -68,7 +70,7 @@ namespace ignite const ProtocolVersion& ProtocolVersion::GetCurrent() { - return VERSION_2_7_0; + return VERSION_2_8_0; } void ThrowParseError()