- 修复 MySql8.0.30 无法使用 ExecuteInserted 的问题;#2001

This commit is contained in:
2881099
2025-03-27 23:47:30 +08:00
parent e1faaa1f5a
commit f861c9da6e
9 changed files with 169 additions and 151 deletions

View File

@@ -621,6 +621,8 @@ namespace base_entity
BaseEntity.Initialization(fsql, () => _asyncUow.Value);
#endregion
fsql.Insert(new User1()).ExecuteInserted();
fsql.InsertOrUpdate<AppInfoEntity>().SetSource(new AppInfoEntity { AppID = "03DN8CW8", AppName = "app_01" }).ExecuteAffrows();
var repo2211 = fsql.GetRepository<AppInfoEntity>();

View File

@@ -1087,93 +1087,6 @@
</summary>
<returns></returns>
</member>
<member name="T:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder">
<summary>
动态创建实体类型
</summary>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.#ctor(IFreeSql,System.String,System.Attribute[])">
<summary>
配置Class
</summary>
<param name="className">类名</param>
<param name="attributes">类标记的特性[Table(Name = "xxx")] [Index(xxxx)]</param>
<returns></returns>
</member>
<member name="P:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.TypeBuilder">
<summary>
获取类型构建器可作为要构建的Type来引用
</summary>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Property(System.String,System.Type,System.Attribute[])">
<summary>
配置属性
</summary>
<param name="propertyName">属性名称</param>
<param name="propertyType">属性类型</param>
<param name="attributes">属性标记的特性-支持多个</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Property(System.String,System.Type,System.Boolean,System.Attribute[])">
<summary>
配置属性
</summary>
<param name="propertyName">属性名称</param>
<param name="propertyType">属性类型</param>
<param name="isOverride">该属性是否重写父类属性</param>
<param name="attributes">属性标记的特性-支持多个</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Property(System.String,System.Type,System.Boolean,System.Object,System.Attribute[])">
<summary>
配置属性
</summary>
<param name="propertyName">属性名称</param>
<param name="propertyType">属性类型</param>
<param name="isOverride">该属性是否重写父类属性</param>
<param name="defaultValue">属性默认值</param>
<param name="attributes">属性标记的特性-支持多个</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Extend(System.Type)">
<summary>
配置父类
</summary>
<param name="superClass">父类类型</param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.OverrideProperty(System.Reflection.Emit.TypeBuilder@,System.Reflection.Emit.MethodBuilder,FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.PropertyMethodEnum,System.String)">
<summary>
Override属性
</summary>
<param name="typeBuilder"></param>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.Build">
<summary>
Emit动态创建出Class - Type
</summary>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.BuildJustType">
<summary>
Emit动态创建出Class - Type不附带获取TableInfo
</summary>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.FirstCharToLower(System.String)">
<summary>
首字母小写
</summary>
<param name="input"></param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.DynamicEntity.DynamicCompileBuilder.FirstCharToUpper(System.String)">
<summary>
首字母大写
</summary>
<param name="input"></param>
<returns></returns>
</member>
<member name="M:FreeSql.Extensions.EntityUtil.EntityUtilExtensions.GetEntityKeyString(IFreeSql,System.Type,System.Object,System.Boolean,System.String)">
<summary>
获取实体的主键值,以 "*|_,[,_|*" 分割,当任意一个主键属性无值时,返回 ""
@@ -1945,7 +1858,7 @@
<member name="M:FreeSql.IInsert`1.ExecuteInserted">
<summary>
执行SQL语句返回插入后的记录<para></para>
注意:此方法只有 Postgresql/SqlServer/Maridb/Firebird/DuckDB/人大金仓 有效果
注意:此方法只有 Postgresql/SqlServer/MySql8.0.30+/Maridb/Firebird/DuckDB/人大金仓 有效果
</summary>
<returns></returns>
</member>
@@ -1958,6 +1871,13 @@
</summary>
<returns></returns>
</member>
<member name="M:FreeSql.IInsert`1.ExecuteInsertedAsync(System.Threading.CancellationToken)">
<summary>
执行SQL语句返回插入后的记录<para></para>
注意:此方法只有 Postgresql/SqlServer/MySql8.0.30+/Maridb/Firebird/DuckDB/人大金仓 有效果
</summary>
<returns></returns>
</member>
<member name="M:FreeSql.IInsertOrUpdate`1.WithTransaction(System.Data.Common.DbTransaction)">
<summary>
指定事务对象
@@ -5955,28 +5875,6 @@
对象池
</summary>
</member>
<member name="M:FreeSqlGlobalDynamicEntityExtensions.DynamicEntity(FreeSql.ICodeFirst,System.String,System.Attribute[])">
<summary>
动态构建Class Type
</summary>
<returns></returns>
</member>
<member name="M:FreeSqlGlobalDynamicEntityExtensions.CreateInstance(FreeSql.Internal.Model.TableInfo,System.Collections.Generic.Dictionary{System.String,System.Object})">
<summary>
根据字典,创建 table 对应的实体对象
</summary>
<param name="table"></param>
<param name="dict"></param>
<returns></returns>
</member>
<member name="M:FreeSqlGlobalDynamicEntityExtensions.CreateDictionary(FreeSql.Internal.Model.TableInfo,System.Object)">
<summary>
根据实体对象,创建 table 对应的字典
</summary>
<param name="table"></param>
<param name="instance"></param>
<returns></returns>
</member>
<member name="M:FreeSqlGlobalExpressionCallExtensions.Between(System.DateTime,System.DateTime,System.DateTime)">
<summary>
C# that >= between &amp;&amp; that &lt;= and<para></para>

View File

@@ -156,7 +156,7 @@ namespace FreeSql
long ExecuteIdentity();
/// <summary>
/// 执行SQL语句返回插入后的记录<para></para>
/// 注意:此方法只有 Postgresql/SqlServer/Maridb/Firebird/DuckDB/人大金仓 有效果
/// 注意:此方法只有 Postgresql/SqlServer/MySql8.0.30+/Maridb/Firebird/DuckDB/人大金仓 有效果
/// </summary>
/// <returns></returns>
List<T1> ExecuteInserted();
@@ -174,6 +174,11 @@ namespace FreeSql
#else
Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default);
Task<long> ExecuteIdentityAsync(CancellationToken cancellationToken = default);
/// <summary>
/// 执行SQL语句返回插入后的记录<para></para>
/// 注意:此方法只有 Postgresql/SqlServer/MySql8.0.30+/Maridb/Firebird/DuckDB/人大金仓 有效果
/// </summary>
/// <returns></returns>
Task<List<T1>> ExecuteInsertedAsync(CancellationToken cancellationToken = default);
#endif
}

View File

@@ -431,7 +431,7 @@ namespace FreeSql.Internal.CommonProvider
if (ss.Length == 1)
{
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, 1, 1));
ret = this.RawExecuteInserted();
ret = this.InternalExecuteInserted();
ClearData();
return ret;
}
@@ -452,7 +452,7 @@ namespace FreeSql.Internal.CommonProvider
{
_source = ss[a];
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, a + 1, ss.Length));
ret.AddRange(this.RawExecuteInserted());
ret.AddRange(this.InternalExecuteInserted());
}
}
else
@@ -469,7 +469,7 @@ namespace FreeSql.Internal.CommonProvider
{
_source = ss[a];
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, a + 1, ss.Length));
ret.AddRange(this.RawExecuteInserted());
ret.AddRange(this.InternalExecuteInserted());
}
_transaction.Commit();
_orm.Aop.TraceAfterHandler?.Invoke(this, new Aop.TraceAfterEventArgs(transBefore, CoreErrorStrings.Commit, null));
@@ -525,6 +525,12 @@ namespace FreeSql.Internal.CommonProvider
protected abstract long RawExecuteIdentity();
protected abstract List<T1> RawExecuteInserted();
private List<T1> InternalExecuteInserted()
{
var ret = RawExecuteInserted();
if (_table.TypeLazySetOrm != null) ret.ForEach(item => _table.TypeLazySetOrm.Invoke(item, new object[] { _orm }));
return ret;
}
public abstract int ExecuteAffrows();
public abstract long ExecuteIdentity();

View File

@@ -189,7 +189,7 @@ namespace FreeSql.Internal.CommonProvider
if (ss.Length == 1)
{
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, 1, 1));
ret = await this.RawExecuteInsertedAsync(cancellationToken);
ret = await this.InternalExecuteInsertedAsync(cancellationToken);
ClearData();
return ret;
}
@@ -210,7 +210,7 @@ namespace FreeSql.Internal.CommonProvider
{
_source = ss[a];
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, a + 1, ss.Length));
ret.AddRange(await this.RawExecuteInsertedAsync(cancellationToken));
ret.AddRange(await this.InternalExecuteInsertedAsync(cancellationToken));
}
}
else
@@ -227,7 +227,7 @@ namespace FreeSql.Internal.CommonProvider
{
_source = ss[a];
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, a + 1, ss.Length));
ret.AddRange(await this.RawExecuteInsertedAsync(cancellationToken));
ret.AddRange(await this.InternalExecuteInsertedAsync(cancellationToken));
}
_transaction.Commit();
_orm.Aop.TraceAfterHandler?.Invoke(this, new Aop.TraceAfterEventArgs(transBefore, CoreErrorStrings.Commit, null));
@@ -282,6 +282,12 @@ namespace FreeSql.Internal.CommonProvider
protected abstract Task<long> RawExecuteIdentityAsync(CancellationToken cancellationToken = default);
protected abstract Task<List<T1>> RawExecuteInsertedAsync(CancellationToken cancellationToken = default);
async private Task<List<T1>> InternalExecuteInsertedAsync(CancellationToken cancellationToken = default)
{
var ret = await RawExecuteInsertedAsync(cancellationToken);
if (_table.TypeLazySetOrm != null) ret.ForEach(item => _table.TypeLazySetOrm.Invoke(item, new object[] { _orm }));
return ret;
}
public abstract Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default);
public abstract Task<long> ExecuteIdentityAsync(CancellationToken cancellationToken = default);

View File

@@ -1752,6 +1752,8 @@ namespace FreeSql.Internal
}
return dr.GetValue(index);
}
public static object ExecuteReaderToClass(string flagStr, Type typeOrg, int[] indexes, DbDataReader row, int dataIndex, CommonUtils _commonUtils) =>
ExecuteArrayRowReadClassOrTuple(flagStr, typeOrg, indexes, row, dataIndex, _commonUtils)?.Value;
internal static RowInfo ExecuteArrayRowReadClassOrTuple(string flagStr, Type typeOrg, int[] indexes, DbDataReader row, int dataIndex, CommonUtils _commonUtils)
{
if (string.IsNullOrEmpty(flagStr)) flagStr = "all";

View File

@@ -89,12 +89,25 @@ namespace FreeSql.Custom.MySql
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
var propidx = 0;
var props = _table.Type.GetPropertiesDictIgnoreCase();
var indexes = new int[props.Count];
var sbflag = new StringBuilder().Append("insertedQuery");
foreach (var prop in props)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
if (_table.ColumnsByCs.TryGetValue(prop.Key, out var col))
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name)));
sbflag.Append(col.Attribute.Name).Append(":").Append(colidx).Append(",");
indexes[propidx] = colidx;
++colidx;
}
else
indexes[propidx] = -1;
++propidx;
}
var flag = sbflag.ToString();
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
@@ -102,12 +115,15 @@ namespace FreeSql.Custom.MySql
Exception exception = null;
try
{
ret = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, _params);
_orm.Ado.ExecuteReader(_connection, _transaction, fetch =>
{
ret.Add((T1)Utils.ExecuteReaderToClass(flag, _table.TypeLazy ?? _table.Type, indexes, fetch.Object, 0, _commonUtils));
}, CommandType.Text, sql, _commandTimeout, _params);
}
catch (Exception ex)
{
exception = ex;
throw ex;
throw;
}
finally
{
@@ -169,12 +185,25 @@ namespace FreeSql.Custom.MySql
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
var propidx = 0;
var props = _table.Type.GetPropertiesDictIgnoreCase();
var indexes = new int[props.Count];
var sbflag = new StringBuilder().Append("insertedQuery");
foreach (var prop in props)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
if (_table.ColumnsByCs.TryGetValue(prop.Key, out var col))
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name)));
sbflag.Append(col.Attribute.Name).Append(":").Append(colidx).Append(",");
indexes[propidx] = colidx;
++colidx;
}
else
indexes[propidx] = -1;
++propidx;
}
var flag = sbflag.ToString();
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
@@ -182,12 +211,16 @@ namespace FreeSql.Custom.MySql
Exception exception = null;
try
{
ret = await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, _params, cancellationToken);
await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, fetch =>
{
ret.Add((T1)Utils.ExecuteReaderToClass(flag, _table.TypeLazy ?? _table.Type, indexes, fetch.Object, 0, _commonUtils));
return Task.FromResult(false);
}, CommandType.Text, sql, _commandTimeout, _params);
}
catch (Exception ex)
{
exception = ex;
throw ex;
throw;
}
finally
{

View File

@@ -77,12 +77,25 @@ namespace FreeSql.MySql.Curd
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
var propidx = 0;
var props = _table.Type.GetPropertiesDictIgnoreCase(); //与 ExecuteArrayRowReadClassOrTuple 顺序同步
var indexes = new int[props.Count];
var sbflag = new StringBuilder().Append("insertedQuery");
foreach (var prop in props)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
if (_table.ColumnsByCs.TryGetValue(prop.Key, out var col))
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name)));
sbflag.Append(col.Attribute.Name).Append(":").Append(colidx).Append(",");
indexes[propidx] = colidx;
++colidx;
}
else
indexes[propidx] = -1;
++propidx;
}
var flag = sbflag.ToString();
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
@@ -90,7 +103,10 @@ namespace FreeSql.MySql.Curd
Exception exception = null;
try
{
ret = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, _params);
_orm.Ado.ExecuteReader(_connection, _transaction, fetch =>
{
ret.Add((T1)Utils.ExecuteReaderToClass(flag, _table.TypeLazy ?? _table.Type, indexes, fetch.Object, 0, _commonUtils));
}, CommandType.Text, sql, _commandTimeout, _params);
}
catch (Exception ex)
{
@@ -146,12 +162,25 @@ namespace FreeSql.MySql.Curd
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
var propidx = 0;
var props = _table.Type.GetPropertiesDictIgnoreCase();
var indexes = new int[props.Count];
var sbflag = new StringBuilder().Append("insertedQuery");
foreach (var prop in props)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
if (_table.ColumnsByCs.TryGetValue(prop.Key, out var col))
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name)));
sbflag.Append(col.Attribute.Name).Append(":").Append(colidx).Append(",");
indexes[propidx] = colidx;
++colidx;
}
else
indexes[propidx] = -1;
++propidx;
}
var flag = sbflag.ToString();
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
@@ -159,7 +188,11 @@ namespace FreeSql.MySql.Curd
Exception exception = null;
try
{
ret = await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, _params, cancellationToken);
await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, fetch =>
{
ret.Add((T1)Utils.ExecuteReaderToClass(flag, _table.TypeLazy ?? _table.Type, indexes, fetch.Object, 0, _commonUtils));
return Task.FromResult(false);
}, CommandType.Text, sql, _commandTimeout, _params);
}
catch (Exception ex)
{

View File

@@ -89,12 +89,25 @@ namespace FreeSql.Odbc.MySql
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
var propidx = 0;
var props = _table.Type.GetPropertiesDictIgnoreCase();
var indexes = new int[props.Count];
var sbflag = new StringBuilder().Append("insertedQuery");
foreach (var prop in props)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
if (_table.ColumnsByCs.TryGetValue(prop.Key, out var col))
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name)));
sbflag.Append(col.Attribute.Name).Append(":").Append(colidx).Append(",");
indexes[propidx] = colidx;
++colidx;
}
else
indexes[propidx] = -1;
++propidx;
}
var flag = sbflag.ToString();
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
@@ -102,12 +115,15 @@ namespace FreeSql.Odbc.MySql
Exception exception = null;
try
{
ret = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, _params);
_orm.Ado.ExecuteReader(_connection, _transaction, fetch =>
{
ret.Add((T1)Utils.ExecuteReaderToClass(flag, _table.TypeLazy ?? _table.Type, indexes, fetch.Object, 0, _commonUtils));
}, CommandType.Text, sql, _commandTimeout, _params);
}
catch (Exception ex)
{
exception = ex;
throw ex;
throw;
}
finally
{
@@ -169,12 +185,25 @@ namespace FreeSql.Odbc.MySql
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
var propidx = 0;
var props = _table.Type.GetPropertiesDictIgnoreCase();
var indexes = new int[props.Count];
var sbflag = new StringBuilder().Append("insertedQuery");
foreach (var prop in props)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
if (_table.ColumnsByCs.TryGetValue(prop.Key, out var col))
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name)));
sbflag.Append(col.Attribute.Name).Append(":").Append(colidx).Append(",");
indexes[propidx] = colidx;
++colidx;
}
else
indexes[propidx] = -1;
++propidx;
}
var flag = sbflag.ToString();
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
@@ -182,12 +211,16 @@ namespace FreeSql.Odbc.MySql
Exception exception = null;
try
{
ret = await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, _params, cancellationToken);
await _orm.Ado.ExecuteReaderAsync(_connection, _transaction, fetch =>
{
ret.Add((T1)Utils.ExecuteReaderToClass(flag, _table.TypeLazy ?? _table.Type, indexes, fetch.Object, 0, _commonUtils));
return Task.FromResult(false);
}, CommandType.Text, sql, _commandTimeout, _params);
}
catch (Exception ex)
{
exception = ex;
throw ex;
throw;
}
finally
{