You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2016/11/09 09:27:20 UTC

[10/17] ignite git commit: Revert Revert Merge remote-tracking branch 'professional/ignite-1.6.11'

  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-4154
Commit: 9726421ff9efb2b19813b2fd6ad27a3728b5ab1a
Parents: 865bbcf
Author: Dmitriy Govorukhin <dg...@gridgain.com>
Authored: Tue Nov 8 15:59:00 2016 +0300
Committer: Dmitriy Govorukhin <dg...@gridgain.com>
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;