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 } }