http://git-wip-us.apache.org/repos/asf/ignite/blob/0bd712dd/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
index a3b42b8..76c7b00 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
@@ -37,7 +37,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
     /// <summary>
     /// Client cache implementation.
     /// </summary>
-    internal class CacheClient<TK, TV> : ICacheClient<TK, TV>
+    internal sealed class CacheClient<TK, TV> : ICacheClient<TK, TV>
     {
         /** Scan query filter platform code: .NET filter. */
         private const byte FilterPlatformDotnet = 2;
@@ -159,14 +159,39 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
         /** <inheritDoc /> */
         public IQueryCursor<ICacheEntry<TK, TV>> Query(ScanQuery<TK, TV> 
scanQuery)
         {
-            IgniteArgumentCheck.NotNull(scanQuery, "query");
+            IgniteArgumentCheck.NotNull(scanQuery, "scanQuery");
 
             // Filter is a binary object for all platforms.
             // For .NET it is a CacheEntryFilterHolder with a predefined id 
(BinaryTypeId.CacheEntryPredicateHolder).
             return DoOutInOp(ClientOp.QueryScan, w => WriteScanQuery(w, 
scanQuery),
-                s => new ClientQueryCursor<TK, TV>(_ignite, s.ReadLong(), 
_keepBinary, s));
+                s => new ClientQueryCursor<TK, TV>(
+                    _ignite, s.ReadLong(), _keepBinary, s, 
ClientOp.QueryScanCursorGetPage));
         }
-        
+
+        /** <inheritDoc /> */
+        public IQueryCursor<ICacheEntry<TK, TV>> Query(SqlQuery sqlQuery)
+        {
+            IgniteArgumentCheck.NotNull(sqlQuery, "sqlQuery");
+            IgniteArgumentCheck.NotNull(sqlQuery.Sql, "sqlQuery.Sql");
+            IgniteArgumentCheck.NotNull(sqlQuery.QueryType, 
"sqlQuery.QueryType");
+
+            return DoOutInOp(ClientOp.QuerySql, w => WriteSqlQuery(w, 
sqlQuery),
+                s => new ClientQueryCursor<TK, TV>(
+                    _ignite, s.ReadLong(), _keepBinary, s, 
ClientOp.QuerySqlCursorGetPage));
+        }
+
+        /** <inheritDoc /> */
+        public IFieldsQueryCursor Query(SqlFieldsQuery sqlFieldsQuery)
+        {
+            IgniteArgumentCheck.NotNull(sqlFieldsQuery, "sqlFieldsQuery");
+            IgniteArgumentCheck.NotNull(sqlFieldsQuery.Sql, 
"sqlFieldsQuery.Sql");
+
+            return DoOutInOp(ClientOp.QuerySqlFields, w => 
WriteSqlFieldsQuery(w, sqlFieldsQuery),
+                s => new ClientFieldsQueryCursor(
+                    _ignite, s.ReadLong(), _keepBinary, s, 
ClientOp.QuerySqlFieldsCursorGetPage,
+                    
ClientFieldsQueryCursor.ReadColumns(_marsh.StartUnmarshal(s))));
+        }
+
         /** <inheritDoc /> */
         public CacheResult<TV> GetAndPut(TK key, TV val)
         {
@@ -426,6 +451,53 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
         }
 
         /// <summary>
+        /// Writes the SQL query.
+        /// </summary>
+        private static void WriteSqlQuery(IBinaryRawWriter writer, SqlQuery 
qry)
+        {
+            Debug.Assert(qry != null);
+
+            writer.WriteString(qry.QueryType);
+            writer.WriteString(qry.Sql);
+            QueryBase.WriteQueryArgs(writer, qry.Arguments);
+            writer.WriteBoolean(qry.EnableDistributedJoins);
+            writer.WriteBoolean(qry.Local);
+            writer.WriteBoolean(qry.ReplicatedOnly);
+            writer.WriteInt(qry.PageSize);
+            writer.WriteTimeSpanAsLong(qry.Timeout);
+        }
+
+        /// <summary>
+        /// Writes the SQL fields query.
+        /// </summary>
+        private static void WriteSqlFieldsQuery(IBinaryRawWriter writer, 
SqlFieldsQuery qry)
+        {
+            Debug.Assert(qry != null);
+
+            writer.WriteString(qry.Schema);
+            writer.WriteInt(qry.PageSize);
+            writer.WriteInt(-1);  // maxRows: unlimited
+            writer.WriteString(qry.Sql);
+            QueryBase.WriteQueryArgs(writer, qry.Arguments);
+
+            // .NET client does not discern between different statements for 
now.
+            // We cound have ExecuteNonQuery method, which uses 
StatementType.Update, for example.
+            writer.WriteByte((byte)StatementType.Any);
+
+            writer.WriteBoolean(qry.EnableDistributedJoins);
+            writer.WriteBoolean(qry.Local);
+            writer.WriteBoolean(qry.ReplicatedOnly);
+            writer.WriteBoolean(qry.EnforceJoinOrder);
+            writer.WriteBoolean(qry.Colocated);
+            writer.WriteBoolean(qry.Lazy);
+            writer.WriteTimeSpanAsLong(qry.Timeout);
+
+            // Always include field names.
+            writer.WriteBoolean(true);
+
+        }
+
+        /// <summary>
         /// Handles the error.
         /// </summary>
         private T HandleError<T>(ClientStatus status, string msg)

http://git-wip-us.apache.org/repos/asf/ignite/blob/0bd712dd/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientFieldsQueryCursor.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientFieldsQueryCursor.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientFieldsQueryCursor.cs
new file mode 100644
index 0000000..2e57863
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientFieldsQueryCursor.cs
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Client.Cache.Query
+{
+    using System.Collections.Generic;
+    using System.Collections.ObjectModel;
+    using System.Diagnostics;
+    using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Cache.Query;
+    using Apache.Ignite.Core.Impl.Binary.IO;
+
+    /// <summary>
+    /// Client fields cursor.
+    /// </summary>
+    internal class ClientFieldsQueryCursor : 
ClientQueryCursorBase<IList<object>>, IFieldsQueryCursor
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ClientQueryCursor{TK, 
TV}" /> class.
+        /// </summary>
+        /// <param name="ignite">The ignite.</param>
+        /// <param name="cursorId">The cursor identifier.</param>
+        /// <param name="keepBinary">Keep binary flag.</param>
+        /// <param name="initialBatchStream">Optional stream with initial 
batch.</param>
+        /// <param name="getPageOp">The get page op.</param>
+        /// <param name="columns">The columns.</param>
+        public ClientFieldsQueryCursor(IgniteClient ignite, long cursorId, 
bool keepBinary,
+            IBinaryStream initialBatchStream, ClientOp getPageOp, 
IList<string> columns)
+            : base(ignite, cursorId, keepBinary, initialBatchStream, getPageOp,
+                r =>
+                {
+                    var res = new List<object>(columns.Count);
+
+                    for (var i = 0; i < columns.Count; i++)
+                    {
+                        res.Add(r.ReadObject<object>());
+                    }
+
+                    return res;
+                })
+        {
+            Debug.Assert(columns != null);
+
+            FieldNames = new ReadOnlyCollection<string>(columns);
+        }
+
+        /** <inheritdoc /> */
+        public IList<string> FieldNames { get; private set; }
+
+        /// <summary>
+        /// Reads the columns.
+        /// </summary>
+        internal static string[] ReadColumns(IBinaryRawReader reader)
+        {
+            var res = new string[reader.ReadInt()];
+
+            for (var i = 0; i < res.Length; i++)
+            {
+                res[i] = reader.ReadString();
+            }
+
+            return res;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/0bd712dd/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursor.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursor.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursor.cs
index ff891db..8e09af7 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursor.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursor.cs
@@ -17,27 +17,16 @@
 
 namespace Apache.Ignite.Core.Impl.Client.Cache.Query
 {
-    using System.Collections.Generic;
-    using System.Diagnostics.CodeAnalysis;
-    using System.Linq;
     using Apache.Ignite.Core.Cache;
-    using Apache.Ignite.Core.Impl.Binary;
     using Apache.Ignite.Core.Impl.Binary.IO;
     using Apache.Ignite.Core.Impl.Cache;
-    using Apache.Ignite.Core.Impl.Cache.Query;
     using Apache.Ignite.Core.Impl.Client;
 
     /// <summary>
     /// Client query cursor.
     /// </summary>
-    internal class ClientQueryCursor<TK, TV> : QueryCursorBase<ICacheEntry<TK, 
TV>>
+    internal sealed class ClientQueryCursor<TK, TV> : 
ClientQueryCursorBase<ICacheEntry<TK, TV>>
     {
-        /** Ignite. */
-        private readonly IgniteClient _ignite;
-
-        /** Cursor ID. */
-        private readonly long _cursorId;
-
         /// <summary>
         /// Initializes a new instance of the <see cref="ClientQueryCursor{TK, 
TV}" /> class.
         /// </summary>
@@ -45,52 +34,13 @@ namespace Apache.Ignite.Core.Impl.Client.Cache.Query
         /// <param name="cursorId">The cursor identifier.</param>
         /// <param name="keepBinary">Keep binary flag.</param>
         /// <param name="initialBatchStream">Optional stream with initial 
batch.</param>
-        public ClientQueryCursor(IgniteClient ignite, long cursorId, bool 
keepBinary, 
-            IBinaryStream initialBatchStream) 
-            : base(ignite.Marshaller, keepBinary, initialBatchStream)
-        {
-            _ignite = ignite;
-            _cursorId = cursorId;
-        }
-
-        /** <inheritdoc /> */
-        protected override void InitIterator()
+        /// <param name="getPageOp">The get page op.</param>
+        public ClientQueryCursor(IgniteClient ignite, long cursorId, bool 
keepBinary,
+            IBinaryStream initialBatchStream, ClientOp getPageOp)
+            : base(ignite, cursorId, keepBinary, initialBatchStream, getPageOp,
+                r => new CacheEntry<TK, TV>(r.ReadObject<TK>(), 
r.ReadObject<TV>()))
         {
             // No-op.
         }
-
-        /** <inheritdoc /> */
-        protected override IList<ICacheEntry<TK, TV>> GetAllInternal()
-        {
-            return this.ToArray();
-        }
-
-        /** <inheritdoc /> */
-        [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of 
public methods")]
-        protected override ICacheEntry<TK, TV> Read(BinaryReader reader)
-        {
-            return new CacheEntry<TK, TV>(reader.ReadObject<TK>(), 
reader.ReadObject<TV>());
-        }
-
-        /** <inheritdoc /> */
-        protected override ICacheEntry<TK, TV>[] GetBatch()
-        {
-            return _ignite.Socket.DoOutInOp(ClientOp.QueryScanCursorGetPage,
-                w => w.WriteLong(_cursorId),
-                s => ConvertGetBatch(s));
-        }
-
-        /** <inheritdoc /> */
-        protected override void Dispose(bool disposing)
-        {
-            try
-            {
-                _ignite.Socket.DoOutInOp<object>(ClientOp.ResourceClose, w => 
w.WriteLong(_cursorId), null);
-            }
-            finally
-            {
-                base.Dispose(disposing);
-            }
-        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/0bd712dd/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs
new file mode 100644
index 0000000..5123537
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+namespace Apache.Ignite.Core.Impl.Client.Cache.Query
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Binary.IO;
+    using Apache.Ignite.Core.Impl.Cache.Query;
+
+    /// <summary>
+    /// Client query cursor base.
+    /// </summary>
+    internal abstract class ClientQueryCursorBase<T> : QueryCursorBase<T>
+    {
+        /** Ignite. */
+        private readonly IgniteClient _ignite;
+
+        /** Cursor ID. */
+        private readonly long _cursorId;
+
+        /** Page op code. */
+        private readonly ClientOp _getPageOp;
+
+        /// <summary>
+        /// Initializes a new instance of the <see 
cref="ClientQueryCursorBase{T}" /> class.
+        /// </summary>
+        /// <param name="ignite">The ignite.</param>
+        /// <param name="cursorId">The cursor identifier.</param>
+        /// <param name="keepBinary">Keep binary flag.</param>
+        /// <param name="initialBatchStream">Optional stream with initial 
batch.</param>
+        /// <param name="getPageOp">The get page op.</param>
+        /// <param name="readFunc">Read func.</param>
+        protected ClientQueryCursorBase(IgniteClient ignite, long cursorId, 
bool keepBinary, 
+            IBinaryStream initialBatchStream, ClientOp getPageOp, 
Func<BinaryReader, T> readFunc) 
+            : base(ignite.Marshaller, keepBinary, readFunc, initialBatchStream)
+        {
+            _ignite = ignite;
+            _cursorId = cursorId;
+            _getPageOp = getPageOp;
+        }
+
+        /** <inheritdoc /> */
+        protected override void InitIterator()
+        {
+            // No-op.
+        }
+
+        /** <inheritdoc /> */
+        protected override IList<T> GetAllInternal()
+        {
+            return this.ToArray();
+        }
+
+        /** <inheritdoc /> */
+        protected override T[] GetBatch()
+        {
+            return _ignite.Socket.DoOutInOp(_getPageOp, w => 
w.WriteLong(_cursorId), s => ConvertGetBatch(s));
+        }
+
+        /** <inheritdoc /> */
+        protected override void Dispose(bool disposing)
+        {
+            try
+            {
+                _ignite.Socket.DoOutInOp<object>(ClientOp.ResourceClose, w => 
w.WriteLong(_cursorId), null);
+            }
+            finally
+            {
+                base.Dispose(disposing);
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/0bd712dd/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/StatementType.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/StatementType.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/StatementType.cs
new file mode 100644
index 0000000..c5143ea
--- /dev/null
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/StatementType.cs
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+namespace Apache.Ignite.Core.Impl.Client.Cache.Query
+{
+    /// <summary>
+    /// Query request type.
+    /// <para />
+    /// When the client knows expected kind of query, we can fail earlier on 
server.
+    /// </summary>
+    internal enum StatementType : byte
+    {
+        /// <summary>
+        /// Any query, SQL or DML.
+        /// </summary>
+        Any = 0,
+
+        /// <summary>
+        /// Select query, "SELECT .. FROM".
+        /// </summary>
+        Select = 1,
+
+        /// <summary>
+        /// Update (DML) query, "UPDATE .. ", "INSERT INTO ..".
+        /// </summary>
+        Update = 2
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/0bd712dd/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
----------------------------------------------------------------------
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs 
b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
index 779b73e..3af089a 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/ClientOp.cs
@@ -56,6 +56,10 @@ namespace Apache.Ignite.Core.Impl.Client
         CacheGetNames = 32,
         CacheGetConfiguration = 33,
         CacheCreateWithConfiguration = 34,
-        CacheGetOrCreateWithConfiguration = 35
+        CacheGetOrCreateWithConfiguration = 35,
+        QuerySql = 36,
+        QuerySqlCursorGetPage = 37,
+        QuerySqlFields = 38,
+        QuerySqlFieldsCursorGetPage = 39
     }
 }

Reply via email to