mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <PropertyGroup>
 | 
				
			||||||
 | 
					    <TargetFramework>net6.0</TargetFramework>
 | 
				
			||||||
 | 
					    <ImplicitUsings>enable</ImplicitUsings>
 | 
				
			||||||
 | 
					    <Nullable>enable</Nullable>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <IsPackable>false</IsPackable>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
 | 
				
			||||||
 | 
					    <PackageReference Include="xunit" Version="2.4.2" />
 | 
				
			||||||
 | 
					    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
 | 
				
			||||||
 | 
					      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
				
			||||||
 | 
					      <PrivateAssets>all</PrivateAssets>
 | 
				
			||||||
 | 
					    </PackageReference>
 | 
				
			||||||
 | 
					    <PackageReference Include="coverlet.collector" Version="3.1.2">
 | 
				
			||||||
 | 
					      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
				
			||||||
 | 
					      <PrivateAssets>all</PrivateAssets>
 | 
				
			||||||
 | 
					    </PackageReference>
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
 | 
				
			||||||
 | 
					    <ProjectReference Include="..\..\Providers\FreeSql.Provider.Xugu\FreeSql.Provider.Xugu.csproj" />
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										44
									
								
								FreeSql.Tests/FreeSql.Tests.Provider.Xugu/UnitDbFirst.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								FreeSql.Tests/FreeSql.Tests.Provider.Xugu/UnitDbFirst.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					 
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.Provider.Xugu
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class UnitDbFirst
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void GetDatabases()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var t1 = g.xugu.DbFirst.GetDatabases();
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            Assert.True(t1.Count > 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void GetTablesByDatabase()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var t2 = g.xugu.DbFirst.GetTablesByDatabase();
 | 
				
			||||||
 | 
					            Assert.True(t2.Count > 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void GetTableByName()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var fsql = g.xugu;
 | 
				
			||||||
 | 
					            var t1 = fsql.DbFirst.GetTableByName("GENERAL.system_log");
 | 
				
			||||||
 | 
					            Assert.NotNull(t1);
 | 
				
			||||||
 | 
					            Assert.True(t1.Columns.Count > 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void ExistsTable()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var fsql = g.xugu;
 | 
				
			||||||
 | 
					            Assert.False(fsql.DbFirst.ExistsTable("GENERAL.system_log"));
 | 
				
			||||||
 | 
					            fsql.CodeFirst.SyncStructure(typeof(test_existstb01));
 | 
				
			||||||
 | 
					            Assert.True(fsql.DbFirst.ExistsTable("test_existstb01"));
 | 
				
			||||||
 | 
					            fsql.Ado.ExecuteNonQuery("drop table test_existstb01");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        class test_existstb01
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public long id { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								FreeSql.Tests/FreeSql.Tests.Provider.Xugu/Usings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								FreeSql.Tests/FreeSql.Tests.Provider.Xugu/Usings.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					global using Xunit;
 | 
				
			||||||
							
								
								
									
										28
									
								
								FreeSql.Tests/FreeSql.Tests.Provider.Xugu/g.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								FreeSql.Tests/FreeSql.Tests.Provider.Xugu/g.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Diagnostics;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Tests.Provider.Xugu
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class g
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static Lazy<IFreeSql> xuguLazy = new Lazy<IFreeSql>(() => new FreeSql.FreeSqlBuilder()
 | 
				
			||||||
 | 
					            .UseConnectionString(FreeSql.DataType.Xugu, "IP=127.0.0.1;DB=SYSTEM;User=SYSDBA;PWD=SYSDBA;Port=5138;AUTO_COMMIT=on;CHAR_SET=UTF8")
 | 
				
			||||||
 | 
					            //.UseAutoSyncStructure(true)
 | 
				
			||||||
 | 
					            //.UseGenerateCommandParameterWithLambda(true)
 | 
				
			||||||
 | 
					            .UseLazyLoading(true)
 | 
				
			||||||
 | 
					            //.UseNameConvert(FreeSql.Internal.NameConvertType.ToUpper)
 | 
				
			||||||
 | 
					            //.UseNoneCommandParameter(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            .UseMonitorCommand(
 | 
				
			||||||
 | 
					                cmd => Trace.WriteLine("\r\n线程" + Thread.CurrentThread.ManagedThreadId + ": " + cmd.CommandText) //监听SQL命令对象,在执行前
 | 
				
			||||||
 | 
					                                                                                                                 //, (cmd, traceLog) => Console.WriteLine(traceLog)
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            .Build());
 | 
				
			||||||
 | 
					        public static IFreeSql xugu => xuguLazy.Value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								FreeSql.sln
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								FreeSql.sln
									
									
									
									
									
								
							@@ -121,6 +121,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.QuestDb",
 | 
				
			|||||||
EndProject
 | 
					EndProject
 | 
				
			||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.AggregateRoot", "Extensions\FreeSql.Extensions.AggregateRoot\FreeSql.Extensions.AggregateRoot.csproj", "{71A6F937-D11B-4AE4-9933-BB6B4D925665}"
 | 
					Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.AggregateRoot", "Extensions\FreeSql.Extensions.AggregateRoot\FreeSql.Extensions.AggregateRoot.csproj", "{71A6F937-D11B-4AE4-9933-BB6B4D925665}"
 | 
				
			||||||
EndProject
 | 
					EndProject
 | 
				
			||||||
 | 
					Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.Xugu", "Providers\FreeSql.Provider.Xugu\FreeSql.Provider.Xugu.csproj", "{8064870C-22EA-4A58-972D-DBD57D096D91}"
 | 
				
			||||||
 | 
					EndProject
 | 
				
			||||||
Global
 | 
					Global
 | 
				
			||||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
						GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
				
			||||||
		Debug|Any CPU = Debug|Any CPU
 | 
							Debug|Any CPU = Debug|Any CPU
 | 
				
			||||||
@@ -719,6 +721,18 @@ Global
 | 
				
			|||||||
		{71A6F937-D11B-4AE4-9933-BB6B4D925665}.Release|x64.Build.0 = Release|Any CPU
 | 
							{71A6F937-D11B-4AE4-9933-BB6B4D925665}.Release|x64.Build.0 = Release|Any CPU
 | 
				
			||||||
		{71A6F937-D11B-4AE4-9933-BB6B4D925665}.Release|x86.ActiveCfg = Release|Any CPU
 | 
							{71A6F937-D11B-4AE4-9933-BB6B4D925665}.Release|x86.ActiveCfg = Release|Any CPU
 | 
				
			||||||
		{71A6F937-D11B-4AE4-9933-BB6B4D925665}.Release|x86.Build.0 = Release|Any CPU
 | 
							{71A6F937-D11B-4AE4-9933-BB6B4D925665}.Release|x86.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{8064870C-22EA-4A58-972D-DBD57D096D91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{8064870C-22EA-4A58-972D-DBD57D096D91}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{8064870C-22EA-4A58-972D-DBD57D096D91}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{8064870C-22EA-4A58-972D-DBD57D096D91}.Debug|x64.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{8064870C-22EA-4A58-972D-DBD57D096D91}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{8064870C-22EA-4A58-972D-DBD57D096D91}.Debug|x86.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{8064870C-22EA-4A58-972D-DBD57D096D91}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{8064870C-22EA-4A58-972D-DBD57D096D91}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{8064870C-22EA-4A58-972D-DBD57D096D91}.Release|x64.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{8064870C-22EA-4A58-972D-DBD57D096D91}.Release|x64.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{8064870C-22EA-4A58-972D-DBD57D096D91}.Release|x86.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{8064870C-22EA-4A58-972D-DBD57D096D91}.Release|x86.Build.0 = Release|Any CPU
 | 
				
			||||||
	EndGlobalSection
 | 
						EndGlobalSection
 | 
				
			||||||
	GlobalSection(SolutionProperties) = preSolution
 | 
						GlobalSection(SolutionProperties) = preSolution
 | 
				
			||||||
		HideSolutionNode = FALSE
 | 
							HideSolutionNode = FALSE
 | 
				
			||||||
@@ -758,10 +772,11 @@ Global
 | 
				
			|||||||
		{ECF7FC70-A7FC-4FC3-9BF7-462EA0A65F9C} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
 | 
							{ECF7FC70-A7FC-4FC3-9BF7-462EA0A65F9C} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
 | 
				
			||||||
		{8A06B18A-A8BF-4AEA-AFE4-0F573C2DBFEE} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
 | 
							{8A06B18A-A8BF-4AEA-AFE4-0F573C2DBFEE} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
 | 
				
			||||||
		{71A6F937-D11B-4AE4-9933-BB6B4D925665} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA}
 | 
							{71A6F937-D11B-4AE4-9933-BB6B4D925665} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA}
 | 
				
			||||||
 | 
							{8064870C-22EA-4A58-972D-DBD57D096D91} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
 | 
				
			||||||
	EndGlobalSection
 | 
						EndGlobalSection
 | 
				
			||||||
	GlobalSection(ExtensibilityGlobals) = postSolution
 | 
						GlobalSection(ExtensibilityGlobals) = postSolution
 | 
				
			||||||
		RESX_NeutralResourcesLanguage = en-US
 | 
					 | 
				
			||||||
		RESX_PrefixTranslations = True
 | 
					 | 
				
			||||||
		SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98}
 | 
							SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98}
 | 
				
			||||||
 | 
							RESX_PrefixTranslations = True
 | 
				
			||||||
 | 
							RESX_NeutralResourcesLanguage = en-US
 | 
				
			||||||
	EndGlobalSection
 | 
						EndGlobalSection
 | 
				
			||||||
EndGlobal
 | 
					EndGlobal
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										121
									
								
								Providers/FreeSql.Provider.Xugu/Curd/XuguDelete.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								Providers/FreeSql.Provider.Xugu/Curd/XuguDelete.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,121 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Xugu.Curd
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class XuguDelete<T1> : Internal.CommonProvider.DeleteProvider<T1>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public XuguDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression, dywhere)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override List<T1> ExecuteDeleted()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var ret = new List<T1>();
 | 
				
			||||||
 | 
					            DbParameter[] dbParms = null;
 | 
				
			||||||
 | 
					            StringBuilder sbret = null;
 | 
				
			||||||
 | 
					            ToSqlFetch(sb =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (dbParms == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    dbParms = _params.ToArray();
 | 
				
			||||||
 | 
					                    sbret = new StringBuilder();
 | 
				
			||||||
 | 
					                    sbret.Append(" RETURNING ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var colidx = 0;
 | 
				
			||||||
 | 
					                    foreach (var col in _table.Columns.Values)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (colidx > 0) sbret.Append(", ");
 | 
				
			||||||
 | 
					                        sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
				
			||||||
 | 
					                        ++colidx;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                var sql = sb.Append(sbret).ToString();
 | 
				
			||||||
 | 
					                var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
 | 
				
			||||||
 | 
					                _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Exception exception = null;
 | 
				
			||||||
 | 
					                try
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ret.AddRange(_orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                catch (Exception ex)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    exception = ex;
 | 
				
			||||||
 | 
					                    throw ex;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                finally
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
				
			||||||
 | 
					                    _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            if (dbParms != null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                this.ClearData();
 | 
				
			||||||
 | 
					                sbret.Clear();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if net40
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        async public override Task<List<T1>> ExecuteDeletedAsync(CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var ret = new List<T1>();
 | 
				
			||||||
 | 
					            DbParameter[] dbParms = null;
 | 
				
			||||||
 | 
					            StringBuilder sbret = null;
 | 
				
			||||||
 | 
					            await ToSqlFetchAsync(async sb =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (dbParms == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    dbParms = _params.ToArray();
 | 
				
			||||||
 | 
					                    sbret = new StringBuilder();
 | 
				
			||||||
 | 
					                    sbret.Append(" RETURNING ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var colidx = 0;
 | 
				
			||||||
 | 
					                    foreach (var col in _table.Columns.Values)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (colidx > 0) sbret.Append(", ");
 | 
				
			||||||
 | 
					                        sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
				
			||||||
 | 
					                        ++colidx;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                var sql = sb.Append(sbret).ToString();
 | 
				
			||||||
 | 
					                var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
 | 
				
			||||||
 | 
					                _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Exception exception = null;
 | 
				
			||||||
 | 
					                try
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ret.AddRange(await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                catch (Exception ex)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    exception = ex;
 | 
				
			||||||
 | 
					                    throw ex;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                finally
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
				
			||||||
 | 
					                    _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            if (dbParms != null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                this.ClearData();
 | 
				
			||||||
 | 
					                sbret.Clear();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										242
									
								
								Providers/FreeSql.Provider.Xugu/Curd/XuguInsert.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								Providers/FreeSql.Provider.Xugu/Curd/XuguInsert.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,242 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using XuguClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Xugu.Curd
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class XuguInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public XuguInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        internal IFreeSql InternalOrm => _orm;
 | 
				
			||||||
 | 
					        internal TableInfo InternalTable => _table;
 | 
				
			||||||
 | 
					        internal DbParameter[] InternalParams => _params;
 | 
				
			||||||
 | 
					        internal DbConnection InternalConnection => _connection;
 | 
				
			||||||
 | 
					        internal DbTransaction InternalTransaction => _transaction;
 | 
				
			||||||
 | 
					        internal CommonUtils InternalCommonUtils => _commonUtils;
 | 
				
			||||||
 | 
					        internal CommonExpression InternalCommonExpression => _commonExpression;
 | 
				
			||||||
 | 
					        internal List<T1> InternalSource => _source;
 | 
				
			||||||
 | 
					        internal Dictionary<string, bool> InternalIgnore => _ignore;
 | 
				
			||||||
 | 
					        internal void InternalClearData() => ClearData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
 | 
					        public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
 | 
					        public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected override long RawExecuteIdentity()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sql = this.ToSql();
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(sql)) return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            long ret = 0;
 | 
				
			||||||
 | 
					            Aop.CurdBeforeEventArgs before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
 | 
				
			||||||
 | 
					            _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
				
			||||||
 | 
					            Exception exception = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true);
 | 
				
			||||||
 | 
					                if (identCols.Any() == false)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    //var ex = new Exception("对没有自增主键的表执行插入操作时不能要求返回自增主键");
 | 
				
			||||||
 | 
					                    //exception = ex; 
 | 
				
			||||||
 | 
					                    _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params);
 | 
				
			||||||
 | 
					                    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, cmd =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var rowid = (cmd as XGCommand).get_insert_rowid();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    //using (var command = cmd.Connection.CreateCommand()) {
 | 
				
			||||||
 | 
					                    //command.CommandType = CommandType.Text;
 | 
				
			||||||
 | 
					                    var sqlIdentity = $"SELECT {_commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)} FROM {_table.DbName} WHERE \"ROWID\"='{rowid}'";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    //command.CommandText = sql;
 | 
				
			||||||
 | 
					                    if (!long.TryParse(_orm.Ado.ExecuteScalar(CommandType.Text, sqlIdentity, _params).ToString(), out ret))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    //    command.Dispose();
 | 
				
			||||||
 | 
					                    //}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }, _params);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                exception = ex;
 | 
				
			||||||
 | 
					                throw;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            finally
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
				
			||||||
 | 
					                _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected override List<T1> RawExecuteInserted()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sql = this.ToSql();
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(sql)) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Aop.CurdBeforeEventArgs before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
 | 
				
			||||||
 | 
					            _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
				
			||||||
 | 
					            Exception exception = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var ret = new List<T1>();
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var sbColumn = new StringBuilder();
 | 
				
			||||||
 | 
					                var colidx = 0;
 | 
				
			||||||
 | 
					                foreach (var col in _table.Columns.Values)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (colidx > 0) sbColumn.Append(", ");
 | 
				
			||||||
 | 
					                    sbColumn.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
				
			||||||
 | 
					                    ++colidx;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, cmd =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var rowid = (cmd as XGCommand).get_insert_rowid();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var sqlIdentity = $"SELECT {sbColumn} FROM {_table.DbName} WHERE \"ROWID\"='{rowid}'";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    ret = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sqlIdentity, _commandTimeout, _params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }, _params);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                exception = ex;
 | 
				
			||||||
 | 
					                throw;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            finally
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
				
			||||||
 | 
					                _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if net40
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
 | 
				
			||||||
 | 
					        public override Task<long> ExecuteIdentityAsync(CancellationToken cancellationToken = default) => base.SplitExecuteIdentityAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
 | 
				
			||||||
 | 
					        public override Task<List<T1>> ExecuteInsertedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteInsertedAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async protected override Task<long> RawExecuteIdentityAsync(CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sql = this.ToSql();
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(sql)) return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
 | 
				
			||||||
 | 
					            _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
				
			||||||
 | 
					            long ret = 0;
 | 
				
			||||||
 | 
					            Exception exception = null;
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true);
 | 
				
			||||||
 | 
					                if (identCols.Any() == false)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    //var ex = new Exception("对没有自增主键的表执行插入操作时不能要求返回自增主键");
 | 
				
			||||||
 | 
					                    //exception = ex; 
 | 
				
			||||||
 | 
					                    _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params);
 | 
				
			||||||
 | 
					                    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, cmd =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var rowid = (cmd as XGCommand).get_insert_rowid();
 | 
				
			||||||
 | 
					                    var sqlIdentity = $"SELECT {_commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)} FROM {_table.DbName} WHERE \"ROWID\"='{rowid}'";
 | 
				
			||||||
 | 
					                    if (!long.TryParse(_orm.Ado.ExecuteScalar(CommandType.Text, sqlIdentity, _params).ToString(), out ret))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    return Task.CompletedTask;
 | 
				
			||||||
 | 
					                }, _params, cancellationToken);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                exception = ex;
 | 
				
			||||||
 | 
					                throw;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            finally
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
				
			||||||
 | 
					                _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        async protected override Task<List<T1>> RawExecuteInsertedAsync(CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sql = this.ToSql();
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(sql)) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
 | 
				
			||||||
 | 
					            _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
				
			||||||
 | 
					            var ret = new List<T1>();
 | 
				
			||||||
 | 
					            Exception exception = null;
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var sbColumn = new StringBuilder();
 | 
				
			||||||
 | 
					                var colidx = 0;
 | 
				
			||||||
 | 
					                foreach (var col in _table.Columns.Values)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (colidx > 0) sbColumn.Append(", ");
 | 
				
			||||||
 | 
					                    sbColumn.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
				
			||||||
 | 
					                    ++colidx;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, cmd =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var rowid = (cmd as XGCommand).get_insert_rowid();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var sqlIdentity = $"SELECT {sbColumn} FROM {_table.DbName} WHERE \"ROWID\"='{rowid}'";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    ret = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sqlIdentity, _commandTimeout, _params);
 | 
				
			||||||
 | 
					                    return Task.CompletedTask;
 | 
				
			||||||
 | 
					                }, _params, cancellationToken);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                exception = ex;
 | 
				
			||||||
 | 
					                throw;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            finally
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
				
			||||||
 | 
					                _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										89
									
								
								Providers/FreeSql.Provider.Xugu/Curd/XuguInsertOrUpdate.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								Providers/FreeSql.Provider.Xugu/Curd/XuguInsertOrUpdate.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Xugu.Curd
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class XuguInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public XuguInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToSql()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var dbParams = new List<DbParameter>();
 | 
				
			||||||
 | 
					            if (_sourceSql != null) return getMergeSql(null);
 | 
				
			||||||
 | 
					            if (_source?.Any() != true) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sqls = new string[2];
 | 
				
			||||||
 | 
					            // 如果实体类有自增属性,分成两个 List,有值的Item1 merge,无值的Item2 insert
 | 
				
			||||||
 | 
					            var ds = SplitSourceByIdentityValueIsNull(_source);
 | 
				
			||||||
 | 
					            if (ds.Item1.Any()) sqls[0] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item1.Select(a => getMergeSql(a)));
 | 
				
			||||||
 | 
					            if (ds.Item2.Any()) sqls[1] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item2.Select(a => getInsertSql(a)));
 | 
				
			||||||
 | 
					            _params = dbParams.ToArray();
 | 
				
			||||||
 | 
					            if (ds.Item2.Any() == false) return sqls[0];
 | 
				
			||||||
 | 
					            if (ds.Item1.Any() == false) return sqls[1];
 | 
				
			||||||
 | 
					            return string.Join("\r\n\r\n;\r\n\r\n", sqls);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            string getMergeSql(List<T1> data)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (_tempPrimarys.Any() == false) throw new Exception(CoreStrings.InsertOrUpdate_Must_Primary_Key(_table.CsName));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var tempPrimaryIsIdentity = _tempPrimarys.Any(b => b.Attribute.IsIdentity);
 | 
				
			||||||
 | 
					                var sb = new StringBuilder().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\nUSING (");
 | 
				
			||||||
 | 
					                WriteSourceSelectUnionAll(data, sb, dbParams);
 | 
				
			||||||
 | 
					                sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _tempPrimarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"))).Append(") \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var cols = _table.Columns.Values.Where(a => _tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
 | 
				
			||||||
 | 
					                if (_doNothing == false && cols.Any())
 | 
				
			||||||
 | 
					                    sb.Append("WHEN MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                        .Append("  update set ").Append(string.Join(", ", cols.Select(a =>
 | 
				
			||||||
 | 
					                            a.Attribute.IsVersion && a.Attribute.MapType != typeof(byte[]) ?
 | 
				
			||||||
 | 
					                            $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
 | 
				
			||||||
 | 
					                            $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"
 | 
				
			||||||
 | 
					                            ))).Append(" \r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                cols = _table.Columns.Values.Where(a => a.Attribute.CanInsert == true);
 | 
				
			||||||
 | 
					                if (tempPrimaryIsIdentity == false) cols = cols.Where(a => a.Attribute.IsIdentity == false || string.IsNullOrEmpty(a.DbInsertValue) == false);
 | 
				
			||||||
 | 
					                if (cols.Any())
 | 
				
			||||||
 | 
					                    sb.Append("WHEN NOT MATCHED THEN \r\n")
 | 
				
			||||||
 | 
					                        .Append("  insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
 | 
				
			||||||
 | 
					                        .Append("  values (").Append(string.Join(", ", cols.Select(a =>
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            //InsertValueSql = "seq.nextval"
 | 
				
			||||||
 | 
					                            if (tempPrimaryIsIdentity == false && a.Attribute.IsIdentity && string.IsNullOrEmpty(a.DbInsertValue) == false) return a.DbInsertValue;
 | 
				
			||||||
 | 
					                            return $"t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}";
 | 
				
			||||||
 | 
					                        }))).Append(")");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return sb.ToString();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            string getInsertSql(List<T1> data)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var insert = _orm.Insert<T1>()
 | 
				
			||||||
 | 
					                    .AsTable(_tableRule).AsType(_table.Type)
 | 
				
			||||||
 | 
					                    .WithConnection(_connection)
 | 
				
			||||||
 | 
					                    .WithTransaction(_transaction)
 | 
				
			||||||
 | 
					                    .NoneParameter(true) as Internal.CommonProvider.InsertProvider<T1>;
 | 
				
			||||||
 | 
					                insert._source = data;
 | 
				
			||||||
 | 
					                insert._table = _table;
 | 
				
			||||||
 | 
					                var sql = insert.ToSql();
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(sql)) return null;
 | 
				
			||||||
 | 
					                if (insert._params?.Any() == true) dbParams.AddRange(insert._params);
 | 
				
			||||||
 | 
					                return sql;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					             
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										216
									
								
								Providers/FreeSql.Provider.Xugu/Curd/XuguSelect.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								Providers/FreeSql.Provider.Xugu/Curd/XuguSelect.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,216 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Xugu.Curd
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class XuguSelect<T1> : FreeSql.Internal.CommonProvider.Select1Provider<T1>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        internal static string ToSqlStatic(CommonUtils _commonUtils, CommonExpression _commonExpression, string _select, bool _distinct, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List<SelectTableInfo> _tables, List<Dictionary<Type, string>> tbUnions, Func<Type, string, string> _aliasRule, string _tosqlAppendContent, List<GlobalFilter.Item> _whereGlobalFilter, IFreeSql _orm)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_orm.CodeFirst.IsAutoSyncStructure)
 | 
				
			||||||
 | 
					                _orm.CodeFirst.SyncStructure(_tables.Select(a => a.Table.Type).ToArray());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (_whereGlobalFilter.Any())
 | 
				
			||||||
 | 
					                foreach (var tb in _tables.Where(a => a.Type != SelectTableInfoType.Parent))
 | 
				
			||||||
 | 
					                    tb.Cascade = _commonExpression.GetWhereCascadeSql(tb, _whereGlobalFilter, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sb = new StringBuilder();
 | 
				
			||||||
 | 
					            var tbUnionsGt0 = tbUnions.Count > 1;
 | 
				
			||||||
 | 
					            for (var tbUnionsIdx = 0; tbUnionsIdx < tbUnions.Count; tbUnionsIdx++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (tbUnionsIdx > 0) sb.Append("\r\n \r\nUNION ALL\r\n \r\n");
 | 
				
			||||||
 | 
					                if (tbUnionsGt0) sb.Append(_select).Append(" * from (");
 | 
				
			||||||
 | 
					                var tbUnion = tbUnions[tbUnionsIdx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var sbnav = new StringBuilder();
 | 
				
			||||||
 | 
					                sb.Append(_select);
 | 
				
			||||||
 | 
					                if (_distinct) sb.Append("DISTINCT ");
 | 
				
			||||||
 | 
					                sb.Append(field).Append(" \r\nFROM ");
 | 
				
			||||||
 | 
					                var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray();
 | 
				
			||||||
 | 
					                var tbsfrom = _tables.Where(a => a.Type == SelectTableInfoType.From).ToArray();
 | 
				
			||||||
 | 
					                for (var a = 0; a < tbsfrom.Length; a++)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    sb.Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[a].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[a].Table.Type, tbsfrom[a].Alias) ?? tbsfrom[a].Alias);
 | 
				
			||||||
 | 
					                    if (tbsjoin.Length > 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        //如果存在 join 查询,则处理 from t1, t2 改为 from t1 inner join t2 on 1 = 1
 | 
				
			||||||
 | 
					                        for (var b = 1; b < tbsfrom.Length; b++)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            sb.Append(" \r\nLEFT JOIN ").Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[b].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[b].Table.Type, tbsfrom[b].Alias) ?? tbsfrom[b].Alias);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if (string.IsNullOrEmpty(tbsfrom[b].NavigateCondition) && string.IsNullOrEmpty(tbsfrom[b].On) && string.IsNullOrEmpty(tbsfrom[b].Cascade)) sb.Append(" ON 1 = 1");
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                var onSql = tbsfrom[b].NavigateCondition ?? tbsfrom[b].On;
 | 
				
			||||||
 | 
					                                sb.Append(" ON ").Append(onSql);
 | 
				
			||||||
 | 
					                                if (string.IsNullOrEmpty(tbsfrom[b].Cascade) == false)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    if (string.IsNullOrEmpty(onSql)) sb.Append(tbsfrom[b].Cascade);
 | 
				
			||||||
 | 
					                                    else sb.Append(" AND ").Append(tbsfrom[b].Cascade);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (!string.IsNullOrEmpty(tbsfrom[a].NavigateCondition)) sbnav.Append(" AND (").Append(tbsfrom[a].NavigateCondition).Append(")");
 | 
				
			||||||
 | 
					                        if (!string.IsNullOrEmpty(tbsfrom[a].On)) sbnav.Append(" AND (").Append(tbsfrom[a].On).Append(")");
 | 
				
			||||||
 | 
					                        if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].Cascade)) sbnav.Append(" AND ").Append(tbsfrom[a].Cascade);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (a < tbsfrom.Length - 1) sb.Append(", ");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                foreach (var tb in tbsjoin)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    switch (tb.Type)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        case SelectTableInfoType.Parent:
 | 
				
			||||||
 | 
					                        case SelectTableInfoType.RawJoin:
 | 
				
			||||||
 | 
					                            continue;
 | 
				
			||||||
 | 
					                        case SelectTableInfoType.LeftJoin:
 | 
				
			||||||
 | 
					                            sb.Append(" \r\nLEFT JOIN ");
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        case SelectTableInfoType.InnerJoin:
 | 
				
			||||||
 | 
					                            sb.Append(" \r\nINNER JOIN ");
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        case SelectTableInfoType.RightJoin:
 | 
				
			||||||
 | 
					                            sb.Append(" \r\nRIGHT JOIN ");
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    sb.Append(_commonUtils.QuoteSqlName(tbUnion[tb.Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tb.Table.Type, tb.Alias) ?? tb.Alias).Append(" ON ").Append(tb.On ?? tb.NavigateCondition);
 | 
				
			||||||
 | 
					                    if (!string.IsNullOrEmpty(tb.Cascade)) sb.Append(" AND ").Append(tb.Cascade);
 | 
				
			||||||
 | 
					                    if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (_join.Length > 0) sb.Append(_join);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                sbnav.Append(_where);
 | 
				
			||||||
 | 
					                if (!string.IsNullOrEmpty(_tables[0].Cascade))
 | 
				
			||||||
 | 
					                    sbnav.Append(" AND ").Append(_tables[0].Cascade);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (sbnav.Length > 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    sb.Append(" \r\nWHERE ").Append(sbnav.Remove(0, 5));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_groupby) == false)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    sb.Append(_groupby);
 | 
				
			||||||
 | 
					                    if (string.IsNullOrEmpty(_having) == false)
 | 
				
			||||||
 | 
					                        sb.Append(" \r\nHAVING ").Append(_having.Substring(5));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                sb.Append(_orderby);
 | 
				
			||||||
 | 
					                if (_limit > 0) {
 | 
				
			||||||
 | 
					                    sb.Append(" \r\nlimit ").Append(_limit);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					       
 | 
				
			||||||
 | 
					                if (_skip > 0)
 | 
				
			||||||
 | 
					                    sb.Append(" \r\noffset ").Append(_skip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                sbnav.Clear();
 | 
				
			||||||
 | 
					                if (tbUnionsGt0) sb.Append(") ftb");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return sb.Append(_tosqlAppendContent).ToString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public XuguSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2> From<T2>(Expression<Func<ISelectFromExpression<T1>, T2, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T2 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> where T2 : class where T3 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4> where T2 : class where T3 : class where T4 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3, T4, T5> : FreeSql.Internal.CommonProvider.Select5Provider<T1, T2, T3, T4, T5> where T2 : class where T3 : class where T4 : class where T5 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3, T4, T5, T6> : FreeSql.Internal.CommonProvider.Select6Provider<T1, T2, T3, T4, T5, T6> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7> : FreeSql.Internal.CommonProvider.Select7Provider<T1, T2, T3, T4, T5, T6, T7> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8> : FreeSql.Internal.CommonProvider.Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> : FreeSql.Internal.CommonProvider.Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : FreeSql.Internal.CommonProvider.Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> : FreeSql.Internal.CommonProvider.Select11Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> : FreeSql.Internal.CommonProvider.Select12Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> : FreeSql.Internal.CommonProvider.Select13Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> : FreeSql.Internal.CommonProvider.Select14Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class where T14 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> : FreeSql.Internal.CommonProvider.Select15Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class where T14 : class where T15 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> : FreeSql.Internal.CommonProvider.Select16Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class where T14 : class where T15 : class where T16 : class
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
				
			||||||
 | 
					        public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										187
									
								
								Providers/FreeSql.Provider.Xugu/Curd/XuguUpdate.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								Providers/FreeSql.Provider.Xugu/Curd/XuguUpdate.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,187 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Xugu.Curd
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class XuguUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public XuguUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
 | 
				
			||||||
 | 
					            : base(orm, commonUtils, commonExpression, dywhere)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        internal string InternalTableAlias { get; set; }
 | 
				
			||||||
 | 
					        internal StringBuilder InternalSbSet => _set;
 | 
				
			||||||
 | 
					        internal StringBuilder InternalSbSetIncr => _setIncr;
 | 
				
			||||||
 | 
					        internal Dictionary<string, bool> InternalIgnore => _ignore;
 | 
				
			||||||
 | 
					        internal void InternalResetSource(List<T1> source) => _source = source;
 | 
				
			||||||
 | 
					        internal string InternalWhereCaseSource(string CsName, Func<string, string> thenValue) => WhereCaseSource(CsName, thenValue);
 | 
				
			||||||
 | 
					        internal void InternalToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col) => ToSqlCaseWhenEnd(sb, col);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
 | 
					        public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected override List<T1> RawExecuteUpdated()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var ret = new List<T1>();
 | 
				
			||||||
 | 
					            DbParameter[] dbParms = null;
 | 
				
			||||||
 | 
					            StringBuilder sbret = null;
 | 
				
			||||||
 | 
					            ToSqlFetch(sb =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (dbParms == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    dbParms = _params.Concat(_paramsSource).ToArray();
 | 
				
			||||||
 | 
					                    sbret = new StringBuilder();
 | 
				
			||||||
 | 
					                    sbret.Append(" RETURNING ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var colidx = 0;
 | 
				
			||||||
 | 
					                    foreach (var col in _table.Columns.Values)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (colidx > 0) sbret.Append(", ");
 | 
				
			||||||
 | 
					                        sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
				
			||||||
 | 
					                        ++colidx;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                var sql = sb.Append(sbret).ToString();
 | 
				
			||||||
 | 
					                var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
 | 
				
			||||||
 | 
					                _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Exception exception = null;
 | 
				
			||||||
 | 
					                try
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var rettmp = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms);
 | 
				
			||||||
 | 
					                    ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
 | 
				
			||||||
 | 
					                    ret.AddRange(rettmp);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                catch (Exception ex)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    exception = ex;
 | 
				
			||||||
 | 
					                    throw;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                finally
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
				
			||||||
 | 
					                    _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            sbret?.Clear();
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (primarys.Length == 1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var pk = primarys.First();
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
 | 
				
			||||||
 | 
					                caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            caseWhen.Append("(");
 | 
				
			||||||
 | 
					            var pkidx = 0;
 | 
				
			||||||
 | 
					            foreach (var pk in primarys)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (pkidx > 0) caseWhen.Append(" || '+' || ");
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
 | 
				
			||||||
 | 
					                caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name))).Append("::text");
 | 
				
			||||||
 | 
					                ++pkidx;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            caseWhen.Append(")");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (primarys.Length == 1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                sb.Append(_commonUtils.FormatSql("{0}", primarys[0].GetDbValue(d)));
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            sb.Append("(");
 | 
				
			||||||
 | 
					            var pkidx = 0;
 | 
				
			||||||
 | 
					            foreach (var pk in primarys)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (pkidx > 0) sb.Append(" || '+' || ");
 | 
				
			||||||
 | 
					                sb.Append(_commonUtils.FormatSql("{0}", pk.GetDbValue(d))).Append("::text");
 | 
				
			||||||
 | 
					                ++pkidx;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            sb.Append(")");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected override void ToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_noneParameter == false) return;
 | 
				
			||||||
 | 
					            if (col.Attribute.MapType == typeof(string))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                sb.Append("::text");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var dbtype = _commonUtils.CodeFirst.GetDbInfo(col.Attribute.MapType)?.dbtype;
 | 
				
			||||||
 | 
					            if (dbtype == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            sb.Append("::").Append(dbtype);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if net40
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
 | 
				
			||||||
 | 
					        public override Task<List<T1>> ExecuteUpdatedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        async protected override Task<List<T1>> RawExecuteUpdatedAsync(CancellationToken cancellationToken = default)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var ret = new List<T1>();
 | 
				
			||||||
 | 
					            DbParameter[] dbParms = null;
 | 
				
			||||||
 | 
					            StringBuilder sbret = null;
 | 
				
			||||||
 | 
					            await ToSqlFetchAsync(async sb =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (dbParms == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    dbParms = _params.Concat(_paramsSource).ToArray();
 | 
				
			||||||
 | 
					                    sbret = new StringBuilder();
 | 
				
			||||||
 | 
					                    sbret.Append(" RETURNING ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var colidx = 0;
 | 
				
			||||||
 | 
					                    foreach (var col in _table.Columns.Values)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (colidx > 0) sbret.Append(", ");
 | 
				
			||||||
 | 
					                        sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
				
			||||||
 | 
					                        ++colidx;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                var sql = sb.Append(sbret).ToString();
 | 
				
			||||||
 | 
					                var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
 | 
				
			||||||
 | 
					                _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Exception exception = null;
 | 
				
			||||||
 | 
					                try
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var rettmp = await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
 | 
				
			||||||
 | 
					                    ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
 | 
				
			||||||
 | 
					                    ret.AddRange(rettmp);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                catch (Exception ex)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    exception = ex;
 | 
				
			||||||
 | 
					                    throw;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                finally
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
				
			||||||
 | 
					                    _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            sbret?.Clear();
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										107
									
								
								Providers/FreeSql.Provider.Xugu/XuguAdo/XuguAdo.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								Providers/FreeSql.Provider.Xugu/XuguAdo/XuguAdo.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using FreeSql.Internal.ObjectPool;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					using XuguClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Xugu
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    class XuguAdo : FreeSql.Internal.CommonProvider.AdoProvider
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public XuguAdo() : base(DataType.PostgreSQL, null, null) { }
 | 
				
			||||||
 | 
					        public XuguAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func<DbConnection> connectionFactory) : base(DataType.PostgreSQL, masterConnectionString, slaveConnectionStrings)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            base._util = util; 
 | 
				
			||||||
 | 
					            if (connectionFactory != null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                MasterPool = new FreeSql.Internal.CommonProvider.DbConnectionPool(DataType.PostgreSQL, connectionFactory);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (!string.IsNullOrEmpty(masterConnectionString))
 | 
				
			||||||
 | 
					                MasterPool = new XuguConnectionPool(CoreStrings.S_MasterDatabase, masterConnectionString, null, null);
 | 
				
			||||||
 | 
					            if (slaveConnectionStrings != null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                foreach (var slaveConnectionString in slaveConnectionStrings)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var slavePool = new XuguConnectionPool($"{CoreStrings.S_SlaveDatabase}{SlavePools.Count + 1}", slaveConnectionString, () => Interlocked.Decrement(ref slaveUnavailables), () => Interlocked.Increment(ref slaveUnavailables));
 | 
				
			||||||
 | 
					                    SlavePools.Add(slavePool);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override object AddslashesProcessParam(object param, Type mapType, ColumnInfo mapColumn)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (param == null) return "NULL";
 | 
				
			||||||
 | 
					            if (mapType != null && mapType != param.GetType() && (param is IEnumerable == false || param is JToken || param is JObject || param is JArray))
 | 
				
			||||||
 | 
					                param = Utils.GetDataReaderValue(mapType, param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            bool isdic;
 | 
				
			||||||
 | 
					            if (param is bool || param is bool?)
 | 
				
			||||||
 | 
					                return (bool)param ? "'t'" : "'f'";
 | 
				
			||||||
 | 
					            else if (param is string)
 | 
				
			||||||
 | 
					                return string.Concat("'", param.ToString().Replace("'", "''"), "'");
 | 
				
			||||||
 | 
					            else if (param is char)
 | 
				
			||||||
 | 
					                return string.Concat("'", param.ToString().Replace("'", "''").Replace('\0', ' '), "'");
 | 
				
			||||||
 | 
					            else if (param is Enum)
 | 
				
			||||||
 | 
					                return ((Enum)param).ToInt64();
 | 
				
			||||||
 | 
					            else if (decimal.TryParse(string.Concat(param), out var trydec))
 | 
				
			||||||
 | 
					                return param;
 | 
				
			||||||
 | 
					            else if (param is DateTime || param is DateTime?)
 | 
				
			||||||
 | 
					                return string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'");
 | 
				
			||||||
 | 
					            else if (param is TimeSpan || param is TimeSpan?)
 | 
				
			||||||
 | 
					                return ((TimeSpan)param).Ticks / 10;
 | 
				
			||||||
 | 
					            else if (param is byte[])
 | 
				
			||||||
 | 
					                return $"'\\x{CommonUtils.BytesSqlRaw(param as byte[])}'";
 | 
				
			||||||
 | 
					            else if (param is JToken || param is JObject || param is JArray)
 | 
				
			||||||
 | 
					                return string.Concat("'", param.ToString().Replace("'", "''"), "'::jsonb");
 | 
				
			||||||
 | 
					            else if ((isdic = param is Dictionary<string, string>) ||
 | 
				
			||||||
 | 
					                param is IEnumerable<KeyValuePair<string, string>>)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var pgdics = isdic ? param as Dictionary<string, string> :
 | 
				
			||||||
 | 
					                    param as IEnumerable<KeyValuePair<string, string>>;
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                var pghstore = new StringBuilder("'");
 | 
				
			||||||
 | 
					                var pairs = pgdics.ToArray();
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                for (var i = 0; i < pairs.Length; i++)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (i != 0) pghstore.Append(",");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    pghstore.AppendFormat("\"{0}\"=>", pairs[i].Key.Replace("'", "''"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (pairs[i].Value == null)
 | 
				
			||||||
 | 
					                        pghstore.Append("NULL");
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                        pghstore.AppendFormat("\"{0}\"", pairs[i].Value.Replace("'", "''"));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                return pghstore.Append("'::hstore");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (param is IEnumerable)
 | 
				
			||||||
 | 
					                return AddslashesIEnumerable(param, mapType, mapColumn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return string.Concat("'", param.ToString().Replace("'", "''"), "'");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override DbCommand CreateCommand()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new XGCommand();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void ReturnConnection(IObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var rawPool = pool as XuguConnectionPool;
 | 
				
			||||||
 | 
					            if (rawPool != null) rawPool.Return(conn, ex);
 | 
				
			||||||
 | 
					            else pool.Return(conn);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										239
									
								
								Providers/FreeSql.Provider.Xugu/XuguAdo/XuguConnectionPool.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								Providers/FreeSql.Provider.Xugu/XuguAdo/XuguConnectionPool.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,239 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal.ObjectPool;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
 | 
					using System.Text.RegularExpressions;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Xugu
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class XuguConnectionPool : ObjectPool<DbConnection>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        internal Action availableHandler;
 | 
				
			||||||
 | 
					        internal Action unavailableHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public XuguConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.availableHandler = availableHandler;
 | 
				
			||||||
 | 
					            this.unavailableHandler = unavailableHandler;
 | 
				
			||||||
 | 
					            var policy = new XuguConnectionPoolPolicy
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _pool = this,
 | 
				
			||||||
 | 
					                Name = name
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            this.Policy = policy;
 | 
				
			||||||
 | 
					            policy.ConnectionString = connectionString;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void Return(Object<DbConnection> obj, Exception exception, bool isRecreate = false)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            //if (exception != null && exception is NpgsqlException)
 | 
				
			||||||
 | 
					            //{
 | 
				
			||||||
 | 
					            //    if (obj.Value.Ping() == false)
 | 
				
			||||||
 | 
					            //        base.SetUnavailable(exception, obj.LastGetTimeCopy);
 | 
				
			||||||
 | 
					            //}
 | 
				
			||||||
 | 
					            base.Return(obj, isRecreate);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class XuguConnectionPoolPolicy : IPolicy<DbConnection>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        internal XuguConnectionPool _pool;
 | 
				
			||||||
 | 
					        public string Name { get; set; } = $"Xugu XuguConnection {CoreStrings.S_ObjectPool}";
 | 
				
			||||||
 | 
					        public int PoolSize { get; set; } = 50;
 | 
				
			||||||
 | 
					        public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
 | 
				
			||||||
 | 
					        public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromSeconds(20);
 | 
				
			||||||
 | 
					        public int AsyncGetCapacity { get; set; } = 10000;
 | 
				
			||||||
 | 
					        public bool IsThrowGetTimeoutException { get; set; } = true;
 | 
				
			||||||
 | 
					        public bool IsAutoDisposeWithSystem { get; set; } = true;
 | 
				
			||||||
 | 
					        public int CheckAvailableInterval { get; set; } = 2;
 | 
				
			||||||
 | 
					        public int Weight { get; set; } = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static ConcurrentDictionary<string, int> dicConnStrIncr = new ConcurrentDictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
 | 
				
			||||||
 | 
					        private string _connectionString;
 | 
				
			||||||
 | 
					        public string ConnectionString
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            get => _connectionString;
 | 
				
			||||||
 | 
					            set
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _connectionString = value ?? "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var minPoolSize = 0;
 | 
				
			||||||
 | 
					                var pattern = @"Min(imum)?\s*pool\s*size\s*=\s*(\d+)";
 | 
				
			||||||
 | 
					                var m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
 | 
				
			||||||
 | 
					                if (m.Success)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    minPoolSize = int.Parse(m.Groups[2].Value);
 | 
				
			||||||
 | 
					                    _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                pattern = @"Max(imum)?\s*pool\s*size\s*=\s*(\d+)";
 | 
				
			||||||
 | 
					                m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
 | 
				
			||||||
 | 
					                if (m.Success == false || int.TryParse(m.Groups[2].Value, out var poolsize) == false || poolsize <= 0) poolsize = Math.Max(50, minPoolSize);
 | 
				
			||||||
 | 
					                var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => Math.Min(5, oldval + 1));
 | 
				
			||||||
 | 
					                PoolSize = poolsize + connStrIncr;
 | 
				
			||||||
 | 
					                _connectionString = m.Success ?
 | 
				
			||||||
 | 
					                    Regex.Replace(_connectionString, pattern, $"Maximum pool size={PoolSize}", RegexOptions.IgnoreCase) :
 | 
				
			||||||
 | 
					                    $"{_connectionString};Maximum pool size={PoolSize}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                pattern = @"Connection\s*LifeTime\s*=\s*(\d+)";
 | 
				
			||||||
 | 
					                m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
 | 
				
			||||||
 | 
					                if (m.Success)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value));
 | 
				
			||||||
 | 
					                    _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                FreeSql.Internal.CommonUtils.PrevReheatConnectionPool(_pool, minPoolSize);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public bool OnCheckAvailable(Object<DbConnection> obj)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (obj.Value == null) return false;
 | 
				
			||||||
 | 
					            if (obj.Value.State == ConnectionState.Closed) obj.Value.Open();
 | 
				
			||||||
 | 
					            return obj.Value.Ping(true);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DbConnection OnCreate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var conn = new XuguClient.XGConnection(_connectionString);
 | 
				
			||||||
 | 
					            return conn;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void OnDestroy(DbConnection obj)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try { if (obj.State != ConnectionState.Closed) obj.Close(); } catch { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //try { XuguClient.XGConnection.ClearPool(obj as XuguClient.XGConnection); } catch { }
 | 
				
			||||||
 | 
					            obj.Dispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void OnGet(Object<DbConnection> obj)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (_pool.IsAvailable)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (obj.Value == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _pool.SetUnavailable(new Exception(CoreStrings.S_ConnectionStringError), obj.LastGetTimeCopy);
 | 
				
			||||||
 | 
					                    throw new Exception(CoreStrings.S_ConnectionStringError_Check(this.Name));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && obj.Value.Ping() == false)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    try
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        obj.Value.Open();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch (Exception ex)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (_pool.SetUnavailable(ex, obj.LastGetTimeCopy) == true)
 | 
				
			||||||
 | 
					                            throw new Exception($"【{this.Name}】Block access and wait for recovery: {ex.Message}");
 | 
				
			||||||
 | 
					                        throw ex;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if net40
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        async public Task OnGetAsync(Object<DbConnection> obj)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (_pool.IsAvailable)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (obj.Value == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _pool.SetUnavailable(new Exception(CoreStrings.S_ConnectionStringError), obj.LastGetTimeCopy);
 | 
				
			||||||
 | 
					                    throw new Exception(CoreStrings.S_ConnectionStringError_Check(this.Name));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && (await obj.Value.PingAsync()) == false)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    try
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        await obj.Value.OpenAsync();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch (Exception ex)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (_pool.SetUnavailable(ex, obj.LastGetTimeCopy) == true)
 | 
				
			||||||
 | 
					                            throw new Exception($"【{this.Name}】Block access and wait for recovery: {ex.Message}");
 | 
				
			||||||
 | 
					                        throw ex;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void OnGetTimeout()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void OnReturn(Object<DbConnection> obj)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            //if (obj?.Value != null && obj.Value.State != ConnectionState.Closed) try { obj.Value.Close(); } catch { }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void OnAvailable()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pool.availableHandler?.Invoke();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void OnUnavailable()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _pool.unavailableHandler?.Invoke();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static class DbConnectionExtensions
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static DbCommand PingCommand(DbConnection conn)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var cmd = conn.CreateCommand();
 | 
				
			||||||
 | 
					            cmd.CommandTimeout = 5;
 | 
				
			||||||
 | 
					            cmd.CommandText = "select 1";
 | 
				
			||||||
 | 
					            return cmd;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public static bool Ping(this DbConnection that, bool isThrow = false)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                PingCommand(that).ExecuteNonQuery();
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
 | 
				
			||||||
 | 
					                if (isThrow) throw;
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if net40
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        async public static Task<bool> PingAsync(this DbConnection that, bool isThrow = false)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                await PingCommand(that).ExecuteNonQueryAsync();
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
 | 
				
			||||||
 | 
					                if (isThrow) throw;
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										155
									
								
								Providers/FreeSql.Provider.Xugu/XuguAdo/XuguTypesConverter.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								Providers/FreeSql.Provider.Xugu/XuguAdo/XuguTypesConverter.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
				
			|||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Net.NetworkInformation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Newtonsoft.Json
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class XuguTypesConverter : JsonConverter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private static readonly Type typeof_BitArray = typeof(BitArray);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_NpgsqlPoint = typeof(NpgsqlPoint);
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_NpgsqlLine = typeof(NpgsqlLine);
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_NpgsqlLSeg = typeof(NpgsqlLSeg);
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_NpgsqlBox = typeof(NpgsqlBox);
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_NpgsqlPath = typeof(NpgsqlPath);
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_NpgsqlPolygon = typeof(NpgsqlPolygon);
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_NpgsqlCircle = typeof(NpgsqlCircle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_Cidr = typeof((IPAddress, int));
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_IPAddress = typeof(IPAddress);
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_PhysicalAddress = typeof(PhysicalAddress);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private static readonly Type typeof_String = typeof(string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_NpgsqlRange_int = typeof(NpgsqlRange<int>);
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_NpgsqlRange_long = typeof(NpgsqlRange<long>);
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_NpgsqlRange_decimal = typeof(NpgsqlRange<decimal>);
 | 
				
			||||||
 | 
					        //private static readonly Type typeof_NpgsqlRange_DateTime = typeof(NpgsqlRange<DateTime>);
 | 
				
			||||||
 | 
					        public override bool CanConvert(Type objectType)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Type ctype = objectType.IsArray ? objectType.GetElementType() : objectType;
 | 
				
			||||||
 | 
					            var ctypeGenericType1 = ctype.GenericTypeArguments.FirstOrDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (ctype == typeof_BitArray) return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //if (ctype == typeof_NpgsqlPoint || ctypeGenericType1 == typeof_NpgsqlPoint) return true;
 | 
				
			||||||
 | 
					            //if (ctype == typeof_NpgsqlLine || ctypeGenericType1 == typeof_NpgsqlLine) return true;
 | 
				
			||||||
 | 
					            //if (ctype == typeof_NpgsqlLSeg || ctypeGenericType1 == typeof_NpgsqlLSeg) return true;
 | 
				
			||||||
 | 
					            //if (ctype == typeof_NpgsqlBox || ctypeGenericType1 == typeof_NpgsqlBox) return true;
 | 
				
			||||||
 | 
					            //if (ctype == typeof_NpgsqlPath || ctypeGenericType1 == typeof_NpgsqlPath) return true;
 | 
				
			||||||
 | 
					            //if (ctype == typeof_NpgsqlPolygon || ctypeGenericType1 == typeof_NpgsqlPolygon) return true;
 | 
				
			||||||
 | 
					            //if (ctype == typeof_NpgsqlCircle || ctypeGenericType1 == typeof_NpgsqlCircle) return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //if (ctype == typeof_Cidr || ctypeGenericType1 == typeof_Cidr) return true;
 | 
				
			||||||
 | 
					            //if (ctype == typeof_IPAddress) return true;
 | 
				
			||||||
 | 
					            //if (ctype == typeof_PhysicalAddress) return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //if (ctype == typeof_NpgsqlRange_int || ctypeGenericType1 == typeof_NpgsqlRange_int) return true;
 | 
				
			||||||
 | 
					            //if (ctype == typeof_NpgsqlRange_long || ctypeGenericType1 == typeof_NpgsqlRange_long) return true;
 | 
				
			||||||
 | 
					            //if (ctype == typeof_NpgsqlRange_decimal || ctypeGenericType1 == typeof_NpgsqlRange_decimal) return true;
 | 
				
			||||||
 | 
					            //if (ctype == typeof_NpgsqlRange_DateTime || ctypeGenericType1 == typeof_NpgsqlRange_DateTime) return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        private object YieldJToken(Type ctype, JToken jt, int rank)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (jt.Type == JTokenType.Null) return null;
 | 
				
			||||||
 | 
					            if (rank == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var ctypeGenericType1 = ctype.GenericTypeArguments.FirstOrDefault();//ctype.Namespace == "System" && ctype.Name.StartsWith("Nullable`") ? ctype.GenericTypeArguments.FirstOrDefault() : null;
 | 
				
			||||||
 | 
					                if (ctype == typeof_BitArray) return jt.ToString().ToBitArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //if (ctype == typeof_NpgsqlPoint || ctypeGenericType1 == typeof_NpgsqlPoint) return NpgsqlPoint.Parse(jt.ToString());
 | 
				
			||||||
 | 
					                //if (ctype == typeof_NpgsqlLine || ctypeGenericType1 == typeof_NpgsqlLine) return NpgsqlLine.Parse(jt.ToString());
 | 
				
			||||||
 | 
					                //if (ctype == typeof_NpgsqlLSeg || ctypeGenericType1 == typeof_NpgsqlLSeg) return NpgsqlLSeg.Parse(jt.ToString());
 | 
				
			||||||
 | 
					                //if (ctype == typeof_NpgsqlBox || ctypeGenericType1 == typeof_NpgsqlBox) return NpgsqlBox.Parse(jt.ToString());
 | 
				
			||||||
 | 
					                //if (ctype == typeof_NpgsqlPath || ctypeGenericType1 == typeof_NpgsqlPath) return NpgsqlPath.Parse(jt.ToString());
 | 
				
			||||||
 | 
					                //if (ctype == typeof_NpgsqlPolygon || ctypeGenericType1 == typeof_NpgsqlPolygon) return NpgsqlPolygon.Parse(jt.ToString());
 | 
				
			||||||
 | 
					                //if (ctype == typeof_NpgsqlCircle || ctypeGenericType1 == typeof_NpgsqlCircle) return NpgsqlCircle.Parse(jt.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //if (ctype == typeof_Cidr || ctypeGenericType1 == typeof_Cidr)
 | 
				
			||||||
 | 
					                //{
 | 
				
			||||||
 | 
					                //    var cidrArgs = jt.ToString().Split(new[] { '/' }, 2);
 | 
				
			||||||
 | 
					                //    return (IPAddress.Parse(cidrArgs.First()), cidrArgs.Length >= 2 ? int.TryParse(cidrArgs[1], out var tryCdirSubnet) ? tryCdirSubnet : 0 : 0);
 | 
				
			||||||
 | 
					                //}
 | 
				
			||||||
 | 
					                //if (ctype == typeof_IPAddress) return IPAddress.Parse(jt.ToString());
 | 
				
			||||||
 | 
					                //if (ctype == typeof_PhysicalAddress) return PhysicalAddress.Parse(jt.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //if (ctype == typeof_NpgsqlRange_int || ctypeGenericType1 == typeof_NpgsqlRange_int) return jt.ToString().ToNpgsqlRange<int>();
 | 
				
			||||||
 | 
					                //if (ctype == typeof_NpgsqlRange_long || ctypeGenericType1 == typeof_NpgsqlRange_long) return jt.ToString().ToNpgsqlRange<long>();
 | 
				
			||||||
 | 
					                //if (ctype == typeof_NpgsqlRange_decimal || ctypeGenericType1 == typeof_NpgsqlRange_decimal) return jt.ToString().ToNpgsqlRange<decimal>();
 | 
				
			||||||
 | 
					                //if (ctype == typeof_NpgsqlRange_DateTime || ctypeGenericType1 == typeof_NpgsqlRange_DateTime) return jt.ToString().ToNpgsqlRange<DateTime>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var jtarr = jt.ToArray();
 | 
				
			||||||
 | 
					            var ret = Array.CreateInstance(ctype, jtarr.Length);
 | 
				
			||||||
 | 
					            var jtarrIdx = 0;
 | 
				
			||||||
 | 
					            foreach (var a in jtarr)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var t2 = YieldJToken(ctype, a, rank - 1);
 | 
				
			||||||
 | 
					                ret.SetValue(t2, jtarrIdx++);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            int rank = objectType.IsArray ? objectType.GetArrayRank() : 0;
 | 
				
			||||||
 | 
					            Type ctype = objectType.IsArray ? objectType.GetElementType() : objectType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var ret = YieldJToken(ctype, JToken.Load(reader), rank);
 | 
				
			||||||
 | 
					            if (ret != null && rank > 0) return ret;
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Type objectType = value.GetType();
 | 
				
			||||||
 | 
					            if (objectType.IsArray)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                int rank = objectType.GetArrayRank();
 | 
				
			||||||
 | 
					                int[] indices = new int[rank];
 | 
				
			||||||
 | 
					                GetJObject(value as Array, indices, 0).WriteTo(writer);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                GetJObject(value).WriteTo(writer);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public static JToken GetJObject(object value)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (value is BitArray) return JToken.FromObject((value as BitArray)?.To1010());
 | 
				
			||||||
 | 
					            if (value is IPAddress) return JToken.FromObject((value as IPAddress)?.ToString());
 | 
				
			||||||
 | 
					            if (value is ValueTuple<IPAddress, int> || value is ValueTuple<IPAddress, int>?)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ValueTuple<IPAddress, int>? cidrValue = (ValueTuple<IPAddress, int>?)value;
 | 
				
			||||||
 | 
					                return JToken.FromObject(cidrValue == null ? null : $"{cidrValue.Value.Item1.ToString()}/{cidrValue.Value.Item2.ToString()}");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return JToken.FromObject(value?.ToString());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public static JToken GetJObject(Array value, int[] indices, int idx)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (idx == indices.Length)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return GetJObject(value.GetValue(indices));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            JArray ja = new JArray();
 | 
				
			||||||
 | 
					            if (indices.Length == 1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                foreach (object a in value)
 | 
				
			||||||
 | 
					                    ja.Add(GetJObject(a));
 | 
				
			||||||
 | 
					                return ja;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            int lb = value.GetLowerBound(idx);
 | 
				
			||||||
 | 
					            int ub = value.GetUpperBound(idx);
 | 
				
			||||||
 | 
					            for (int b = lb; b <= ub; b++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                indices[idx] = b;
 | 
				
			||||||
 | 
					                ja.Add(GetJObject(value, indices, idx + 1));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ja;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					using System.Collections;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public static partial class XuguTypesExtensions
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					    public static string To1010(this BitArray ba)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        char[] ret = new char[ba.Length];
 | 
				
			||||||
 | 
					        for (int a = 0; a < ba.Length; a++) ret[a] = ba[a] ? '1' : '0';
 | 
				
			||||||
 | 
					        return new string(ret);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 将 1010101010 这样的二进制字符串转换成 BitArray
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="_1010Str">1010101010</param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public static BitArray ToBitArray(this string _1010Str)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (_1010Str == null) return null;
 | 
				
			||||||
 | 
					        BitArray ret = new BitArray(_1010Str.Length);
 | 
				
			||||||
 | 
					        for (int a = 0; a < _1010Str.Length; a++) ret[a] = _1010Str[a] == '1';
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										511
									
								
								Providers/FreeSql.Provider.Xugu/XuguCodeFirst.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										511
									
								
								Providers/FreeSql.Provider.Xugu/XuguCodeFirst.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,511 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Net.NetworkInformation;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Text.RegularExpressions;
 | 
				
			||||||
 | 
					using XuguClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Xugu
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class XuguCodeFirst : Internal.CommonProvider.CodeFirstProvider
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public readonly string DefaultSchema = "SYSDBA";//默认模式
 | 
				
			||||||
 | 
					        public XuguCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { 
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static object _dicCsToDbLock = new object();
 | 
				
			||||||
 | 
					        static Dictionary<string, CsToDb<XGDbType>> _dicCsToDb = new Dictionary<string, CsToDb<XGDbType>>() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                { 
 | 
				
			||||||
 | 
					                    typeof(byte).FullName, 
 | 
				
			||||||
 | 
					                    CsToDb.New(XGDbType.SmallInt, "TINYINT","TINYINT NOT NULL", false, false, 0) 
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                { typeof(byte?).FullName, CsToDb.New(XGDbType.SmallInt, "TINYINT", "TINYINT", false, true, null) },
 | 
				
			||||||
 | 
					                { typeof(short).FullName, CsToDb.New(XGDbType.SmallInt, "SMALLINT","SMALLINT NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(XGDbType.SmallInt, "SMALLINT", "SMALLINT", false, true, null) },
 | 
				
			||||||
 | 
					                { typeof(int).FullName, CsToDb.New(XGDbType.Int, "INTEGER","INTEGER NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(XGDbType.Int, "INTEGER", "INTEGER", false, true, null) },
 | 
				
			||||||
 | 
					                { typeof(long).FullName, CsToDb.New(XGDbType.BigInt, "BIGINT","BIGINT NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(XGDbType.BigInt, "BIGINT", "BIGINT", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                 
 | 
				
			||||||
 | 
					                { typeof(ushort).FullName, CsToDb.New(XGDbType.Int, "INT","INT NOT NULL", false, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(XGDbType.Int, "INT", "INT", false, true, null) },
 | 
				
			||||||
 | 
					                { typeof(uint).FullName, CsToDb.New(XGDbType.BigInt, "BIGINT","BIGINT NOT NULL", false, false, 0) },{ typeof(uint?).FullName, CsToDb.New(XGDbType.BigInt, "BIGINT", "BIGINT", false, true, null) },
 | 
				
			||||||
 | 
					                { typeof(ulong).FullName, CsToDb.New(XGDbType.Numeric, "NUMERIC","NUMERIC(20,0) NOT NULL", false, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(XGDbType.Numeric, "NUMERIC", "NUMERIC(20,0)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                { typeof(float).FullName, CsToDb.New(XGDbType.Real, "FLOAT","FLOAT NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(XGDbType.Real, "FLOAT", "FLOAT", false, true, null) },
 | 
				
			||||||
 | 
					                { typeof(double).FullName, CsToDb.New(XGDbType.Double, "DOUBLE","DOUBLE NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(XGDbType.Double, "DOUBLE", "DOUBLE", false, true, null) },
 | 
				
			||||||
 | 
					                { typeof(decimal).FullName, CsToDb.New(XGDbType.Numeric, "NUMERIC", "NUMERIC(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(XGDbType.Numeric, "NUMERIC", "NUMERIC(10,2)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                { typeof(string).FullName, CsToDb.New(XGDbType.VarChar, "VARCHAR", "VARCHAR(255)", false, null, "") },
 | 
				
			||||||
 | 
					               
 | 
				
			||||||
 | 
					                { typeof(char).FullName, CsToDb.New(XGDbType.Char, "CHAR", "CHAR(1)", false, null, '\0') },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //{ typeof(TimeSpan).FullName, CsToDb.New(XGDbType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(XGDbType.Time, "time", "time",false, true, null) },
 | 
				
			||||||
 | 
					                { typeof(DateTime).FullName, CsToDb.New(XGDbType.DateTime, "DATETIME", "DATETIME NOT NULL", false, false, new DateTime(1970,1,1)) },
 | 
				
			||||||
 | 
					                { typeof(DateTime?).FullName, CsToDb.New(XGDbType.DateTime, "DATETIME", "DATETIME", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                { typeof(bool).FullName, CsToDb.New(XGDbType.Bool, "BOOLEAN","BOOLEAN NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(XGDbType.Bool, "BOOLEAN","BOOLEAN", null, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                { typeof(byte[]).FullName, CsToDb.New(XGDbType.VarBinary, "blob", "blob NULL", false, null, new byte[0]) },
 | 
				
			||||||
 | 
					                 { typeof(Guid).FullName, CsToDb.New(XGDbType.Char, "char", "char(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(XGDbType.Char, "char", "char(36) NULL", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //{ typeof(Dictionary<string, string>).FullName, CsToDb.New(XGDbType.Hstore, "hstore", "hstore", false, null, new Dictionary<string, string>()) },
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override DbInfoResult GetDbInfo(Type type)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _dicCsToDb.TryGetValue(type.FullName, out var info);
 | 
				
			||||||
 | 
					            if (info == null) return null;
 | 
				
			||||||
 | 
					            return new DbInfoResult((int)info.type, info.dbtype, info.dbtypeFull, info.isnullable, info.defaultValue);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        internal static string GetXuguSqlTypeFullName(object[] row)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var a = row;
 | 
				
			||||||
 | 
					            var sqlType = string.Concat(a[1]).ToUpper();
 | 
				
			||||||
 | 
					            var data_length = long.Parse(string.Concat(a[2])); 
 | 
				
			||||||
 | 
					            var char_used = string.Concat(a[5]);
 | 
				
			||||||
 | 
					            bool.TryParse(a[9]?.ToString(), out var isVar);
 | 
				
			||||||
 | 
					            if (sqlType == "CHAR" && isVar)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                sqlType = "VARCHAR";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (data_length <= 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (sqlType.StartsWith("TIMESTAMP", StringComparison.CurrentCultureIgnoreCase))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (sqlType.StartsWith("DATETIME", StringComparison.CurrentCultureIgnoreCase))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (sqlType.StartsWith("BLOB"))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (sqlType.StartsWith("CLOB"))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					            } 
 | 
				
			||||||
 | 
					            else if (sqlType.ToUpper()== "NUMERIC")
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                //data_length=655362
 | 
				
			||||||
 | 
					                //实际类型是 NUMRIC(10,2) 计算得到的是 NUMRIC(10,12)
 | 
				
			||||||
 | 
					                //标度计算错误
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var data_precision= data_length % 65536;
 | 
				
			||||||
 | 
					                var data_scale = data_length / 65536;
 | 
				
			||||||
 | 
					                sqlType += $"({data_scale},{data_precision})";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (sqlType.ToLower() == "float")
 | 
				
			||||||
 | 
					            { }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                sqlType += $"({data_length})";
 | 
				
			||||||
 | 
					            return sqlType;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sb = new StringBuilder();
 | 
				
			||||||
 | 
					            var seqcols = new List<NativeTuple<ColumnInfo, string[], bool>>(); //序列
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var obj in objects)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (sb.Length > 0) sb.Append("\r\n");
 | 
				
			||||||
 | 
					                var tb = _commonUtils.GetTableByEntity(obj.entityType);
 | 
				
			||||||
 | 
					                if (tb == null) throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.entityType.FullName));
 | 
				
			||||||
 | 
					                if (tb.Columns.Any() == false) throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.entityType.FullName));
 | 
				
			||||||
 | 
					                var tbname = _commonUtils.SplitTableName(tb.DbName);
 | 
				
			||||||
 | 
					                if (tbname?.Length == 1) tbname = new[] { DefaultSchema, tbname[0] };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var tboldname = _commonUtils.SplitTableName(tb.DbOldName); //旧表名
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (tboldname?.Length == 1) tboldname = new[] { DefaultSchema, tboldname[0] };
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(obj.tableName) == false)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var tbtmpname = _commonUtils.SplitTableName(obj.tableName);
 | 
				
			||||||
 | 
					                    if (tbtmpname?.Length == 1) tbtmpname = new[] { DefaultSchema, tbtmpname[0] };
 | 
				
			||||||
 | 
					                    if (tbname[0] != tbtmpname[0] || tbname[1] != tbtmpname[1])
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        tbname = tbtmpname;
 | 
				
			||||||
 | 
					                        tboldname = null;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                //codefirst 不支持表名、模式名、数据库名中带 .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from all_schemas where schema_name={0}", tbname[0])) == null) //创建模式
 | 
				
			||||||
 | 
					                    throw new Exception($"模式“{tbname[0]}”不存在,请手动创建");
 | 
				
			||||||
 | 
					                    //sb.Append($"CREATE SCHEMA {tbname[0]};\r\n");
 | 
				
			||||||
 | 
					                    //sb.Append("CREATE SCHEMA IF NOT EXISTS ").Append(tbname[0]).Append(";\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var sbalter = new StringBuilder();
 | 
				
			||||||
 | 
					                var istmpatler = false; //创建临时表,导入数据,删除旧表,修改
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //虚谷
 | 
				
			||||||
 | 
					                var sql0 = string.Format("select 1 from all_tables a inner join all_schemas b on b.schema_id = a.schema_id where b.schema_name || '.' || a.table_name = '{0}.{1}'", tbname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					                //判断表是否存在
 | 
				
			||||||
 | 
					                if (_orm.Ado.ExecuteScalar(CommandType.Text, sql0) == null)
 | 
				
			||||||
 | 
					                { 
 | 
				
			||||||
 | 
					                    //表不存在
 | 
				
			||||||
 | 
					                    if (tboldname != null)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format(" select 1 from all_tables a inner join all_schemas b on b.schema_id = a.schema_id  where b.schema_name || '.' || a.table_name = '{0}.{1}'", tboldname)) == null)
 | 
				
			||||||
 | 
					                            //旧表不存在
 | 
				
			||||||
 | 
					                            tboldname = null;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (tboldname == null)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        //创建表
 | 
				
			||||||
 | 
					                        var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}");
 | 
				
			||||||
 | 
					                        sb.Append("CREATE TABLE ").Append(createTableName).Append(" ( ");
 | 
				
			||||||
 | 
					                        foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ");
 | 
				
			||||||
 | 
					                            if (tbcol.Attribute.IsIdentity == true)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                sb.Append(tbcol.Attribute.DbType.Replace("NOT NULL",""));
 | 
				
			||||||
 | 
					                                sb.Append(" identity(1,1)");
 | 
				
			||||||
 | 
					                                //seqcols.Add(NativeTuple.Create(tbcol, tbname, true));
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                sb.Append(tbcol.Attribute.DbType.Replace("NTEXT", "CLOB").Replace("TEXT", "CLOB"));
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            sb.Append(",");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (tb.Primarys.Any())
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var pkname = $"{tbname[0]}_{tbname[1]}_pkey";
 | 
				
			||||||
 | 
					                            sb.Append(" \r\n  CONSTRAINT ").Append(_commonUtils.QuoteSqlName(pkname)).Append(" PRIMARY KEY (");
 | 
				
			||||||
 | 
					                            foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
 | 
				
			||||||
 | 
					                            sb.Remove(sb.Length - 2, 2).Append("),");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        sb.Remove(sb.Length - 1, 1);
 | 
				
			||||||
 | 
					                        sb.Append("\r\n);\r\n");
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                        //创建表的索引
 | 
				
			||||||
 | 
					                        foreach (var uk in tb.Indexes)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            sb.Append("CREATE ");
 | 
				
			||||||
 | 
					                            if (uk.IsUnique) sb.Append("UNIQUE ");
 | 
				
			||||||
 | 
					                            sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(createTableName).Append("(");
 | 
				
			||||||
 | 
					                            foreach (var tbcol in uk.Columns)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
 | 
				
			||||||
 | 
					                                if (tbcol.IsDesc) sb.Append(" DESC");
 | 
				
			||||||
 | 
					                                sb.Append(", ");
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            sb.Remove(sb.Length - 2, 2).Append(");\r\n");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        //备注
 | 
				
			||||||
 | 
					                        foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            if (string.IsNullOrEmpty(tbcol.Comment) == false)
 | 
				
			||||||
 | 
					                                sb.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (string.IsNullOrEmpty(tb.Comment) == false)
 | 
				
			||||||
 | 
					                            sb.Append("COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment)).Append(";\r\n");
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    //如果新表,旧表在一个数据库和模式下,直接修改表名
 | 
				
			||||||
 | 
					                    if (string.Compare(tbname[0], tboldname[0], true) == 0)
 | 
				
			||||||
 | 
					                        sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}")).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}")).Append(";\r\n");
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        //如果新表,旧表不在一起,创建新表,导入数据,删除旧表
 | 
				
			||||||
 | 
					                        istmpatler = true;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    tboldname = null; //如果新表已经存在,不走改表名逻辑
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              
 | 
				
			||||||
 | 
					                var sql = _commonUtils.FormatSql($@"
 | 
				
			||||||
 | 
					select 
 | 
				
			||||||
 | 
					a.COL_NAME,
 | 
				
			||||||
 | 
					a.TYPE_NAME,
 | 
				
			||||||
 | 
					a.SCALE,
 | 
				
			||||||
 | 
					case when a.NOT_NULL then '0' else '1' end as is_nullable,
 | 
				
			||||||
 | 
					seq.SEQ_ID,
 | 
				
			||||||
 | 
					seq.IS_SYS,
 | 
				
			||||||
 | 
					a.COMMENTS,
 | 
				
			||||||
 | 
					tb.table_name,
 | 
				
			||||||
 | 
					ns.schema_id,
 | 
				
			||||||
 | 
					a.`VARYING`
 | 
				
			||||||
 | 
					from all_columns as a  
 | 
				
			||||||
 | 
					left join all_tables tb on a.table_id=tb.table_id
 | 
				
			||||||
 | 
					left join all_schemas ns on tb.schema_id = ns.schema_id
 | 
				
			||||||
 | 
					left join all_sequences seq on seq.SEQ_ID=a.Serial_ID
 | 
				
			||||||
 | 
					WHERE ns.SCHEMA_NAME={{0}} and tb.TABLE_NAME={{1}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					", tboldname ?? tbname);
 | 
				
			||||||
 | 
					                var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
				
			||||||
 | 
					                //从系统表读取的现有字段的基本信息
 | 
				
			||||||
 | 
					                var tbstruct = ds.ToDictionary(a => string.Concat(a[0]), a =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var sqlType = GetXuguSqlTypeFullName(a);    
 | 
				
			||||||
 | 
					                    var max_length = long.Parse(string.Concat(a[2]));
 | 
				
			||||||
 | 
					                    //long SEQ_ID =  0;
 | 
				
			||||||
 | 
					                    long.TryParse(a[4]?.ToString() ?? "0", out long SEQ_ID);
 | 
				
			||||||
 | 
					                    var SEQ_IS_SYS = (a[5]?.ToString() ?? "false")?.ToLower();
 | 
				
			||||||
 | 
					                    try
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        return new
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            column = string.Concat(a[0]),
 | 
				
			||||||
 | 
					                            sqlType = string.Concat(sqlType),
 | 
				
			||||||
 | 
					                            max_length = long.Parse(string.Concat(a[2]) ?? "0"),
 | 
				
			||||||
 | 
					                            is_nullable = string.Concat(a[3]) == "1",
 | 
				
			||||||
 | 
					                            is_identity = (SEQ_ID > 0 && SEQ_IS_SYS == "true"),
 | 
				
			||||||
 | 
					                            comment = string.Concat(a[6])
 | 
				
			||||||
 | 
					                        };
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch (Exception ex)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        throw ex;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                   
 | 
				
			||||||
 | 
					                }, StringComparer.CurrentCultureIgnoreCase);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (istmpatler == false)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    //基本信息对比 比如名称 添加列 数据类型 Identity
 | 
				
			||||||
 | 
					                    foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        //对别数据库中列和C#中的信息是否一致
 | 
				
			||||||
 | 
					                        if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
 | 
				
			||||||
 | 
					                            string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var isCommentChanged = tbstructcol.comment != (tbcol.Comment ?? "");
 | 
				
			||||||
 | 
					                            var sqlTypeSize = tbstructcol.sqlType;
 | 
				
			||||||
 | 
					                            //如果数据中是CHAR或VARCHAR 要加上C#中定义的长度
 | 
				
			||||||
 | 
					                            if (sqlTypeSize.Contains("(") == false)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                switch (sqlTypeSize)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    case "char":
 | 
				
			||||||
 | 
					                                    case "varchar":
 | 
				
			||||||
 | 
					                                        sqlTypeSize = $"{sqlTypeSize}({tbstructcol.max_length})"; break;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            var dbType = tbcol.Attribute.DbType.Replace("NTEXT", "CLOB").Replace("TEXT", "CLOB");
 | 
				
			||||||
 | 
					                            if (dbType.StartsWith(sqlTypeSize, StringComparison.CurrentCultureIgnoreCase) == false)
 | 
				
			||||||
 | 
					                                sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(tbcol.Attribute.DbType.Split(' ').First().Replace("NTEXT", "CLOB").Replace("TEXT", "CLOB")).Append(";\r\n");//为了适应FreeSQL的长文本规则采用Replace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                if (tbcol.Attribute.IsNullable != true || tbcol.Attribute.IsNullable == true && tbcol.Attribute.IsPrimary == false)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    if (tbcol.Attribute.IsNullable == false)
 | 
				
			||||||
 | 
					                                        sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" = ").Append(tbcol.DbDefaultValue).Append(" WHERE ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" IS NULL;\r\n");
 | 
				
			||||||
 | 
					                                    sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(tbcol.Attribute.IsNullable == true ? "DROP" : "SET").Append(" NOT NULL;\r\n");
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                //sbalter.Append(" identity(1,1)");
 | 
				
			||||||
 | 
					                                seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            if (string.Compare(tbstructcol.column, tbcol.Attribute.OldName, true) == 0)
 | 
				
			||||||
 | 
					                                //修改列名
 | 
				
			||||||
 | 
					                                sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(";\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if (isCommentChanged)
 | 
				
			||||||
 | 
					                                sbalter.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            continue;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        //添加列
 | 
				
			||||||
 | 
					                        sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType.Split(' ').First()).Append(";\r\n");
 | 
				
			||||||
 | 
					                        sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue).Append(";\r\n");
 | 
				
			||||||
 | 
					                        if (tbcol.Attribute.IsNullable == false) sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" SET NOT NULL;\r\n");
 | 
				
			||||||
 | 
					                        if (tbcol.Attribute.IsIdentity == true)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                   
 | 
				
			||||||
 | 
					                    var dsuksql = _commonUtils.FormatSql($@"
 | 
				
			||||||
 | 
					select 
 | 
				
			||||||
 | 
					keys,
 | 
				
			||||||
 | 
					a.index_name,
 | 
				
			||||||
 | 
					case when a.IS_UNIQUE  then 1 else 0 end as IsUnique,
 | 
				
			||||||
 | 
					t.table_name,
 | 
				
			||||||
 | 
					ns.SCHEMA_NAME,
 | 
				
			||||||
 | 
					a.IS_SYS
 | 
				
			||||||
 | 
					from all_INDEXES a
 | 
				
			||||||
 | 
					left join all_tables t on a.TABLE_ID=t.TABLE_ID
 | 
				
			||||||
 | 
					left join all_schemas ns on t.SCHEMA_ID=ns.SCHEMA_ID
 | 
				
			||||||
 | 
					WHERE a.IS_Primary = false and t.table_name={{1}} and schema_name={{0}}",
 | 
				
			||||||
 | 
					                    tboldname ?? tbname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]), string.Concat(a[4]) }).ToList();
 | 
				
			||||||
 | 
					                    foreach (var uk in tb.Indexes)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue;
 | 
				
			||||||
 | 
					                        //获取C#中定义的索引名称
 | 
				
			||||||
 | 
					                        var ukname = ReplaceIndexName(uk.Name, tbname[1]);
 | 
				
			||||||
 | 
					                        //数据库和C#定义名称一致的
 | 
				
			||||||
 | 
					                        var dsukfind1 = dsuk.FirstOrDefault(a => string.Compare(a[1], ukname, true) == 0);
 | 
				
			||||||
 | 
					                        
 | 
				
			||||||
 | 
					                        if (dsukfind1==null || //没有找到一致的索引,表示新定义的
 | 
				
			||||||
 | 
					                            dsukfind1[0].Split(',').Length!=uk.Columns.Length ||
 | 
				
			||||||
 | 
					                            uk.Columns.Any(x=>dsukfind1[0].ToLower().IndexOf( x.Column.Attribute.Name.ToLower())==-1) ||
 | 
				
			||||||
 | 
					                            uk.IsUnique != (dsukfind1[2]== "1")
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            if (dsukfind1 != null) sbalter.Append("DROP INDEX ").Append($"\"{dsukfind1[4]}\".\"{dsukfind1[3]}\".\"{ukname}\"").Append(";\r\n");
 | 
				
			||||||
 | 
					                            sbalter.Append("CREATE ");
 | 
				
			||||||
 | 
					                            if (uk.IsUnique) sbalter.Append("UNIQUE ");
 | 
				
			||||||
 | 
					                            sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append("(");
 | 
				
			||||||
 | 
					                            foreach (var tbcol in uk.Columns)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
 | 
				
			||||||
 | 
					                                //if (tbcol.IsDesc) sbalter.Append(" DESC");
 | 
				
			||||||
 | 
					                                sbalter.Append(", ");
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            sbalter.Remove(sbalter.Length - 2, 2).Append(");\r\n");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (istmpatler == false)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    //描述
 | 
				
			||||||
 | 
					                    var dbcomment = string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql($@" 
 | 
				
			||||||
 | 
					select COMMENTS,TABLE_NAME,SCHEMA_NAME from all_tables as a
 | 
				
			||||||
 | 
					left join all_schemas as b on a.SCHEMA_ID=b.SCHEMA_ID
 | 
				
			||||||
 | 
					WHERE a.Table_Name={{1}} and b.SCHEMA_NAME={{0}}
 | 
				
			||||||
 | 
					",tbname)));
 | 
				
			||||||
 | 
					                    if ((dbcomment??"") != (tb.Comment ?? ""))
 | 
				
			||||||
 | 
					                        sbalter.Append("COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment)).Append(";\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    sb.Append(sbalter);
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //约束primary key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var oldpk = _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" 
 | 
				
			||||||
 | 
					select cons_name from all_constraints as a
 | 
				
			||||||
 | 
					left join all_tables as b on a.Table_ID=b.Table_ID
 | 
				
			||||||
 | 
					left Join all_SCHEMAS AS c on b.SCHEMA_ID=c.SCHEMA_ID
 | 
				
			||||||
 | 
					where b.TABLE_NAME={0} and c.SCHEMA_NAME={1} and a.cons_TYPE='P'
 | 
				
			||||||
 | 
					", tbname))?.ToString();
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(oldpk) == false)
 | 
				
			||||||
 | 
					                    sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP CONSTRAINT ").Append(oldpk).Append(";\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名
 | 
				
			||||||
 | 
					                var tablename = tboldname == null ? _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}") : _commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //创建临时表
 | 
				
			||||||
 | 
					                var tmptablename = _commonUtils.QuoteSqlName($"{tbname[0]}.FreeSqlTmp_{tbname[1]}");
 | 
				
			||||||
 | 
					                sb.Append("CREATE TABLE IF NOT EXISTS ").Append(tmptablename).Append(" ( ");
 | 
				
			||||||
 | 
					                foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
 | 
				
			||||||
 | 
					                    if (tbcol.Attribute.IsIdentity == true)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        //sb.Append(" identity(1,1)");
 | 
				
			||||||
 | 
					                         seqcols.Add(NativeTuple.Create(tbcol, tbname, true));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    sb.Append(",");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (tb.Primarys.Any())
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var pkname = $"{tbname[0]}_{tbname[1]}_pkey";
 | 
				
			||||||
 | 
					                    sb.Append(" \r\n  CONSTRAINT ").Append(_commonUtils.QuoteSqlName(pkname)).Append(" PRIMARY KEY (");
 | 
				
			||||||
 | 
					                    foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
 | 
				
			||||||
 | 
					                    sb.Remove(sb.Length - 2, 2).Append("),");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                sb.Remove(sb.Length - 1, 1);
 | 
				
			||||||
 | 
					                sb.Append("\r\n);\r\n");
 | 
				
			||||||
 | 
					                //备注
 | 
				
			||||||
 | 
					                foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (string.IsNullOrEmpty(tbcol.Comment) == false)
 | 
				
			||||||
 | 
					                        sb.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.FreeSqlTmp_{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(tb.Comment) == false)
 | 
				
			||||||
 | 
					                    sb.Append("COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.FreeSqlTmp_{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment)).Append(";\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                sb.Append("INSERT INTO ").Append(tmptablename).Append(" (");
 | 
				
			||||||
 | 
					                foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
 | 
					                    sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
 | 
				
			||||||
 | 
					                sb.Remove(sb.Length - 2, 2).Append(")\r\nSELECT ");
 | 
				
			||||||
 | 
					                foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var insertvalue = "NULL";
 | 
				
			||||||
 | 
					                    if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
 | 
				
			||||||
 | 
					                        string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        insertvalue = _commonUtils.QuoteSqlName(tbstructcol.column);
 | 
				
			||||||
 | 
					                        if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false)
 | 
				
			||||||
 | 
					                            insertvalue = $"cast({insertvalue} as {tbcol.Attribute.DbType.Split(' ').First()})";
 | 
				
			||||||
 | 
					                        if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
 | 
				
			||||||
 | 
					                            insertvalue = $"coalesce({insertvalue},{tbcol.DbDefaultValue})";
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else if (tbcol.Attribute.IsNullable == false)
 | 
				
			||||||
 | 
					                        insertvalue = tbcol.DbDefaultValue;
 | 
				
			||||||
 | 
					                    sb.Append(insertvalue).Append(", ");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append(";\r\n");
 | 
				
			||||||
 | 
					                sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n");
 | 
				
			||||||
 | 
					                sb.Append("ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName(tbname[1])).Append(";\r\n");
 | 
				
			||||||
 | 
					                //创建表的索引
 | 
				
			||||||
 | 
					                foreach (var uk in tb.Indexes)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    sb.Append("CREATE ");
 | 
				
			||||||
 | 
					                    if (uk.IsUnique) sb.Append("UNIQUE ");
 | 
				
			||||||
 | 
					                    sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(tablename).Append("(");
 | 
				
			||||||
 | 
					                    foreach (var tbcol in uk.Columns)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
 | 
				
			||||||
 | 
					                        if (tbcol.IsDesc) sb.Append(" DESC");
 | 
				
			||||||
 | 
					                        sb.Append(", ");
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    sb.Remove(sb.Length - 2, 2).Append(");\r\n");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //foreach (var seqcol in seqcols)
 | 
				
			||||||
 | 
					            //{
 | 
				
			||||||
 | 
					            //    var tbname = seqcol.Item2;
 | 
				
			||||||
 | 
					            //    var seqname = Utils.GetCsName($"{tbname[0]}.{tbname[1]}_{seqcol.Item1.Attribute.Name}_sequence_name").ToLower();
 | 
				
			||||||
 | 
					            //    var tbname2 = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}");
 | 
				
			||||||
 | 
					            //    var colname2 = _commonUtils.QuoteSqlName(seqcol.Item1.Attribute.Name);
 | 
				
			||||||
 | 
					            //    sb.Append("ALTER TABLE ").Append(tbname2).Append(" ALTER COLUMN ").Append(colname2).Append(" SET DEFAULT null;\r\n");
 | 
				
			||||||
 | 
					            //    sb.Append("DROP SEQUENCE IF EXISTS ").Append(seqname).Append(";\r\n");
 | 
				
			||||||
 | 
					            //    if (seqcol.Item3)
 | 
				
			||||||
 | 
					            //    {
 | 
				
			||||||
 | 
					            //        sb.Append("CREATE SEQUENCE ").Append(seqname).Append(";\r\n");
 | 
				
			||||||
 | 
					            //        sb.Append("ALTER TABLE ").Append(tbname2).Append(" ALTER COLUMN ").Append(colname2).Append(" SET DEFAULT nextval('").Append(seqname).Append("'::regclass);\r\n");
 | 
				
			||||||
 | 
					            //        sb.Append(" SELECT case when max(").Append(colname2).Append(") is null then 0 else setval('").Append(seqname).Append("', max(").Append(colname2).Append(")) end FROM ").Append(tbname2).Append(";\r\n");
 | 
				
			||||||
 | 
					            //    }
 | 
				
			||||||
 | 
					            //}
 | 
				
			||||||
 | 
					            Console.Write(sb.ToString());
 | 
				
			||||||
 | 
					            //throw new Exception(sb.ToString());
 | 
				
			||||||
 | 
					            return sb.Length == 0 ? null : sb.ToString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										543
									
								
								Providers/FreeSql.Provider.Xugu/XuguDbFirst.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										543
									
								
								Providers/FreeSql.Provider.Xugu/XuguDbFirst.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,543 @@
 | 
				
			|||||||
 | 
					using FreeSql.DatabaseModel;
 | 
				
			||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Data.SqlTypes;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Net.NetworkInformation;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Text.RegularExpressions;
 | 
				
			||||||
 | 
					using XuguClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Xugu
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    class XuguDbFirst : IDbFirst
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public readonly string DefaultSchema = "SYSDBA";//默认模式
 | 
				
			||||||
 | 
					        IFreeSql _orm;
 | 
				
			||||||
 | 
					        protected CommonUtils _commonUtils;
 | 
				
			||||||
 | 
					        protected CommonExpression _commonExpression;
 | 
				
			||||||
 | 
					        public XuguDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _orm = orm;
 | 
				
			||||||
 | 
					            _commonUtils = commonUtils;
 | 
				
			||||||
 | 
					            _commonExpression = commonExpression;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public bool IsPg10 => ServerVersion >= 10;
 | 
				
			||||||
 | 
					        public int ServerVersion
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            get
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (_ServerVersionValue == 0 && _orm.Ado.MasterPool != null)
 | 
				
			||||||
 | 
					                    using (var conn = _orm.Ado.MasterPool.Get())
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        try
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            _ServerVersionValue = int.Parse(conn.Value.ServerVersion.Split('.')[0]);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        catch
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            _ServerVersionValue = 9;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                return _ServerVersionValue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        int _ServerVersionValue = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public int GetDbType(DbColumnInfo column) => (int)GetXGDbType(column);
 | 
				
			||||||
 | 
					        XGDbType GetXGDbType(DbColumnInfo column)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var dbtype = column.DbTypeText;
 | 
				
			||||||
 | 
					            var isarray = dbtype?.EndsWith("[]") == true;
 | 
				
			||||||
 | 
					            if (isarray) dbtype = dbtype.Remove(dbtype.Length - 2);
 | 
				
			||||||
 | 
					            XGDbType ret = XGDbType.LongVarChar;
 | 
				
			||||||
 | 
					            switch (dbtype?.ToUpper().TrimStart('_'))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case "SMALLINT": ret = XGDbType.SmallInt; break;
 | 
				
			||||||
 | 
					                case "INTEGER": ret = XGDbType.Int; break;
 | 
				
			||||||
 | 
					                case "BIGINT": ret = XGDbType.BigInt; break;
 | 
				
			||||||
 | 
					                case "NUMERIC": ret = XGDbType.Numeric; break;
 | 
				
			||||||
 | 
					                case "FLOAT": ret = XGDbType.Real; break;
 | 
				
			||||||
 | 
					                case "DOUBLE": ret = XGDbType.Double; break;
 | 
				
			||||||
 | 
					                //case "money": ret = XGDbType.; break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                case "CHAR": ret = XGDbType.Char; break;
 | 
				
			||||||
 | 
					                case "VARCHAR": ret = XGDbType.VarChar; break;
 | 
				
			||||||
 | 
					                case "CLOB": ret = XGDbType.LongVarChar; break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //case "timestamp": ret = XGDbType.DateTime; break;
 | 
				
			||||||
 | 
					                //case "timestamptz": ret = XGDbType.DateTime; break;
 | 
				
			||||||
 | 
					                //case "date": ret = XGDbType.Date; break;
 | 
				
			||||||
 | 
					                //case "time": ret = XGDbType.Time; break;
 | 
				
			||||||
 | 
					                //case "timetz": ret = XGDbType.TimeTz; break;
 | 
				
			||||||
 | 
					                //case "interval": ret = XGDbType.Interval; break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                case "BOOLEAN": ret = XGDbType.Bool; break;
 | 
				
			||||||
 | 
					                //case "bytea": ret = XGDbType.Bytea; break;
 | 
				
			||||||
 | 
					                //case "bit": ret = XGDbType.Bool; break;
 | 
				
			||||||
 | 
					                //case "varbit": ret = XGDbType.Varbit; break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //case "point": ret = XGDbType.Point; break;
 | 
				
			||||||
 | 
					                //case "line": ret = XGDbType.Line; break;
 | 
				
			||||||
 | 
					                //case "lseg": ret = XGDbType.LSeg; break;
 | 
				
			||||||
 | 
					                //case "box": ret = XGDbType.Box; break;
 | 
				
			||||||
 | 
					                //case "path": ret = XGDbType.Path; break;
 | 
				
			||||||
 | 
					                //case "polygon": ret = XGDbType.Polygon; break;
 | 
				
			||||||
 | 
					                //case "circle": ret = XGDbType.Circle; break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //case "cidr": ret = XGDbType.Cidr; break;
 | 
				
			||||||
 | 
					                //case "inet": ret = XGDbType.Inet; break;
 | 
				
			||||||
 | 
					                //case "macaddr": ret = XGDbType.MacAddr; break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //case "json": ret = XGDbType.Json; break;
 | 
				
			||||||
 | 
					                //case "jsonb": ret = XGDbType.Jsonb; break;
 | 
				
			||||||
 | 
					                //case "uuid": ret = XGDbType.Uuid; break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //case "int4range": ret = XGDbType.Range | XGDbType.Integer; break;
 | 
				
			||||||
 | 
					                //case "int8range": ret = XGDbType.Range | XGDbType.Bigint; break;
 | 
				
			||||||
 | 
					                //case "numrange": ret = XGDbType.Range | XGDbType.Numeric; break;
 | 
				
			||||||
 | 
					                //case "tsrange": ret = XGDbType.Range | XGDbType.Timestamp; break;
 | 
				
			||||||
 | 
					                //case "tstzrange": ret = XGDbType.Range | XGDbType.TimestampTz; break;
 | 
				
			||||||
 | 
					                //case "daterange": ret = XGDbType.Range | XGDbType.Date; break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //case "hstore": ret = XGDbType.Hstore; break;
 | 
				
			||||||
 | 
					                //case "geometry": ret = XGDbType.Geometry; break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret  ;
 | 
				
			||||||
 | 
					            //return isarray ? (ret | XGDbType.Array) : ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static readonly Dictionary<int, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)> _dicDbToCs = new Dictionary<int, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)>() {
 | 
				
			||||||
 | 
					                { (int)XGDbType.SmallInt, ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
				
			||||||
 | 
					                { (int)XGDbType.Int, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
				
			||||||
 | 
					                { (int)XGDbType.BigInt, ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
				
			||||||
 | 
					                { (int)XGDbType.Numeric, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
				
			||||||
 | 
					                { (int)XGDbType.Real, ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
				
			||||||
 | 
					                { (int)XGDbType.Double, ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
				
			||||||
 | 
					              
 | 
				
			||||||
 | 
					                { (int)XGDbType.Char, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
 | 
					                { (int)XGDbType.VarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
 | 
					                { (int)XGDbType.LongVarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                { (int)XGDbType.DateTime, ("(DateTime?)", "new DateTime({0})", "{0}.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
				
			||||||
 | 
					              
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                { (int)XGDbType.Bool, ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
				
			||||||
 | 
					                 
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
 | 
				
			||||||
 | 
					        public string GetCsParse(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csParse : null;
 | 
				
			||||||
 | 
					        public string GetCsStringify(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csStringify : null;
 | 
				
			||||||
 | 
					        public string GetCsType(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csType : trydc.csType.Replace("?", "")) : null;
 | 
				
			||||||
 | 
					        public Type GetCsTypeInfo(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeInfo : null;
 | 
				
			||||||
 | 
					        public string GetCsTypeValue(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeValue : null;
 | 
				
			||||||
 | 
					        public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public List<string> GetDatabases()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var sql = @" select DB_NAME from all_databases where DROPED=FALSE AND USER_ID>0";
 | 
				
			||||||
 | 
					            var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
				
			||||||
 | 
					            return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public bool ExistsTable(string name, bool ignoreCase)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(name)) return false;
 | 
				
			||||||
 | 
					            var tbname = _commonUtils.SplitTableName(name);
 | 
				
			||||||
 | 
					            if (tbname?.Length == 1) tbname = new[] { DefaultSchema, tbname[0] };
 | 
				
			||||||
 | 
					            var sql = string.Format("select 1 from all_tables a inner join all_schemas b on b.schema_id = a.schema_id where b.schema_name || '.' || a.table_name = '{0}.{1}'", tbname);
 | 
				
			||||||
 | 
					           
 | 
				
			||||||
 | 
					            return string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, sql)) == "1";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DbTableInfo GetTableByName(string name, bool ignoreCase = true) => GetTables(null, name, ignoreCase)?.FirstOrDefault();
 | 
				
			||||||
 | 
					        public List<DbTableInfo> GetTablesByDatabase(params string[] database) => GetTables(database, null,false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public List<DbTableInfo> GetTables(string[] database, string tablename, bool ignoreCase)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var olddatabase = "";
 | 
				
			||||||
 | 
					            using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                olddatabase = conn.Value.Database;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            string[] tbname = null;
 | 
				
			||||||
 | 
					            string[] dbs = database == null || database.Any() == false ? new[] { olddatabase } : database;
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(tablename) == false)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                tbname = _commonUtils.SplitTableName(tablename);
 | 
				
			||||||
 | 
					                if (tbname?.Length == 1) tbname = new[] { DefaultSchema, tbname[0] };
 | 
				
			||||||
 | 
					                dbs = new[] { olddatabase };
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var tables = new List<DbTableInfo>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var db in dbs)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(db) || string.Compare(db, olddatabase, true) != 0) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var loc1 = new List<DbTableInfo>();
 | 
				
			||||||
 | 
					                var loc2 = new Dictionary<string, DbTableInfo>();
 | 
				
			||||||
 | 
					                var loc3 = new Dictionary<string, Dictionary<string, DbColumnInfo>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var sql = $@"
 | 
				
			||||||
 | 
					{(tbname == null ? "" : $"select * from (")}select b.schema_name || '.' || a.table_name as ns,
 | 
				
			||||||
 | 
					b.schema_name,
 | 
				
			||||||
 | 
					a.table_name,
 | 
				
			||||||
 | 
					a.comments,
 | 
				
			||||||
 | 
					'TABLE' AS type
 | 
				
			||||||
 | 
					from all_tables a 
 | 
				
			||||||
 | 
					inner join all_schemas b on b.schema_id = a.schema_id
 | 
				
			||||||
 | 
					where a.IS_SYS=FALSE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					union all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select b.schema_name || '.' || a.view_name as ns,
 | 
				
			||||||
 | 
					b.schema_name,
 | 
				
			||||||
 | 
					a.view_name,
 | 
				
			||||||
 | 
					a.comments,
 | 
				
			||||||
 | 
					'VIEW' AS type
 | 
				
			||||||
 | 
					from all_views a 
 | 
				
			||||||
 | 
					inner join all_schemas b on b.schema_id = a.schema_id
 | 
				
			||||||
 | 
					where a.IS_SYS=FALSE
 | 
				
			||||||
 | 
					{(tbname == null ? "" : $") ft_dbf where schema_name ={_commonUtils.FormatSql("{0}", tbname[0])} and ft_dbf.Table_Name={_commonUtils.FormatSql("{0}", tbname[1])}")}";
 | 
				
			||||||
 | 
					                var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
				
			||||||
 | 
					                if (ds == null) return loc1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var loc6 = new List<string[]>();
 | 
				
			||||||
 | 
					                var loc66 = new List<string[]>();
 | 
				
			||||||
 | 
					                var loc6_1000 = new List<string>();
 | 
				
			||||||
 | 
					                var loc66_1000 = new List<string>();
 | 
				
			||||||
 | 
					                foreach (object[] row in ds)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var object_id = string.Concat(row[0]);
 | 
				
			||||||
 | 
					                    var owner = string.Concat(row[1]);
 | 
				
			||||||
 | 
					                    var table = string.Concat(row[2]);
 | 
				
			||||||
 | 
					                    var comment = string.Concat(row[3]);
 | 
				
			||||||
 | 
					                    Enum.TryParse<DbTableType>(string.Concat(row[4]), out var type);
 | 
				
			||||||
 | 
					                    loc2.Add(object_id, new DbTableInfo { Id = object_id.ToString(), Schema = owner, Name = table, Comment = comment, Type = type });
 | 
				
			||||||
 | 
					                    loc3.Add(object_id, new Dictionary<string, DbColumnInfo>());
 | 
				
			||||||
 | 
					                    switch (type)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        case DbTableType.VIEW:
 | 
				
			||||||
 | 
					                        case DbTableType.TABLE:
 | 
				
			||||||
 | 
					                            loc6_1000.Add(object_id);
 | 
				
			||||||
 | 
					                            if (loc6_1000.Count >= 500)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                loc6.Add(loc6_1000.ToArray());
 | 
				
			||||||
 | 
					                                loc6_1000.Clear();
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        case DbTableType.StoreProcedure:
 | 
				
			||||||
 | 
					                            loc66_1000.Add(object_id);
 | 
				
			||||||
 | 
					                            if (loc66_1000.Count >= 500)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                loc66.Add(loc66_1000.ToArray());
 | 
				
			||||||
 | 
					                                loc66_1000.Clear();
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (loc6_1000.Count > 0) loc6.Add(loc6_1000.ToArray());
 | 
				
			||||||
 | 
					                if (loc66_1000.Count > 0) loc66.Add(loc66_1000.ToArray());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (loc6.Count == 0) return loc1;
 | 
				
			||||||
 | 
					                var loc8 = new StringBuilder().Append("(");
 | 
				
			||||||
 | 
					                for (var loc8idx = 0; loc8idx < loc6.Count; loc8idx++)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (loc8idx > 0) loc8.Append(" OR ");
 | 
				
			||||||
 | 
					                    loc8.Append("a.table_name in (");
 | 
				
			||||||
 | 
					                    for (var loc8idx2 = 0; loc8idx2 < loc6[loc8idx].Length; loc8idx2++)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (loc8idx2 > 0) loc8.Append(",");
 | 
				
			||||||
 | 
					                        loc8.Append($"'{loc6[loc8idx][loc8idx2]}'");
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    loc8.Append(")");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                loc8.Append(")"); 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                sql = $@"
 | 
				
			||||||
 | 
					select 
 | 
				
			||||||
 | 
					ns.schema_name || '.' || tb.table_name as id,
 | 
				
			||||||
 | 
					a.COL_NAME,
 | 
				
			||||||
 | 
					a.TYPE_NAME,
 | 
				
			||||||
 | 
					a.SCALE,
 | 
				
			||||||
 | 
					case when a.NOT_NULL then '0' else '1' end as is_nullable,
 | 
				
			||||||
 | 
					seq.SEQ_ID,
 | 
				
			||||||
 | 
					seq.IS_SYS,
 | 
				
			||||||
 | 
					seq.MIN_VAL,
 | 
				
			||||||
 | 
					seq.STEP_VAL,
 | 
				
			||||||
 | 
					a.COMMENTS,
 | 
				
			||||||
 | 
					tb.table_name,
 | 
				
			||||||
 | 
					a.def_val,
 | 
				
			||||||
 | 
					ns.schema_id,
 | 
				
			||||||
 | 
					a.`VARYING`
 | 
				
			||||||
 | 
					from all_columns as a  
 | 
				
			||||||
 | 
					left join all_tables tb on a.table_id=tb.table_id
 | 
				
			||||||
 | 
					left join all_schemas ns on tb.schema_id = ns.schema_id
 | 
				
			||||||
 | 
					left join all_sequences seq on seq.SEQ_ID=a.Serial_ID
 | 
				
			||||||
 | 
					where {loc8.ToString().Replace("a.table_name", "ns.schema_name || '.' || tb.table_name")}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
				
			||||||
 | 
					                if (ds == null) return loc1;
 | 
				
			||||||
 | 
					                var position = 1;
 | 
				
			||||||
 | 
					                foreach (object[] row in ds)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var object_id = string.Concat(row[0]);
 | 
				
			||||||
 | 
					                    var column = string.Concat(row[1]);
 | 
				
			||||||
 | 
					                    var type = string.Concat(row[2]);
 | 
				
			||||||
 | 
					                    var max_length = int.Parse(string.Concat(row[3]));
 | 
				
			||||||
 | 
					                    //var sqlType = string.Concat(row[4]);
 | 
				
			||||||
 | 
					                    var is_nullable = string.Concat(row[5]) == "1";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    long.TryParse(row[5]?.ToString() ?? "0", out long SEQ_ID);
 | 
				
			||||||
 | 
					                    var SEQ_IS_SYS = (row[6]?.ToString() ?? "false")?.ToLower();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var is_identity = (SEQ_ID > 0 && SEQ_IS_SYS == "true");
 | 
				
			||||||
 | 
					                    var comment = string.Concat(row[9]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var defaultValue = string.Concat(row[11]);
 | 
				
			||||||
 | 
					                    //int attndims = int.Parse(string.Concat(row[8]));
 | 
				
			||||||
 | 
					                    //string typtype = string.Concat(row[9]);
 | 
				
			||||||
 | 
					                    //string owner = string.Concat(row[10]);
 | 
				
			||||||
 | 
					                    //int attnum = int.Parse(string.Concat(row[11]));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    //switch (sqlType.ToLower())
 | 
				
			||||||
 | 
					                    //{
 | 
				
			||||||
 | 
					                    //    case "bool": case "name": case "bit": case "varbit": case "bpchar": case "varchar": case "bytea": case "text": case "uuid": break;
 | 
				
			||||||
 | 
					                    //    default: max_length *= 8; break;
 | 
				
			||||||
 | 
					                    //}
 | 
				
			||||||
 | 
					                    if (max_length <= 0) max_length = -1;
 | 
				
			||||||
 | 
					                    //if (type.StartsWith("_"))
 | 
				
			||||||
 | 
					                    //{
 | 
				
			||||||
 | 
					                    //    type = type.Substring(1);
 | 
				
			||||||
 | 
					                    //    if (attndims == 0) attndims++;
 | 
				
			||||||
 | 
					                    //}
 | 
				
			||||||
 | 
					                    var sqlType = type;
 | 
				
			||||||
 | 
					                    if (max_length > 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        switch (type.ToUpper())
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            //case "numeric": sqlType += $"({max_length})"; break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            case "NUMERIC":
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    var data_precision = max_length % 65536;
 | 
				
			||||||
 | 
					                                    var data_scale = max_length / 65536;
 | 
				
			||||||
 | 
					                                    sqlType += $"({data_scale},{data_precision})"; break;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                               
 | 
				
			||||||
 | 
					                            //case "DATETIME":
 | 
				
			||||||
 | 
					                            //    break;
 | 
				
			||||||
 | 
					                            default:
 | 
				
			||||||
 | 
					                                sqlType += $"({max_length})"; break;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    //if (attndims > 0) type += "[]";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    loc3[object_id].Add(column, new DbColumnInfo
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        Name = column,
 | 
				
			||||||
 | 
					                        MaxLength = max_length,
 | 
				
			||||||
 | 
					                        IsIdentity = is_identity,
 | 
				
			||||||
 | 
					                        IsNullable = is_nullable,
 | 
				
			||||||
 | 
					                        IsPrimary = false,
 | 
				
			||||||
 | 
					                        DbTypeText = type,
 | 
				
			||||||
 | 
					                        DbTypeTextFull = sqlType,
 | 
				
			||||||
 | 
					                        Table = loc2[object_id],
 | 
				
			||||||
 | 
					                        Comment = comment,
 | 
				
			||||||
 | 
					                        DefaultValue = defaultValue,
 | 
				
			||||||
 | 
					                        Position = position
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    loc3[object_id][column].DbType = this.GetDbType(loc3[object_id][column]);
 | 
				
			||||||
 | 
					                    loc3[object_id][column].CsType = this.GetCsTypeInfo(loc3[object_id][column]);
 | 
				
			||||||
 | 
					                    position++;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                sql = $@"
 | 
				
			||||||
 | 
					select 
 | 
				
			||||||
 | 
					ns.SCHEMA_NAME || '.' || t.table_name as table_id, 
 | 
				
			||||||
 | 
					keys,
 | 
				
			||||||
 | 
					a.index_name,
 | 
				
			||||||
 | 
					case when a.IS_UNIQUE  then 1 else 0 end as IsUnique,
 | 
				
			||||||
 | 
					case when a.IS_Primary then 1 else 0 end as IsPrimary,
 | 
				
			||||||
 | 
					0,
 | 
				
			||||||
 | 
					0,
 | 
				
			||||||
 | 
					t.table_name,
 | 
				
			||||||
 | 
					ns.SCHEMA_NAME,
 | 
				
			||||||
 | 
					a.IS_SYS
 | 
				
			||||||
 | 
					from all_INDEXES a
 | 
				
			||||||
 | 
					left join all_tables t on a.TABLE_ID=t.TABLE_ID
 | 
				
			||||||
 | 
					left join all_schemas ns on t.SCHEMA_ID=ns.SCHEMA_ID
 | 
				
			||||||
 | 
					where IS_SYS=false and {loc8.ToString().Replace("a.table_name", "ns.SCHEMA_NAME || '.' || t.table_name")}
 | 
				
			||||||
 | 
					";
 | 
				
			||||||
 | 
					                ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
				
			||||||
 | 
					                if (ds == null) return loc1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var indexColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>();
 | 
				
			||||||
 | 
					                var uniqueColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>();
 | 
				
			||||||
 | 
					                foreach (object[] row in ds)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var object_id = string.Concat(row[0]);
 | 
				
			||||||
 | 
					                    var column = string.Concat(row[1]);
 | 
				
			||||||
 | 
					                    var index_id = string.Concat(row[2]);
 | 
				
			||||||
 | 
					                    var is_unique = string.Concat(row[3]) == "1";
 | 
				
			||||||
 | 
					                    var is_primary_key = string.Concat(row[4]) == "1";
 | 
				
			||||||
 | 
					                    var is_clustered = false;//= string.Concat(row[5]) == "1";
 | 
				
			||||||
 | 
					                    var is_desc = false;//string.Concat(row[6]) == "1";
 | 
				
			||||||
 | 
					                    //var inkey = string.Concat(row[7]).Split(' ');
 | 
				
			||||||
 | 
					                    //var attnum = int.Parse(string.Concat(row[8]));
 | 
				
			||||||
 | 
					                    //attnum = int.Parse(inkey[attnum - 1]);
 | 
				
			||||||
 | 
					                    //foreach (string tc in loc3[object_id].Keys) //bug: https://github.com/2881099/FreeSql.Wiki.VuePress/issues/9
 | 
				
			||||||
 | 
					                    //{
 | 
				
			||||||
 | 
					                    //    if (loc3[object_id][tc].DbTypeText.EndsWith("[]"))
 | 
				
			||||||
 | 
					                    //    {
 | 
				
			||||||
 | 
					                    //        column = tc;
 | 
				
			||||||
 | 
					                    //        break;
 | 
				
			||||||
 | 
					                    //    }
 | 
				
			||||||
 | 
					                    //}
 | 
				
			||||||
 | 
					                    if (loc3.ContainsKey(object_id) == false || loc3[object_id].ContainsKey(column) == false) continue;
 | 
				
			||||||
 | 
					                    var loc9 = loc3[object_id][column];
 | 
				
			||||||
 | 
					                    if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    Dictionary<string, DbIndexInfo> loc10 = null;
 | 
				
			||||||
 | 
					                    DbIndexInfo loc11 = null;
 | 
				
			||||||
 | 
					                    if (!indexColumns.TryGetValue(object_id, out loc10))
 | 
				
			||||||
 | 
					                        indexColumns.Add(object_id, loc10 = new Dictionary<string, DbIndexInfo>());
 | 
				
			||||||
 | 
					                    if (!loc10.TryGetValue(index_id, out loc11))
 | 
				
			||||||
 | 
					                        loc10.Add(index_id, loc11 = new DbIndexInfo());
 | 
				
			||||||
 | 
					                    loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
 | 
				
			||||||
 | 
					                    if (is_unique && !is_primary_key)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (!uniqueColumns.TryGetValue(object_id, out loc10))
 | 
				
			||||||
 | 
					                            uniqueColumns.Add(object_id, loc10 = new Dictionary<string, DbIndexInfo>());
 | 
				
			||||||
 | 
					                        if (!loc10.TryGetValue(index_id, out loc11))
 | 
				
			||||||
 | 
					                            loc10.Add(index_id, loc11 = new DbIndexInfo());
 | 
				
			||||||
 | 
					                        loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                foreach (var object_id in indexColumns.Keys)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    foreach (var column in indexColumns[object_id])
 | 
				
			||||||
 | 
					                        loc2[object_id].IndexesDict.Add(column.Key, column.Value);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                foreach (var object_id in uniqueColumns.Keys)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    foreach (var column in uniqueColumns[object_id])
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name));
 | 
				
			||||||
 | 
					                        loc2[object_id].UniquesDict.Add(column.Key, column.Value);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (tbname == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    sql = $@"
 | 
				
			||||||
 | 
					select 
 | 
				
			||||||
 | 
					schema_name || '.' || b.table_name as table_id,
 | 
				
			||||||
 | 
					cons_name as FKId,
 | 
				
			||||||
 | 
					cons_type,
 | 
				
			||||||
 | 
					define
 | 
				
			||||||
 | 
					from all_constraints as a
 | 
				
			||||||
 | 
					left join all_tables as b on a.Table_ID=b.Table_ID
 | 
				
			||||||
 | 
					left Join all_SCHEMAS AS c on b.SCHEMA_ID=c.SCHEMA_ID
 | 
				
			||||||
 | 
					where  IS_SYS=false AND {loc8.ToString().Replace("a.table_name", "schema_name || '.' || b.table_name")}
 | 
				
			||||||
 | 
					";
 | 
				
			||||||
 | 
					                    ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
				
			||||||
 | 
					                    if (ds == null) return loc1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var fkColumns = new Dictionary<string, Dictionary<string, DbForeignInfo>>();
 | 
				
			||||||
 | 
					                    foreach (object[] row in ds)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var table_id = string.Concat(row[0]);
 | 
				
			||||||
 | 
					                        var column = row[3] as string[];
 | 
				
			||||||
 | 
					                        var fk_id = string.Concat(row[1]);
 | 
				
			||||||
 | 
					                        var ref_table_id = string.Concat(row[0]);
 | 
				
			||||||
 | 
					                        var is_foreign_key = string.Concat(row[2]) == "F";
 | 
				
			||||||
 | 
					                        var referenced_column = row[5] as string[];
 | 
				
			||||||
 | 
					                        //var referenced_db = string.Concat(row[6]);
 | 
				
			||||||
 | 
					                        //var referenced_table = string.Concat(row[7]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (loc2.ContainsKey(ref_table_id) == false) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        Dictionary<string, DbForeignInfo> loc12 = null;
 | 
				
			||||||
 | 
					                        DbForeignInfo loc13 = null;
 | 
				
			||||||
 | 
					                        if (!fkColumns.TryGetValue(table_id, out loc12))
 | 
				
			||||||
 | 
					                            fkColumns.Add(table_id, loc12 = new Dictionary<string, DbForeignInfo>());
 | 
				
			||||||
 | 
					                        if (!loc12.TryGetValue(fk_id, out loc13))
 | 
				
			||||||
 | 
					                            loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[table_id], ReferencedTable = loc2[ref_table_id] });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        for (int a = 0; a < column.Length; a++)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            loc13.Columns.Add(loc3[table_id][column[a]]);
 | 
				
			||||||
 | 
					                            loc13.ReferencedColumns.Add(loc3[ref_table_id][referenced_column[a]]);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    foreach (var table_id in fkColumns.Keys)
 | 
				
			||||||
 | 
					                        foreach (var fk in fkColumns[table_id])
 | 
				
			||||||
 | 
					                            loc2[table_id].ForeignsDict.Add(fk.Key, fk.Value);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                foreach (var table_id in loc3.Keys)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    foreach (var loc5 in loc3[table_id].Values)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        loc2[table_id].Columns.Add(loc5);
 | 
				
			||||||
 | 
					                        if (loc5.IsIdentity) loc2[table_id].Identitys.Add(loc5);
 | 
				
			||||||
 | 
					                        if (loc5.IsPrimary) loc2[table_id].Primarys.Add(loc5);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                foreach (var loc4 in loc2.Values)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    //if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0)
 | 
				
			||||||
 | 
					                    //{
 | 
				
			||||||
 | 
					                    //    foreach (var loc5 in loc4.UniquesDict.First().Value.Columns)
 | 
				
			||||||
 | 
					                    //    {
 | 
				
			||||||
 | 
					                    //        loc5.Column.IsPrimary = true;
 | 
				
			||||||
 | 
					                    //        loc4.Primarys.Add(loc5.Column);
 | 
				
			||||||
 | 
					                    //    }
 | 
				
			||||||
 | 
					                    //}
 | 
				
			||||||
 | 
					                    loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name));
 | 
				
			||||||
 | 
					                    loc4.Columns.Sort((c1, c2) =>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        int compare = c2.IsPrimary.CompareTo(c1.IsPrimary);
 | 
				
			||||||
 | 
					                        if (compare == 0)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            bool b1 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c1.Name).Any()).Any();
 | 
				
			||||||
 | 
					                            bool b2 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c2.Name).Any()).Any();
 | 
				
			||||||
 | 
					                            compare = b2.CompareTo(b1);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (compare == 0) compare = c1.Name.CompareTo(c2.Name);
 | 
				
			||||||
 | 
					                        return compare;
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    loc1.Add(loc4);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                loc1.Sort((t1, t2) =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var ret = t1.Schema.CompareTo(t2.Schema);
 | 
				
			||||||
 | 
					                    if (ret == 0) ret = t1.Name.CompareTo(t2.Name);
 | 
				
			||||||
 | 
					                    return ret;
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                loc2.Clear();
 | 
				
			||||||
 | 
					                loc3.Clear();
 | 
				
			||||||
 | 
					                tables.AddRange(loc1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return tables;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public List<DbEnumInfo> GetEnumsByDatabase(params string[] database)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return new List<DbEnumInfo>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										689
									
								
								Providers/FreeSql.Provider.Xugu/XuguExpression.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										689
									
								
								Providers/FreeSql.Provider.Xugu/XuguExpression.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,689 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Text.RegularExpressions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Xugu
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    class XuguExpression : CommonExpression
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public XuguExpression(CommonUtils common) : base(common) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
 | 
				
			||||||
 | 
					            switch (exp.NodeType)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case ExpressionType.ArrayLength:
 | 
				
			||||||
 | 
					                    var arrOper = (exp as UnaryExpression)?.Operand;
 | 
				
			||||||
 | 
					                    var arrOperExp = getExp(arrOper);
 | 
				
			||||||
 | 
					                    if (arrOperExp.StartsWith("(") || arrOperExp.EndsWith(")")) return $"array_length(array[{arrOperExp.TrimStart('(').TrimEnd(')')}],1)";
 | 
				
			||||||
 | 
					                    if (arrOper.Type == typeof(byte[])) return $"octet_length({getExp(arrOper)})";
 | 
				
			||||||
 | 
					                    return $"case when {arrOperExp} is null then 0 else array_length({arrOperExp},1) end";
 | 
				
			||||||
 | 
					                case ExpressionType.Convert:
 | 
				
			||||||
 | 
					                    var operandExp = (exp as UnaryExpression)?.Operand;
 | 
				
			||||||
 | 
					                    var gentype = exp.Type.NullableTypeOrThis();
 | 
				
			||||||
 | 
					                    if (gentype != operandExp.Type.NullableTypeOrThis())
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        switch (exp.Type.NullableTypeOrThis().ToString())
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            case "System.Boolean": return $"(({getExp(operandExp)})::varchar not in ('0','false','f','no'))";
 | 
				
			||||||
 | 
					                            case "System.Byte": return $"({getExp(operandExp)})::int2";
 | 
				
			||||||
 | 
					                            case "System.Char": return $"substr(({getExp(operandExp)})::char, 1, 1)";
 | 
				
			||||||
 | 
					                            case "System.DateTime": return ExpressionConstDateTime(operandExp) ?? $"({getExp(operandExp)})::timestamp";
 | 
				
			||||||
 | 
					                            case "System.Decimal": return $"({getExp(operandExp)})::numeric";
 | 
				
			||||||
 | 
					                            case "System.Double": return $"({getExp(operandExp)})::float8";
 | 
				
			||||||
 | 
					                            case "System.Int16": return $"({getExp(operandExp)})::int2";
 | 
				
			||||||
 | 
					                            case "System.Int32": return $"({getExp(operandExp)})::int4";
 | 
				
			||||||
 | 
					                            case "System.Int64": return $"({getExp(operandExp)})::int8";
 | 
				
			||||||
 | 
					                            case "System.SByte": return $"({getExp(operandExp)})::int2";
 | 
				
			||||||
 | 
					                            case "System.Single": return $"({getExp(operandExp)})::float4";
 | 
				
			||||||
 | 
					                            case "System.String": return $"({getExp(operandExp)})::text";
 | 
				
			||||||
 | 
					                            case "System.UInt16": return $"({getExp(operandExp)})::int2";
 | 
				
			||||||
 | 
					                            case "System.UInt32": return $"({getExp(operandExp)})::int4";
 | 
				
			||||||
 | 
					                            case "System.UInt64": return $"({getExp(operandExp)})::int8";
 | 
				
			||||||
 | 
					                            case "System.Guid": return $"({getExp(operandExp)})::uuid";
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case ExpressionType.Call:
 | 
				
			||||||
 | 
					                    var callExp = exp as MethodCallExpression;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    switch (callExp.Method.Name)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        case "Parse":
 | 
				
			||||||
 | 
					                        case "TryParse":
 | 
				
			||||||
 | 
					                            switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString())
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                case "System.Boolean": return $"(({getExp(callExp.Arguments[0])})::varchar not in ('0','false','f','no'))";
 | 
				
			||||||
 | 
					                                case "System.Byte": return $"({getExp(callExp.Arguments[0])})::int2";
 | 
				
			||||||
 | 
					                                case "System.Char": return $"substr(({getExp(callExp.Arguments[0])})::char, 1, 1)";
 | 
				
			||||||
 | 
					                                case "System.DateTime": return ExpressionConstDateTime(callExp.Arguments[0]) ?? $"({getExp(callExp.Arguments[0])})::timestamp";
 | 
				
			||||||
 | 
					                                case "System.Decimal": return $"({getExp(callExp.Arguments[0])})::numeric";
 | 
				
			||||||
 | 
					                                case "System.Double": return $"({getExp(callExp.Arguments[0])})::float8";
 | 
				
			||||||
 | 
					                                case "System.Int16": return $"({getExp(callExp.Arguments[0])})::int2";
 | 
				
			||||||
 | 
					                                case "System.Int32": return $"({getExp(callExp.Arguments[0])})::int4";
 | 
				
			||||||
 | 
					                                case "System.Int64": return $"({getExp(callExp.Arguments[0])})::int8";
 | 
				
			||||||
 | 
					                                case "System.SByte": return $"({getExp(callExp.Arguments[0])})::int2";
 | 
				
			||||||
 | 
					                                case "System.Single": return $"({getExp(callExp.Arguments[0])})::float4";
 | 
				
			||||||
 | 
					                                case "System.UInt16": return $"({getExp(callExp.Arguments[0])})::int2";
 | 
				
			||||||
 | 
					                                case "System.UInt32": return $"({getExp(callExp.Arguments[0])})::int4";
 | 
				
			||||||
 | 
					                                case "System.UInt64": return $"({getExp(callExp.Arguments[0])})::int8";
 | 
				
			||||||
 | 
					                                case "System.Guid": return $"({getExp(callExp.Arguments[0])})::uuid";
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        case "NewGuid":
 | 
				
			||||||
 | 
					                            return null;
 | 
				
			||||||
 | 
					                        case "Next":
 | 
				
			||||||
 | 
					                            if (callExp.Object?.Type == typeof(Random)) return "(random()*1000000000)::int4";
 | 
				
			||||||
 | 
					                            return null;
 | 
				
			||||||
 | 
					                        case "NextDouble":
 | 
				
			||||||
 | 
					                            if (callExp.Object?.Type == typeof(Random)) return "random()";
 | 
				
			||||||
 | 
					                            return null;
 | 
				
			||||||
 | 
					                        case "Random":
 | 
				
			||||||
 | 
					                            if (callExp.Method.DeclaringType.IsNumberType()) return "random()";
 | 
				
			||||||
 | 
					                            return null;
 | 
				
			||||||
 | 
					                        case "ToString":
 | 
				
			||||||
 | 
					                            if (callExp.Object != null) return callExp.Arguments.Count == 0 ? $"({getExp(callExp.Object)})::text" : null;
 | 
				
			||||||
 | 
					                            return null;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var objExp = callExp.Object;
 | 
				
			||||||
 | 
					                    var objType = objExp?.Type;
 | 
				
			||||||
 | 
					                    if (objType?.FullName == "System.Byte[]") return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var argIndex = 0;
 | 
				
			||||||
 | 
					                    if (objType == null && callExp.Method.DeclaringType == typeof(Enumerable))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        objExp = callExp.Arguments.FirstOrDefault();
 | 
				
			||||||
 | 
					                        objType = objExp?.Type;
 | 
				
			||||||
 | 
					                        argIndex++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (objType == typeof(string))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            switch (callExp.Method.Name)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                case "First":
 | 
				
			||||||
 | 
					                                case "FirstOrDefault":
 | 
				
			||||||
 | 
					                                    return $"substr({getExp(callExp.Arguments[0])}, 1, 1)";
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (objType == null) objType = callExp.Method.DeclaringType;
 | 
				
			||||||
 | 
					                    if (objType != null || objType.IsArrayOrList())
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        string left = null;
 | 
				
			||||||
 | 
					                        switch (objType.FullName)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            case "Newtonsoft.Json.Linq.JToken":
 | 
				
			||||||
 | 
					                            case "Newtonsoft.Json.Linq.JObject":
 | 
				
			||||||
 | 
					                            case "Newtonsoft.Json.Linq.JArray":
 | 
				
			||||||
 | 
					                                left = objExp == null ? null : getExp(objExp);
 | 
				
			||||||
 | 
					                                switch (callExp.Method.Name)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    case "get_Item": return $"{left}->{getExp(callExp.Arguments[argIndex])}";
 | 
				
			||||||
 | 
					                                    case "Any": return $"(jsonb_array_length(coalesce({left},'[]')) > 0)";
 | 
				
			||||||
 | 
					                                    case "Contains":
 | 
				
			||||||
 | 
					                                        var json = getExp(callExp.Arguments[argIndex]);
 | 
				
			||||||
 | 
					                                        if (objType == typeof(JArray))
 | 
				
			||||||
 | 
					                                            return $"(coalesce({left},'[]') ? ({json})::text)";
 | 
				
			||||||
 | 
					                                        if (json.StartsWith("'") && json.EndsWith("'"))
 | 
				
			||||||
 | 
					                                            return $"(coalesce({left},'{{}}') @> {_common.FormatSql("{0}", JToken.Parse(json.Trim('\'')))})";
 | 
				
			||||||
 | 
					                                        return $"(coalesce({left},'{{}}') @> ({json})::jsonb)";
 | 
				
			||||||
 | 
					                                    case "ContainsKey": return $"(coalesce({left},'{{}}') ? {getExp(callExp.Arguments[argIndex])})";
 | 
				
			||||||
 | 
					                                    case "Concat":
 | 
				
			||||||
 | 
					                                        var right2 = getExp(callExp.Arguments[argIndex]);
 | 
				
			||||||
 | 
					                                        return $"(coalesce({left},'{{}}') || {right2})";
 | 
				
			||||||
 | 
					                                    case "LongCount":
 | 
				
			||||||
 | 
					                                    case "Count": return $"jsonb_array_length(coalesce({left},'[]'))";
 | 
				
			||||||
 | 
					                                    case "Parse":
 | 
				
			||||||
 | 
					                                        var json2 = getExp(callExp.Arguments[argIndex]);
 | 
				
			||||||
 | 
					                                        if (json2.StartsWith("'") && json2.EndsWith("'")) return _common.FormatSql("{0}", JToken.Parse(json2.Trim('\'')));
 | 
				
			||||||
 | 
					                                        return $"({json2})::jsonb";
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                break;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (objType == typeof(Dictionary<string, string>))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            left = objExp == null ? null : getExp(objExp);
 | 
				
			||||||
 | 
					                            switch (callExp.Method.Name)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                case "get_Item": return $"{left}->{getExp(callExp.Arguments[argIndex])}";
 | 
				
			||||||
 | 
					                                case "Contains":
 | 
				
			||||||
 | 
					                                    var right = getExp(callExp.Arguments[argIndex]);
 | 
				
			||||||
 | 
					                                    return $"({left} @> ({right}))";
 | 
				
			||||||
 | 
					                                case "ContainsKey": return $"({left} ? {getExp(callExp.Arguments[argIndex])})";
 | 
				
			||||||
 | 
					                                case "Concat": return $"({left} || {getExp(callExp.Arguments[argIndex])})";
 | 
				
			||||||
 | 
					                                case "GetLength":
 | 
				
			||||||
 | 
					                                case "GetLongLength":
 | 
				
			||||||
 | 
					                                case "Count": return $"case when {left} is null then 0 else array_length(akeys({left}),1) end";
 | 
				
			||||||
 | 
					                                case "Keys": return $"akeys({left})";
 | 
				
			||||||
 | 
					                                case "Values": return $"avals({left})";
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        switch (callExp.Method.Name)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            case "Any":
 | 
				
			||||||
 | 
					                                left = objExp == null ? null : getExp(objExp);
 | 
				
			||||||
 | 
					                                if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
 | 
				
			||||||
 | 
					                                return $"(case when {left} is null then 0 else array_length({left},1) end > 0)";
 | 
				
			||||||
 | 
					                            case "Contains":
 | 
				
			||||||
 | 
					                                tsc.SetMapColumnTmp(null);
 | 
				
			||||||
 | 
					                                var args1 = getExp(callExp.Arguments[argIndex]);
 | 
				
			||||||
 | 
					                                var oldMapType = tsc.SetMapTypeReturnOld(tsc.mapTypeTmp);
 | 
				
			||||||
 | 
					                                var oldDbParams = objExp?.NodeType == ExpressionType.MemberAccess ? tsc.SetDbParamsReturnOld(null) : null; //#900 UseGenerateCommandParameterWithLambda(true) 子查询 bug、以及 #1173 参数化 bug
 | 
				
			||||||
 | 
					                                tsc.isNotSetMapColumnTmp = true;
 | 
				
			||||||
 | 
					                                left = objExp == null ? null : getExp(objExp);
 | 
				
			||||||
 | 
					                                tsc.isNotSetMapColumnTmp = false;
 | 
				
			||||||
 | 
					                                tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
 | 
				
			||||||
 | 
					                                if (oldDbParams != null) tsc.SetDbParamsReturnOld(oldDbParams);
 | 
				
			||||||
 | 
					                                //判断 in 或 array @> array
 | 
				
			||||||
 | 
					                                if (left.StartsWith("array[") || left.EndsWith("]"))
 | 
				
			||||||
 | 
					                                    return $"({args1}) in ({left.Substring(6, left.Length - 7)})";
 | 
				
			||||||
 | 
					                                if (left.StartsWith("(") || left.EndsWith(")")) //在各大 Provider AdoProvider 中已约定,500元素分割, 3空格\r\n4空格
 | 
				
			||||||
 | 
					                                    return $"(({args1}) in {left.Replace(",   \r\n    \r\n", $") \r\n OR ({args1}) in (")})";
 | 
				
			||||||
 | 
					                                if (args1.StartsWith("(") || args1.EndsWith(")")) args1 = $"array[{args1.TrimStart('(').TrimEnd(')')}]";
 | 
				
			||||||
 | 
					                                args1 = $"array[{args1}]";
 | 
				
			||||||
 | 
					                                if (objExp != null)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    var dbinfo = _common._orm.CodeFirst.GetDbInfo(objExp.Type);
 | 
				
			||||||
 | 
					                                    if (dbinfo != null) args1 = $"{args1}::{dbinfo.dbtype}";
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                return $"({left} @> {args1})";
 | 
				
			||||||
 | 
					                            case "Concat":
 | 
				
			||||||
 | 
					                                left = objExp == null ? null : getExp(objExp);
 | 
				
			||||||
 | 
					                                if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
 | 
				
			||||||
 | 
					                                var right2 = getExp(callExp.Arguments[argIndex]);
 | 
				
			||||||
 | 
					                                if (right2.StartsWith("(") || right2.EndsWith(")")) right2 = $"array[{right2.TrimStart('(').TrimEnd(')')}]";
 | 
				
			||||||
 | 
					                                return $"({left} || {right2})";
 | 
				
			||||||
 | 
					                            case "GetLength":
 | 
				
			||||||
 | 
					                            case "GetLongLength":
 | 
				
			||||||
 | 
					                            case "Length":
 | 
				
			||||||
 | 
					                            case "Count":
 | 
				
			||||||
 | 
					                                left = objExp == null ? null : getExp(objExp);
 | 
				
			||||||
 | 
					                                if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
 | 
				
			||||||
 | 
					                                return $"case when {left} is null then 0 else array_length({left},1) end";
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case ExpressionType.MemberAccess:
 | 
				
			||||||
 | 
					                    var memExp = exp as MemberExpression;
 | 
				
			||||||
 | 
					                    var memParentExp = memExp.Expression?.Type;
 | 
				
			||||||
 | 
					                    if (memParentExp?.FullName == "System.Byte[]") return null;
 | 
				
			||||||
 | 
					                    if (memParentExp != null)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (memParentExp.IsArray == true)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var left = getExp(memExp.Expression);
 | 
				
			||||||
 | 
					                            if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
 | 
				
			||||||
 | 
					                            switch (memExp.Member.Name)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                case "Length":
 | 
				
			||||||
 | 
					                                case "Count": return $"case when {left} is null then 0 else array_length({left},1) end";
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        switch (memParentExp.FullName)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            case "Newtonsoft.Json.Linq.JToken":
 | 
				
			||||||
 | 
					                            case "Newtonsoft.Json.Linq.JObject":
 | 
				
			||||||
 | 
					                            case "Newtonsoft.Json.Linq.JArray":
 | 
				
			||||||
 | 
					                                var left = getExp(memExp.Expression);
 | 
				
			||||||
 | 
					                                switch (memExp.Member.Name)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    case "Count": return $"jsonb_array_length(coalesce({left},'[]'))";
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                break;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (memParentExp == typeof(Dictionary<string, string>))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var left = getExp(memExp.Expression);
 | 
				
			||||||
 | 
					                            switch (memExp.Member.Name)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                case "Count": return $"case when {left} is null then 0 else array_length(akeys({left}),1) end";
 | 
				
			||||||
 | 
					                                case "Keys": return $"akeys({left})";
 | 
				
			||||||
 | 
					                                case "Values": return $"avals({left})";
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case ExpressionType.NewArrayInit:
 | 
				
			||||||
 | 
					                    var arrExp = exp as NewArrayExpression;
 | 
				
			||||||
 | 
					                    var arrSb = new StringBuilder();
 | 
				
			||||||
 | 
					                    arrSb.Append("array[");
 | 
				
			||||||
 | 
					                    for (var a = 0; a < arrExp.Expressions.Count; a++)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (a > 0) arrSb.Append(",");
 | 
				
			||||||
 | 
					                        arrSb.Append(getExp(arrExp.Expressions[a]));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (arrSb.Length == 1) arrSb.Append("NULL");
 | 
				
			||||||
 | 
					                    return arrSb.Append("]").ToString();
 | 
				
			||||||
 | 
					                case ExpressionType.ListInit:
 | 
				
			||||||
 | 
					                    var listExp = exp as ListInitExpression;
 | 
				
			||||||
 | 
					                    var listSb = new StringBuilder();
 | 
				
			||||||
 | 
					                    listSb.Append("(");
 | 
				
			||||||
 | 
					                    for (var a = 0; a < listExp.Initializers.Count; a++)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (listExp.Initializers[a].Arguments.Any() == false) continue;
 | 
				
			||||||
 | 
					                        if (a > 0) listSb.Append(",");
 | 
				
			||||||
 | 
					                        listSb.Append(getExp(listExp.Initializers[a].Arguments.FirstOrDefault()));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (listSb.Length == 1) listSb.Append("NULL");
 | 
				
			||||||
 | 
					                    return listSb.Append(")").ToString();
 | 
				
			||||||
 | 
					                case ExpressionType.New:
 | 
				
			||||||
 | 
					                    var newExp = exp as NewExpression;
 | 
				
			||||||
 | 
					                    if (typeof(IList).IsAssignableFrom(newExp.Type))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (newExp.Arguments.Count == 0) return "(NULL)";
 | 
				
			||||||
 | 
					                        if (typeof(IEnumerable).IsAssignableFrom(newExp.Arguments[0].Type) == false) return "(NULL)";
 | 
				
			||||||
 | 
					                        return getExp(newExp.Arguments[0]);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    return null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, ExpTSC tsc)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (exp.Expression == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                switch (exp.Member.Name)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case "Empty": return "''";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var left = ExpressionLambdaToSql(exp.Expression, tsc);
 | 
				
			||||||
 | 
					            switch (exp.Member.Name)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case "Length": return $"char_length({left})";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (exp.Expression == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                switch (exp.Member.Name)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case "Now": return _common.Now;
 | 
				
			||||||
 | 
					                    case "UtcNow": return _common.NowUtc;
 | 
				
			||||||
 | 
					                    case "Today": return "current_date";
 | 
				
			||||||
 | 
					                    case "MinValue": return "'0001/1/1 0:00:00'::timestamp";
 | 
				
			||||||
 | 
					                    case "MaxValue": return "'9999/12/31 23:59:59'::timestamp";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var left = ExpressionLambdaToSql(exp.Expression, tsc);
 | 
				
			||||||
 | 
					            switch (exp.Member.Name)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case "Date": return $"({left})::date";
 | 
				
			||||||
 | 
					                case "TimeOfDay": return $"(extract(epoch from ({left})::time)*1000000)";
 | 
				
			||||||
 | 
					                case "DayOfWeek": return $"extract(dow from ({left})::timestamp)";
 | 
				
			||||||
 | 
					                case "Day": return $"extract(day from ({left})::timestamp)";
 | 
				
			||||||
 | 
					                case "DayOfYear": return $"extract(doy from ({left})::timestamp)";
 | 
				
			||||||
 | 
					                case "Month": return $"extract(month from ({left})::timestamp)";
 | 
				
			||||||
 | 
					                case "Year": return $"extract(year from ({left})::timestamp)";
 | 
				
			||||||
 | 
					                case "Hour": return $"extract(hour from ({left})::timestamp)";
 | 
				
			||||||
 | 
					                case "Minute": return $"extract(minute from ({left})::timestamp)";
 | 
				
			||||||
 | 
					                case "Second": return $"extract(second from ({left})::timestamp)";
 | 
				
			||||||
 | 
					                case "Millisecond": return $"(extract(milliseconds from ({left})::timestamp)-extract(second from ({left})::timestamp)*1000)";
 | 
				
			||||||
 | 
					                case "Ticks": return $"(extract(epoch from ({left})::timestamp)*10000000+621355968000000000)";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, ExpTSC tsc)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (exp.Expression == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                switch (exp.Member.Name)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case "Zero": return "0";
 | 
				
			||||||
 | 
					                    case "MinValue": return "-922337203685477580"; //微秒 Ticks / 10
 | 
				
			||||||
 | 
					                    case "MaxValue": return "922337203685477580";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var left = ExpressionLambdaToSql(exp.Expression, tsc);
 | 
				
			||||||
 | 
					            switch (exp.Member.Name)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case "Days": return $"floor(({left})/{(long)1000000 * 60 * 60 * 24})";
 | 
				
			||||||
 | 
					                case "Hours": return $"floor(({left})/{(long)1000000 * 60 * 60}%24)";
 | 
				
			||||||
 | 
					                case "Milliseconds": return $"(floor(({left})/1000)::int8%1000)";
 | 
				
			||||||
 | 
					                case "Minutes": return $"(floor(({left})/{(long)1000000 * 60})::int8%60)";
 | 
				
			||||||
 | 
					                case "Seconds": return $"(floor(({left})/1000000)::int8%60)";
 | 
				
			||||||
 | 
					                case "Ticks": return $"(({left})*10)";
 | 
				
			||||||
 | 
					                case "TotalDays": return $"(({left})/{(long)1000000 * 60 * 60 * 24})";
 | 
				
			||||||
 | 
					                case "TotalHours": return $"(({left})/{(long)1000000 * 60 * 60})";
 | 
				
			||||||
 | 
					                case "TotalMilliseconds": return $"(({left})/1000)";
 | 
				
			||||||
 | 
					                case "TotalMinutes": return $"(({left})/{(long)1000000 * 60})";
 | 
				
			||||||
 | 
					                case "TotalSeconds": return $"(({left})/1000000)";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, ExpTSC tsc)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
 | 
				
			||||||
 | 
					            if (exp.Object == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                switch (exp.Method.Name)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case "IsNullOrEmpty":
 | 
				
			||||||
 | 
					                        var arg1 = getExp(exp.Arguments[0]);
 | 
				
			||||||
 | 
					                        return $"({arg1} is null or {arg1} = '')";
 | 
				
			||||||
 | 
					                    case "IsNullOrWhiteSpace":
 | 
				
			||||||
 | 
					                        var arg2 = getExp(exp.Arguments[0]);
 | 
				
			||||||
 | 
					                        return $"({arg2} is null or {arg2} = '' or ltrim({arg2}) = '')";
 | 
				
			||||||
 | 
					                    case "Concat":
 | 
				
			||||||
 | 
					                        return _common.StringConcat(exp.Arguments.Select(a => getExp(a)).ToArray(), null);
 | 
				
			||||||
 | 
					                    case "Format":
 | 
				
			||||||
 | 
					                        if (exp.Arguments[0].NodeType != ExpressionType.Constant) throw new Exception(CoreStrings.Not_Implemented_Expression_ParameterUseConstant(exp,exp.Arguments[0]));
 | 
				
			||||||
 | 
					                        var expArgsHack = exp.Arguments.Count == 2 && exp.Arguments[1].NodeType == ExpressionType.NewArrayInit ?
 | 
				
			||||||
 | 
					                            (exp.Arguments[1] as NewArrayExpression).Expressions : exp.Arguments.Where((a, z) => z > 0);
 | 
				
			||||||
 | 
					                        //3个 {} 时,Arguments 解析出来是分开的
 | 
				
			||||||
 | 
					                        //4个 {} 时,Arguments[1] 只能解析这个出来,然后里面是 NewArray []
 | 
				
			||||||
 | 
					                        var expArgs = expArgsHack.Select(a =>
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var atype = (a as UnaryExpression)?.Operand.Type.NullableTypeOrThis() ?? a.Type.NullableTypeOrThis();
 | 
				
			||||||
 | 
					                            if (atype == typeof(string)) return $"'||{_common.IsNull(ExpressionLambdaToSql(a, tsc), "''")}||'";
 | 
				
			||||||
 | 
					                            return $"'||{_common.IsNull($"({ExpressionLambdaToSql(a, tsc)})::text", "''")}||'";
 | 
				
			||||||
 | 
					                        }).ToArray();
 | 
				
			||||||
 | 
					                        return string.Format(ExpressionLambdaToSql(exp.Arguments[0], tsc), expArgs);
 | 
				
			||||||
 | 
					                    case "Join":
 | 
				
			||||||
 | 
					                        if (exp.IsStringJoin(out var tolistObjectExp, out var toListMethod, out var toListArgs1))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var newToListArgs0 = Expression.Call(tolistObjectExp, toListMethod,
 | 
				
			||||||
 | 
					                                Expression.Lambda(
 | 
				
			||||||
 | 
					                                    Expression.Call(
 | 
				
			||||||
 | 
					                                        typeof(SqlExtExtensions).GetMethod("StringJoinPgsqlGroupConcat"),
 | 
				
			||||||
 | 
					                                        Expression.Convert(toListArgs1.Body, typeof(object)),
 | 
				
			||||||
 | 
					                                        Expression.Convert(exp.Arguments[0], typeof(object))),
 | 
				
			||||||
 | 
					                                    toListArgs1.Parameters));
 | 
				
			||||||
 | 
					                            var newToListSql = getExp(newToListArgs0);
 | 
				
			||||||
 | 
					                            return newToListSql;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var left = getExp(exp.Object);
 | 
				
			||||||
 | 
					                switch (exp.Method.Name)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case "StartsWith":
 | 
				
			||||||
 | 
					                    case "EndsWith":
 | 
				
			||||||
 | 
					                    case "Contains":
 | 
				
			||||||
 | 
					                        var args0Value = getExp(exp.Arguments[0]);
 | 
				
			||||||
 | 
					                        if (args0Value == "NULL") return $"({left}) IS NULL";
 | 
				
			||||||
 | 
					                        if (args0Value.Contains("%"))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            if (exp.Method.Name == "StartsWith") return $"strpos({args0Value}, {left}) = 1";
 | 
				
			||||||
 | 
					                            if (exp.Method.Name == "EndsWith") return $"strpos({args0Value}, {left}) = char_length({args0Value})";
 | 
				
			||||||
 | 
					                            return $"strpos({args0Value}, {left}) > 0";
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        var likeOpt = "LIKE";
 | 
				
			||||||
 | 
					                        if (exp.Arguments.Count > 1)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            if (exp.Arguments[1].Type == typeof(bool) ||
 | 
				
			||||||
 | 
					                                exp.Arguments[1].Type == typeof(StringComparison)) likeOpt = "ILIKE";
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::text || '%')")}";
 | 
				
			||||||
 | 
					                        if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::text)")}";
 | 
				
			||||||
 | 
					                        if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
 | 
				
			||||||
 | 
					                        return $"({left}) {likeOpt} ('%' || ({args0Value})::text || '%')";
 | 
				
			||||||
 | 
					                    case "ToLower": return $"lower({left})";
 | 
				
			||||||
 | 
					                    case "ToUpper": return $"upper({left})";
 | 
				
			||||||
 | 
					                    case "Substring":
 | 
				
			||||||
 | 
					                        var substrArgs1 = getExp(exp.Arguments[0]);
 | 
				
			||||||
 | 
					                        if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString();
 | 
				
			||||||
 | 
					                        else substrArgs1 += "+1";
 | 
				
			||||||
 | 
					                        if (exp.Arguments.Count == 1) return $"substr({left}, {substrArgs1})";
 | 
				
			||||||
 | 
					                        return $"substr({left}, {substrArgs1}, {getExp(exp.Arguments[1])})";
 | 
				
			||||||
 | 
					                    case "IndexOf": return $"(strpos({left}, {getExp(exp.Arguments[0])})-1)";
 | 
				
			||||||
 | 
					                    case "PadLeft":
 | 
				
			||||||
 | 
					                        if (exp.Arguments.Count == 1) return $"lpad({left}, {getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                        return $"lpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
				
			||||||
 | 
					                    case "PadRight":
 | 
				
			||||||
 | 
					                        if (exp.Arguments.Count == 1) return $"rpad({left}, {getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                        return $"rpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
				
			||||||
 | 
					                    case "Trim":
 | 
				
			||||||
 | 
					                    case "TrimStart":
 | 
				
			||||||
 | 
					                    case "TrimEnd":
 | 
				
			||||||
 | 
					                        if (exp.Arguments.Count == 0)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            if (exp.Method.Name == "Trim") return $"trim({left})";
 | 
				
			||||||
 | 
					                            if (exp.Method.Name == "TrimStart") return $"ltrim({left})";
 | 
				
			||||||
 | 
					                            if (exp.Method.Name == "TrimEnd") return $"rtrim({left})";
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        var trimArg1 = "";
 | 
				
			||||||
 | 
					                        var trimArg2 = "";
 | 
				
			||||||
 | 
					                        foreach (var argsTrim02 in exp.Arguments)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var argsTrim01s = new[] { argsTrim02 };
 | 
				
			||||||
 | 
					                            if (argsTrim02.NodeType == ExpressionType.NewArrayInit)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                var arritem = argsTrim02 as NewArrayExpression;
 | 
				
			||||||
 | 
					                                argsTrim01s = arritem.Expressions.ToArray();
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            foreach (var argsTrim01 in argsTrim01s)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                var trimChr = getExp(argsTrim01).Trim('\'');
 | 
				
			||||||
 | 
					                                if (trimChr.Length == 1) trimArg1 += trimChr;
 | 
				
			||||||
 | 
					                                else trimArg2 += $" || ({trimChr})";
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (exp.Method.Name == "Trim") left = $"trim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
 | 
				
			||||||
 | 
					                        if (exp.Method.Name == "TrimStart") left = $"ltrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
 | 
				
			||||||
 | 
					                        if (exp.Method.Name == "TrimEnd") left = $"rtrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
 | 
				
			||||||
 | 
					                        return left;
 | 
				
			||||||
 | 
					                    case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
				
			||||||
 | 
					                    case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end";
 | 
				
			||||||
 | 
					                    case "Equals": return $"({left} = ({getExp(exp.Arguments[0])})::text)";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, ExpTSC tsc)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
 | 
				
			||||||
 | 
					            switch (exp.Method.Name)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case "Abs": return $"abs({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Sign": return $"sign({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Floor": return $"floor({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Ceiling": return $"ceiling({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Round":
 | 
				
			||||||
 | 
					                    if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
				
			||||||
 | 
					                    return $"round({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Exp": return $"exp({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Log": return $"log({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Log10": return $"log10({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Pow": return $"pow({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
				
			||||||
 | 
					                case "Sqrt": return $"sqrt({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Cos": return $"cos({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Sin": return $"sin({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Tan": return $"tan({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Acos": return $"acos({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Asin": return $"asin({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Atan": return $"atan({getExp(exp.Arguments[0])})";
 | 
				
			||||||
 | 
					                case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
				
			||||||
 | 
					                case "Truncate": return $"trunc({getExp(exp.Arguments[0])}, 0)";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, ExpTSC tsc)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
 | 
				
			||||||
 | 
					            if (exp.Object == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                switch (exp.Method.Name)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case "Compare": return $"extract(epoch from ({getExp(exp.Arguments[0])})::timestamp-({getExp(exp.Arguments[1])})::timestamp)";
 | 
				
			||||||
 | 
					                    case "DaysInMonth": return $"extract(day from ({getExp(exp.Arguments[0])} || '-' || {getExp(exp.Arguments[1])} || '-01')::timestamp+'1 month'::interval-'1 day'::interval)";
 | 
				
			||||||
 | 
					                    case "Equals": return $"(({getExp(exp.Arguments[0])})::timestamp = ({getExp(exp.Arguments[1])})::timestamp)";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    case "IsLeapYear":
 | 
				
			||||||
 | 
					                        var isLeapYearArgs1 = getExp(exp.Arguments[0]);
 | 
				
			||||||
 | 
					                        return $"(({isLeapYearArgs1})::int8%4=0 AND ({isLeapYearArgs1})::int8%100<>0 OR ({isLeapYearArgs1})::int8%400=0)";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    case "Parse": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"({getExp(exp.Arguments[0])})::timestamp";
 | 
				
			||||||
 | 
					                    case "ParseExact":
 | 
				
			||||||
 | 
					                    case "TryParse":
 | 
				
			||||||
 | 
					                    case "TryParseExact": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"({getExp(exp.Arguments[0])})::timestamp";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var left = getExp(exp.Object);
 | 
				
			||||||
 | 
					                var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]);
 | 
				
			||||||
 | 
					                switch (exp.Method.Name)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case "Add": return $"(({left})::timestamp+((({args1})/1000)||' milliseconds')::interval)";
 | 
				
			||||||
 | 
					                    case "AddDays": return $"(({left})::timestamp+(({args1})||' day')::interval)";
 | 
				
			||||||
 | 
					                    case "AddHours": return $"(({left})::timestamp+(({args1})||' hour')::interval)";
 | 
				
			||||||
 | 
					                    case "AddMilliseconds": return $"(({left})::timestamp+(({args1})||' milliseconds')::interval)";
 | 
				
			||||||
 | 
					                    case "AddMinutes": return $"(({left})::timestamp+(({args1})||' minute')::interval)";
 | 
				
			||||||
 | 
					                    case "AddMonths": return $"(({left})::timestamp+(({args1})||' month')::interval)";
 | 
				
			||||||
 | 
					                    case "AddSeconds": return $"(({left})::timestamp+(({args1})||' second')::interval)";
 | 
				
			||||||
 | 
					                    case "AddTicks": return $"(({left})::timestamp+(({args1})/10||' microseconds')::interval)";
 | 
				
			||||||
 | 
					                    case "AddYears": return $"(({left})::timestamp+(({args1})||' year')::interval)";
 | 
				
			||||||
 | 
					                    case "Subtract":
 | 
				
			||||||
 | 
					                        switch ((exp.Arguments[0].Type.IsNullableType() ? exp.Arguments[0].Type.GetGenericArguments().FirstOrDefault() : exp.Arguments[0].Type).FullName)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            case "System.DateTime": return $"(extract(epoch from ({left})::timestamp-({args1})::timestamp)*1000000)";
 | 
				
			||||||
 | 
					                            case "System.TimeSpan": return $"(({left})::timestamp-((({args1})/1000)||' milliseconds')::interval)";
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case "Equals": return $"({left} = ({args1})::timestamp)";
 | 
				
			||||||
 | 
					                    case "CompareTo": return $"extract(epoch from ({left})::timestamp-({args1})::timestamp)";
 | 
				
			||||||
 | 
					                    case "ToString":
 | 
				
			||||||
 | 
					                        if (left.EndsWith("::timestamp") == false) left = $"({left})::timestamp";
 | 
				
			||||||
 | 
					                        if (exp.Arguments.Count == 0) return $"to_char({left},'YYYY-MM-DD HH24:MI:SS.US')";
 | 
				
			||||||
 | 
					                        switch (args1)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            case "'yyyy-MM-dd HH:mm:ss'": return $"to_char({left},'YYYY-MM-DD HH24:MI:SS')";
 | 
				
			||||||
 | 
					                            case "'yyyy-MM-dd HH:mm'": return $"to_char({left},'YYYY-MM-DD HH24:MI')";
 | 
				
			||||||
 | 
					                            case "'yyyy-MM-dd HH'": return $"to_char({left},'YYYY-MM-DD HH24')";
 | 
				
			||||||
 | 
					                            case "'yyyy-MM-dd'": return $"to_char({left},'YYYY-MM-DD')";
 | 
				
			||||||
 | 
					                            case "'yyyy-MM'": return $"to_char({left},'YYYY-MM')";
 | 
				
			||||||
 | 
					                            case "'yyyyMMddHHmmss'": return $"to_char({left},'YYYYMMDDHH24MISS')";
 | 
				
			||||||
 | 
					                            case "'yyyyMMddHHmm'": return $"to_char({left},'YYYYMMDDHH24MI')";
 | 
				
			||||||
 | 
					                            case "'yyyyMMddHH'": return $"to_char({left},'YYYYMMDDHH24')";
 | 
				
			||||||
 | 
					                            case "'yyyyMMdd'": return $"to_char({left},'YYYYMMDD')";
 | 
				
			||||||
 | 
					                            case "'yyyyMM'": return $"to_char({left},'YYYYMM')";
 | 
				
			||||||
 | 
					                            case "'yyyy'": return $"to_char({left},'YYYY')";
 | 
				
			||||||
 | 
					                            case "'HH:mm:ss'": return $"to_char({left},'HH24:MI:SS')";
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        args1 = Regex.Replace(args1, "(yyyy|yy|MM|dd|HH|hh|mm|ss|tt)", m =>
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            switch (m.Groups[1].Value)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                case "yyyy": return $"YYYY";
 | 
				
			||||||
 | 
					                                case "yy": return $"YY";
 | 
				
			||||||
 | 
					                                case "MM": return $"%_a1";
 | 
				
			||||||
 | 
					                                case "dd": return $"%_a2";
 | 
				
			||||||
 | 
					                                case "HH": return $"%_a3";
 | 
				
			||||||
 | 
					                                case "hh": return $"%_a4";
 | 
				
			||||||
 | 
					                                case "mm": return $"%_a5";
 | 
				
			||||||
 | 
					                                case "ss": return $"SS";
 | 
				
			||||||
 | 
					                                case "tt": return $"%_a6";
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            return m.Groups[0].Value;
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                        var argsFinds = new[] { "YYYY", "YY", "%_a1", "%_a2", "%_a3", "%_a4", "%_a5", "SS", "%_a6" };
 | 
				
			||||||
 | 
					                        var argsSpts = Regex.Split(args1, "(M|d|H|h|m|s|t)");
 | 
				
			||||||
 | 
					                        for (var a = 0; a < argsSpts.Length; a++)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            switch (argsSpts[a])
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                case "M": argsSpts[a] = $"ltrim(to_char({left},'MM'),'0')"; break;
 | 
				
			||||||
 | 
					                                case "d": argsSpts[a] = $"case when substr(to_char({left},'DD'),1,1) = '0' then substr(to_char({left},'DD'),2,1) else to_char({left},'DD') end"; break;
 | 
				
			||||||
 | 
					                                case "H": argsSpts[a] = $"case when substr(to_char({left},'HH24'),1,1) = '0' then substr(to_char({left},'HH24'),2,1) else to_char({left},'HH24') end"; break;
 | 
				
			||||||
 | 
					                                case "h": argsSpts[a] = $"case when substr(to_char({left},'HH12'),1,1) = '0' then substr(to_char({left},'HH12'),2,1) else to_char({left},'HH12') end"; break;
 | 
				
			||||||
 | 
					                                case "m": argsSpts[a] = $"case when substr(to_char({left},'MI'),1,1) = '0' then substr(to_char({left},'MI'),2,1) else to_char({left},'MI') end"; break;
 | 
				
			||||||
 | 
					                                case "s": argsSpts[a] = $"case when substr(to_char({left},'SS'),1,1) = '0' then substr(to_char({left},'SS'),2,1) else to_char({left},'SS') end"; break;
 | 
				
			||||||
 | 
					                                case "t": argsSpts[a] = $"rtrim(to_char({left},'AM'),'M')"; break;
 | 
				
			||||||
 | 
					                                default:
 | 
				
			||||||
 | 
					                                    var argsSptsA = argsSpts[a];
 | 
				
			||||||
 | 
					                                    if (argsSptsA.StartsWith("'")) argsSptsA = argsSptsA.Substring(1);
 | 
				
			||||||
 | 
					                                    if (argsSptsA.EndsWith("'")) argsSptsA = argsSptsA.Remove(argsSptsA.Length - 1);
 | 
				
			||||||
 | 
					                                    argsSpts[a] = argsFinds.Any(m => argsSptsA.Contains(m)) ? $"to_char({left},'{argsSptsA}')" : $"'{argsSptsA}'"; 
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (argsSpts.Length > 0) args1 = $"({string.Join(" || ", argsSpts.Where(a => a != "''"))})";
 | 
				
			||||||
 | 
					                        return args1.Replace("%_a1", "MM").Replace("%_a2", "DD").Replace("%_a3", "HH24").Replace("%_a4", "HH12").Replace("%_a5", "MI").Replace("%_a6", "AM");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, ExpTSC tsc)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
 | 
				
			||||||
 | 
					            if (exp.Object == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                switch (exp.Method.Name)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case "Compare": return $"({getExp(exp.Arguments[0])}-({getExp(exp.Arguments[1])}))";
 | 
				
			||||||
 | 
					                    case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})";
 | 
				
			||||||
 | 
					                    case "FromDays": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60 * 60 * 24})";
 | 
				
			||||||
 | 
					                    case "FromHours": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60 * 60})";
 | 
				
			||||||
 | 
					                    case "FromMilliseconds": return $"(({getExp(exp.Arguments[0])})*1000)";
 | 
				
			||||||
 | 
					                    case "FromMinutes": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60})";
 | 
				
			||||||
 | 
					                    case "FromSeconds": return $"(({getExp(exp.Arguments[0])})*1000000)";
 | 
				
			||||||
 | 
					                    case "FromTicks": return $"(({getExp(exp.Arguments[0])})/10)";
 | 
				
			||||||
 | 
					                    case "Parse": return $"({getExp(exp.Arguments[0])})::int8";
 | 
				
			||||||
 | 
					                    case "ParseExact":
 | 
				
			||||||
 | 
					                    case "TryParse":
 | 
				
			||||||
 | 
					                    case "TryParseExact": return $"({getExp(exp.Arguments[0])})::int8";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var left = getExp(exp.Object);
 | 
				
			||||||
 | 
					                var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]);
 | 
				
			||||||
 | 
					                switch (exp.Method.Name)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case "Add": return $"({left}+{args1})";
 | 
				
			||||||
 | 
					                    case "Subtract": return $"({left}-({args1}))";
 | 
				
			||||||
 | 
					                    case "Equals": return $"({left} = {args1})";
 | 
				
			||||||
 | 
					                    case "CompareTo": return $"({left}-({args1}))";
 | 
				
			||||||
 | 
					                    case "ToString": return $"({left})::varchar";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, ExpTSC tsc)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
 | 
				
			||||||
 | 
					            if (exp.Object == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                switch (exp.Method.Name)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case "ToBoolean": return $"(({getExp(exp.Arguments[0])})::varchar not in ('0','false','f','no'))";
 | 
				
			||||||
 | 
					                    case "ToByte": return $"({getExp(exp.Arguments[0])})::int2";
 | 
				
			||||||
 | 
					                    case "ToChar": return $"substr(({getExp(exp.Arguments[0])})::char, 1, 1)";
 | 
				
			||||||
 | 
					                    case "ToDateTime": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"({getExp(exp.Arguments[0])})::timestamp";
 | 
				
			||||||
 | 
					                    case "ToDecimal": return $"({getExp(exp.Arguments[0])})::numeric";
 | 
				
			||||||
 | 
					                    case "ToDouble": return $"({getExp(exp.Arguments[0])})::float8";
 | 
				
			||||||
 | 
					                    case "ToInt16": return $"({getExp(exp.Arguments[0])})::int2";
 | 
				
			||||||
 | 
					                    case "ToInt32": return $"({getExp(exp.Arguments[0])})::int4";
 | 
				
			||||||
 | 
					                    case "ToInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
				
			||||||
 | 
					                    case "ToSByte": return $"({getExp(exp.Arguments[0])})::int2";
 | 
				
			||||||
 | 
					                    case "ToSingle": return $"({getExp(exp.Arguments[0])})::float4";
 | 
				
			||||||
 | 
					                    case "ToString": return $"({getExp(exp.Arguments[0])})::text";
 | 
				
			||||||
 | 
					                    case "ToUInt16": return $"({getExp(exp.Arguments[0])})::int2";
 | 
				
			||||||
 | 
					                    case "ToUInt32": return $"({getExp(exp.Arguments[0])})::int4";
 | 
				
			||||||
 | 
					                    case "ToUInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										20
									
								
								Providers/FreeSql.Provider.Xugu/XuguExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Providers/FreeSql.Provider.Xugu/XuguExtensions.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					using FreeSql;
 | 
				
			||||||
 | 
					using FreeSql.Xugu.Curd;
 | 
				
			||||||
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using XuguClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public static partial class FreeSqlXuguGlobalExtensions
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="that"></param>
 | 
				
			||||||
 | 
					    /// <param name="args"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public static string FormatXuguSQL(this string that, params object[] args) => _xgsqlAdo.Addslashes(that, args);
 | 
				
			||||||
 | 
					    static FreeSql.Xugu.XuguAdo _xgsqlAdo = new FreeSql.Xugu.XuguAdo();
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										131
									
								
								Providers/FreeSql.Provider.Xugu/XuguProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								Providers/FreeSql.Provider.Xugu/XuguProvider.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.CommonProvider;
 | 
				
			||||||
 | 
					using FreeSql.Xugu.Curd;
 | 
				
			||||||
 | 
					using Newtonsoft.Json;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					using System.Reflection;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Xugu
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class XuguProvider<TMark> : BaseDbProvider, IFreeSql<TMark>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        static XuguProvider()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Utils.dicExecuteArrayRowReadClassOrTuple[typeof(BigInteger)] = true;
 | 
				
			||||||
 | 
					            Utils.dicExecuteArrayRowReadClassOrTuple[typeof(BitArray)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlPoint)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlLine)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlLSeg)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlBox)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlPath)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlPolygon)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlCircle)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof((IPAddress Address, int Subnet))] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(IPAddress)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PhysicalAddress)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlRange<int>)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlRange<long>)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlRange<decimal>)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlRange<DateTime>)] = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisPoint)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisLineString)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisPolygon)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisMultiPoint)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisMultiLineString)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisMultiPolygon)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisGeometry)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisGeometryCollection)] = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(Dictionary<string, string>)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(JToken)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(JObject)] = true;
 | 
				
			||||||
 | 
					            //Utils.dicExecuteArrayRowReadClassOrTuple[typeof(JArray)] = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var MethodJTokenFromObject = typeof(JToken).GetMethod("FromObject", new[] { typeof(object) });
 | 
				
			||||||
 | 
					            var MethodJObjectFromObject = typeof(JObject).GetMethod("FromObject", new[] { typeof(object) });
 | 
				
			||||||
 | 
					            var MethodJArrayFromObject = typeof(JArray).GetMethod("FromObject", new[] { typeof(object) });
 | 
				
			||||||
 | 
					            var MethodJTokenParse = typeof(JToken).GetMethod("Parse", new[] { typeof(string) });
 | 
				
			||||||
 | 
					            var MethodJObjectParse = typeof(JObject).GetMethod("Parse", new[] { typeof(string) });
 | 
				
			||||||
 | 
					            var MethodJArrayParse = typeof(JArray).GetMethod("Parse", new[] { typeof(string) });
 | 
				
			||||||
 | 
					            var MethodJsonConvertDeserializeObject = typeof(JsonConvert).GetMethod("DeserializeObject", new[] { typeof(string), typeof(Type) });
 | 
				
			||||||
 | 
					            var MethodToString = typeof(Utils).GetMethod("ToStringConcat", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(object) }, null);
 | 
				
			||||||
 | 
					            Utils.GetDataReaderValueBlockExpressionSwitchTypeFullName.Add((LabelTarget returnTarget, Expression valueExp, Type type) =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                switch (type.FullName)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case "Newtonsoft.Json.Linq.JToken":
 | 
				
			||||||
 | 
					                        return Expression.IfThenElse(
 | 
				
			||||||
 | 
					                            Expression.TypeIs(valueExp, typeof(string)),
 | 
				
			||||||
 | 
					                            Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJTokenParse, Expression.Convert(valueExp, typeof(string))), typeof(JToken))),
 | 
				
			||||||
 | 
					                            Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJTokenFromObject, valueExp), typeof(JToken))));
 | 
				
			||||||
 | 
					                    case "Newtonsoft.Json.Linq.JObject":
 | 
				
			||||||
 | 
					                        return Expression.IfThenElse(
 | 
				
			||||||
 | 
					                            Expression.TypeIs(valueExp, typeof(string)),
 | 
				
			||||||
 | 
					                            Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJObjectParse, Expression.Convert(valueExp, typeof(string))), typeof(JObject))),
 | 
				
			||||||
 | 
					                            Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJObjectFromObject, valueExp), typeof(JObject))));
 | 
				
			||||||
 | 
					                    case "Newtonsoft.Json.Linq.JArray":
 | 
				
			||||||
 | 
					                        return Expression.IfThenElse(
 | 
				
			||||||
 | 
					                            Expression.TypeIs(valueExp, typeof(string)),
 | 
				
			||||||
 | 
					                            Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJArrayParse, Expression.Convert(valueExp, typeof(string))), typeof(JArray))),
 | 
				
			||||||
 | 
					                            Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJArrayFromObject, valueExp), typeof(JArray))));
 | 
				
			||||||
 | 
					                    //case "Npgsql.LegacyPostgis.PostgisGeometry": 
 | 
				
			||||||
 | 
					                    //    return Expression.Return(returnTarget, valueExp);
 | 
				
			||||||
 | 
					                    //case "NetTopologySuite.Geometries.Geometry": 
 | 
				
			||||||
 | 
					                    //    return Expression.Return(returnTarget, valueExp);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (typeof(IList).IsAssignableFrom(type))
 | 
				
			||||||
 | 
					                    return Expression.IfThenElse(
 | 
				
			||||||
 | 
					                        Expression.TypeIs(valueExp, typeof(string)),
 | 
				
			||||||
 | 
					                        Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJsonConvertDeserializeObject, Expression.Convert(valueExp, typeof(string)), Expression.Constant(type, typeof(Type))), type)),
 | 
				
			||||||
 | 
					                        Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJsonConvertDeserializeObject, Expression.Convert(Expression.Call(MethodToString, valueExp), typeof(string)), Expression.Constant(type, typeof(Type))), type)));
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					            }); 
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            Select0Provider._dicMethodDataReaderGetValue[typeof(Guid)] = typeof(DbDataReader).GetMethod("GetGuid", new Type[] { typeof(int) });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override ISelect<T1> CreateSelectProvider<T1>(object dywhere) => new XuguSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public override IInsert<T1> CreateInsertProvider<T1>() => new XuguInsert<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					        public override IUpdate<T1> CreateUpdateProvider<T1>(object dywhere) => new XuguUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public override IDelete<T1> CreateDeleteProvider<T1>(object dywhere) => new XuguDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
					        public override IInsertOrUpdate<T1> CreateInsertOrUpdateProvider<T1>() => new XuguInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public XuguProvider(string masterConnectionString, string[] slaveConnectionString, Func<DbConnection> connectionFactory = null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.InternalCommonUtils = new XuguUtils(this);
 | 
				
			||||||
 | 
					            this.InternalCommonExpression = new XuguExpression(this.InternalCommonUtils);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Ado = new XuguAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString, connectionFactory);
 | 
				
			||||||
 | 
					            this.Aop = new AopProvider();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.DbFirst = new XuguDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					            this.CodeFirst = new XuguCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //this.Aop.AuditDataReader += (_, e) =>
 | 
				
			||||||
 | 
					            //{
 | 
				
			||||||
 | 
					            //    var dbtype = e.DataReader.GetDataTypeName(e.Index);
 | 
				
			||||||
 | 
					            //    var m = Regex.Match(dbtype, @"numeric\((\d+)\)", RegexOptions.IgnoreCase);
 | 
				
			||||||
 | 
					            //    if (m.Success && int.Parse(m.Groups[1].Value) > 19)
 | 
				
			||||||
 | 
					            //        e.Value = e.DataReader.GetFieldValue<BigInteger>(e.Index);
 | 
				
			||||||
 | 
					            //};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ~XuguProvider() => this.Dispose();
 | 
				
			||||||
 | 
					        int _disposeCounter;
 | 
				
			||||||
 | 
					        public override void Dispose()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (Interlocked.Increment(ref _disposeCounter) != 1) return;
 | 
				
			||||||
 | 
					            (this.Ado as AdoProvider)?.Dispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										185
									
								
								Providers/FreeSql.Provider.Xugu/XuguUtils.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								Providers/FreeSql.Provider.Xugu/XuguUtils.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,185 @@
 | 
				
			|||||||
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections;
 | 
				
			||||||
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
 | 
					using System.Globalization;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using XuguClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Xugu
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class XuguUtils : CommonUtils
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public XuguUtils(IFreeSql orm) : base(orm)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static Array getParamterArrayValue(Type arrayType, object value, object defaultValue)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var valueArr = value as Array;
 | 
				
			||||||
 | 
					            var len = valueArr.GetLength(0);
 | 
				
			||||||
 | 
					            var ret = Array.CreateInstance(arrayType, len);
 | 
				
			||||||
 | 
					            for (var a = 0; a < len; a++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var item = valueArr.GetValue(a);
 | 
				
			||||||
 | 
					                ret.SetValue(item == null ? defaultValue : getParamterValue(item.GetType(), item, 1), a);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public override string QuoteSqlNameAdapter(params string[] name)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (name.Length == 1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var nametrim = name[0].Trim();
 | 
				
			||||||
 | 
					                if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
 | 
				
			||||||
 | 
					                    return nametrim; //原生SQL
 | 
				
			||||||
 | 
					                if (nametrim.StartsWith("\"") && nametrim.EndsWith("\""))
 | 
				
			||||||
 | 
					                    return nametrim;
 | 
				
			||||||
 | 
					                return $"\"{nametrim.Replace(".", "\".\"")}\"";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return $"\"{string.Join("\".\"", name)}\"";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        static Dictionary<string, Func<object, object>> dicGetParamterValue = new Dictionary<string, Func<object, object>> {
 | 
				
			||||||
 | 
					            //{ typeof(JToken).FullName, a => string.Concat(a) }, { typeof(JToken[]).FullName, a => getParamterArrayValue(typeof(string), a, null) },
 | 
				
			||||||
 | 
					            //{ typeof(JObject).FullName, a => string.Concat(a) }, { typeof(JObject[]).FullName, a => getParamterArrayValue(typeof(string), a, null) },
 | 
				
			||||||
 | 
					            //{ typeof(JArray).FullName, a => string.Concat(a) }, { typeof(JArray[]).FullName, a => getParamterArrayValue(typeof(string), a, null) },
 | 
				
			||||||
 | 
					            { typeof(uint).FullName, a => long.Parse(string.Concat(a)) }, { typeof(uint[]).FullName, a => getParamterArrayValue(typeof(long), a, 0) }, { typeof(uint?[]).FullName, a => getParamterArrayValue(typeof(long?), a, null) },
 | 
				
			||||||
 | 
					            { typeof(ulong).FullName, a => decimal.Parse(string.Concat(a)) }, { typeof(ulong[]).FullName, a => getParamterArrayValue(typeof(decimal), a, 0) }, { typeof(ulong?[]).FullName, a => getParamterArrayValue(typeof(decimal?), a, null) },
 | 
				
			||||||
 | 
					            { typeof(ushort).FullName, a => int.Parse(string.Concat(a)) }, { typeof(ushort[]).FullName, a => getParamterArrayValue(typeof(int), a, 0) }, { typeof(ushort?[]).FullName, a => getParamterArrayValue(typeof(int?), a, null) },
 | 
				
			||||||
 | 
					            { typeof(byte).FullName, a => short.Parse(string.Concat(a)) }, { typeof(byte[]).FullName, a => getParamterArrayValue(typeof(short), a, 0) }, { typeof(byte?[]).FullName, a => getParamterArrayValue(typeof(short?), a, null) },
 | 
				
			||||||
 | 
					            { typeof(sbyte).FullName, a => short.Parse(string.Concat(a)) }, { typeof(sbyte[]).FullName, a => getParamterArrayValue(typeof(short), a, 0) }, { typeof(sbyte?[]).FullName, a => getParamterArrayValue(typeof(short?), a, null) },
 | 
				
			||||||
 | 
					            { typeof(char).FullName, a => string.Concat(a).Replace('\0', ' ').ToCharArray().FirstOrDefault() }, 
 | 
				
			||||||
 | 
					            { typeof(BigInteger).FullName, a => BigInteger.Parse(string.Concat(a), System.Globalization.NumberStyles.Any) }, { typeof(BigInteger[]).FullName, a => getParamterArrayValue(typeof(BigInteger), a, 0) }, { typeof(BigInteger?[]).FullName, a => getParamterArrayValue(typeof(BigInteger?), a, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         
 | 
				
			||||||
 | 
					            { typeof((IPAddress Address, int Subnet)).FullName, a => {
 | 
				
			||||||
 | 
					                var inet = ((IPAddress Address, int Subnet))a;
 | 
				
			||||||
 | 
					                if (inet.Address == null) return (IPAddress.Any, inet.Subnet);
 | 
				
			||||||
 | 
					                return inet;
 | 
				
			||||||
 | 
					            } }, 
 | 
				
			||||||
 | 
					            { typeof((IPAddress Address, int Subnet)[]).FullName, a => getParamterArrayValue(typeof((IPAddress Address, int Subnet)), a, (IPAddress.Any, 0)) }, 
 | 
				
			||||||
 | 
					            { typeof((IPAddress Address, int Subnet)?[]).FullName, a => getParamterArrayValue(typeof((IPAddress Address, int Subnet)?), a, null) },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        static object getParamterValue(Type type, object value, int level = 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (type.FullName == "System.Byte[]") return value;
 | 
				
			||||||
 | 
					            if (type.FullName == "System.Char[]") return value;
 | 
				
			||||||
 | 
					            if (type.IsArray && level == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var elementType = type.GetElementType();
 | 
				
			||||||
 | 
					                Type enumType = null;
 | 
				
			||||||
 | 
					                if (elementType.IsEnum) enumType = elementType;
 | 
				
			||||||
 | 
					                else if (elementType.IsNullableType() && elementType.GenericTypeArguments.First().IsEnum) enumType = elementType.GenericTypeArguments.First();
 | 
				
			||||||
 | 
					                if (enumType != null) return enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
				
			||||||
 | 
					                    getParamterArrayValue(typeof(long), value, elementType.IsEnum ? null : enumType.CreateInstanceGetDefaultValue()) :
 | 
				
			||||||
 | 
					                    getParamterArrayValue(typeof(int), value, elementType.IsEnum ? null : enumType.CreateInstanceGetDefaultValue());
 | 
				
			||||||
 | 
					                return dicGetParamterValue.TryGetValue(type.FullName, out var trydicarr) ? trydicarr(value) : value;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (type.IsNullableType()) type = type.GenericTypeArguments.First();
 | 
				
			||||||
 | 
					            if (type.IsEnum) return (int)value;
 | 
				
			||||||
 | 
					            if (dicGetParamterValue.TryGetValue(type.FullName, out var trydic)) return trydic(value);
 | 
				
			||||||
 | 
					            return value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override DbParameter AppendParamter(List<DbParameter> _params, string parameterName, ColumnInfo col, Type type, object value)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}";
 | 
				
			||||||
 | 
					            if (value != null) value = getParamterValue(type, value);
 | 
				
			||||||
 | 
					            var ret = new XGParameters { ParameterName = QuoteParamterName(parameterName), Value = value };
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					            var tp = _orm.CodeFirst.GetDbInfo(type)?.type; 
 | 
				
			||||||
 | 
					            if (col != null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var dbtype = (XGDbType)_orm.DbFirst.GetDbType(new DatabaseModel.DbColumnInfo { DbTypeText = col.DbTypeText });
 | 
				
			||||||
 | 
					                if (dbtype != null)
 | 
				
			||||||
 | 
					                { 
 | 
				
			||||||
 | 
					                    if (col.DbPrecision != 0) ret.Precision = col.DbPrecision;
 | 
				
			||||||
 | 
					                    if (col.DbScale != 0) ret.Scale = col.DbScale;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } 
 | 
				
			||||||
 | 
					            _params?.Add(ret);
 | 
				
			||||||
 | 
					            return ret;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override DbParameter[] GetDbParamtersByObject(string sql, object obj) =>
 | 
				
			||||||
 | 
					            Utils.GetDbParamtersByObject<XGParameters>(sql, obj, "@", (name, type, value) =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (value != null) value = getParamterValue(type, value);
 | 
				
			||||||
 | 
					                var ret = new XGParameters { ParameterName = $"@{name}", Value = value };
 | 
				
			||||||
 | 
					             
 | 
				
			||||||
 | 
					                var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
 | 
				
			||||||
 | 
					               
 | 
				
			||||||
 | 
					                return ret;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string FormatSql(string sql, params object[] args) => sql?.FormatXuguSQL(args);
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					        public override string TrimQuoteSqlName(string name)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var nametrim = name.Trim();
 | 
				
			||||||
 | 
					            if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
 | 
				
			||||||
 | 
					                return nametrim; //原生SQL
 | 
				
			||||||
 | 
					            return $"{nametrim.Trim('"').Replace("\".\"", ".").Replace(".\"", ".")}";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public override string[] SplitTableName(string name) => GetSplitTableNames(name, '"', '"', 2);
 | 
				
			||||||
 | 
					        public override string QuoteParamterName(string name) => $"@{name}";
 | 
				
			||||||
 | 
					        public override string IsNull(string sql, object value) => $"coalesce({sql}, {value})";
 | 
				
			||||||
 | 
					        public override string StringConcat(string[] objs, Type[] types) => $"{string.Join(" || ", objs)}";
 | 
				
			||||||
 | 
					        public override string Mod(string left, string right, Type leftType, Type rightType) => $"{left} % {right}";
 | 
				
			||||||
 | 
					        public override string Div(string left, string right, Type leftType, Type rightType) => $"{left} / {right}";
 | 
				
			||||||
 | 
					        public override string Now => "current_timestamp";
 | 
				
			||||||
 | 
					        public override string NowUtc => "(current_timestamp at time zone 'UTC')";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string QuoteWriteParamterAdapter(Type type, string paramterName) => paramterName;
 | 
				
			||||||
 | 
					        protected override string QuoteReadColumnAdapter(Type type, Type mapType, string columnName) => columnName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static ConcurrentDictionary<Type, bool> _dicIsAssignableFromPostgisGeometry = new ConcurrentDictionary<Type, bool>();
 | 
				
			||||||
 | 
					        public override string GetNoneParamaterSqlValue(List<DbParameter> specialParams, string specialParamFlag, ColumnInfo col, Type type, object value)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (value == null) return "NULL";
 | 
				
			||||||
 | 
					            if (type.IsNumberType()) return string.Format(CultureInfo.InvariantCulture, "{0}", value);
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					            value = getParamterValue(type, value);
 | 
				
			||||||
 | 
					            var type2 = value.GetType();
 | 
				
			||||||
 | 
					            if (type2 == typeof(byte[])) return $"'\\x{CommonUtils.BytesSqlRaw(value as byte[])}'";
 | 
				
			||||||
 | 
					            if (type2 == typeof(TimeSpan) || type2 == typeof(TimeSpan?))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var ts = (TimeSpan)value;
 | 
				
			||||||
 | 
					                return $"'{Math.Min(24, (int)Math.Floor(ts.TotalHours))}:{ts.Minutes}:{ts.Seconds}'";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (value is Array)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var valueArr = value as Array;
 | 
				
			||||||
 | 
					                var eleType = type2.GetElementType();
 | 
				
			||||||
 | 
					                var len = valueArr.GetLength(0);
 | 
				
			||||||
 | 
					                var sb = new StringBuilder().Append("ARRAY[");
 | 
				
			||||||
 | 
					                for (var a = 0; a < len; a++)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var item = valueArr.GetValue(a);
 | 
				
			||||||
 | 
					                    if (a > 0) sb.Append(",");
 | 
				
			||||||
 | 
					                    sb.Append(GetNoneParamaterSqlValue(specialParams, specialParamFlag, col, eleType, item));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                sb.Append("]");
 | 
				
			||||||
 | 
					                var dbinfo = _orm.CodeFirst.GetDbInfo(type);
 | 
				
			||||||
 | 
					                if (dbinfo != null) sb.Append("::").Append(dbinfo.dbtype);
 | 
				
			||||||
 | 
					                return sb.ToString();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (type2 == typeof(BitArray))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return $"'{(value as BitArray).To1010()}'";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (dicGetParamterValue.ContainsKey(type2.FullName))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                value = string.Concat(value);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return FormatSql("{0}", value, 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								Providers/FreeSql.Provider.Xugu/key.snk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Providers/FreeSql.Provider.Xugu/key.snk
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Reference in New Issue
	
	Block a user