- 增加 人大金仓 OdbcKingbaseES 实现;#325

This commit is contained in:
28810
2020-05-27 05:59:33 +08:00
parent 0d6ebc1e26
commit 7d8457a988
57 changed files with 11687 additions and 188 deletions

View File

@ -88,7 +88,7 @@ namespace FreeSql.Odbc.Dameng
return $"{nametrim.Trim('"').Replace("\".\"", ".").Replace(".\"", ".")}";
}
public override string[] SplitTableName(string name) => GetSplitTableNames(name, '"', '"', 2);
public override string QuoteParamterName(string name) => $":{(_orm.CodeFirst.IsSyncStructureToLower ? name.ToLower() : name)}";
public override string QuoteParamterName(string name) => $":{name}";
public override string IsNull(string sql, object value) => $"nvl({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) => $"mod({left}, {right})";

View File

@ -58,7 +58,7 @@ namespace FreeSql.Odbc.Default
return $"{nametrim.TrimStart(Adapter.QuoteSqlNameLeft).TrimEnd(Adapter.QuoteSqlNameRight).Replace($"{Adapter.QuoteSqlNameRight}.{Adapter.QuoteSqlNameLeft}", ".").Replace($".{Adapter.QuoteSqlNameLeft}", ".")}";
}
public override string[] SplitTableName(string name) => GetSplitTableNames(name, Adapter.QuoteSqlNameLeft, Adapter.QuoteSqlNameRight, 2);
public override string QuoteParamterName(string name) => $"@{(_orm.CodeFirst.IsSyncStructureToLower ? name.ToLower() : name)}";
public override string QuoteParamterName(string name) => $"@{name}";
public override string IsNull(string sql, object value) => Adapter.IsNullSql(sql, value);
public override string StringConcat(string[] objs, Type[] types) => Adapter.ConcatSql(objs, types);
public override string Mod(string left, string right, Type leftType, Type rightType) => Adapter.Mod(left, right, leftType, rightType);

View File

@ -54,4 +54,13 @@
/// <returns></returns>
public static string FormatOdbcDameng(this string that, params object[] args) => _odbcDamengAdo.Addslashes(that, args);
static FreeSql.Odbc.Dameng.OdbcDamengAdo _odbcDamengAdo = new FreeSql.Odbc.Dameng.OdbcDamengAdo();
/// <summary>
/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
/// </summary>
/// <param name="that"></param>
/// <param name="args"></param>
/// <returns></returns>
public static string FormatOdbcKingbaseES(this string that, params object[] args) => _odbcKingbaseESAdo.Addslashes(that, args);
static FreeSql.Odbc.KingbaseES.OdbcKingbaseESAdo _odbcKingbaseESAdo = new FreeSql.Odbc.KingbaseES.OdbcKingbaseESAdo();
}

View File

@ -0,0 +1,99 @@
using FreeSql.Internal;
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Threading.Tasks;
namespace FreeSql.Odbc.KingbaseES
{
class OdbcKingbaseESDelete<T1> : Internal.CommonProvider.DeleteProvider<T1> where T1 : class
{
public OdbcKingbaseESDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
public override List<T1> ExecuteDeleted()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var sb = new StringBuilder();
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.QuoteReadColumn(col.CsType, col.Attribute.MapType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
sql = sb.ToString();
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var ret = new List<T1>();
Exception exception = null;
try
{
ret = _orm.Ado.Query<T1>(_connection, _transaction, CommandType.Text, sql, dbParms);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
this.ClearData();
return ret;
}
#if net40
#else
async public override Task<List<T1>> ExecuteDeletedAsync()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var sb = new StringBuilder();
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.QuoteReadColumn(col.CsType, col.Attribute.MapType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
sql = sb.ToString();
var dbParms = _params.ToArray();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var ret = new List<T1>();
Exception exception = null;
try
{
ret = await _orm.Ado.QueryAsync<T1>(_connection, _transaction, CommandType.Text, sql, dbParms);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
this.ClearData();
return ret;
}
#endif
}
}

View File

@ -0,0 +1,216 @@
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.Tasks;
namespace FreeSql.Odbc.KingbaseES
{
class OdbcKingbaseESInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class
{
public OdbcKingbaseESInsert(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;
Exception exception = null;
Aop.CurdBeforeEventArgs before = null;
var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true);
if (identCols.Any() == false)
{
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
ret = _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _params);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return 0;
}
sql = string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name));
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_connection, _transaction, CommandType.Text, sql, _params)), out ret);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
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 new List<T1>();
var sb = new StringBuilder();
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.QuoteReadColumn(col.CsType, col.Attribute.MapType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
sql = sb.ToString();
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
{
ret = _orm.Ado.Query<T1>(_connection, _transaction, CommandType.Text, sql, _params);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
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() => base.SplitExecuteAffrowsAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
public override Task<long> ExecuteIdentityAsync() => base.SplitExecuteIdentityAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
public override Task<List<T1>> ExecuteInsertedAsync() => base.SplitExecuteInsertedAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
async protected override Task<long> RawExecuteIdentityAsync()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
long ret = 0;
Exception exception = null;
Aop.CurdBeforeEventArgs before = null;
var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true);
if (identCols.Any() == false)
{
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
ret = await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _params);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return 0;
}
sql = string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name));
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_connection, _transaction, CommandType.Text, sql, _params)), out ret);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
async protected override Task<List<T1>> RawExecuteInsertedAsync()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var sb = new StringBuilder();
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.QuoteReadColumn(col.CsType, col.Attribute.MapType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
sql = sb.ToString();
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
{
ret = await _orm.Ado.QueryAsync<T1>(_connection, _transaction, CommandType.Text, sql, _params);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
#endif
}
}

View File

@ -0,0 +1,57 @@
using FreeSql.Internal;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
namespace FreeSql.Odbc.KingbaseES
{
class OdbcKingbaseESInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
{
public OdbcKingbaseESInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
: base(orm, commonUtils, commonExpression)
{
}
public override string ToSql()
{
if (_source?.Any() != true) return null;
var sqls = new string[2];
var dbParams = new List<DbParameter>();
var ds = SplitSourceByIdentityValueIsNull(_source);
if (ds.Item1.Any()) sqls[0] = getInsertSql(ds.Item1, false);
if (ds.Item2.Any()) sqls[1] = getInsertSql(ds.Item2, true);
_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 getInsertSql(List<T1> data, bool flagInsert)
{
var insert = _orm.Insert<T1>()
.AsTable(_tableRule).AsType(_table.Type)
.WithConnection(_connection)
.WithTransaction(_transaction)
.NoneParameter(true) as Internal.CommonProvider.InsertProvider<T1>;
insert._source = data;
string sql = "";
if (IdentityColumn != null && flagInsert) sql = insert.ToSql();
else
{
var ocdu = new OdbcKingbaseESOnConflictDoUpdate<T1>(insert.InsertIdentity());
ocdu.IgnoreColumns(_table.Columns.Values.Where(a => a.Attribute.CanUpdate == false).Select(a => a.Attribute.Name).ToArray());
if (_table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true).Any() == false)
ocdu.DoNothing();
sql = ocdu.ToSql();
}
if (string.IsNullOrEmpty(sql)) return null;
if (insert._params?.Any() == true) dbParams.AddRange(insert._params);
return sql;
}
}
}
}

View File

@ -0,0 +1,207 @@
using FreeSql.Aop;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace FreeSql.Odbc.KingbaseES
{
public class OdbcKingbaseESOnConflictDoUpdate<T1> where T1 : class
{
internal OdbcKingbaseESInsert<T1> _pgsqlInsert;
internal OdbcKingbaseESUpdate<T1> _pgsqlUpdatePriv;
internal OdbcKingbaseESUpdate<T1> _pgsqlUpdate => _pgsqlUpdatePriv ??
(_pgsqlUpdatePriv = new OdbcKingbaseESUpdate<T1>(_pgsqlInsert.InternalOrm, _pgsqlInsert.InternalCommonUtils, _pgsqlInsert.InternalCommonExpression, null) { InternalTableAlias = "EXCLUDED" }
.NoneParameter().SetSource(_pgsqlInsert.InternalSource) as OdbcKingbaseESUpdate<T1>);
ColumnInfo[] _columns;
bool _doNothing;
public OdbcKingbaseESOnConflictDoUpdate(IInsert<T1> insert, Expression<Func<T1, object>> columns = null)
{
_pgsqlInsert = insert as OdbcKingbaseESInsert<T1>;
if (_pgsqlInsert == null) throw new Exception("OnConflictDoUpdate 是 FreeSql.Provider.Odbc/KingbaseES 特有的功能");
if (columns != null)
{
var colsList = new List<ColumnInfo>();
var cols = _pgsqlInsert.InternalCommonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false, null).ToDictionary(a => a, a => true);
foreach (var col in _pgsqlInsert.InternalTable.Columns.Values)
if (cols.ContainsKey(col.Attribute.Name))
colsList.Add(col);
_columns = colsList.ToArray();
}
if (_columns == null || _columns.Any() == false)
_columns = _pgsqlInsert.InternalTable.Primarys;
if (_columns.Any() == false) throw new Exception("OnConflictDoUpdate 功能要求实体类必须设置 IsPrimary 属性");
}
protected void ClearData()
{
_pgsqlInsert.InternalClearData();
_pgsqlUpdatePriv = null;
}
public OdbcKingbaseESOnConflictDoUpdate<T1> IgnoreColumns(Expression<Func<T1, object>> columns)
{
_pgsqlUpdate.IgnoreColumns(columns);
return this;
}
public OdbcKingbaseESOnConflictDoUpdate<T1> UpdateColumns(Expression<Func<T1, object>> columns)
{
_pgsqlUpdate.UpdateColumns(columns);
return this;
}
public OdbcKingbaseESOnConflictDoUpdate<T1> IgnoreColumns(string[] columns)
{
_pgsqlUpdate.IgnoreColumns(columns);
return this;
}
public OdbcKingbaseESOnConflictDoUpdate<T1> UpdateColumns(string[] columns)
{
_pgsqlUpdate.UpdateColumns(columns);
return this;
}
public OdbcKingbaseESOnConflictDoUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> column, TMember value)
{
_pgsqlUpdate.Set(column, value);
return this;
}
//由于表达式解析问题ON CONFLICT("id") DO UPDATE SET 需要指定表别名,如 Set(a => a.Clicks + 1) 解析会失败
//暂时不开放这个功能,如有需要使用 SetRaw("click = t.click + 1") 替代该操作
//public OnConflictDoUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> exp)
//{
// _pgsqlUpdate.Set(exp);
// return this;
//}
public OdbcKingbaseESOnConflictDoUpdate<T1> SetRaw(string sql)
{
_pgsqlUpdate.SetRaw(sql);
return this;
}
public OdbcKingbaseESOnConflictDoUpdate<T1> DoNothing()
{
_doNothing = true;
return this;
}
public string ToSql()
{
var sb = new StringBuilder();
sb.Append(_pgsqlInsert.ToSql()).Append("\r\nON CONFLICT(");
for (var a = 0; a < _columns.Length; a++)
{
if (a > 0) sb.Append(", ");
sb.Append(_pgsqlInsert.InternalCommonUtils.QuoteSqlName(_columns[a].Attribute.Name));
}
if (_doNothing)
{
sb.Append(") DO NOTHING");
}
else
{
sb.Append(") DO UPDATE SET\r\n");
var sbSetEmpty = _pgsqlUpdate.InternalSbSet.Length == 0;
var sbSetIncrEmpty = _pgsqlUpdate.InternalSbSetIncr.Length == 0;
if (sbSetEmpty == false || sbSetIncrEmpty == false)
{
if (sbSetEmpty == false) sb.Append(_pgsqlUpdate.InternalSbSet.ToString().Substring(2));
if (sbSetIncrEmpty == false) sb.Append(sbSetEmpty ? _pgsqlUpdate.InternalSbSetIncr.ToString().Substring(2) : _pgsqlUpdate.InternalSbSetIncr.ToString());
}
else
{
var colidx = 0;
foreach (var col in _pgsqlInsert.InternalTable.Columns.Values)
{
if (col.Attribute.IsPrimary || _pgsqlUpdate.InternalIgnore.ContainsKey(col.Attribute.Name)) continue;
if (colidx > 0) sb.Append(", \r\n");
if (col.Attribute.IsVersion == true)
{
var field = _pgsqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
sb.Append(field).Append(" = ").Append(_pgsqlInsert.InternalCommonUtils.QuoteSqlName(_pgsqlInsert.InternalTable.DbName)).Append(".").Append(field).Append(" + 1");
}
else if (_pgsqlInsert.InternalIgnore.ContainsKey(col.Attribute.Name))
{
var caseWhen = _pgsqlUpdate.InternalWhereCaseSource(col.CsName, sqlval => sqlval).Trim();
sb.Append(caseWhen);
if (caseWhen.EndsWith(" END")) _pgsqlUpdate.InternalToSqlCaseWhenEnd(sb, col);
}
else
{
var field = _pgsqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
sb.Append(field).Append(" = EXCLUDED.").Append(field);
}
++colidx;
}
}
}
return sb.ToString();
}
public long ExecuteAffrows()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
var before = new CurdBeforeEventArgs(_pgsqlInsert.InternalTable.Type, _pgsqlInsert.InternalTable, CurdType.Insert, sql, _pgsqlInsert.InternalParams);
_pgsqlInsert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_pgsqlInsert, before);
long ret = 0;
Exception exception = null;
try
{
ret = _pgsqlInsert.InternalOrm.Ado.ExecuteNonQuery(_pgsqlInsert.InternalConnection, _pgsqlInsert.InternalTransaction, CommandType.Text, sql, _pgsqlInsert.InternalParams);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new CurdAfterEventArgs(before, exception, ret);
_pgsqlInsert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_pgsqlInsert, after);
ClearData();
}
return ret;
}
#if net40
#else
async public Task<long> ExecuteAffrowsAsync()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
var before = new CurdBeforeEventArgs(_pgsqlInsert.InternalTable.Type, _pgsqlInsert.InternalTable, CurdType.Insert, sql, _pgsqlInsert.InternalParams);
_pgsqlInsert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_pgsqlInsert, before);
long ret = 0;
Exception exception = null;
try
{
ret = await _pgsqlInsert.InternalOrm.Ado.ExecuteNonQueryAsync(_pgsqlInsert.InternalConnection, _pgsqlInsert.InternalTransaction, CommandType.Text, sql, _pgsqlInsert.InternalParams);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new CurdAfterEventArgs(before, exception, ret);
_pgsqlInsert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_pgsqlInsert, after);
ClearData();
}
return ret;
}
#endif
}
}

View File

@ -0,0 +1,174 @@
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.Odbc.KingbaseES
{
class OdbcKingbaseESSelect<T1> : FreeSql.Internal.CommonProvider.Select1Provider<T1> where T1 : class
{
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<LambdaExpression> _whereCascadeExpression, IFreeSql _orm)
{
if (_orm.CodeFirst.IsAutoSyncStructure)
_orm.CodeFirst.SyncStructure(_tables.Select(a => a.Table.Type).ToArray());
if (_whereCascadeExpression.Any())
foreach (var tb in _tables.Where(a => a.Type != SelectTableInfoType.Parent))
tb.Cascade = _commonExpression.GetWhereCascadeSql(tb, _whereCascadeExpression, 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).Append(")");
}
}
}
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).Append(")");
}
if (a < tbsfrom.Length - 1) sb.Append(", ");
}
foreach (var tb in tbsjoin)
{
if (tb.Type == SelectTableInfoType.Parent) continue;
switch (tb.Type)
{
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).Append(")");
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).Append(")");
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 OdbcKingbaseESSelect(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 OdbcKingbaseESSelect<T1, T2>(_orm, _commonUtils, _commonExpression, null); OdbcKingbaseESSelect<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 OdbcKingbaseESSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); OdbcKingbaseESSelect<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 OdbcKingbaseESSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); OdbcKingbaseESSelect<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 OdbcKingbaseESSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); OdbcKingbaseESSelect<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 OdbcKingbaseESSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); OdbcKingbaseESSelect<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 OdbcKingbaseESSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); OdbcKingbaseESSelect<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 OdbcKingbaseESSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); OdbcKingbaseESSelect<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 OdbcKingbaseESSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); OdbcKingbaseESSelect<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 OdbcKingbaseESSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); OdbcKingbaseESSelect<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, _whereCascadeExpression, _orm);
}
class OdbcKingbaseESSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T1 : class where T2 : class
{
public OdbcKingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => OdbcKingbaseESSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
}
class OdbcKingbaseESSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> where T1 : class where T2 : class where T3 : class
{
public OdbcKingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => OdbcKingbaseESSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
}
class OdbcKingbaseESSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4> where T1 : class where T2 : class where T3 : class where T4 : class
{
public OdbcKingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => OdbcKingbaseESSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
}
class OdbcKingbaseESSelect<T1, T2, T3, T4, T5> : FreeSql.Internal.CommonProvider.Select5Provider<T1, T2, T3, T4, T5> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class
{
public OdbcKingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => OdbcKingbaseESSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
}
class OdbcKingbaseESSelect<T1, T2, T3, T4, T5, T6> : FreeSql.Internal.CommonProvider.Select6Provider<T1, T2, T3, T4, T5, T6> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class
{
public OdbcKingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => OdbcKingbaseESSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
}
class OdbcKingbaseESSelect<T1, T2, T3, T4, T5, T6, T7> : FreeSql.Internal.CommonProvider.Select7Provider<T1, T2, T3, T4, T5, T6, T7> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class
{
public OdbcKingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => OdbcKingbaseESSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
}
class OdbcKingbaseESSelect<T1, T2, T3, T4, T5, T6, T7, T8> : FreeSql.Internal.CommonProvider.Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class
{
public OdbcKingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => OdbcKingbaseESSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
}
class OdbcKingbaseESSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> : FreeSql.Internal.CommonProvider.Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9> where T1 : class 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 OdbcKingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => OdbcKingbaseESSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
}
class OdbcKingbaseESSelect<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 T1 : class 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 OdbcKingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => OdbcKingbaseESSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
}
}

View File

@ -0,0 +1,164 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FreeSql.Odbc.KingbaseES
{
class OdbcKingbaseESUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1> where T1 : class
{
public OdbcKingbaseESUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
internal string InternalTableAlias;
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 sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var sb = new StringBuilder();
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.QuoteReadColumn(col.CsType, col.Attribute.MapType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
sql = sb.ToString();
var dbParms = _params.Concat(_paramsSource).ToArray();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var ret = new List<T1>();
Exception exception = null;
try
{
ret = _orm.Ado.Query<T1>(_connection, _transaction, CommandType.Text, sql, dbParms);
ValidateVersionAndThrow(ret.Count);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
{
if (_table.Primarys.Length == 1)
{
var pk = _table.Primarys.First();
if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
caseWhen.Append(_commonUtils.QuoteReadColumn(pk.CsType, pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
return;
}
caseWhen.Append("(");
var pkidx = 0;
foreach (var pk in _table.Primarys)
{
if (pkidx > 0) caseWhen.Append(" || '+' || ");
if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
caseWhen.Append(_commonUtils.QuoteReadColumn(pk.CsType, pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.Attribute.Name))).Append("::varchar");
++pkidx;
}
caseWhen.Append(")");
}
protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d)
{
if (_table.Primarys.Length == 1)
{
sb.Append(_commonUtils.FormatSql("{0}", _table.Primarys.First().GetMapValue(d)));
return;
}
sb.Append("(");
var pkidx = 0;
foreach (var pk in _table.Primarys)
{
if (pkidx > 0) sb.Append(" || '+' || ");
sb.Append(_commonUtils.FormatSql("{0}", pk.GetMapValue(d))).Append("::varchar");
++pkidx;
}
sb.Append(")");
}
protected override void ToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col)
{
if (_noneParameter == false) 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() => base.SplitExecuteAffrowsAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
public override Task<List<T1>> ExecuteUpdatedAsync() => base.SplitExecuteUpdatedAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
async protected override Task<List<T1>> RawExecuteUpdatedAsync()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var sb = new StringBuilder();
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.QuoteReadColumn(col.CsType, col.Attribute.MapType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
sql = sb.ToString();
var dbParms = _params.Concat(_paramsSource).ToArray();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var ret = new List<T1>();
Exception exception = null;
try
{
ret = await _orm.Ado.QueryAsync<T1>(_connection, _transaction, CommandType.Text, sql, dbParms);
ValidateVersionAndThrow(ret.Count);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
#endif
}
}

View File

@ -0,0 +1,77 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using FreeSql.Internal.ObjectPool;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Odbc;
using System.Text;
using System.Threading;
namespace FreeSql.Odbc.KingbaseES
{
class OdbcKingbaseESAdo : FreeSql.Internal.CommonProvider.AdoProvider
{
public OdbcKingbaseESAdo() : base(DataType.OdbcKingbaseES, null, null) { }
public OdbcKingbaseESAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func<DbConnection> connectionFactory) : base(DataType.OdbcKingbaseES, masterConnectionString, slaveConnectionStrings)
{
base._util = util;
if (connectionFactory != null)
{
MasterPool = new FreeSql.Internal.CommonProvider.DbConnectionPool(DataType.OdbcKingbaseES, connectionFactory);
return;
}
if (!string.IsNullOrEmpty(masterConnectionString))
MasterPool = new OdbcKingbaseESConnectionPool("主库", masterConnectionString, null, null);
if (slaveConnectionStrings != null)
{
foreach (var slaveConnectionString in slaveConnectionStrings)
{
var slavePool = new OdbcKingbaseESConnectionPool($"从库{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 = 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)
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
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 IEnumerable)
return AddslashesIEnumerable(param, mapType, mapColumn);
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
}
protected override DbCommand CreateCommand()
{
return new OdbcCommand();
}
protected override void ReturnConnection(IObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex)
{
var rawPool = pool as OdbcKingbaseESConnectionPool;
if (rawPool != null) rawPool.Return(conn, ex);
else pool.Return(conn);
}
protected override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
}
}

View File

@ -0,0 +1,258 @@
using FreeSql.Internal.ObjectPool;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.Odbc;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace FreeSql.Odbc.KingbaseES
{
class OdbcKingbaseESConnectionPool : ObjectPool<DbConnection>
{
internal Action availableHandler;
internal Action unavailableHandler;
internal string UserId { get; set; }
public OdbcKingbaseESConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null)
{
this.UserId = OdbcKingbaseESConnectionPool.GetUserId(connectionString);
this.availableHandler = availableHandler;
this.unavailableHandler = unavailableHandler;
var policy = new OdbcKingbaseESConnectionPoolPolicy
{
_pool = this,
Name = name
};
this.Policy = policy;
policy.ConnectionString = connectionString;
}
public static string GetUserId(string connectionString)
{
var userIdMatch = Regex.Match(connectionString, @"(User\s+Id|Uid)\s*=\s*([^;]+)", RegexOptions.IgnoreCase);
if (userIdMatch.Success == false) throw new Exception(@"从 ConnectionString 中无法匹配 (User\s+Id|Uid)\s*=\s*([^;]+)");
return userIdMatch.Groups[2].Value.Trim().ToUpper();
}
public void Return(Object<DbConnection> obj, Exception exception, bool isRecreate = false)
{
if (exception != null && exception is OdbcException)
{
if (exception is System.IO.IOException)
{
base.SetUnavailable(exception);
}
else if (obj.Value.Ping() == false)
{
base.SetUnavailable(exception);
}
}
base.Return(obj, isRecreate);
}
}
class OdbcKingbaseESConnectionPoolPolicy : IPolicy<DbConnection>
{
internal OdbcKingbaseESConnectionPool _pool;
public string Name { get; set; } = "KingbaseES OdbcConnection 对象池";
public int PoolSize { get; set; } = 100;
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; } = 5;
static ConcurrentDictionary<string, int> dicConnStrIncr = new ConcurrentDictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
private string _connectionString;
public string ConnectionString
{
get => _connectionString;
set
{
_connectionString = value ?? "";
var pattern = @"Max\s*pool\s*size\s*=\s*(\d+)";
Match m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100;
var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => Math.Min(5, oldval + 1));
PoolSize = poolsize + connStrIncr;
_connectionString = m.Success ?
Regex.Replace(_connectionString, pattern, $"Max pool size={PoolSize}", RegexOptions.IgnoreCase) :
$"{_connectionString};Max 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);
}
var minPoolSize = 0;
pattern = @"Min\s*pool\s*size\s*=\s*(\d+)";
m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
if (m.Success)
{
minPoolSize = 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.State == ConnectionState.Closed) obj.Value.Open();
return obj.Value.Ping(true);
}
public DbConnection OnCreate()
{
var conn = new OdbcConnection(_connectionString);
return conn;
}
public void OnDestroy(DbConnection obj)
{
if (obj.State != ConnectionState.Closed) obj.Close();
obj.Dispose();
}
public void OnGet(Object<DbConnection> obj)
{
if (_pool.IsAvailable)
{
if (obj.Value == null)
{
if (_pool.SetUnavailable(new Exception("连接字符串错误")) == true)
throw new Exception($"【{this.Name}】连接字符串错误,请检查。");
return;
}
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) == true)
throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}");
}
}
}
}
#if net40
#else
async public Task OnGetAsync(Object<DbConnection> obj)
{
if (_pool.IsAvailable)
{
if (obj.Value == null)
{
if (_pool.SetUnavailable(new Exception("连接字符串错误")) == true)
throw new Exception($"【{this.Name}】连接字符串错误,请检查。");
return;
}
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) == true)
throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}");
}
}
}
}
#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 from dual";
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
}
}

View File

@ -0,0 +1,459 @@
using FreeSql.DataAnnotations;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Odbc;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Odbc.KingbaseES
{
class OdbcKingbaseESCodeFirst : Internal.CommonProvider.CodeFirstProvider
{
public override bool IsNoneCommandParameter { get => true; set => base.IsNoneCommandParameter = true; }
public OdbcKingbaseESCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
static object _dicCsToDbLock = new object();
static Dictionary<string, CsToDb<OdbcType>> _dicCsToDb = new Dictionary<string, CsToDb<OdbcType>>() {
{ typeof(sbyte).FullName, CsToDb.New(OdbcType.TinyInt, "tinyint","tinyint NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(OdbcType.TinyInt, "tinyint", "tinyint", false, true, null) },
{ typeof(short).FullName, CsToDb.New(OdbcType.SmallInt, "int2","int2 NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(OdbcType.SmallInt, "int2", "int2", false, true, null) },
{ typeof(int).FullName, CsToDb.New(OdbcType.Int, "int4","int4 NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(OdbcType.Int, "int4", "int4", false, true, null) },
{ typeof(long).FullName, CsToDb.New(OdbcType.BigInt, "int8","int8 NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(OdbcType.BigInt, "int8", "int8", false, true, null) },
{ typeof(byte).FullName, CsToDb.New(OdbcType.SmallInt, "int2","int2 NOT NULL", false, false, 0) },{ typeof(byte?).FullName, CsToDb.New(OdbcType.SmallInt, "int2", "int2", false, true, null) },
{ typeof(ushort).FullName, CsToDb.New(OdbcType.Int, "int4","int4 NOT NULL", false, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(OdbcType.Int, "int4", "int4", false, true, null) },
{ typeof(uint).FullName, CsToDb.New(OdbcType.BigInt, "int8","int8 NOT NULL", false, false, 0) },{ typeof(uint?).FullName, CsToDb.New(OdbcType.BigInt, "int8", "int8", false, true, null) },
{ typeof(ulong).FullName, CsToDb.New(OdbcType.Numeric, "numeric","numeric(20,0) NOT NULL", false, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(OdbcType.Numeric, "numeric", "numeric(20,0)", false, true, null) },
{ typeof(float).FullName, CsToDb.New(OdbcType.Real, "float4","float4 NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(OdbcType.Real, "float4", "float4", false, true, null) },
{ typeof(double).FullName, CsToDb.New(OdbcType.Double, "float8","float8 NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(OdbcType.Double, "float8", "float8", false, true, null) },
{ typeof(decimal).FullName, CsToDb.New(OdbcType.Numeric, "numeric", "numeric(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(OdbcType.Numeric, "numeric", "numeric(10,2)", false, true, null) },
{ typeof(string).FullName, CsToDb.New(OdbcType.VarChar, "varchar", "varchar(255)", false, null, "") },
{ typeof(TimeSpan).FullName, CsToDb.New(OdbcType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(OdbcType.Time, "time", "time",false, true, null) },
{ typeof(DateTime).FullName, CsToDb.New(OdbcType.DateTime, "timestamp", "timestamp NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(OdbcType.DateTime, "timestamp", "timestamp", false, true, null) },
{ 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) },
};
public override DbInfoResult GetDbInfo(Type type)
{
if (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue);
if (type.IsArray) return null;
var enumType = type.IsEnum ? type : null;
if (enumType == null && type.IsNullableType())
{
var genericTypes = type.GetGenericArguments();
if (genericTypes.Length == 1 && genericTypes.First().IsEnum) enumType = genericTypes.First();
}
if (enumType != null)
{
var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
CsToDb.New(OdbcType.BigInt, "int8", $"int8{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, enumType.CreateInstanceGetDefaultValue()) :
CsToDb.New(OdbcType.Int, "int4", $"int4{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, enumType.CreateInstanceGetDefaultValue());
if (_dicCsToDb.ContainsKey(type.FullName) == false)
{
lock (_dicCsToDbLock)
{
if (_dicCsToDb.ContainsKey(type.FullName) == false)
_dicCsToDb.Add(type.FullName, newItem);
}
}
return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue);
}
return null;
}
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<NaviteTuple<ColumnInfo, string[], bool>>(); //序列:列,表,自增
var seqnameDel = new List<string>(); //要删除的序列+触发器
var sb = new StringBuilder();
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($"类型 {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] };
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 (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;
primaryKeyName = null;
}
}
//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) //创建数据库
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 (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)
//模式或表不存在
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(" ").Append(tbcol.Attribute.DbType).Append(",");
if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, true));
}
if (tb.Primarys.Any())
{
var pkname = primaryKeyName ?? $"{tbname[0]}_{tbname[1]}_PK1";
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(uk.Name)).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.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 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);
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])
};
}, StringComparer.CurrentCultureIgnoreCase);
if (istmpatler == false)
{
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.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 (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");
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");
}
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 (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();
foreach (var uk in tb.Indexes)
{
if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue;
var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Name, true) == 0).ToArray();
if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => uk.Columns.Where(b => (a[3] == "1") == uk.IsUnique && string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length)
{
if (dsukfind1.Any()) sbalter.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(";\r\n");
sbalter.Append("CREATE ");
if (uk.IsUnique) sbalter.Append("UNIQUE ");
sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).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 from all_tab_comments where owner = {0} and table_name = {1} and table_type = 'TABLE'", userId, 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();
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");
//创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名
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(" ( ");
foreach (var tbcol in tb.ColumnsByPosition)
{
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, true));
}
if (tb.Primarys.Any())
{
var pkname = primaryKeyName ?? $"{tbname[0]}_{tbname[1]}_PK2";
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]}.FTmp_{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]}.FTmp_{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)
{
var dbtypeNoneNotNull = Regex.Replace(tbcol.Attribute.DbType, @"(NOT\s+)?NULL", "");
insertvalue = $"cast({insertvalue} as {dbtypeNoneNotNull})";
}
if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
insertvalue = $"nvl({insertvalue},{tbcol.DbDefaultValue})";
}
else if (tbcol.Attribute.IsNullable == false)
insertvalue = tbcol.DbDefaultValue;
sb.Append(insertvalue.Replace("'", "''")).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(uk.Name)).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]}_seq_{seqcol.Item1.Attribute.Name}").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");
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");
}
}
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;
}
}
}

View File

@ -0,0 +1,120 @@
using FreeSql.DatabaseModel;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.Odbc;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Odbc.KingbaseES
{
class OdbcKingbaseESDbFirst : IDbFirst
{
IFreeSql _orm;
protected CommonUtils _commonUtils;
protected CommonExpression _commonExpression;
public OdbcKingbaseESDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
{
_orm = orm;
_commonUtils = commonUtils;
_commonExpression = commonExpression;
}
public int GetDbType(DbColumnInfo column) => (int)GetSqlDbType(column);
OdbcType GetSqlDbType(DbColumnInfo column)
{
var dbtype = column.DbTypeText;
var isarray = dbtype.EndsWith("[]");
if (isarray) dbtype = dbtype.Remove(dbtype.Length - 2);
var ret = OdbcType.VarChar;
switch (dbtype.ToLower().TrimStart('_'))
{
case "tinyint": ret = OdbcType.TinyInt; break;
case "int2": ret = OdbcType.SmallInt; break;
case "int4": ret = OdbcType.Int; break;
case "int8": ret = OdbcType.BigInt; break;
case "numeric": ret = OdbcType.Numeric; break;
case "float4": ret = OdbcType.Real; break;
case "float8": ret = OdbcType.Double; break;
case "money": ret = OdbcType.Numeric; break;
case "char": ret = column.MaxLength == 36 ? OdbcType.UniqueIdentifier : OdbcType.Char; break;
case "bpchar": ret = OdbcType.Char; break;
case "varchar": ret = OdbcType.VarChar; break;
case "text": ret = OdbcType.Text; break;
case "timestamp": ret = OdbcType.Timestamp; break;
case "timestamptz": ret = OdbcType.Timestamp; break;
case "date": ret = OdbcType.Date; break;
case "time": ret = OdbcType.Time; break;
case "timetz": ret = OdbcType.Time; break;
case "interval": ret = OdbcType.Time; break;
case "bool": ret = OdbcType.Bit; break;
case "blob": ret = OdbcType.VarBinary; break;
case "bytea": ret = OdbcType.VarBinary; break;
case "bit": ret = OdbcType.Bit; break;
case "varbit": ret = OdbcType.VarBinary; break;
case "uuid": ret = OdbcType.UniqueIdentifier; break;
}
return ret;
}
static ConcurrentDictionary<int, DbToCs> _dicDbToCs = new ConcurrentDictionary<int, DbToCs>();
static OdbcKingbaseESDbFirst()
{
var defaultDbToCs = new Dictionary<int, DbToCs>() {
{ (int)OdbcType.TinyInt, new DbToCs("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
{ (int)OdbcType.SmallInt, new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(int), typeof(int?), "{0}.Value", "GetInt16") },
{ (int)OdbcType.Int, new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(long), typeof(long?), "{0}.Value", "GetInt32") },
{ (int)OdbcType.BigInt, new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
{ (int)OdbcType.Real, new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
{ (int)OdbcType.Double, new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
{ (int)OdbcType.Numeric, new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
{ (int)OdbcType.Char, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
{ (int)OdbcType.VarChar, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
{ (int)OdbcType.Text, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
{ (int)OdbcType.DateTime, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
{ (int)OdbcType.Date, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
{ (int)OdbcType.Time, new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
{ (int)OdbcType.Bit, new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
{ (int)OdbcType.VarBinary, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
{ (int)OdbcType.UniqueIdentifier, new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid", typeof(Guid), typeof(Guid?), "{0}", "GetString") },
};
foreach (var kv in defaultDbToCs)
_dicDbToCs.TryAdd(kv.Key, kv.Value);
}
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 schema_name from information_schema.schemata where schema_owner<>'SYSTEM'";
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
return new[] { "PUBLIC" }.Concat(ds.Select(a => a.FirstOrDefault()?.ToString())).ToList();
}
public List<DbTableInfo> GetTablesByDatabase(params string[] database2) => throw new NotImplementedException();
public List<DbEnumInfo> GetEnumsByDatabase(params string[] database)
{
return new List<DbEnumInfo>();
}
}
}

View File

@ -0,0 +1,585 @@
using FreeSql.Internal;
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.Odbc.KingbaseES
{
class OdbcKingbaseESExpression : CommonExpression
{
public OdbcKingbaseESExpression(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.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 $"({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)})::varchar";
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.ArrayLength:
var arrOperExp = getExp((exp as UnaryExpression).Operand);
if (arrOperExp.StartsWith("(") || arrOperExp.EndsWith(")")) return $"array_length(array[{arrOperExp.TrimStart('(').TrimEnd(')')}],1)";
return $"case when {arrOperExp} is null then 0 else array_length({arrOperExp},1) end";
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 $"({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)})::varchar" : 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 == null) objType = callExp.Method.DeclaringType;
if (objType != null || objType.IsArrayOrList())
{
string left = null;
if (objType.FullName == typeof(Dictionary<string, string>).FullName)
{
left = objExp == null ? null : getExp(objExp);
switch (callExp.Method.Name)
{
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 = tsc.SetDbParamsReturnOld(null);
left = objExp == null ? null : getExp(objExp);
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
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";
}
}
}
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);
}
}
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";
var likeOpt = "LIKE";
if (exp.Arguments.Count > 1)
{
if (exp.Arguments[1].Type == typeof(bool) ||
exp.Arguments[1].Type == typeof(StringComparison) && getExp(exp.Arguments[0]).Contains("IgnoreCase")) likeOpt = "ILIKE";
}
if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::varchar || '%')")}";
if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::varchar)")}";
if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
return $"({left}) {likeOpt} ('%' || ({args0Value})::varchar || '%')";
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})";
}
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)
{
if (exp.Method.Name == "Trim") left = $"trim(both {getExp(argsTrim01)} from {left})";
if (exp.Method.Name == "TrimStart") left = $"ltrim({left},{getExp(argsTrim01)})";
if (exp.Method.Name == "TrimEnd") left = $"rtrim({left},{getExp(argsTrim01)})";
}
}
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])})::varchar)";
}
}
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":
if (exp.Arguments.Count > 1) return $"log({getExp(exp.Arguments[1])},{getExp(exp.Arguments[0])})";
return $"log(2.7182818284590451,{getExp(exp.Arguments[0])})";
case "Log10": return $"log({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 $"({getExp(exp.Arguments[0])})::timestamp";
case "ParseExact":
case "TryParse":
case "TryParseExact": return $"({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 $"({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])})::varchar";
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;
}
}
}

View File

@ -0,0 +1,60 @@
using FreeSql.Internal;
using FreeSql.Internal.CommonProvider;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Threading;
namespace FreeSql.Odbc.KingbaseES
{
public class OdbcKingbaseESProvider<TMark> : IFreeSql<TMark>
{
public ISelect<T1> Select<T1>() where T1 : class => new OdbcKingbaseESSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
public ISelect<T1> Select<T1>(object dywhere) where T1 : class => new OdbcKingbaseESSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public IInsert<T1> Insert<T1>() where T1 : class => new OdbcKingbaseESInsert<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public IInsert<T1> Insert<T1>(T1 source) where T1 : class => this.Insert<T1>().AppendData(source);
public IInsert<T1> Insert<T1>(T1[] source) where T1 : class => this.Insert<T1>().AppendData(source);
public IInsert<T1> Insert<T1>(List<T1> source) where T1 : class => this.Insert<T1>().AppendData(source);
public IInsert<T1> Insert<T1>(IEnumerable<T1> source) where T1 : class => this.Insert<T1>().AppendData(source);
public IUpdate<T1> Update<T1>() where T1 : class => new OdbcKingbaseESUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcKingbaseESUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public IDelete<T1> Delete<T1>() where T1 : class => new OdbcKingbaseESDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcKingbaseESDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public IInsertOrUpdate<T1> InsertOrUpdate<T1>() where T1 : class => new OdbcKingbaseESInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public IAdo Ado { get; }
public IAop Aop { get; }
public ICodeFirst CodeFirst { get; }
public IDbFirst DbFirst { get; }
public OdbcKingbaseESProvider(string masterConnectionString, string[] slaveConnectionString, Func<DbConnection> connectionFactory = null)
{
this.InternalCommonUtils = new OdbcKingbaseESUtils(this);
this.InternalCommonExpression = new OdbcKingbaseESExpression(this.InternalCommonUtils);
this.Ado = new OdbcKingbaseESAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString, connectionFactory);
this.Aop = new AopProvider();
this.DbFirst = new OdbcKingbaseESDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
this.CodeFirst = new OdbcKingbaseESCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
}
internal CommonUtils InternalCommonUtils { get; }
internal CommonExpression InternalCommonExpression { get; }
public void Transaction(Action handler) => Ado.Transaction(handler);
public void Transaction(IsolationLevel isolationLevel, Action handler) => Ado.Transaction(isolationLevel, handler);
public GlobalFilter GlobalFilter { get; } = new GlobalFilter();
~OdbcKingbaseESProvider() => this.Dispose();
int _disposeCounter;
public void Dispose()
{
if (Interlocked.Increment(ref _disposeCounter) != 1) return;
(this.Ado as AdoProvider)?.Dispose();
}
}
}

View File

@ -0,0 +1,161 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Odbc;
using System.Globalization;
using System.Linq;
using System.Text;
namespace FreeSql.Odbc.KingbaseES
{
class OdbcKingbaseESUtils : CommonUtils
{
public OdbcKingbaseESUtils(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;
}
static Dictionary<string, Func<object, object>> dicGetParamterValue = new Dictionary<string, Func<object, object>> {
{ 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) },
};
static object getParamterValue(Type type, object value, int level = 0)
{
if (type.FullName == "System.Byte[]") return value;
if (type.IsArray && level == 0)
{
var elementType = type.GetElementType();
Type enumType = null;
if (elementType.IsEnum) enumType = elementType;
else if (elementType.IsNullableType())
{
var genericTypesFirst = elementType.GetGenericArguments().First();
if (genericTypesFirst.IsEnum) enumType = genericTypesFirst;
}
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.GetGenericArguments().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 OdbcParameter { ParameterName = QuoteParamterName(parameterName), Value = value };
//if (value.GetType().IsEnum || value.GetType().GenericTypeArguments.FirstOrDefault()?.IsEnum == true) {
// ret.DataTypeName = "";
//} else {
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
if (tp != null) ret.OdbcType = (OdbcType)tp.Value;
//}
_params?.Add(ret);
return ret;
}
public override DbParameter[] GetDbParamtersByObject(string sql, object obj) =>
Utils.GetDbParamtersByObject<OdbcParameter>(sql, obj, null, (name, type, value) =>
{
if (value != null) value = getParamterValue(type, value);
var ret = new OdbcParameter { ParameterName = $"@{name.ToUpper()}", Value = value };
//if (value.GetType().IsEnum || value.GetType().GenericTypeArguments.FirstOrDefault()?.IsEnum == true) {
// ret.DataTypeName = "";
//} else {
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
if (tp != null) ret.OdbcType = (OdbcType)tp.Value;
//}
return ret;
});
public override string FormatSql(string sql, params object[] args) => sql?.FormatOdbcKingbaseES(args);
public override string QuoteSqlName(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)}\"";
}
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.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 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 QuoteWriteParamter(Type type, string paramterName) => paramterName;
public override string QuoteReadColumn(Type type, Type mapType, string columnName) => columnName;
public override string GetNoneParamaterSqlValue(List<DbParameter> specialParams, 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, eleType, item));
}
sb.Append("]");
var dbinfo = _orm.CodeFirst.GetDbInfo(type);
if (dbinfo != null) sb.Append("::").Append(dbinfo.dbtype);
return sb.ToString();
}
else if (dicGetParamterValue.ContainsKey(type2.FullName))
{
value = string.Concat(value);
}
return FormatSql("{0}", value, 1);
}
}
}

View File

@ -58,7 +58,7 @@ namespace FreeSql.Odbc.MySql
return $"{nametrim.Trim('`').Replace("`.`", ".").Replace(".`", ".")}";
}
public override string[] SplitTableName(string name) => GetSplitTableNames(name, '`', '`', 2);
public override string QuoteParamterName(string name) => $"?{(_orm.CodeFirst.IsSyncStructureToLower ? name.ToLower() : name)}";
public override string QuoteParamterName(string name) => $"?{name}";
public override string IsNull(string sql, object value) => $"ifnull({sql}, {value})";
public override string StringConcat(string[] objs, Type[] types) => $"concat({string.Join(", ", objs)})";
public override string Mod(string left, string right, Type leftType, Type rightType) => $"{left} % {right}";

View File

@ -88,7 +88,7 @@ namespace FreeSql.Odbc.Oracle
return $"{nametrim.Trim('"').Replace("\".\"", ".").Replace(".\"", ".")}";
}
public override string[] SplitTableName(string name) => GetSplitTableNames(name, '"', '"', 2);
public override string QuoteParamterName(string name) => $":{(_orm.CodeFirst.IsSyncStructureToLower ? name.ToLower() : name)}";
public override string QuoteParamterName(string name) => $":{name}";
public override string IsNull(string sql, object value) => $"nvl({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) => $"mod({left}, {right})";

View File

@ -111,7 +111,7 @@ namespace FreeSql.Odbc.PostgreSQL
return $"{nametrim.Trim('"').Replace("\".\"", ".").Replace(".\"", ".")}";
}
public override string[] SplitTableName(string name) => GetSplitTableNames(name, '"', '"', 2);
public override string QuoteParamterName(string name) => $"@{(_orm.CodeFirst.IsSyncStructureToLower ? name.ToLower() : name)}";
public override string QuoteParamterName(string name) => $"@{(name.ToLower())}";
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}";

View File

@ -63,7 +63,7 @@ namespace FreeSql.Odbc.SqlServer
return $"{nametrim.TrimStart('[').TrimEnd(']').Replace("].[", ".").Replace(".[", ".")}";
}
public override string[] SplitTableName(string name) => GetSplitTableNames(name, '[', ']', 3);
public override string QuoteParamterName(string name) => $"@{(_orm.CodeFirst.IsSyncStructureToLower ? name.ToLower() : name)}";
public override string QuoteParamterName(string name) => $"@{name}";
public override string IsNull(string sql, object value) => $"isnull({sql}, {value})";
public override string StringConcat(string[] objs, Type[] types)
{