Revert Revert Merge remote-tracking branch 'professional/ignite-1.6.11'
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/9726421f Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/9726421f Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/9726421f Branch: refs/heads/ignite-4242 Commit: 9726421ff9efb2b19813b2fd6ad27a3728b5ab1a Parents: 865bbcf Author: Dmitriy Govorukhin <[email protected]> Authored: Tue Nov 8 15:59:00 2016 +0300 Committer: Dmitriy Govorukhin <[email protected]> Committed: Tue Nov 8 15:59:00 2016 +0300 ---------------------------------------------------------------------- .../internal/processors/job/GridJobWorker.java | 10 +- .../service/GridServiceProcessor.java | 61 +++++++- .../internal/util/SerializableTransient.java | 58 +++++++ .../ignite/marshaller/MarshallerUtils.java | 22 +++ .../optimized/OptimizedClassDescriptor.java | 90 ++++++++++- modules/platforms/cpp/binary/Makefile.am | 4 +- modules/platforms/cpp/core/Makefile.am | 4 +- .../cpp/examples/odbc-example/Makefile.am | 4 +- .../cpp/examples/putget-example/Makefile.am | 4 +- .../cpp/examples/query-example/Makefile.am | 4 +- modules/platforms/cpp/ignite/Makefile.am | 4 +- modules/platforms/cpp/jni/Makefile.am | 4 +- .../cpp/odbc-test/src/api_robustness_test.cpp | 63 ++++++++ .../cpp/odbc-test/src/queries_test.cpp | 9 +- modules/platforms/cpp/odbc/Makefile.am | 4 +- .../cpp/odbc/include/ignite/odbc/statement.h | 42 ++++++ modules/platforms/cpp/odbc/src/odbc.cpp | 116 +------------- modules/platforms/cpp/odbc/src/statement.cpp | 151 +++++++++++++++++++ 18 files changed, 526 insertions(+), 128 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/core/src/main/java/org/apache/ignite/internal/processors/job/GridJobWorker.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/job/GridJobWorker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/job/GridJobWorker.java index 8169eb1..5f38b29 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/job/GridJobWorker.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/job/GridJobWorker.java @@ -57,6 +57,7 @@ import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.lang.IgniteRunnable; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.marshaller.MarshallerUtils; import org.jetbrains.annotations.Nullable; import static org.apache.ignite.events.EventType.EVT_JOB_CANCELLED; @@ -421,7 +422,14 @@ public class GridJobWorker extends GridWorker implements GridTimeoutObject { try { if (job == null) { - job = U.unmarshal(marsh, jobBytes, U.resolveClassLoader(dep.classLoader(), ctx.config())); + MarshallerUtils.jobSenderVersion(taskNode.version()); + + try { + job = U.unmarshal(marsh, jobBytes, U.resolveClassLoader(dep.classLoader(), ctx.config())); + } + finally { + MarshallerUtils.jobSenderVersion(null); + } // No need to hold reference any more. jobBytes = null; http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java index 527d360..6c26363 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProcessor.java @@ -20,11 +20,14 @@ package org.apache.ignite.internal.processors.service; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; @@ -87,6 +90,7 @@ import org.apache.ignite.lang.IgniteFuture; import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.internal.util.SerializableTransient; import org.apache.ignite.resources.IgniteInstanceResource; import org.apache.ignite.resources.JobContextResource; import org.apache.ignite.resources.LoggerResource; @@ -115,6 +119,9 @@ public class GridServiceProcessor extends GridProcessorAdapter { /** */ public static final IgniteProductVersion LAZY_SERVICES_CFG_SINCE = IgniteProductVersion.fromString("1.5.22"); + /** Versions that only compatible with each other, and from 1.5.33. */ + private static final Set<IgniteProductVersion> SERVICE_TOP_CALLABLE_VER1; + /** */ private final Boolean srvcCompatibilitySysProp; @@ -162,6 +169,31 @@ public class GridServiceProcessor extends GridProcessorAdapter { /** Topology listener. */ private GridLocalEventListener topLsnr = new TopologyListener(); + static { + Set<IgniteProductVersion> versions = new TreeSet<>(new Comparator<IgniteProductVersion>() { + @Override public int compare(final IgniteProductVersion o1, final IgniteProductVersion o2) { + return o1.compareToIgnoreTimestamp(o2); + } + }); + + versions.add(IgniteProductVersion.fromString("1.5.30")); + versions.add(IgniteProductVersion.fromString("1.5.31")); + versions.add(IgniteProductVersion.fromString("1.5.32")); + versions.add(IgniteProductVersion.fromString("1.6.3")); + versions.add(IgniteProductVersion.fromString("1.6.4")); + versions.add(IgniteProductVersion.fromString("1.6.5")); + versions.add(IgniteProductVersion.fromString("1.6.6")); + versions.add(IgniteProductVersion.fromString("1.6.7")); + versions.add(IgniteProductVersion.fromString("1.6.8")); + versions.add(IgniteProductVersion.fromString("1.6.9")); + versions.add(IgniteProductVersion.fromString("1.6.10")); + versions.add(IgniteProductVersion.fromString("1.7.0")); + versions.add(IgniteProductVersion.fromString("1.7.1")); + versions.add(IgniteProductVersion.fromString("1.7.2")); + + SERVICE_TOP_CALLABLE_VER1 = Collections.unmodifiableSet(versions); + } + /** * @param ctx Kernal context. */ @@ -668,9 +700,13 @@ public class GridServiceProcessor extends GridProcessorAdapter { ClusterNode node = cache.affinity().mapKeyToNode(name); if (node.version().compareTo(ServiceTopologyCallable.SINCE_VER) >= 0) { + final ServiceTopologyCallable call = new ServiceTopologyCallable(name); + + call.serialize = SERVICE_TOP_CALLABLE_VER1.contains(node.version()); + return ctx.closure().callAsyncNoFailover( GridClosureCallMode.BROADCAST, - new ServiceTopologyCallable(name), + call, Collections.singletonList(node), false ).get(); @@ -1829,6 +1865,7 @@ public class GridServiceProcessor extends GridProcessorAdapter { /** */ @GridInternal + @SerializableTransient(methodName = "serializableTransient") private static class ServiceTopologyCallable implements IgniteCallable<Map<UUID, Integer>> { /** */ private static final long serialVersionUID = 0L; @@ -1837,10 +1874,13 @@ public class GridServiceProcessor extends GridProcessorAdapter { private static final IgniteProductVersion SINCE_VER = IgniteProductVersion.fromString("1.5.7"); /** */ + private static final String[] SER_FIELDS = {"waitedCacheInit", "jCtx", "log"}; + + /** */ private final String svcName; /** */ - private boolean waitedCacheInit; + private transient boolean waitedCacheInit; /** */ @IgniteInstanceResource @@ -1848,11 +1888,14 @@ public class GridServiceProcessor extends GridProcessorAdapter { /** */ @JobContextResource - private ComputeJobContext jCtx; + private transient ComputeJobContext jCtx; /** */ @LoggerResource - private IgniteLogger log; + private transient IgniteLogger log; + + /** */ + transient boolean serialize; /** * @param svcName Service name. @@ -1898,6 +1941,16 @@ public class GridServiceProcessor extends GridProcessorAdapter { return serviceTopology(cache, svcName); } + + /** + * @param self Instance of current class before serialization. + * @param ver Sender job version. + * @return List of serializable transient fields. + */ + @SuppressWarnings("unused") + private static String[] serializableTransient(ServiceTopologyCallable self, IgniteProductVersion ver) { + return (self != null && self.serialize) || (ver != null && SERVICE_TOP_CALLABLE_VER1.contains(ver)) ? SER_FIELDS : null; + } } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/core/src/main/java/org/apache/ignite/internal/util/SerializableTransient.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/SerializableTransient.java b/modules/core/src/main/java/org/apache/ignite/internal/util/SerializableTransient.java new file mode 100644 index 0000000..14a2f27 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/SerializableTransient.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.util; + +import org.apache.ignite.lang.IgniteProductVersion; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks class as it has transient fields that should be serialized. + * Annotated class must have method that returns list of transient + * fields that should be serialized. + * <p> + * Works only for jobs. For other messages node version is not available. + * </p> + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SerializableTransient { + /** + * Name of the private static method that returns list of transient fields + * that should be serialized (String[]), and accepts itself (before serialization) + * and {@link IgniteProductVersion}, e.g. + * <pre> + * private static String[] fields(Object self, IgniteProductVersion ver){ + * return ver.compareTo("1.5.30") > 0 ? SERIALIZABLE_FIELDS : null; + * } + * </pre> + * <p> + * On serialization version argument <tt>ver</tt> is null, on deserialization - <tt>self</tt> is null. + * </p> + * <p> + * If it returns empty array or null all transient fields will be normally + * ignored. + * </p> + * + * @return Name of the method. + */ + String methodName(); +} http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/core/src/main/java/org/apache/ignite/marshaller/MarshallerUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/MarshallerUtils.java b/modules/core/src/main/java/org/apache/ignite/marshaller/MarshallerUtils.java index 9668baf..ad63702 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/MarshallerUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/MarshallerUtils.java @@ -17,6 +17,7 @@ package org.apache.ignite.marshaller; +import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.marshaller.jdk.JdkMarshaller; import org.jetbrains.annotations.Nullable; @@ -24,6 +25,9 @@ import org.jetbrains.annotations.Nullable; * Utility marshaller methods. */ public class MarshallerUtils { + /** Job sender node version. */ + private static final ThreadLocal<IgniteProductVersion> JOB_SND_NODE_VER = new ThreadLocal<>(); + /** * Set node name to marshaller context if possible. * @@ -55,4 +59,22 @@ public class MarshallerUtils { private MarshallerUtils() { // No-op. } + + /** + * Sets thread local job sender node version. + * + * @param ver Thread local job sender node version. + */ + public static void jobSenderVersion(IgniteProductVersion ver) { + JOB_SND_NODE_VER.set(ver); + } + + /** + * Returns thread local job sender node version. + * + * @return Thread local job sender node version. + */ + public static IgniteProductVersion jobSenderVersion() { + return JOB_SND_NODE_VER.get(); + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java index 5a5b54d..160f2c1 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java @@ -47,8 +47,11 @@ import java.util.UUID; import java.util.concurrent.ConcurrentMap; import org.apache.ignite.internal.util.GridUnsafe; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.marshaller.MarshallerContext; import org.apache.ignite.marshaller.MarshallerExclusions; +import org.apache.ignite.internal.util.SerializableTransient; +import org.apache.ignite.marshaller.MarshallerUtils; import static java.lang.reflect.Modifier.isFinal; import static java.lang.reflect.Modifier.isPrivate; @@ -166,6 +169,9 @@ class OptimizedClassDescriptor { /** Proxy interfaces. */ private Class<?>[] proxyIntfs; + /** Method returns serializable transient fields. */ + private Method serTransMtd; + /** * Creates descriptor for class. * @@ -441,6 +447,27 @@ class OptimizedClassDescriptor { readObjMtds.add(mtd); + final SerializableTransient serTransAn = c.getAnnotation(SerializableTransient.class); + + // Custom serialization policy for transient fields. + if (serTransAn != null) { + try { + serTransMtd = c.getDeclaredMethod(serTransAn.methodName(), cls, IgniteProductVersion.class); + + int mod = serTransMtd.getModifiers(); + + if (isStatic(mod) && isPrivate(mod) + && serTransMtd.getReturnType() == String[].class) + serTransMtd.setAccessible(true); + else + // Set method back to null if it has incorrect signature. + serTransMtd = null; + } + catch (NoSuchMethodException ignored) { + serTransMtd = null; + } + } + Field[] clsFields0 = c.getDeclaredFields(); Map<String, Field> fieldNames = new HashMap<>(); @@ -797,7 +824,7 @@ class OptimizedClassDescriptor { writeTypeData(out); out.writeShort(checksum); - out.writeSerializable(obj, writeObjMtds, fields); + out.writeSerializable(obj, writeObjMtds, serializableFields(obj.getClass(), obj, null)); break; @@ -807,6 +834,60 @@ class OptimizedClassDescriptor { } /** + * Gets list of serializable fields. If {@link #serTransMtd} method + * returns list of transient fields, they will be added to other fields. + * Transient fields that are not included in that list will be normally + * ignored. + * + * @param cls Class. + * @param obj Object. + * @param ver Job sender version. + * @return Serializable fields. + */ + @SuppressWarnings("ForLoopReplaceableByForEach") + private Fields serializableFields(Class<?> cls, Object obj, IgniteProductVersion ver) { + if (serTransMtd == null) + return fields; + + try { + final String[] transFields = (String[])serTransMtd.invoke(cls, obj, ver); + + if (transFields == null || transFields.length == 0) + return fields; + + List<FieldInfo> clsFields = new ArrayList<>(); + + clsFields.addAll(fields.fields.get(0).fields); + + for (int i = 0; i < transFields.length; i++) { + final String fieldName = transFields[i]; + + final Field f = cls.getDeclaredField(fieldName); + + FieldInfo fieldInfo = new FieldInfo(f, f.getName(), + GridUnsafe.objectFieldOffset(f), fieldType(f.getType())); + + clsFields.add(fieldInfo); + } + + Collections.sort(clsFields, new Comparator<FieldInfo>() { + @Override public int compare(FieldInfo t1, FieldInfo t2) { + return t1.name().compareTo(t2.name()); + } + }); + + List<ClassFields> fields = new ArrayList<>(); + + fields.add(new ClassFields(clsFields)); + + return new Fields(fields); + } + catch (Exception e) { + return fields; + } + } + + /** * @param out Output stream. * @throws IOException In case of error. */ @@ -838,7 +919,12 @@ class OptimizedClassDescriptor { case SERIALIZABLE: verifyChecksum(in.readShort()); - return in.readSerializable(cls, readObjMtds, readResolveMtd, fields); + // If no serialize method, then unmarshal as usual. + if (serTransMtd != null) + return in.readSerializable(cls, readObjMtds, readResolveMtd, + serializableFields(cls, null, MarshallerUtils.jobSenderVersion())); + else + return in.readSerializable(cls, readObjMtds, readResolveMtd, fields); default: assert false : "Unexpected type: " + type; http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/platforms/cpp/binary/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/binary/Makefile.am b/modules/platforms/cpp/binary/Makefile.am index 4876776..ca301a6 100644 --- a/modules/platforms/cpp/binary/Makefile.am +++ b/modules/platforms/cpp/binary/Makefile.am @@ -26,7 +26,9 @@ AM_CPPFLAGS = \ -I$(srcdir)/include \ -I@top_srcdir@/common/include \ -I@top_srcdir@/common/os/linux/include \ - -DIGNITE_IMPL + -DIGNITE_IMPL \ + -D__STDC_LIMIT_MACROS \ + -D__STDC_CONSTANT_MACROS AM_CXXFLAGS = \ -Wall \ http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/platforms/cpp/core/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/Makefile.am b/modules/platforms/cpp/core/Makefile.am index bbb7720..97523cf 100644 --- a/modules/platforms/cpp/core/Makefile.am +++ b/modules/platforms/cpp/core/Makefile.am @@ -31,7 +31,9 @@ AM_CPPFLAGS = \ -I@top_srcdir@/jni/os/linux/include \ -I$(JAVA_HOME)/include \ -I$(JAVA_HOME)/include/linux \ - -DIGNITE_IMPL + -DIGNITE_IMPL \ + -D__STDC_LIMIT_MACROS \ + -D__STDC_CONSTANT_MACROS AM_CXXFLAGS = \ -Wall \ http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/platforms/cpp/examples/odbc-example/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/examples/odbc-example/Makefile.am b/modules/platforms/cpp/examples/odbc-example/Makefile.am index e584105..83cc63e 100644 --- a/modules/platforms/cpp/examples/odbc-example/Makefile.am +++ b/modules/platforms/cpp/examples/odbc-example/Makefile.am @@ -30,7 +30,9 @@ AM_CPPFLAGS = \ -I@top_srcdir@/../jni/os/linux/include \ -I$(JAVA_HOME)/include \ -I$(JAVA_HOME)/include/linux \ - -DIGNITE_IMPL + -DIGNITE_IMPL \ + -D__STDC_LIMIT_MACROS \ + -D__STDC_CONSTANT_MACROS AM_CXXFLAGS = \ -Wall \ http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/platforms/cpp/examples/putget-example/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/examples/putget-example/Makefile.am b/modules/platforms/cpp/examples/putget-example/Makefile.am index 5301ea1..cf39002 100644 --- a/modules/platforms/cpp/examples/putget-example/Makefile.am +++ b/modules/platforms/cpp/examples/putget-example/Makefile.am @@ -30,7 +30,9 @@ AM_CPPFLAGS = \ -I@top_srcdir@/../jni/os/linux/include \ -I$(JAVA_HOME)/include \ -I$(JAVA_HOME)/include/linux \ - -DIGNITE_IMPL + -DIGNITE_IMPL \ + -D__STDC_LIMIT_MACROS \ + -D__STDC_CONSTANT_MACROS AM_CXXFLAGS = \ -Wall \ http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/platforms/cpp/examples/query-example/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/examples/query-example/Makefile.am b/modules/platforms/cpp/examples/query-example/Makefile.am index 1437303..01231ec 100644 --- a/modules/platforms/cpp/examples/query-example/Makefile.am +++ b/modules/platforms/cpp/examples/query-example/Makefile.am @@ -30,7 +30,9 @@ AM_CPPFLAGS = \ -I@top_srcdir@/../jni/os/linux/include \ -I$(JAVA_HOME)/include \ -I$(JAVA_HOME)/include/linux \ - -DIGNITE_IMPL + -DIGNITE_IMPL \ + -D__STDC_LIMIT_MACROS \ + -D__STDC_CONSTANT_MACROS AM_CXXFLAGS = \ -Wall \ http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/platforms/cpp/ignite/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/ignite/Makefile.am b/modules/platforms/cpp/ignite/Makefile.am index 625f1df..2dbc4d6 100644 --- a/modules/platforms/cpp/ignite/Makefile.am +++ b/modules/platforms/cpp/ignite/Makefile.am @@ -30,7 +30,9 @@ AM_CPPFLAGS = \ -I@top_srcdir@/jni/os/linux/include \ -I$(JAVA_HOME)/include \ -I$(JAVA_HOME)/include/linux \ - -DIGNITE_IMPL + -DIGNITE_IMPL \ + -D__STDC_LIMIT_MACROS \ + -D__STDC_CONSTANT_MACROS AM_CXXFLAGS = \ -Wall \ http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/platforms/cpp/jni/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/jni/Makefile.am b/modules/platforms/cpp/jni/Makefile.am index b9b3913..2cb4b90 100644 --- a/modules/platforms/cpp/jni/Makefile.am +++ b/modules/platforms/cpp/jni/Makefile.am @@ -29,7 +29,9 @@ AM_CPPFLAGS = \ -I@top_srcdir@/common/os/linux/include \ -I$(JAVA_HOME)/include \ -I$(JAVA_HOME)/include/linux \ - -DIGNITE_IMPL + -DIGNITE_IMPL \ + -D__STDC_LIMIT_MACROS \ + -D__STDC_CONSTANT_MACROS AM_CXXFLAGS = \ -Wall \ http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp b/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp index 008cf25..fbd5f12 100644 --- a/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp +++ b/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp @@ -161,6 +161,54 @@ struct ApiRobustnessTestSuiteFixture } /** + * Check that SQLFetchScroll does not crash with unsupported orientation. + * + * @param orientation Fetch orientation. + */ + void CheckFetchScrollUnsupportedOrientation(SQLUSMALLINT orientation) + { + Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;CACHE=cache"); + + SQLRETURN ret; + + const int64_t recordsNum = 100; + + for (int i = 0; i < recordsNum; ++i) + { + TestType val; + + val.i32Field = i * 10; + + testCache.Put(i, val); + } + + int32_t i32Field = -1; + + // Binding column. + ret = SQLBindCol(stmt, 1, SQL_C_SLONG, &i32Field, 0, 0); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + SQLCHAR request[] = "SELECT i32Field FROM TestType ORDER BY _key"; + + ret = SQLExecDirect(stmt, request, SQL_NTS); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLFetchScroll(stmt, SQL_FETCH_NEXT, 0); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + BOOST_CHECK_EQUAL(i32Field, 0); + + ret = SQLFetchScroll(stmt, orientation, 0); + + // Operation is not supported. However, there should be no crash. + BOOST_CHECK(ret == SQL_ERROR); + } + + /** * Destructor. */ ~ApiRobustnessTestSuiteFixture() @@ -1003,4 +1051,19 @@ BOOST_AUTO_TEST_CASE(TestSQLSpecialColumns) SQLCloseCursor(stmt); } +BOOST_AUTO_TEST_CASE(TestFetchScrollLast) +{ + CheckFetchScrollUnsupportedOrientation(SQL_FETCH_LAST); +} + +BOOST_AUTO_TEST_CASE(TestFetchScrollPrior) +{ + CheckFetchScrollUnsupportedOrientation(SQL_FETCH_PRIOR); +} + +BOOST_AUTO_TEST_CASE(TestFetchScrollFirst) +{ + CheckFetchScrollUnsupportedOrientation(SQL_FETCH_FIRST); +} + BOOST_AUTO_TEST_SUITE_END() http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/platforms/cpp/odbc-test/src/queries_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/queries_test.cpp b/modules/platforms/cpp/odbc-test/src/queries_test.cpp index eb6e153..82e9972 100644 --- a/modules/platforms/cpp/odbc-test/src/queries_test.cpp +++ b/modules/platforms/cpp/odbc-test/src/queries_test.cpp @@ -200,6 +200,8 @@ struct QueriesTestSuiteFixture "floatField, doubleField, boolField, guidField, dateField, timestampField FROM TestType"; ret = SQLExecDirect(stmt, reinterpret_cast<SQLCHAR*>(request), SQL_NTS); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); if (!SQL_SUCCEEDED(ret)) BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); @@ -364,6 +366,8 @@ BOOST_AUTO_TEST_CASE(TestTwoRowsString) "floatField, doubleField, boolField, guidField, dateField, timestampField FROM TestType"; ret = SQLExecDirect(stmt, request, SQL_NTS); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); if (!SQL_SUCCEEDED(ret)) BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); @@ -460,6 +464,8 @@ BOOST_AUTO_TEST_CASE(TestOneRowString) "floatField, doubleField, boolField, guidField, dateField, timestampField FROM TestType"; ret = SQLExecDirect(stmt, request, SQL_NTS); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); ret = SQLFetch(stmt); if (!SQL_SUCCEEDED(ret)) @@ -522,6 +528,8 @@ BOOST_AUTO_TEST_CASE(TestOneRowStringLen) "floatField, doubleField, boolField, guidField, dateField, timestampField FROM TestType"; ret = SQLExecDirect(stmt, request, SQL_NTS); + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); ret = SQLFetch(stmt); if (!SQL_SUCCEEDED(ret)) @@ -666,5 +674,4 @@ BOOST_AUTO_TEST_CASE(TestDataAtExecution) BOOST_CHECK(ret == SQL_NO_DATA); } - BOOST_AUTO_TEST_SUITE_END() http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/platforms/cpp/odbc/Makefile.am ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/Makefile.am b/modules/platforms/cpp/odbc/Makefile.am index 3c8b37a..b0cc5f8 100644 --- a/modules/platforms/cpp/odbc/Makefile.am +++ b/modules/platforms/cpp/odbc/Makefile.am @@ -27,7 +27,9 @@ AM_CPPFLAGS = \ -I@top_srcdir@/common/include \ -I@top_srcdir@/common/os/linux/include \ -I@top_srcdir@/binary/include \ - -DIGNITE_IMPL + -DIGNITE_IMPL \ + -D__STDC_LIMIT_MACROS \ + -D__STDC_CONSTANT_MACROS AM_CXXFLAGS = \ -Wall \ http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h b/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h index 35f1e98..db6205e 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/statement.h @@ -118,6 +118,25 @@ namespace ignite void UnbindAllParameters(); /** + * Set statement attribute. + * + * @param attr Attribute type. + * @param value Value pointer. + * @param valueLen Value length. + */ + void SetAttribute(int attr, void* value, SQLINTEGER valueLen); + + /** + * Get statement attribute. + * + * @param attr Attribute type. + * @param buf Buffer for value. + * @param bufLen Buffer length. + * @param valueLen Resulting value length. + */ + void GetAttribute(int attr, void* buf, SQLINTEGER bufLen, SQLINTEGER *valueLen); + + /** * Get number of binded parameters. * * @return Number of binded parameters. @@ -356,6 +375,29 @@ namespace ignite SqlResult InternalBindParameter(uint16_t paramIdx, const app::Parameter& param); /** + * Set statement attribute. + * Internal call. + * + * @param attr Attribute type. + * @param value Value pointer. + * @param valueLen Value length. + * @return Operation result. + */ + SqlResult InternalSetAttribute(int attr, void* value, SQLINTEGER valueLen); + + /** + * Get statement attribute. + * Internal call. + * + * @param attr Attribute type. + * @param buf Buffer for value. + * @param bufLen Buffer length. + * @param valueLen Resulting value length. + * @return Operation result. + */ + SqlResult InternalGetAttribute(int attr, void* buf, SQLINTEGER bufLen, SQLINTEGER* valueLen); + + /** * Get value of the column in the result set. * * @param columnIdx Column index. http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/platforms/cpp/odbc/src/odbc.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/odbc.cpp b/modules/platforms/cpp/odbc/src/odbc.cpp index 7416ad2..612d51a 100644 --- a/modules/platforms/cpp/odbc/src/odbc.cpp +++ b/modules/platforms/cpp/odbc/src/odbc.cpp @@ -854,73 +854,9 @@ namespace ignite if (!statement) return SQL_INVALID_HANDLE; - if (!valueBuf) - return SQL_ERROR; - - switch (attr) - { - case SQL_ATTR_APP_ROW_DESC: - case SQL_ATTR_APP_PARAM_DESC: - case SQL_ATTR_IMP_ROW_DESC: - case SQL_ATTR_IMP_PARAM_DESC: - { - SQLPOINTER *val = reinterpret_cast<SQLPOINTER*>(valueBuf); - - *val = static_cast<SQLPOINTER>(stmt); - - break; - } - - case SQL_ATTR_ROW_ARRAY_SIZE: - { - SQLINTEGER *val = reinterpret_cast<SQLINTEGER*>(valueBuf); - - *val = static_cast<SQLINTEGER>(1); - - break; - } - - case SQL_ATTR_ROWS_FETCHED_PTR: - { - SQLULEN** val = reinterpret_cast<SQLULEN**>(valueBuf); - - *val = reinterpret_cast<SQLULEN*>(statement->GetRowsFetchedPtr()); - - break; - } + statement->GetAttribute(attr, valueBuf, valueBufLen, valueResLen); - case SQL_ATTR_ROW_STATUS_PTR: - { - SQLUSMALLINT** val = reinterpret_cast<SQLUSMALLINT**>(valueBuf); - - *val = reinterpret_cast<SQLUSMALLINT*>(statement->GetRowStatusesPtr()); - - break; - } - - case SQL_ATTR_PARAM_BIND_OFFSET_PTR: - { - SQLULEN** val = reinterpret_cast<SQLULEN**>(valueBuf); - - *val = reinterpret_cast<SQLULEN*>(statement->GetParamBindOffsetPtr()); - - break; - } - - case SQL_ATTR_ROW_BIND_OFFSET_PTR: - { - SQLULEN** val = reinterpret_cast<SQLULEN**>(valueBuf); - - *val = reinterpret_cast<SQLULEN*>(statement->GetColumnBindOffsetPtr()); - - break; - } - - default: - return SQL_ERROR; - } - - return SQL_SUCCESS; + return statement->GetDiagnosticRecords().GetReturnCode(); } SQLRETURN SQLSetStmtAttr(SQLHSTMT stmt, @@ -943,53 +879,9 @@ namespace ignite if (!statement) return SQL_INVALID_HANDLE; - switch (attr) - { - case SQL_ATTR_ROW_ARRAY_SIZE: - { - SQLULEN val = reinterpret_cast<SQLULEN>(value); - - LOG_MSG("Value: %d\n", val); - - if (val != 1) - return SQL_ERROR; - - break; - } - - case SQL_ATTR_ROWS_FETCHED_PTR: - { - statement->SetRowsFetchedPtr(reinterpret_cast<size_t*>(value)); - - break; - } - - case SQL_ATTR_ROW_STATUS_PTR: - { - statement->SetRowStatusesPtr(reinterpret_cast<uint16_t*>(value)); - - break; - } - - case SQL_ATTR_PARAM_BIND_OFFSET_PTR: - { - statement->SetParamBindOffsetPtr(reinterpret_cast<int*>(value)); - - break; - } - - case SQL_ATTR_ROW_BIND_OFFSET_PTR: - { - statement->SetColumnBindOffsetPtr(reinterpret_cast<int*>(value)); + statement->SetAttribute(attr, value, valueLen); - break; - } - - default: - return SQL_ERROR; - } - - return SQL_SUCCESS; + return statement->GetDiagnosticRecords().GetReturnCode(); } SQLRETURN SQLPrimaryKeys(SQLHSTMT stmt, http://git-wip-us.apache.org/repos/asf/ignite/blob/9726421f/modules/platforms/cpp/odbc/src/statement.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/statement.cpp b/modules/platforms/cpp/odbc/src/statement.cpp index 32f7c3f..f1a577a 100644 --- a/modules/platforms/cpp/odbc/src/statement.cpp +++ b/modules/platforms/cpp/odbc/src/statement.cpp @@ -145,6 +145,157 @@ namespace ignite paramBindings.clear(); } + void Statement::SetAttribute(int attr, void* value, SQLINTEGER valueLen) + { + IGNITE_ODBC_API_CALL(InternalSetAttribute(attr, value, valueLen)); + } + + SqlResult Statement::InternalSetAttribute(int attr, void* value, SQLINTEGER valueLen) + { + switch (attr) + { + case SQL_ATTR_ROW_ARRAY_SIZE: + { + SQLULEN val = reinterpret_cast<SQLULEN>(value); + + LOG_MSG("SQL_ATTR_ROW_ARRAY_SIZE: %d\n", val); + + if (val != 1) + { + AddStatusRecord(SQL_STATE_HYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED, + "Fetching of more than one row by call is not supported."); + + return SQL_RESULT_ERROR; + } + + break; + } + + case SQL_ATTR_ROWS_FETCHED_PTR: + { + SetRowsFetchedPtr(reinterpret_cast<size_t*>(value)); + + break; + } + + case SQL_ATTR_ROW_STATUS_PTR: + { + SetRowStatusesPtr(reinterpret_cast<uint16_t*>(value)); + + break; + } + + case SQL_ATTR_PARAM_BIND_OFFSET_PTR: + { + SetParamBindOffsetPtr(reinterpret_cast<int*>(value)); + + break; + } + + case SQL_ATTR_ROW_BIND_OFFSET_PTR: + { + SetColumnBindOffsetPtr(reinterpret_cast<int*>(value)); + + break; + } + + default: + { + AddStatusRecord(SQL_STATE_HYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED, + "Specified attribute is not supported."); + + return SQL_RESULT_ERROR; + } + } + + return SQL_RESULT_SUCCESS; + } + + void Statement::GetAttribute(int attr, void* buf, SQLINTEGER bufLen, SQLINTEGER* valueLen) + { + IGNITE_ODBC_API_CALL(InternalGetAttribute(attr, buf, bufLen, valueLen)); + } + + SqlResult Statement::InternalGetAttribute(int attr, void* buf, SQLINTEGER bufLen, SQLINTEGER* valueLen) + { + if (!buf) + { + AddStatusRecord(SQL_STATE_HY000_GENERAL_ERROR, "Data buffer is NULL."); + + return SQL_RESULT_ERROR; + } + + switch (attr) + { + case SQL_ATTR_APP_ROW_DESC: + case SQL_ATTR_APP_PARAM_DESC: + case SQL_ATTR_IMP_ROW_DESC: + case SQL_ATTR_IMP_PARAM_DESC: + { + SQLPOINTER *val = reinterpret_cast<SQLPOINTER*>(buf); + + *val = static_cast<SQLPOINTER>(this); + + break; + } + + case SQL_ATTR_ROW_ARRAY_SIZE: + { + SQLINTEGER *val = reinterpret_cast<SQLINTEGER*>(buf); + + *val = static_cast<SQLINTEGER>(1); + + break; + } + + case SQL_ATTR_ROWS_FETCHED_PTR: + { + SQLULEN** val = reinterpret_cast<SQLULEN**>(buf); + + *val = reinterpret_cast<SQLULEN*>(GetRowsFetchedPtr()); + + break; + } + + case SQL_ATTR_ROW_STATUS_PTR: + { + SQLUSMALLINT** val = reinterpret_cast<SQLUSMALLINT**>(buf); + + *val = reinterpret_cast<SQLUSMALLINT*>(GetRowStatusesPtr()); + + break; + } + + case SQL_ATTR_PARAM_BIND_OFFSET_PTR: + { + SQLULEN** val = reinterpret_cast<SQLULEN**>(buf); + + *val = reinterpret_cast<SQLULEN*>(GetParamBindOffsetPtr()); + + break; + } + + case SQL_ATTR_ROW_BIND_OFFSET_PTR: + { + SQLULEN** val = reinterpret_cast<SQLULEN**>(buf); + + *val = reinterpret_cast<SQLULEN*>(GetColumnBindOffsetPtr()); + + break; + } + + default: + { + AddStatusRecord(SQL_STATE_HYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED, + "Specified attribute is not supported."); + + return SQL_RESULT_ERROR; + } + } + + return SQL_RESULT_SUCCESS; + } + uint16_t Statement::GetParametersNumber() { IGNITE_ODBC_API_CALL_ALWAYS_SUCCESS;
