From 792d579c59a7fee418c2e160a152331af7e444e0 Mon Sep 17 00:00:00 2001 From: xiaolei li <85657333+xleili@users.noreply.github.com> Date: Thu, 10 Mar 2022 15:41:06 +0800 Subject: [PATCH] [TD-13710]:csharp connector add test cases for query async (#10673) * [TD-13710]:csharp connector add test cases for query async * [TD-13710]:uncomment database fixture dispose --- .../C#/src/test/FunctionTest/QueryAsync.cs | 296 ++++++++++++++++++ .../C#/src/test/FunctionTest/lib/DBFixture.cs | 79 +++++ .../FunctionTest/lib/DatabaseCollection.cs | 9 + .../src/test/FunctionTest/lib/TestExeOrder.cs | 12 + .../test/FunctionTest/lib/TestExeOrderer.cs | 43 +++ .../C#/src/test/FunctionTest/lib/Utils.cs | 275 +++++++++------- 6 files changed, 594 insertions(+), 120 deletions(-) create mode 100644 src/connector/C#/src/test/FunctionTest/QueryAsync.cs create mode 100644 src/connector/C#/src/test/FunctionTest/lib/DBFixture.cs create mode 100644 src/connector/C#/src/test/FunctionTest/lib/DatabaseCollection.cs create mode 100644 src/connector/C#/src/test/FunctionTest/lib/TestExeOrder.cs create mode 100644 src/connector/C#/src/test/FunctionTest/lib/TestExeOrderer.cs diff --git a/src/connector/C#/src/test/FunctionTest/QueryAsync.cs b/src/connector/C#/src/test/FunctionTest/QueryAsync.cs new file mode 100644 index 0000000000..23546b51f5 --- /dev/null +++ b/src/connector/C#/src/test/FunctionTest/QueryAsync.cs @@ -0,0 +1,296 @@ +using TDengineDriver; +using Test.UtilsTools; +using System; +using System.Runtime.InteropServices; +using Xunit; +using System.Collections.Generic; +using Test.UtilsTools.DataSource; +using Test.UtilsTools.ResultSet; +using Xunit.Abstractions; +using Test.Fixture; +using Test.Case.Attributes; + +namespace Cases +{ + [TestCaseOrderer("XUnit.Case.Orderers.TestExeOrderer", "Cases.ExeOrder")] + [Collection("Database collection")] + + public class QueryAsyncCases + { + DatabaseFixture database; + + private readonly ITestOutputHelper output; + + public QueryAsyncCases(DatabaseFixture fixture, ITestOutputHelper output) + { + this.database = fixture; + this.output = output; + } + /// xiaolei + /// QueryAsyncCases.QueryAsyncCases + /// Test query without condition + /// QueryAsync.cs + /// pass or failed + [Fact(DisplayName = "QueryAsyncCases.QueryWithoutCondition()"),TestExeOrder(1),Trait("Category", "QueryAWithoutCondition")] + public void QueryWithoutCondition() + { + IntPtr conn = database.conn; + IntPtr _res = IntPtr.Zero; + + var tableName = "query_a_without_condition"; + var createSql = $"create table if not exists {tableName}(ts timestamp,bl bool,i8 tinyint,i16 smallint,i32 int,i64 bigint,bnr binary(50),nchr nchar(50))tags(t_i32 int,t_bnr binary(50),t_nchr nchar(50))"; + var dropSql = $"drop table if exists {tableName}"; + + var colData = new List{1646150410100,true,1,11,1111,11111111,"value one","值壹", + 1646150410200,true,2,22,2222,22222222,"value two","值贰", + 1646150410300,false,3,33,3333,33333333,"value three","值三", + }; + var tagData = new List { 1, "tag_one", "标签壹" }; + String insertSql = UtilsTools.ConstructInsertSql(tableName + "_s01", tableName, colData, tagData, 3); + List expectResMeta = DataSource.GetMetaFromDLL(createSql); + List expectResData = UtilsTools.CombineColAndTagData(colData, tagData, 3); + + var querySql = $"select * from {tableName}"; + UtilsTools.ExecuteUpdate(conn, dropSql); + UtilsTools.ExecuteUpdate(conn, createSql); + UtilsTools.ExecuteUpdate(conn, insertSql); + + QueryAsyncCallback fq = new QueryAsyncCallback(QueryCallback); + TDengine.QueryAsync(conn, querySql, fq, IntPtr.Zero); + + void QueryCallback(IntPtr param, IntPtr taosRes, int code) + { + if (code == 0 && taosRes != IntPtr.Zero) + { + FetchRowAsyncCallback fetchRowAsyncCallback = new FetchRowAsyncCallback(FetchCallback); + TDengine.FetchRowAsync(taosRes, fetchRowAsyncCallback, param); + } + else + { + Console.WriteLine($"async query data failed, failed code {code}"); + } + + } + + void FetchCallback(IntPtr param, IntPtr taosRes, int numOfRows) + { + if (numOfRows > 0) + { + ResultSet actualResult = new ResultSet(taosRes); + List actualMeta = actualResult.GetResultMeta(); + List actualResData = actualResult.GetResultData(); + //Assert Meta data + for (int i = 0; i < actualMeta.Count; i++) + { + Assert.Equal(expectResMeta[i].name, actualMeta[i].name); + Assert.Equal(expectResMeta[i].type, actualMeta[i].type); + Assert.Equal(expectResMeta[i].size, actualMeta[i].size); + } + // Assert retrieve data + for (int i = 0; i < actualResData.Count; i++) + { + // Console.WriteLine("{0},{1},{2}", i, expectResData[i], actualResData[i]); + Assert.Equal(expectResData[i].ToString(), actualResData[i]); + } + + TDengine.FetchRowAsync(taosRes, FetchCallback, param); + } + else + { + if (numOfRows == 0) + { + Console.WriteLine("async retrieve complete."); + + } + else + { + Console.WriteLine($"FetchRowAsync callback error, error code {numOfRows}"); + } + TDengine.FreeResult(taosRes); + } + } + } + + /// xiaolei + /// QueryAsyncCases.QueryWithCondition + /// Test query with condition + /// QueryAsync.cs + /// pass or failed + [Fact(DisplayName = "QueryAsyncCases.QueryWithCondition()"),TestExeOrder(2),Trait("Category", "QueryAWithCondition")] + public void QueryWithCondition() + { + IntPtr conn = database.conn; + IntPtr _res = IntPtr.Zero; + + var tableName = "query_a_with_condition"; + var createSql = $"create table if not exists {tableName}(ts timestamp,bl bool,i8 tinyint,i16 smallint,i32 int,i64 bigint,bnr binary(50),nchr nchar(50))tags(t_i32 int,t_bnr binary(50),t_nchr nchar(50))"; + var dropSql = $"drop table if exists {tableName}"; + + var colData = new List{1646150410100,true,1,11,1111,11111111,"value one","值壹", + 1646150410200,true,2,22,2222,22222222,"value two","值贰", + 1646150410300,false,3,33,3333,33333333,"value three","值三", + }; + var colDataActual = colData.GetRange(8, 8); + var tagData = new List { 1, "tag_one", "标签壹" }; + String insertSql = UtilsTools.ConstructInsertSql(tableName + "_s01", tableName, colData, tagData, 3); + List expectResMeta = DataSource.GetMetaFromDLL(createSql); + List expectResData = UtilsTools.CombineColAndTagData(colDataActual, tagData, 1); + colDataActual.ForEach((item) => { Console.Write("{0}\t", item); }); + + var querySql = $"select * from {tableName} where bl=true and t_bnr='tag_one' and i8>1 and t_nchr = '标签壹'"; + UtilsTools.ExecuteUpdate(conn, dropSql); + UtilsTools.ExecuteUpdate(conn, createSql); + UtilsTools.ExecuteUpdate(conn, insertSql); + QueryAsyncCallback fq = new QueryAsyncCallback(QueryCallback); + TDengine.QueryAsync(conn, querySql, fq, IntPtr.Zero); + + void QueryCallback(IntPtr param, IntPtr taosRes, int code) + { + if (code == 0 && taosRes != IntPtr.Zero) + { + FetchRowAsyncCallback fetchRowAsyncCallback = new FetchRowAsyncCallback(FetchCallback); + TDengine.FetchRowAsync(taosRes, fetchRowAsyncCallback, param); + } + else + { + Console.WriteLine($"async query data failed, failed code {code}"); + } + + } + + void FetchCallback(IntPtr param, IntPtr taosRes, int numOfRows) + { + if (numOfRows > 0) + { + ResultSet actualResult = new ResultSet(taosRes); + List actualMeta = actualResult.GetResultMeta(); + List actualResData = actualResult.GetResultData(); + //Assert Meta data + for (int i = 0; i < actualMeta.Count; i++) + { + Assert.Equal(expectResMeta[i].name, actualMeta[i].name); + Assert.Equal(expectResMeta[i].type, actualMeta[i].type); + Assert.Equal(expectResMeta[i].size, actualMeta[i].size); + } + // Assert retrieve data + for (int i = 0; i < actualResData.Count; i++) + { + // Console.WriteLine("{0},{1},{2}", i, expectResData[i], actualResData[i]); + Assert.Equal(expectResData[i].ToString(), actualResData[i]); + } + + TDengine.FetchRowAsync(taosRes, FetchCallback, param); + } + else + { + if (numOfRows == 0) + { + Console.WriteLine("async retrieve complete."); + + } + else + { + Console.WriteLine($"FetchRowAsync callback error, error code {numOfRows}"); + } + TDengine.FreeResult(taosRes); + } + } + + } + + /// xiaolei + /// QueryAsyncCases.QueryWithJsonCondition + /// Test query with condition + /// QueryAsync.cs + /// pass or failed + [Fact(DisplayName = "QueryAsyncCases.QueryWithJsonCondition()"),TestExeOrder(3),Trait("Category", "QueryAWithJsonCondition")] + public void QueryWithJsonCondition() + { + IntPtr conn = database.conn; + IntPtr _res = IntPtr.Zero; + + var tableName = "query_a_json_condition"; + var createSql = $"create table if not exists {tableName}(ts timestamp,bl bool,i8 tinyint,i16 smallint,i32 int,i64 bigint,bnr binary(50),nchr nchar(50))tags(jtag json)"; + var dropSql = $"drop table if exists {tableName}"; + + var colData1 = new List{1646150410100,true,1,11,1111,11111111,"value one","值壹", + 1646150410200,true,2,22,2222,22222222,"value two","值贰", + 1646150410300,false,3,33,3333,33333333,"value three","值三", + }; + var colData2 = new List{1646150410400,false,4,44,4444,44444444,"value three","值肆", + 1646150410500,true,5,55,5555,55555555,"value one","值伍", + 1646150410600,true,6,66,6666,66666666,"value two","值陆", + }; + var tagData1 = new List { "{\"t_bnr\":\"tag1\",\"t_i32\":1,\"t_nchr\":\"标签壹\"}" }; + var tagData2 = new List { "{\"t_bnr\":\"tag2\",\"t_i32\":2,\"t_nchar\":\"标签贰\"}" }; + var querySql = $"select * from {tableName} where jtag->'t_bnr'='tag1';"; + + + String insertSql1 = UtilsTools.ConstructInsertSql(tableName + "_s01", tableName, colData1, tagData1, 3); + String insertSql2 = UtilsTools.ConstructInsertSql(tableName + "_s02", tableName, colData1, tagData2, 3); + List expectResMeta = DataSource.GetMetaFromDLL(createSql); + List expectResData = UtilsTools.CombineColAndTagData(colData1, tagData1, 3); + + UtilsTools.ExecuteUpdate(conn, dropSql); + UtilsTools.ExecuteUpdate(conn, createSql); + UtilsTools.ExecuteUpdate(conn, insertSql1); + UtilsTools.ExecuteUpdate(conn, insertSql2); + QueryAsyncCallback fq = new QueryAsyncCallback(QueryCallback); + TDengine.QueryAsync(conn, querySql, fq, IntPtr.Zero); + + void QueryCallback(IntPtr param, IntPtr taosRes, int code) + { + if (code == 0 && taosRes != IntPtr.Zero) + { + FetchRowAsyncCallback fetchRowAsyncCallback = new FetchRowAsyncCallback(FetchCallback); + TDengine.FetchRowAsync(taosRes, fetchRowAsyncCallback, param); + } + else + { + Console.WriteLine($"async query data failed, failed code {code}"); + } + + } + + void FetchCallback(IntPtr param, IntPtr taosRes, int numOfRows) + { + if (numOfRows > 0) + { + ResultSet actualResult = new ResultSet(taosRes); + List actualMeta = actualResult.GetResultMeta(); + List actualResData = actualResult.GetResultData(); + //Assert Meta data + for (int i = 0; i < actualMeta.Count; i++) + { + Assert.Equal(expectResMeta[i].name, actualMeta[i].name); + Assert.Equal(expectResMeta[i].type, actualMeta[i].type); + Assert.Equal(expectResMeta[i].size, actualMeta[i].size); + } + // Assert retrieve data + for (int i = 0; i < actualResData.Count; i++) + { + // Console.WriteLine("{0},{1},{2}", i, expectResData[i], actualResData[i]); + Assert.Equal(expectResData[i].ToString(), actualResData[i]); + } + + TDengine.FetchRowAsync(taosRes, FetchCallback, param); + } + else + { + if (numOfRows == 0) + { + Console.WriteLine("async retrieve complete."); + + } + else + { + Console.WriteLine($"FetchRowAsync callback error, error code {numOfRows}"); + } + TDengine.FreeResult(taosRes); + } + } + + + } + } +} diff --git a/src/connector/C#/src/test/FunctionTest/lib/DBFixture.cs b/src/connector/C#/src/test/FunctionTest/lib/DBFixture.cs new file mode 100644 index 0000000000..83492536fe --- /dev/null +++ b/src/connector/C#/src/test/FunctionTest/lib/DBFixture.cs @@ -0,0 +1,79 @@ +using System; +using System.Configuration; +using System.Data.SqlClient; +using System.Runtime.InteropServices; +using TDengineDriver; + +namespace Test.Fixture +{ + public class DatabaseFixture : IDisposable + { + public IntPtr conn { get; set; } + + private string user = "root"; + private string password = "taosdata"; + private string ip = "127.0.0.1"; + private short port = 0; + + private string db = "xunit_test_fixture"; + public DatabaseFixture() + { + conn = TDengine.Connect(ip, user, password, "", port); + IntPtr res; + if (conn != IntPtr.Zero) + { + if ((res = TDengine.Query(conn, $"create database if not exists {db} keep 3650")) != IntPtr.Zero) + { + if ((res = TDengine.Query(conn, $"use {db}")) != IntPtr.Zero) + { + Console.WriteLine("Get connection success"); + } + else + { + throw new Exception(TDengine.Error(res)); + } + } + else + { + throw new Exception(TDengine.Error(res)); + } + } + else + { + throw new Exception("Get TDConnection failed"); + } + } + + // public IntPtr TDConnection { get; } + + public void Dispose() + { + // IntPtr res; + // if (conn != IntPtr.Zero) + // { + // if ((res = TDengine.Query(conn, $"drop database if exists {db}")) != IntPtr.Zero) + // { + // if (TDengine.Close(conn) == 0) + // { + // Console.WriteLine("close connection success"); + // } + // else + // { + // throw new Exception("close connection failed"); + // } + + // } + // else + // { + // throw new Exception(TDengine.Error(res)); + // } + // } + // else + // { + // throw new Exception("connection if already null"); + // } + + } + + } +} diff --git a/src/connector/C#/src/test/FunctionTest/lib/DatabaseCollection.cs b/src/connector/C#/src/test/FunctionTest/lib/DatabaseCollection.cs new file mode 100644 index 0000000000..11651f99b9 --- /dev/null +++ b/src/connector/C#/src/test/FunctionTest/lib/DatabaseCollection.cs @@ -0,0 +1,9 @@ +using Xunit; +using Test.Fixture; +[CollectionDefinition("Database collection")] +public class DatabaseCollection : ICollectionFixture +{ + // This class has no code, and is never created. Its purpose is simply + // to be the place to apply [CollectionDefinition] and all the + // ICollectionFixture<> interfaces. +} \ No newline at end of file diff --git a/src/connector/C#/src/test/FunctionTest/lib/TestExeOrder.cs b/src/connector/C#/src/test/FunctionTest/lib/TestExeOrder.cs new file mode 100644 index 0000000000..8fec01c0ba --- /dev/null +++ b/src/connector/C#/src/test/FunctionTest/lib/TestExeOrder.cs @@ -0,0 +1,12 @@ +using System; + +namespace Test.Case.Attributes +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class TestExeOrderAttribute : Attribute + { + public int ExeOrder { get; private set; } + + public TestExeOrderAttribute(int exeOrder) => ExeOrder = exeOrder; + } +} \ No newline at end of file diff --git a/src/connector/C#/src/test/FunctionTest/lib/TestExeOrderer.cs b/src/connector/C#/src/test/FunctionTest/lib/TestExeOrderer.cs new file mode 100644 index 0000000000..798244941a --- /dev/null +++ b/src/connector/C#/src/test/FunctionTest/lib/TestExeOrderer.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Linq; +using Xunit.Abstractions; +using Xunit.Sdk; +using Test.Case.Attributes; + +namespace XUnit.Case.Orderers +{ + public class TestExeOrderer : ITestCaseOrderer + { + public IEnumerable OrderTestCases( + IEnumerable testCases) where TTestCase : ITestCase + { + string assemblyName = typeof(TestExeOrderAttribute).AssemblyQualifiedName!; + var sortedMethods = new SortedDictionary>(); + foreach (TTestCase testCase in testCases) + { + int exeOrder = testCase.TestMethod.Method + .GetCustomAttributes(assemblyName) + .FirstOrDefault() + ?.GetNamedArgument(nameof(TestExeOrderAttribute.ExeOrder)) ?? 0; + + GetOrCreate(sortedMethods, exeOrder).Add(testCase); + } + + foreach (TTestCase testCase in + sortedMethods.Keys.SelectMany( + exeOrder => sortedMethods[exeOrder].OrderBy( + testCase => testCase.TestMethod.Method.Name))) + { + yield return testCase; + } + } + + private static TValue GetOrCreate( + IDictionary dictionary, TKey key) + where TKey : struct + where TValue : new() => + dictionary.TryGetValue(key, out TValue? result) + ? result + : (dictionary[key] = new TValue()); + } +} \ No newline at end of file diff --git a/src/connector/C#/src/test/FunctionTest/lib/Utils.cs b/src/connector/C#/src/test/FunctionTest/lib/Utils.cs index c2bba9298d..3de6c609f8 100644 --- a/src/connector/C#/src/test/FunctionTest/lib/Utils.cs +++ b/src/connector/C#/src/test/FunctionTest/lib/Utils.cs @@ -3,6 +3,7 @@ using TDengineDriver; using System.Runtime.InteropServices; using System.Text; using System.Collections.Generic; +using Xunit.Abstractions; namespace Test.UtilsTools { public class UtilsTools @@ -28,20 +29,20 @@ namespace Test.UtilsTools //get taos.cfg file based on different os public static string GetConfigPath() { - string configDir = "" ; - if(OperatingSystem.IsOSPlatform("Windows")) - { - configDir = "C:/TDengine/cfg"; - } - else if(OperatingSystem.IsOSPlatform("Linux")) - { - configDir = "/etc/taos"; - } - else if(OperatingSystem.IsOSPlatform("macOS")) - { - configDir = "/etc/taos"; - } - return configDir; + string configDir = ""; + if (OperatingSystem.IsOSPlatform("Windows")) + { + configDir = "C:/TDengine/cfg"; + } + else if (OperatingSystem.IsOSPlatform("Linux")) + { + configDir = "/etc/taos"; + } + else if (OperatingSystem.IsOSPlatform("macOS")) + { + configDir = "/usr/local/etc/taos"; + } + return configDir; } public static IntPtr ExecuteQuery(IntPtr conn, String sql) @@ -102,23 +103,16 @@ namespace Test.UtilsTools int fieldCount = metas.Count; IntPtr rowdata; - // StringBuilder builder = new StringBuilder(); List datas = QueryRes(res, metas); - Console.Write(" DisplayRes ---"); for (int i = 0; i < metas.Count; i++) { for (int j = 0; j < datas.Count; j++) { - Console.Write(" {0} ---", datas[i * j + i]); + Console.Write(" {0} \t|", datas[j]); } Console.WriteLine(""); } - // if (TDengine.ErrorNo(res) != 0) - // { - // Console.Write("Query is not complete, Error {0:G}", TDengine.ErrorNo(res), TDengine.Error(res)); - // } - // TDengine.FreeResult(res); Console.WriteLine(""); } public static List> GetResultSet(IntPtr res) @@ -197,14 +191,8 @@ namespace Test.UtilsTools } public static List GetResData(IntPtr res) { - List colName = new List(); - List dataRaw = new List(); - if (!IsValidResult(res)) - { - ExitProgram(); - } - List metas = GetResField(res); - dataRaw = QueryRes(res, metas); + List dataRaw = GetResDataWithoutFree(res); + FreeResult(res); return dataRaw; } @@ -288,107 +276,23 @@ namespace Test.UtilsTools private static List QueryRes(IntPtr res, List metas) { - IntPtr rowdata; - long queryRows = 0; + IntPtr taosRow; List dataRaw = new List(); int fieldCount = metas.Count; - while ((rowdata = TDengine.FetchRows(res)) != IntPtr.Zero) + while ((taosRow = TDengine.FetchRows(res)) != IntPtr.Zero) { - queryRows++; - IntPtr colLengthPtr = TDengine.FetchLengths(res); - int[] colLengthArr = new int[fieldCount]; - Marshal.Copy(colLengthPtr, colLengthArr, 0, fieldCount); - - for (int fields = 0; fields < fieldCount; ++fields) - { - TDengineMeta meta = metas[fields]; - int offset = IntPtr.Size * fields; - IntPtr data = Marshal.ReadIntPtr(rowdata, offset); - - if (data == IntPtr.Zero) - { - dataRaw.Add("NULL"); - continue; - } - - switch ((TDengineDataType)meta.type) - { - case TDengineDataType.TSDB_DATA_TYPE_BOOL: - bool v1 = Marshal.ReadByte(data) == 0 ? false : true; - dataRaw.Add(v1.ToString()); - break; - case TDengineDataType.TSDB_DATA_TYPE_TINYINT: - sbyte v2 = (sbyte)Marshal.ReadByte(data); - dataRaw.Add(v2.ToString()); - break; - case TDengineDataType.TSDB_DATA_TYPE_SMALLINT: - short v3 = Marshal.ReadInt16(data); - dataRaw.Add(v3.ToString()); - break; - case TDengineDataType.TSDB_DATA_TYPE_INT: - int v4 = Marshal.ReadInt32(data); - dataRaw.Add(v4.ToString()); - break; - case TDengineDataType.TSDB_DATA_TYPE_BIGINT: - long v5 = Marshal.ReadInt64(data); - dataRaw.Add(v5.ToString()); - break; - case TDengineDataType.TSDB_DATA_TYPE_FLOAT: - float v6 = (float)Marshal.PtrToStructure(data, typeof(float)); - dataRaw.Add(v6.ToString()); - break; - case TDengineDataType.TSDB_DATA_TYPE_DOUBLE: - double v7 = (double)Marshal.PtrToStructure(data, typeof(double)); - dataRaw.Add(v7.ToString()); - break; - case TDengineDataType.TSDB_DATA_TYPE_BINARY: - // string v8 = Marshal.PtrToStringAnsi(data, colLengthArr[fields]); - string v8 = Marshal.PtrToStringUTF8(data, colLengthArr[fields]); - dataRaw.Add(v8); - break; - case TDengineDataType.TSDB_DATA_TYPE_TIMESTAMP: - long v9 = Marshal.ReadInt64(data); - dataRaw.Add(v9.ToString()); - break; - case TDengineDataType.TSDB_DATA_TYPE_NCHAR: - // string v10 = Marshal.PtrToStringAnsi(data, colLengthArr[fields]); - string v10 = Marshal.PtrToStringUTF8(data, colLengthArr[fields]); - dataRaw.Add(v10); - break; - case TDengineDataType.TSDB_DATA_TYPE_UTINYINT: - byte v12 = Marshal.ReadByte(data); - dataRaw.Add(v12.ToString()); - break; - case TDengineDataType.TSDB_DATA_TYPE_USMALLINT: - ushort v13 = (ushort)Marshal.ReadInt16(data); - dataRaw.Add(v13.ToString()); - break; - case TDengineDataType.TSDB_DATA_TYPE_UINT: - uint v14 = (uint)Marshal.ReadInt32(data); - dataRaw.Add(v14.ToString()); - break; - case TDengineDataType.TSDB_DATA_TYPE_UBIGINT: - ulong v15 = (ulong)Marshal.ReadInt64(data); - dataRaw.Add(v15.ToString()); - break; - default: - dataRaw.Add("unknown value"); - break; - } - } - + dataRaw.AddRange(FetchRow(taosRow, res)); } if (TDengine.ErrorNo(res) != 0) { Console.Write("Query is not complete, Error {0:G}", TDengine.ErrorNo(res), TDengine.Error(res)); } - TDengine.FreeResult(res); Console.WriteLine(""); return dataRaw; } // Generate insert sql for the with the coldata and tag data - public static string ConstructInsertSql(string table,string stable,List colData,List tagData,int numOfRows) + public static string ConstructInsertSql(string table, string stable, List colData, List tagData, int numOfRows) { int numofFileds = colData.Count / numOfRows; StringBuilder insertSql; @@ -453,8 +357,8 @@ namespace Test.UtilsTools return insertSql.ToString(); } - - public static List CombineColAndTagData(List colData,List tagData, int numOfRows) + + public static List CombineColAndTagData(List colData, List tagData, int numOfRows) { var list = new List(); for (int i = 0; i < colData.Count; i++) @@ -470,6 +374,137 @@ namespace Test.UtilsTools } return list; } + + /// + /// Using this method to free TAOS_RES,otherwise will lead memory + /// leak.Notice do not call this method while subscribe/consume until + /// end of the program. + /// + /// TAOS_RES, the resultset usually is return by taos_query() + public static void FreeResult(IntPtr res) + { + TDengine.FreeResult(res); + } + + + /// + /// Using to parse TAOS_ROW. + /// + /// This is TAOS_RES pointer + /// This is TAOS_ROW pointer + /// + public static List FetchRow(IntPtr taosRow, IntPtr taosRes) + { + List metaList = TDengine.FetchFields(taosRes); + int numOfFiled = TDengine.FieldCount(taosRes); + + List dataRaw = new List(); + + IntPtr colLengthPrt = TDengine.FetchLengths(taosRes); + int[] colLengthArr = new int[numOfFiled]; + Marshal.Copy(colLengthPrt, colLengthArr, 0, numOfFiled); + + for (int i = 0; i < numOfFiled; i++) + { + TDengineMeta meta = metaList[i]; + IntPtr data = Marshal.ReadIntPtr(taosRow, IntPtr.Size * i); + + if (data == IntPtr.Zero) + { + dataRaw.Add("NULL"); + continue; + } + switch ((TDengineDataType)meta.type) + { + case TDengineDataType.TSDB_DATA_TYPE_BOOL: + bool v1 = Marshal.ReadByte(data) == 0 ? false : true; + dataRaw.Add(v1.ToString()); + break; + case TDengineDataType.TSDB_DATA_TYPE_TINYINT: + sbyte v2 = (sbyte)Marshal.ReadByte(data); + dataRaw.Add(v2.ToString()); + break; + case TDengineDataType.TSDB_DATA_TYPE_SMALLINT: + short v3 = Marshal.ReadInt16(data); + dataRaw.Add(v3.ToString()); + break; + case TDengineDataType.TSDB_DATA_TYPE_INT: + int v4 = Marshal.ReadInt32(data); + dataRaw.Add(v4.ToString()); + break; + case TDengineDataType.TSDB_DATA_TYPE_BIGINT: + long v5 = Marshal.ReadInt64(data); + dataRaw.Add(v5.ToString()); + break; + case TDengineDataType.TSDB_DATA_TYPE_FLOAT: + float v6 = (float)Marshal.PtrToStructure(data, typeof(float)); + dataRaw.Add(v6.ToString()); + break; + case TDengineDataType.TSDB_DATA_TYPE_DOUBLE: + double v7 = (double)Marshal.PtrToStructure(data, typeof(double)); + dataRaw.Add(v7.ToString()); + break; + case TDengineDataType.TSDB_DATA_TYPE_BINARY: + string v8 = Marshal.PtrToStringUTF8(data, colLengthArr[i]); + dataRaw.Add(v8); + break; + case TDengineDataType.TSDB_DATA_TYPE_TIMESTAMP: + long v9 = Marshal.ReadInt64(data); + dataRaw.Add(v9.ToString()); + break; + case TDengineDataType.TSDB_DATA_TYPE_NCHAR: + string v10 = Marshal.PtrToStringUTF8(data, colLengthArr[i]); + dataRaw.Add(v10); + break; + case TDengineDataType.TSDB_DATA_TYPE_UTINYINT: + byte v12 = Marshal.ReadByte(data); + dataRaw.Add(v12.ToString()); + break; + case TDengineDataType.TSDB_DATA_TYPE_USMALLINT: + ushort v13 = (ushort)Marshal.ReadInt16(data); + dataRaw.Add(v13.ToString()); + break; + case TDengineDataType.TSDB_DATA_TYPE_UINT: + uint v14 = (uint)Marshal.ReadInt32(data); + dataRaw.Add(v14.ToString()); + break; + case TDengineDataType.TSDB_DATA_TYPE_UBIGINT: + ulong v15 = (ulong)Marshal.ReadInt64(data); + dataRaw.Add(v15.ToString()); + break; + case TDengineDataType.TSDB_DATA_TYPE_JSONTAG: + string v16 = Marshal.PtrToStringUTF8(data, colLengthArr[i]); + dataRaw.Add(v16); + break; + default: + dataRaw.Add("nonsupport data type value"); + break; + } + + } + return dataRaw; + } + + /// + /// Get the result data from TAO_RES but this interface will + /// not free the TAO_RES at the end. Remember to free the TAOS_RES + /// when you need to do so. + /// + /// This is a TAOS_RES pointer. + /// + public static List GetResDataWithoutFree(IntPtr res) + { + List colName = new List(); + List dataRaw = new List(); + if (!IsValidResult(res)) + { + ExitProgram(); + } + List metas = GetResField(res); + dataRaw = QueryRes(res, metas); + return dataRaw; + } } + } -- GitLab