From 8331f43252ce471830a64f9079db3ba6b49b6925 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Thu, 28 May 2020 02:05:57 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=20FreeSql.Generator=20?= =?UTF-8?q?=E4=BA=BA=E5=A4=A7=E9=87=91=E4=BB=93=20=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E7=B1=BB=E7=94=9F=E6=88=90=E5=99=A8=EF=BC=9B#325?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Extensions/FreeSql.Generator/ConsoleApp.cs | 11 +- .../FreeSql.Generator.csproj | 1 + FreeSql.DbContext/FreeSql.DbContext.xml | 16 - .../FreeSql.Tests.Provider.Odbc.csproj | 5 + .../FreeSql.Tests.Provider.Odbc.xml | 103 +++++ .../KingbaseES/KingbaseESDbFirstTest.cs | 5 +- .../OdbcKingbaseESAdo/OdbcKingbaseESAdo.cs | 1 - .../KingbaseES/OdbcKingbaseESCodeFirst.cs | 270 +++++------- .../KingbaseES/OdbcKingbaseESDbFirst.cs | 388 +++++++++++++++++- .../KingbaseES/OdbcKingbaseESUtils.cs | 2 +- 10 files changed, 608 insertions(+), 194 deletions(-) create mode 100644 FreeSql.Tests/FreeSql.Tests.Provider.Odbc/FreeSql.Tests.Provider.Odbc.xml diff --git a/Extensions/FreeSql.Generator/ConsoleApp.cs b/Extensions/FreeSql.Generator/ConsoleApp.cs index cf65031c..040f374f 100644 --- a/Extensions/FreeSql.Generator/ConsoleApp.cs +++ b/Extensions/FreeSql.Generator/ConsoleApp.cs @@ -109,7 +109,10 @@ new Colorful.Formatter("v" + string.Join(".", typeof(ConsoleApp).Assembly.GetNam -DB ""{10},Data Source=document.db"" -DB ""{11},server=127.0.0.1;port=5236;user id=2user;password=123456789;database=2user;poolsize=2"" - {11} 是国产达梦数据库 + {11} 达梦数据库 + + -DB ""{12},Driver={KingbaseES 8.2 ODBC Driver ANSI};Server=127.0.0.1;Port=54321;UID=USER2;PWD=123456789;database=数据库"" + {12} 人大金仓数据库 -Filter Table+View+StoreProcedure 默认生成:表+视图+存储过程 @@ -120,7 +123,7 @@ new Colorful.Formatter("v" + string.Join(".", typeof(ConsoleApp).Assembly.GetNam -FileName 文件名,默认:{name}.cs -Output 保存路径,默认为当前 shell 所在目录 - {12} + {13} ", Color.SlateGray, new Colorful.Formatter("使用 FreeSql 快速生成数据库的实体类", Color.SlateGray), @@ -135,6 +138,7 @@ new Colorful.Formatter("PostgreSQL", Color.Yellow), new Colorful.Formatter("Oracle", Color.Yellow), new Colorful.Formatter("Sqlite", Color.Yellow), new Colorful.Formatter("Dameng", Color.Yellow), +new Colorful.Formatter("OdbcKingbaseES", Color.Yellow), new Colorful.Formatter("推荐在实体类目录创建 gen.bat,双击它重新所有实体类", Color.ForestGreen) ); wait.Set(); @@ -175,7 +179,8 @@ new Colorful.Formatter("推荐在实体类目录创建 gen.bat,双击它重新 case "oracle": ArgsDbType = DataType.Oracle; break; case "sqlite": ArgsDbType = DataType.Sqlite; break; case "dameng": ArgsDbType = DataType.Dameng; break; - default: throw new ArgumentException($"-DB 参数错误,不支持的类型:{dbargs[0]}"); + case "odbckingbasees": ArgsDbType = DataType.OdbcKingbaseES; break; + default: throw new ArgumentException($"-DB 参数错误,不支持的类型:\"{dbargs[0]}\""); } ArgsConnectionString = dbargs[1].Trim(); a++; diff --git a/Extensions/FreeSql.Generator/FreeSql.Generator.csproj b/Extensions/FreeSql.Generator/FreeSql.Generator.csproj index d4318157..0f6294e3 100644 --- a/Extensions/FreeSql.Generator/FreeSql.Generator.csproj +++ b/Extensions/FreeSql.Generator/FreeSql.Generator.csproj @@ -31,6 +31,7 @@ + diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 4854f49c..132d875e 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -125,13 +125,6 @@ 清空状态数据 - - - 根据 lambda 条件删除数据 - - - - 添加 @@ -486,14 +479,5 @@ - - - 批量注入 Repository,可以参考代码自行调整 - - - - - - diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/FreeSql.Tests.Provider.Odbc.csproj b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/FreeSql.Tests.Provider.Odbc.csproj index 3ece19a4..6aded025 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/FreeSql.Tests.Provider.Odbc.csproj +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/FreeSql.Tests.Provider.Odbc.csproj @@ -6,6 +6,11 @@ false + + FreeSql.Tests.Provider.Odbc.xml + 3 + + diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/FreeSql.Tests.Provider.Odbc.xml b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/FreeSql.Tests.Provider.Odbc.xml new file mode 100644 index 00000000..95f041b4 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/FreeSql.Tests.Provider.Odbc.xml @@ -0,0 +1,103 @@ + + + + FreeSql.Tests.Provider.Odbc + + + + + 保存或添加,如果主键有值则尝试 Update,如果影响的行为 0 则尝试 Insert + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 类型 + + + + + 内容简介 + + + + + 缩略图 + + + + + 点击量 + + + + + + + + + + + + + + + + + + + + + + + + + 测试中文重命名id + + + + + 姓名 + + + + + 试卷表 + + + + + 考核计划ID + + + + + 总分 + + + + diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/KingbaseES/KingbaseESDbFirstTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/KingbaseES/KingbaseESDbFirstTest.cs index 39adb728..eb3dc40b 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/KingbaseES/KingbaseESDbFirstTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/KingbaseES/KingbaseESDbFirstTest.cs @@ -9,16 +9,13 @@ namespace FreeSql.Tests.Odbc.KingbaseES [Fact] public void GetDatabases() { - var t1 = g.kingbaseES.DbFirst.GetDatabases(); - } [Fact] public void GetTablesByDatabase() { - - //var t2 = g.kingbaseES.DbFirst.GetTablesByDatabase(); + var t2 = g.kingbaseES.DbFirst.GetTablesByDatabase(); //var tb = g.kingbaseES.Ado.ExecuteArray(System.Data.CommandType.Text, "select * from \"tb_dbfirst\""); } } diff --git a/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESAdo/OdbcKingbaseESAdo.cs b/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESAdo/OdbcKingbaseESAdo.cs index 0a3d947f..b647490f 100644 --- a/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESAdo/OdbcKingbaseESAdo.cs +++ b/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESAdo/OdbcKingbaseESAdo.cs @@ -39,7 +39,6 @@ namespace FreeSql.Odbc.KingbaseES if (mapType != null && mapType != param.GetType() && (param is IEnumerable == false)) param = Utils.GetDataReaderValue(mapType, param); - bool isdic; if (param is bool || param is bool?) return (bool)param ? "'t'" : "'f'"; else if (param is string || param is char) diff --git a/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESCodeFirst.cs b/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESCodeFirst.cs index f777d3ae..efde626e 100644 --- a/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESCodeFirst.cs +++ b/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESCodeFirst.cs @@ -42,7 +42,7 @@ namespace FreeSql.Odbc.KingbaseES { typeof(bool).FullName, CsToDb.New(OdbcType.Bit, "bool","bool NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(OdbcType.Bit, "bool","bool", null, true, null) }, { typeof(Byte[]).FullName, CsToDb.New(OdbcType.VarBinary, "bytea", "bytea", false, null, new byte[0]) }, - { typeof(Guid).FullName, CsToDb.New(OdbcType.UniqueIdentifier, "char", "char(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(OdbcType.UniqueIdentifier, "char", "char(36)", false, true, null) }, + { typeof(Guid).FullName, CsToDb.New(OdbcType.UniqueIdentifier, "uuid", "uuid NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(OdbcType.UniqueIdentifier, "uuid", "uuid", false, true, null) }, }; public override DbInfoResult GetDbInfo(Type type) @@ -75,18 +75,9 @@ namespace FreeSql.Odbc.KingbaseES protected override string GetComparisonDDLStatements(params TypeAndName[] objects) { - var userId = (_orm.Ado.MasterPool as OdbcKingbaseESConnectionPool)?.UserId; - if (string.IsNullOrEmpty(userId)) - using (var conn = _orm.Ado.MasterPool.Get()) - { - userId = OdbcKingbaseESConnectionPool.GetUserId(conn.Value.ConnectionString); - } - - var defaultSchema = "PUBLIC"; - var seqcols = new List>(); //序列:列,表,自增 - var seqnameDel = new List(); //要删除的序列+触发器 - var sb = new StringBuilder(); + var seqcols = new List>(); //序列 + foreach (var obj in objects) { if (sb.Length > 0) sb.Append("\r\n"); @@ -94,42 +85,40 @@ namespace FreeSql.Odbc.KingbaseES if (tb == null) throw new Exception($"类型 {obj.entityType.FullName} 不可迁移"); if (tb.Columns.Any() == false) throw new Exception($"类型 {obj.entityType.FullName} 不可迁移,可迁移属性0个"); var tbname = _commonUtils.SplitTableName(tb.DbName); - if (tbname?.Length == 1) tbname = new[] { defaultSchema, tbname[0] }; + if (tbname?.Length == 1) tbname = new[] { "PUBLIC", tbname[0] }; var tboldname = _commonUtils.SplitTableName(tb.DbOldName); //旧表名 - if (tboldname?.Length == 1) tboldname = new[] { defaultSchema, tboldname[0] }; - var primaryKeyName = (obj.entityType.GetCustomAttributes(typeof(OraclePrimaryKeyNameAttribute), false)?.FirstOrDefault() as OraclePrimaryKeyNameAttribute)?.Name; + if (tboldname?.Length == 1) tboldname = new[] { "PUBLIC", tboldname[0] }; if (string.IsNullOrEmpty(obj.tableName) == false) { var tbtmpname = _commonUtils.SplitTableName(obj.tableName); - if (tbtmpname?.Length == 1) tbtmpname = new[] { defaultSchema, tbtmpname[0] }; + if (tbtmpname?.Length == 1) tbtmpname = new[] { "PUBLIC", tbtmpname[0] }; if (tbname[0] != tbtmpname[0] || tbname[1] != tbtmpname[1]) { tbname = tbtmpname; tboldname = null; - primaryKeyName = null; } } - //codefirst 不支持表名中带 . + //codefirst 不支持表名、模式名、数据库名中带 . - if (string.Compare(tbname[0], defaultSchema) != 0 && _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" SELECT 1 FROM information_schema.schemata WHERE schema_name={0}", tbname[0])) == null) //创建数据库 + if (string.Compare(tbname[0], "PUBLIC", true) != 0 && _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from sys_namespace where nspname={0}", tbname[0])) == null) //创建模式 sb.Append("CREATE SCHEMA IF NOT EXISTS ").Append(tbname[0]).Append(";\r\n"); var sbalter = new StringBuilder(); var istmpatler = false; //创建临时表,导入数据,删除旧表,修改 - if (_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from information_schema.tables where table_schema={0} and table_name={1}", tbname)) == null) + if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format(" select 1 from sys_tables a inner join sys_namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = '{0}.{1}'", tbname)) == null) { //表不存在 if (tboldname != null) { - if (_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from information_schema.tables where table_schema={0} and table_name={1}", tboldname)) == null) - //模式或表不存在 + if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format(" select 1 from sys_tables a inner join sys_namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = '{0}.{1}'", tboldname)) == null) + //旧表不存在 tboldname = null; } if (tboldname == null) { //创建表 var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"); - sb.Append("CREATE TABLE ").Append(createTableName).Append(" ( "); + sb.Append("CREATE TABLE IF NOT EXISTS ").Append(createTableName).Append(" ( "); foreach (var tbcol in tb.ColumnsByPosition) { sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(","); @@ -137,13 +126,13 @@ namespace FreeSql.Odbc.KingbaseES } if (tb.Primarys.Any()) { - var pkname = primaryKeyName ?? $"{tbname[0]}_{tbname[1]}_PK1"; + 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"); + sb.Append("\r\n) WITH (OIDS=FALSE);\r\n"); //创建表的索引 foreach (var uk in tb.Indexes) { @@ -168,7 +157,7 @@ namespace FreeSql.Odbc.KingbaseES 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 @@ -181,32 +170,53 @@ namespace FreeSql.Odbc.KingbaseES tboldname = null; //如果新表已经存在,不走改表名逻辑 //对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段 - var sql = _commonUtils.FormatSql($@" -select -a.column_name, -a.data_type, -a.data_length, -a.data_precision, -a.data_scale, -a.char_used, -case when a.nullable = 'N' then 0 else 1 end, -nvl((select 1 from user_sequences where upper(sequence_owner)={{0}} and upper(sequence_name)=upper({{2}}||'_'||{{1}}||'_seq_'||a.column_name) limit 1), 0), -b.comments -from all_tab_columns a -left join all_col_comments b on b.owner = a.owner and b.table_name = a.table_name and b.column_name = a.column_name -where a.owner={{0}} and a.table_name={{1}}", userId, (tboldname ?? tbname)[1], (tboldname ?? tbname)[0]); + var sql = _commonUtils.FormatSql(@" +select +a.attname, +t.typname, +case when a.atttypmod > 0 and a.atttypmod < 32767 then a.atttypmod - 4 else a.attlen end len, +case when t.typelem > 0 and t.typinput::varchar = 'ARRAY_IN' then t2.typname else t.typname end, +case when a.attnotnull then '0' else '1' end as is_nullable, +--e.adsrc, +(select sys_get_expr(adbin, adrelid) from sys_attrdef where adrelid = e.adrelid limit 1) is_identity, +a.attndims, +d.description as comment +from sys_class c +inner join sys_attribute a on a.attnum > 0 and a.attrelid = c.oid +inner join sys_type t on t.oid = a.atttypid +left join sys_type t2 on t2.oid = t.typelem +left join sys_description d on d.objoid = a.attrelid and d.objsubid = a.attnum +left join sys_attrdef e on e.adrelid = a.attrelid and e.adnum = a.attnum +inner join sys_namespace ns on ns.oid = c.relnamespace +inner join sys_namespace ns2 on ns2.oid = t.typnamespace +where ns.nspname = {0} and c.relname = {1}", tboldname ?? tbname); var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); - if (ds.Length != ds.Select(a => string.Concat(a[0])).Count()) throw new Exception("检查到多个模式下存在相同的表名,无法完成对比结构"); var tbstruct = ds.ToDictionary(a => string.Concat(a[0]), a => { - var sqlType = GetKingbaseESSqlTypeFullName(a); + var attndims = int.Parse(string.Concat(a[6])); + var type = string.Concat(a[1]); + var sqlType = string.Concat(a[3]); + var max_length = long.Parse(string.Concat(a[2])); + 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 (type.StartsWith("_")) + { + type = type.Substring(1); + if (attndims == 0) attndims++; + } + if (sqlType.StartsWith("_")) sqlType = sqlType.Substring(1); return new { column = string.Concat(a[0]), - sqlType, - is_nullable = string.Concat(a[6]) == "1", - is_identity = string.Concat(a[7]) == "1", - comment = string.Concat(a[8]) + sqlType = string.Concat(sqlType), + max_length = long.Parse(string.Concat(a[2])), + is_nullable = string.Concat(a[4]) == "1", + is_identity = string.Concat(a[5]).StartsWith(@"NEXTVAL('") && string.Concat(a[5]).EndsWith(@"'::REGCLASS)"), + attndims, + comment = string.Concat(a[7]) }; }, StringComparer.CurrentCultureIgnoreCase); @@ -214,71 +224,51 @@ where a.owner={{0}} and a.table_name={{1}}", userId, (tboldname ?? tbname)[1], ( { foreach (var tbcol in tb.ColumnsByPosition) { - var dbtypeNoneNotNull = Regex.Replace(tbcol.Attribute.DbType, @"NOT\s+NULL", "NULL"); 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 ?? ""); - if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false) - { - istmpatler = true; - if (istmpatler && tbcol.Attribute.DbType.StartsWith("varchar", StringComparison.CurrentCultureIgnoreCase) && tbstructcol.sqlType.StartsWith("varchar", StringComparison.CurrentCultureIgnoreCase) - && Regex.Match(tbcol.Attribute.DbType, @"\(\d+").Groups[0].Value == Regex.Match(tbstructcol.sqlType, @"\(\d+").Groups[0].Value) - istmpatler = false; - if (istmpatler && Regex.IsMatch(tbcol.Attribute.DbType, @"\(\d+") == false && Regex.IsMatch(tbstructcol.sqlType, @"\(\d+") - && string.Compare(tbcol.Attribute.DbType, Regex.Replace(tbstructcol.sqlType, @"\([^\)]+\)", ""), StringComparison.CurrentCultureIgnoreCase) == 0) - istmpatler = false; - if (istmpatler) - break; - } + if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false || + tbcol.Attribute.DbType.Contains("[]") != (tbstructcol.attndims > 0)) + sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TYPE ").Append(tbcol.Attribute.DbType.Split(' ').First()).Append(";\r\n"); if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable) { - 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(tbcol.Attribute.IsNullable == true ? " DROP NOT NULL" : " SET NOT NULL").Append(";\r\n"); + 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) + seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true)); if (string.Compare(tbstructcol.column, tbcol.Attribute.OldName, true) == 0) - { - if (tbstructcol.is_identity) - seqnameDel.Add(Utils.GetCsName($"{tbname[1]}_seq_{tbstructcol.column}")); //修改列名 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 (tbcol.Attribute.IsIdentity) - seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true)); - } - else if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity) - seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true)); 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"); + 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 (").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(dbtypeNoneNotNull).Append(");\r\n"); - if (tbcol.Attribute.IsNullable == false) - { - 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"); - 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"); - } + 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(NaviteTuple.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"); + 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"); } - } - if (istmpatler == false) - { var dsuksql = _commonUtils.FormatSql(@" select -c.column_name, -a.index_name, -case when c.descend = 'DESC' then 1 else 0 end, -case when a.uniqueness = 'UNIQUE' then 1 else 0 end -from all_indexes a, -all_ind_columns c -where a.index_name = c.index_name -and a.table_owner = c.table_owner -and a.table_name = c.table_name -and a.owner in ({0}) and a.table_name in ({1}) -and not exists(select 1 from all_constraints where index_name = a.index_name and constraint_type = 'P')", userId, (tboldname ?? tbname)[1]); - var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]).Trim('"'), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) }).ToArray(); +c.attname, +b.relname, +case when sys_index_column_has_property(b.oid, c.attnum, 'desc') = 't' then 1 else 0 end IsDesc, +case when indisunique = 't' then 1 else 0 end IsUnique +from sys_index a +inner join sys_class b on b.oid = a.indexrelid +inner join sys_attribute c on c.attnum > 0 and c.attrelid = b.oid +inner join sys_namespace ns on ns.oid = b.relnamespace +inner join sys_class d on d.oid = a.indrelid +where ns.nspname in ({0}) and d.relname in ({1}) and a.indisprimary = 'f'", 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]) }); foreach (var uk in tb.Indexes) { if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue; @@ -301,22 +291,32 @@ and not exists(select 1 from all_constraints where index_name = a.index_name and } if (istmpatler == false) { - var dbcomment = string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select comments from all_tab_comments where owner = {0} and table_name = {1} and table_type = 'TABLE'", userId, tbname[1]))); + var dbcomment = string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select +d.description +from sys_class a +inner join sys_namespace b on b.oid = a.relnamespace +left join sys_description d on d.objoid = a.oid and objsubid = 0 +where b.nspname not in ('SYS_CATALOG', 'INFORMATION_SCHEMA', 'TOPOLOGY', 'SYSAUDIT', 'SYSLOGICAL', 'SYS_TEMP_1', 'SYS_TOAST', 'SYS_TOAST_TEMP_1', 'XLOG_RECORD_READ') and a.relkind in ('r') and b.nspname = {0} and a.relname = {1} +and b.nspname || '.' || a.relname not in ('PUBLIC.GEOGRAPHY_COLUMNS','PUBLIC.GEOMETRY_COLUMNS','PUBLIC.RASTER_COLUMNS','PUBLIC.RASTER_OVERVIEWS')", tbname[0], tbname[1]))); if (dbcomment != (tb.Comment ?? "")) sb.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; } - var oldpk = _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select constraint_name from user_constraints where owner={0} and table_name={1} and constraint_type='P'", userId, tbname[1]))?.ToString(); + var oldpk = _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select sys_constraint.conname as pk_name from sys_constraint +inner join sys_class on sys_constraint.conrelid = sys_class.oid +inner join sys_namespace on sys_namespace.oid = sys_class.relnamespace +where sys_namespace.nspname={0} and sys_class.relname={1} and sys_constraint.contype='p' +", tbname))?.ToString(); if (string.IsNullOrEmpty(oldpk) == false) - sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP CONSTRAINT ").Append(_commonUtils.QuoteSqlName(oldpk)).Append(";\r\n"); + 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]}.FTmp_{tbname[1]}"); //创建临时表 - sb.Append("CREATE TABLE ").Append(tmptablename).Append(" ( "); + 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).Append(","); @@ -324,13 +324,13 @@ and not exists(select 1 from all_constraints where index_name = a.index_name and } if (tb.Primarys.Any()) { - var pkname = primaryKeyName ?? $"{tbname[0]}_{tbname[1]}_PK2"; + 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"); + sb.Append("\r\n) WITH (OIDS=FALSE);\r\n"); //备注 foreach (var tbcol in tb.ColumnsByPosition) { @@ -352,20 +352,17 @@ and not exists(select 1 from all_constraints where index_name = a.index_name and { insertvalue = _commonUtils.QuoteSqlName(tbstructcol.column); if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false) - { - var dbtypeNoneNotNull = Regex.Replace(tbcol.Attribute.DbType, @"(NOT\s+)?NULL", ""); - insertvalue = $"cast({insertvalue} as {dbtypeNoneNotNull})"; - } + insertvalue = $"cast({insertvalue} as {tbcol.Attribute.DbType.Split(' ').First()})"; if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable) - insertvalue = $"nvl({insertvalue},{tbcol.DbDefaultValue})"; + insertvalue = $"coalesce({insertvalue},{tbcol.DbDefaultValue})"; } else if (tbcol.Attribute.IsNullable == false) insertvalue = tbcol.DbDefaultValue; - sb.Append(insertvalue.Replace("'", "''")).Append(", "); + 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"); + sb.Append("ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName(tbname[1])).Append(";\r\n"); //创建表的索引 foreach (var uk in tb.Indexes) { @@ -384,7 +381,7 @@ and not exists(select 1 from all_constraints where index_name = a.index_name and foreach (var seqcol in seqcols) { var tbname = seqcol.Item2; - var seqname = Utils.GetCsName($"{tbname[0]}.{tbname[1]}_seq_{seqcol.Item1.Attribute.Name}").ToUpper(); + var seqname = Utils.GetCsName($"{tbname[0]}.{tbname[1]}_{seqcol.Item1.Attribute.Name}_seq").ToUpper(); ; 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"); @@ -392,68 +389,11 @@ and not exists(select 1 from all_constraints where index_name = a.index_name and 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("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"); } } return sb.Length == 0 ? null : sb.ToString(); } - - public override int ExecuteDDLStatements(string ddl) - { - if (string.IsNullOrEmpty(ddl)) return 0; - var scripts = ddl.Split(new string[] { ";\r\n" }, StringSplitOptions.None).Where(a => string.IsNullOrEmpty(a.Trim()) == false).ToArray(); - - if (scripts.Any() == false) return 0; - if (scripts.Length == 1) return base.ExecuteDDLStatements(ddl); - - var affrows = 0; - foreach (var script in scripts) - affrows += base.ExecuteDDLStatements(script); - return affrows; - } - - internal static string GetKingbaseESSqlTypeFullName(object[] row) - { - var a = row; - var sqlType = string.Concat(a[1]).ToUpper(); - var data_length = long.Parse(string.Concat(a[2])); - long.TryParse(string.Concat(a[3]), out var data_precision); - long.TryParse(string.Concat(a[4]), out var data_scale); - //var char_used = string.Concat(a[5]); - if (sqlType.StartsWith("TIMESTAMP", StringComparison.CurrentCultureIgnoreCase)) - { - } - else if (sqlType.StartsWith("BLOB")) - { - } - else if (sqlType == "DOUBLE" || sqlType == "FLOAT") - { - } - else if (sqlType == "INT2" || sqlType == "INT4" || sqlType == "INT8") - { - } - else if (sqlType == "TINYINT") - { - } - else if (sqlType == "BOOL") - { - } - else if (sqlType == "FLOAT4" || sqlType == "FLOAT8") - { - } - else if (sqlType == "TIME" || sqlType == "TIMESTAMP") - { - } - else if (sqlType == "NUMERIC") - sqlType += $"({data_precision},{data_scale})"; - else if (data_precision > 0 && data_scale > 0) - sqlType += $"({data_precision},{data_scale})"; - else if (data_precision > 0) - sqlType += $"({data_precision})"; - else - sqlType += $"({data_length})"; - return sqlType; - } } } \ No newline at end of file diff --git a/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESDbFirst.cs b/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESDbFirst.cs index 4a4c3f47..41c69855 100644 --- a/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESDbFirst.cs +++ b/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESDbFirst.cs @@ -105,16 +105,396 @@ namespace FreeSql.Odbc.KingbaseES public List GetDatabases() { - var sql = @" select schema_name from information_schema.schemata where schema_owner<>'SYSTEM'"; + var sql = @" select datname from sys_database where datname not in ('TEMPLATE1', 'TEMPLATE0', 'TEMPLATE2')"; var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); - return new[] { "PUBLIC" }.Concat(ds.Select(a => a.FirstOrDefault()?.ToString())).ToList(); + return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList(); } - public List GetTablesByDatabase(params string[] database2) => throw new NotImplementedException(); + public List GetTablesByDatabase(params string[] database) + { + var olddatabase = ""; + using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5))) + { + olddatabase = conn.Value.Database; + } + var dbs = database == null || database.Any() == false ? new[] { olddatabase } : database; + var tables = new List(); + foreach (var db in dbs) + { + if (string.IsNullOrEmpty(db) || string.Compare(db, olddatabase, true) != 0) continue; + + var loc1 = new List(); + var loc2 = new Dictionary(); + var loc3 = new Dictionary>(); + + var sql = $@" +select +b.nspname || '.' || a.tablename, +a.schemaname, +a.tablename , +d.description, +'TABLE' +from sys_tables a +inner join sys_namespace b on b.nspname = a.schemaname +inner join sys_class c on c.relnamespace = b.oid and c.relname = a.tablename +left join sys_description d on d.objoid = c.oid and objsubid = 0 +where a.schemaname not in ('SYS_CATALOG', 'INFORMATION_SCHEMA', 'TOPOLOGY', 'SYSAUDIT', 'SYSLOGICAL', 'SYS_TEMP_1', 'SYS_TOAST', 'SYS_TOAST_TEMP_1', 'XLOG_RECORD_READ') +and b.nspname || '.' || a.tablename not in ('PUBLIC.SPATIAL_REF_SYS') + +union all + +select +b.nspname || '.' || a.relname, +b.nspname, +a.relname, +d.description, +'VIEW' +from sys_class a +inner join sys_namespace b on b.oid = a.relnamespace +left join sys_description d on d.objoid = a.oid and objsubid = 0 +where b.nspname not in ('SYS_CATALOG', 'INFORMATION_SCHEMA', 'TOPOLOGY', 'SYSAUDIT', 'SYSLOGICAL', 'SYS_TEMP_1', 'SYS_TOAST', 'SYS_TOAST_TEMP_1', 'XLOG_RECORD_READ') and a.relkind in ('m','v') +and b.nspname || '.' || a.relname not in ('PUBLIC.GEOGRAPHY_COLUMNS','PUBLIC.GEOMETRY_COLUMNS','PUBLIC.RASTER_COLUMNS','PUBLIC.RASTER_OVERVIEWS') +"; + var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var loc6 = new List(); + var loc66 = new List(); + var loc6_1000 = new List(); + var loc66_1000 = new List(); + 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(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()); + 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.nspname || '.' || c.relname as id, +a.attname, +t.typname, +case when a.atttypmod > 0 and a.atttypmod < 32767 then a.atttypmod - 4 else a.attlen end len, +case when t.typelem = 0 then t.typname else t2.typname end, +case when a.attnotnull then 0 else 1 end as is_nullable, +--e.adsrc as is_identity, pg12以下 +(select sys_get_expr(adbin, adrelid) from sys_attrdef where adrelid = e.adrelid limit 1) is_identity, +d.description as comment, +a.attndims, +case when t.typelem = 0 then t.typtype else t2.typtype end, +ns2.nspname, +a.attnum +from sys_class c +inner join sys_attribute a on a.attnum > 0 and a.attrelid = c.oid +inner join sys_type t on t.oid = a.atttypid +left join sys_type t2 on t2.oid = t.typelem +left join sys_description d on d.objoid = a.attrelid and d.objsubid = a.attnum +left join sys_attrdef e on e.adrelid = a.attrelid and e.adnum = a.attnum +inner join sys_namespace ns on ns.oid = c.relnamespace +inner join sys_namespace ns2 on ns2.oid = t.typnamespace +where {loc8.ToString().Replace("a.table_name", "ns.nspname || '.' || c.relname")}"; + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var position = 0; + 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"; + var is_identity = string.Concat(row[6]).StartsWith(@"NEXTVAL('") && string.Concat(row[6]).EndsWith(@"'::REGCLASS)"); + var comment = string.Concat(row[7]); + var defaultValue = string.Concat(row[6]); + 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++; + } + if (sqlType.StartsWith("_")) sqlType = sqlType.Substring(1); + if (max_length > 0) + { + switch (sqlType.ToLower()) + { + //case "numeric": sqlType += $"({max_length})"; break; + case "bpchar": case "varchar": case "bytea": case "bit": case "varbit": sqlType += $"({max_length})"; break; + } + } + + 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], + Coment = 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]); + } + + sql = $@" +select +ns.nspname || '.' || d.relname as table_id, +c.attname, +b.relname as index_id, +case when a.indisunique then 1 else 0 end IsUnique, +case when a.indisprimary then 1 else 0 end IsPrimary, +case when a.indisclustered then 0 else 1 end IsClustered, +case when sys_index_column_has_property(b.oid, c.attnum, 'desc') = 't' then 1 else 0 end IsDesc, +a.indkey::text, +c.attnum +from sys_index a +inner join sys_class b on b.oid = a.indexrelid +inner join sys_attribute c on c.attnum > 0 and c.attrelid = b.oid +inner join sys_namespace ns on ns.oid = b.relnamespace +inner join sys_class d on d.oid = a.indrelid +where {loc8.ToString().Replace("a.table_name", "ns.nspname || '.' || d.relname")} +"; + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var indexColumns = new Dictionary>(); + var uniqueColumns = new Dictionary>(); + 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 = string.Concat(row[5]) == "1"; + var is_desc = 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) + { + 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 loc10 = null; + DbIndexInfo loc11 = null; + if (!indexColumns.TryGetValue(object_id, out loc10)) + indexColumns.Add(object_id, loc10 = new Dictionary()); + 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()); + 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); + } + } + + sql = $@" +select +ns.nspname || '.' || b.relname as table_id, +array(select attname from sys_attribute where attrelid = a.conrelid and attnum = any(a.conkey)) as column_name, +a.conname as FKId, +ns2.nspname || '.' || c.relname as ref_table_id, +1 as IsForeignKey, +array(select attname from sys_attribute where attrelid = a.confrelid and attnum = any(a.confkey)) as ref_column, +null ref_sln, +null ref_table +from sys_constraint a +inner join sys_class b on b.oid = a.conrelid +inner join sys_class c on c.oid = a.confrelid +inner join sys_namespace ns on ns.oid = b.relnamespace +inner join sys_namespace ns2 on ns2.oid = c.relnamespace +where {loc8.ToString().Replace("a.table_name", "ns.nspname || '.' || b.relname")} +"; + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var fkColumns = new Dictionary>(); + foreach (object[] row in ds) + { + var table_id = string.Concat(row[0]); + var column = row[1] as string[]; + var fk_id = string.Concat(row[2]); + var ref_table_id = string.Concat(row[3]); + var is_foreign_key = string.Concat(row[4]) == "1"; + 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 loc12 = null; + DbForeignInfo loc13 = null; + if (!fkColumns.TryGetValue(table_id, out loc12)) + fkColumns.Add(table_id, loc12 = new Dictionary()); + 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 class GetEnumsByDatabaseQueryInfo + { + public string name { get; set; } + public string label { get; set; } + } public List GetEnumsByDatabase(params string[] database) { - return new List(); + if (database == null || database.Length == 0) return new List(); + var drs = _orm.Ado.Query(CommandType.Text, _commonUtils.FormatSql(@" +select +ns.nspname || '.' || a.typname AS name, +b.enumlabel AS label +from sys_type a +inner join sys_enum b on b.enumtypid = a.oid +inner join sys_namespace ns on ns.oid = a.typnamespace +where a.typtype = 'e' and ns.nspname in (SELECT schema_name FROM information_schema.schemata where catalog_name in {0})", database)); + var ret = new Dictionary>(); + foreach (var dr in drs) + { + if (ret.TryGetValue(dr.name, out var labels) == false) ret.Add(dr.name, labels = new Dictionary()); + var key = dr.label; + if (Regex.IsMatch(key, @"^[\u0391-\uFFE5a-zA-Z_\$][\u0391-\uFFE5a-zA-Z_\$\d]*$") == false) + key = $"Unkown{ret[dr.name].Count + 1}"; + if (labels.ContainsKey(key) == false) labels.Add(key, dr.label); + } + return ret.Select(a => new DbEnumInfo { Name = a.Key, Labels = a.Value }).ToList(); } } } \ No newline at end of file diff --git a/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESUtils.cs b/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESUtils.cs index 3cddc2e4..56bb6382 100644 --- a/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESUtils.cs +++ b/Providers/FreeSql.Provider.Odbc/KingbaseES/OdbcKingbaseESUtils.cs @@ -113,7 +113,7 @@ namespace FreeSql.Odbc.KingbaseES public override string[] SplitTableName(string name) => GetSplitTableNames(name, '"', '"', 2); public override string QuoteParamterName(string name) => $"@{name.ToUpper()}"; 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 StringConcat(string[] objs, Type[] types) => $"{string.Join(" || ", objs.Select((a, b) => b == 0 ? $"{a}::varchar" : a))}"; //First ::varchar 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";