| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548 |
- //------------------------------------------------------------------------------
- // <copyright file="DbDataAdapter.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">Microsoft</owner>
- // <owner current="true" primary="false">Microsoft</owner>
- //------------------------------------------------------------------------------
- namespace System.Data.Common {
- using System;
- using System.ComponentModel;
- using System.Collections;
- using System.Collections.Generic;
- using System.Data;
- using System.Data.ProviderBase;
- using System.Diagnostics;
- using System.Reflection;
- using System.Threading;
- public abstract class DbDataAdapter : DataAdapter, IDbDataAdapter, ICloneable { // V1.0.3300, MDAC 69629
- public const string DefaultSourceTableName = "Table"; // V1.0.3300
- internal static readonly object ParameterValueNonNullValue = 0;
- internal static readonly object ParameterValueNullValue = 1;
- private IDbCommand _deleteCommand, _insertCommand, _selectCommand, _updateCommand;
- private CommandBehavior _fillCommandBehavior;
- private struct BatchCommandInfo {
- internal int CommandIdentifier; // whatever AddToBatch returns, so we can reference the command later in GetBatchedParameter
- internal int ParameterCount; // number of parameters on the command, so we know how many to loop over when processing output parameters
- internal DataRow Row; // the row that the command is intended to update
- internal StatementType StatementType; // the statement type of the command, needed for accept changes
- internal UpdateRowSource UpdatedRowSource; // the UpdatedRowSource value from the command, to know whether we need to look for output parameters or not
- internal int? RecordsAffected;
- internal Exception Errors;
- }
- protected DbDataAdapter() : base() { // V1.0.3300
- }
- protected DbDataAdapter(DbDataAdapter adapter) : base(adapter) { // V1.0.5000
- CloneFrom(adapter);
- }
- private IDbDataAdapter _IDbDataAdapter {
- get {
- return (IDbDataAdapter)this;
- }
- }
- [
- Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
- ]
- public DbCommand DeleteCommand { // V1.2.3300
- get {
- return (DbCommand)(_IDbDataAdapter.DeleteCommand);
- }
- set {
- _IDbDataAdapter.DeleteCommand = value;
- }
- }
- IDbCommand IDbDataAdapter.DeleteCommand { // V1.2.3300
- get {
- return _deleteCommand;
- }
- set {
- _deleteCommand = value;
- }
- }
- protected internal CommandBehavior FillCommandBehavior { // V1.2.3300, MDAC 87511
- get {
- //Bid.Trace("<comm.DbDataAdapter.get_FillCommandBehavior|API> %d#\n", ObjectID);
- return (_fillCommandBehavior | CommandBehavior.SequentialAccess);
- }
- set {
- // setting |= SchemaOnly; /* similar to FillSchema (which also uses KeyInfo) */
- // setting |= KeyInfo; /* same as MissingSchemaAction.AddWithKey */
- // setting |= SequentialAccess; /* required and always present */
- // setting |= CloseConnection; /* close connection regardless of start condition */
- _fillCommandBehavior = (value | CommandBehavior.SequentialAccess);
- //Bid.Trace("<comm.DbDataAdapter.set_FillCommandBehavior|API> %d#, %d{ds.CommandBehavior}\n", (int)value);
- }
- }
- [
- Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
- ]
- public DbCommand InsertCommand { // V1.2.3300
- get {
- return (DbCommand)(_IDbDataAdapter.InsertCommand);
- }
- set {
- _IDbDataAdapter.InsertCommand = value;
- }
- }
- IDbCommand IDbDataAdapter.InsertCommand { // V1.2.3300
- get {
- return _insertCommand;
- }
- set {
- _insertCommand = value;
- }
- }
- [
- Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
- ]
- public DbCommand SelectCommand { // V1.2.3300
- get {
- return (DbCommand)(_IDbDataAdapter.SelectCommand);
- }
- set {
- _IDbDataAdapter.SelectCommand = value;
- }
- }
- IDbCommand IDbDataAdapter.SelectCommand { // V1.2.3300
- get {
- return _selectCommand;
- }
- set {
- _selectCommand = value;
- }
- }
- [
- DefaultValue(1),
- ResCategoryAttribute(Res.DataCategory_Update),
- ResDescriptionAttribute(Res.DbDataAdapter_UpdateBatchSize),
- ]
- virtual public int UpdateBatchSize {
- get {
- return 1;
- }
- set {
- if (1 != value) {
- throw ADP.NotSupported();
- }
- }
- }
- [
- Browsable(false),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
- ]
- public DbCommand UpdateCommand { // V1.2.3300
- get {
- return (DbCommand)(_IDbDataAdapter.UpdateCommand);
- }
- set {
- _IDbDataAdapter.UpdateCommand = value;
- }
- }
- IDbCommand IDbDataAdapter.UpdateCommand { // V1.2.3300
- get {
- return _updateCommand;
- }
- set {
- _updateCommand = value;
- }
- }
- private System.Data.MissingMappingAction UpdateMappingAction {
- get {
- if (System.Data.MissingMappingAction.Passthrough == MissingMappingAction) {
- return System.Data.MissingMappingAction.Passthrough;
- }
- return System.Data.MissingMappingAction.Error;
- }
- }
- private System.Data.MissingSchemaAction UpdateSchemaAction {
- get {
- System.Data.MissingSchemaAction action = MissingSchemaAction;
- if ((System.Data.MissingSchemaAction.Add == action) || (System.Data.MissingSchemaAction.AddWithKey == action)) {
- return System.Data.MissingSchemaAction.Ignore;
- }
- return System.Data.MissingSchemaAction.Error;
- }
- }
- protected virtual int AddToBatch(IDbCommand command) {
- // Called to add a single command to the batch of commands that need
- // to be executed as a batch, when batch updates are requested. It
- // must return an identifier that can be used to identify the command
- // to GetBatchedParameter later.
- throw ADP.NotSupported();
- }
- virtual protected void ClearBatch() {
- // Called when batch updates are requested to clear out the contents
- // of the batch, whether or not it's been executed.
- throw ADP.NotSupported();
- }
- object ICloneable.Clone() { // V1.0.3300, MDAC 69629
- #pragma warning disable 618 // ignore obsolete warning about CloneInternals
- DbDataAdapter clone = (DbDataAdapter)CloneInternals();
- #pragma warning restore 618
- clone.CloneFrom(this);
- return clone;
- }
- private void CloneFrom(DbDataAdapter from) {
- IDbDataAdapter pfrom = from._IDbDataAdapter;
- _IDbDataAdapter.SelectCommand = CloneCommand(pfrom.SelectCommand);
- _IDbDataAdapter.InsertCommand = CloneCommand(pfrom.InsertCommand);
- _IDbDataAdapter.UpdateCommand = CloneCommand(pfrom.UpdateCommand);
- _IDbDataAdapter.DeleteCommand = CloneCommand(pfrom.DeleteCommand);
- }
- private IDbCommand CloneCommand(IDbCommand command) {
- return (IDbCommand) ((command is ICloneable) ? ((ICloneable) command).Clone() : null);
- }
- virtual protected RowUpdatedEventArgs CreateRowUpdatedEvent(DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping) { // V1.0.3300
- return new RowUpdatedEventArgs(dataRow, command, statementType, tableMapping);
- }
- virtual protected RowUpdatingEventArgs CreateRowUpdatingEvent(DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping) { // V1.0.3300
- return new RowUpdatingEventArgs(dataRow, command, statementType, tableMapping);
- }
- override protected void Dispose(bool disposing) { // V1.0.3300, MDAC 69629
- if (disposing) { // release mananged objects
- IDbDataAdapter pthis = (IDbDataAdapter) this; // must cast to interface to obtain correct value
- pthis.SelectCommand = null;
- pthis.InsertCommand = null;
- pthis.UpdateCommand = null;
- pthis.DeleteCommand = null;
- }
- // release unmanaged objects
- base.Dispose(disposing); // notify base classes
- }
- protected virtual int ExecuteBatch() {
- // Called to execute the batched update command, returns the number
- // of rows affected, just as ExecuteNonQuery would.
- throw ADP.NotSupported();
- }
- public DataTable FillSchema(DataTable dataTable, SchemaType schemaType) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.FillSchema|API> %d#, dataTable, schemaType=%d{ds.SchemaType}\n", ObjectID, (int)schemaType);
- try {
- IDbCommand selectCmd = _IDbDataAdapter.SelectCommand;
- CommandBehavior cmdBehavior = FillCommandBehavior;
- return FillSchema(dataTable, schemaType, selectCmd, cmdBehavior); // MDAC 67666
- }
- finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- override public DataTable[] FillSchema(DataSet dataSet, SchemaType schemaType) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.FillSchema|API> %d#, dataSet, schemaType=%d{ds.SchemaType}\n", ObjectID, (int)schemaType);
- try {
- IDbCommand command = _IDbDataAdapter.SelectCommand;
- if (DesignMode && ((null == command) || (null == command.Connection) || ADP.IsEmpty(command.CommandText))) {
- return new DataTable[0]; // design-time support
- }
- CommandBehavior cmdBehavior = FillCommandBehavior;
- return FillSchema(dataSet, schemaType, command, DbDataAdapter.DefaultSourceTableName, cmdBehavior);
- }
- finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- public DataTable[] FillSchema(DataSet dataSet, SchemaType schemaType, string srcTable) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.FillSchema|API> %d#, dataSet, schemaType=%d{ds.SchemaType}, srcTable=%ls%\n", ObjectID, (int)schemaType, srcTable);
- try {
- IDbCommand selectCmd = _IDbDataAdapter.SelectCommand;
- CommandBehavior cmdBehavior = FillCommandBehavior;
- return FillSchema(dataSet, schemaType, selectCmd, srcTable, cmdBehavior);
- }
- finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- virtual protected DataTable[] FillSchema(DataSet dataSet, SchemaType schemaType, IDbCommand command, string srcTable, CommandBehavior behavior) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.FillSchema|API> %d#, dataSet, schemaType, command, srcTable, behavior=%d{ds.CommandBehavior}\n", ObjectID, (int)behavior);
- try {
- if (null == dataSet) {
- throw ADP.ArgumentNull("dataSet");
- }
- if ((SchemaType.Source != schemaType) && (SchemaType.Mapped != schemaType)) {
- throw ADP.InvalidSchemaType(schemaType);
- }
- if (ADP.IsEmpty(srcTable)) {
- throw ADP.FillSchemaRequiresSourceTableName("srcTable");
- }
- if (null == command) {
- throw ADP.MissingSelectCommand(ADP.FillSchema);
- }
- return (DataTable[]) FillSchemaInternal(dataSet, null, schemaType, command, srcTable, behavior);
- } finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- virtual protected DataTable FillSchema(DataTable dataTable, SchemaType schemaType, IDbCommand command, CommandBehavior behavior) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.FillSchema|API> %d#, dataTable, schemaType, command, behavior=%d{ds.CommandBehavior}\n", ObjectID, (int)behavior);
- try {
- if (null == dataTable) {
- throw ADP.ArgumentNull("dataTable");
- }
- if ((SchemaType.Source != schemaType) && (SchemaType.Mapped != schemaType)) {
- throw ADP.InvalidSchemaType(schemaType);
- }
- if (null == command) {
- throw ADP.MissingSelectCommand(ADP.FillSchema);
- }
- string srcTableName = dataTable.TableName;
- int index = IndexOfDataSetTable(srcTableName);
- if (-1 != index) {
- srcTableName = TableMappings[index].SourceTable;
- }
- return (DataTable) FillSchemaInternal(null, dataTable, schemaType, command, srcTableName, behavior | CommandBehavior.SingleResult);
- } finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- private object FillSchemaInternal(DataSet dataset, DataTable datatable, SchemaType schemaType, IDbCommand command, string srcTable, CommandBehavior behavior) {
- object dataTables = null;
- bool restoreNullConnection = (null == command.Connection);
- try {
- IDbConnection activeConnection = DbDataAdapter.GetConnection3(this, command, ADP.FillSchema);
- ConnectionState originalState = ConnectionState.Open;
- try {
- QuietOpen(activeConnection, out originalState);
- using(IDataReader dataReader = command.ExecuteReader(behavior | CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo)) {
- if (null != datatable) { // delegate to next set of protected FillSchema methods
- dataTables = FillSchema(datatable, schemaType, dataReader);
- }
- else {
- dataTables = FillSchema(dataset, schemaType, srcTable, dataReader);
- }
- }
- }
- finally {
- QuietClose(activeConnection, originalState);
- }
- }
- finally {
- if (restoreNullConnection) {
- command.Transaction = null;
- command.Connection = null;
- }
- }
- return dataTables;
- }
- override public int Fill(DataSet dataSet) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.Fill|API> %d#, dataSet\n", ObjectID);
- try {
- // delegate to Fill4
- IDbCommand selectCmd = _IDbDataAdapter.SelectCommand;
- CommandBehavior cmdBehavior = FillCommandBehavior;
- return Fill(dataSet, 0, 0, DbDataAdapter.DefaultSourceTableName, selectCmd, cmdBehavior);
- }
- finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- public int Fill(DataSet dataSet, string srcTable) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.Fill|API> %d#, dataSet, srcTable='%ls'\n", ObjectID, srcTable);
- try {
- // delegate to Fill4
- IDbCommand selectCmd = _IDbDataAdapter.SelectCommand;
- CommandBehavior cmdBehavior = FillCommandBehavior;
- return Fill(dataSet, 0, 0, srcTable, selectCmd, cmdBehavior);
- }
- finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- public int Fill(DataSet dataSet, int startRecord, int maxRecords, string srcTable) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.Fill|API> %d#, dataSet, startRecord=%d, maxRecords=%d, srcTable='%ls'\n", ObjectID, startRecord, maxRecords, srcTable);
- try {
- // delegate to Fill4
- IDbCommand selectCmd = _IDbDataAdapter.SelectCommand;
- CommandBehavior cmdBehavior = FillCommandBehavior;
- return Fill(dataSet, startRecord, maxRecords, srcTable, selectCmd, cmdBehavior);
- }
- finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- virtual protected int Fill(DataSet dataSet, int startRecord, int maxRecords, string srcTable, IDbCommand command, CommandBehavior behavior) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.Fill|API> %d#, dataSet, startRecord, maxRecords, srcTable, command, behavior=%d{ds.CommandBehavior}\n", ObjectID, (int)behavior);
- try {
- if (null == dataSet) {
- throw ADP.FillRequires("dataSet");
- }
- if (startRecord < 0) {
- throw ADP.InvalidStartRecord("startRecord", startRecord);
- }
- if (maxRecords < 0) {
- throw ADP.InvalidMaxRecords("maxRecords", maxRecords);
- }
- if (ADP.IsEmpty(srcTable)) {
- throw ADP.FillRequiresSourceTableName("srcTable");
- }
- if (null == command) {
- throw ADP.MissingSelectCommand(ADP.Fill);
- }
- return FillInternal(dataSet, null, startRecord, maxRecords, srcTable, command, behavior);
- }finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- public int Fill(DataTable dataTable) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.Fill|API> %d#, dataTable\n", ObjectID);
- try {
- // delegate to Fill8
- DataTable[] dataTables = new DataTable[1] { dataTable};
- IDbCommand selectCmd = _IDbDataAdapter.SelectCommand;
- CommandBehavior cmdBehavior = FillCommandBehavior;
- return Fill(dataTables, 0, 0, selectCmd, cmdBehavior);
- }
- finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- public int Fill(int startRecord, int maxRecords, params DataTable[] dataTables) { // V1.2.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.Fill|API> %d#, startRecord=%d, maxRecords=%d, dataTable[]\n", ObjectID, startRecord, maxRecords);
- try {
- // delegate to Fill8
- IDbCommand selectCmd = _IDbDataAdapter.SelectCommand;
- CommandBehavior cmdBehavior = FillCommandBehavior;
- return Fill(dataTables, startRecord, maxRecords, selectCmd, cmdBehavior);
- }
- finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- virtual protected int Fill(DataTable dataTable, IDbCommand command, CommandBehavior behavior) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.Fill|API> dataTable, command, behavior=%d{ds.CommandBehavior}%d#\n", ObjectID, (int)behavior);
- try {
- // delegate to Fill8
- DataTable[] dataTables = new DataTable[1] { dataTable};
- return Fill(dataTables, 0, 0, command, behavior);
- }
- finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- virtual protected int Fill(DataTable[] dataTables, int startRecord, int maxRecords, IDbCommand command, CommandBehavior behavior) { // V1.2.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.Fill|API> %d#, dataTables[], startRecord, maxRecords, command, behavior=%d{ds.CommandBehavior}\n", ObjectID, (int)behavior);
- try {
- if ((null == dataTables) || (0 == dataTables.Length) || (null == dataTables[0])) {
- throw ADP.FillRequires("dataTable");
- }
- if (startRecord < 0) {
- throw ADP.InvalidStartRecord("startRecord", startRecord);
- }
- if (maxRecords < 0) {
- throw ADP.InvalidMaxRecords("maxRecords", maxRecords);
- }
- if ((1 < dataTables.Length) && ((0 != startRecord) || (0 != maxRecords))) {
- throw ADP.OnlyOneTableForStartRecordOrMaxRecords();
- }
- if (null == command) {
- throw ADP.MissingSelectCommand(ADP.Fill);
- }
- if (1 == dataTables.Length) {
- behavior |= CommandBehavior.SingleResult;
- }
- return FillInternal(null, dataTables, startRecord, maxRecords, null, command, behavior);
- }
- finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- private int FillInternal(DataSet dataset, DataTable[] datatables, int startRecord, int maxRecords, string srcTable, IDbCommand command, CommandBehavior behavior) {
- int rowsAddedToDataSet = 0;
- bool restoreNullConnection = (null == command.Connection);
- try {
- IDbConnection activeConnection = DbDataAdapter.GetConnection3(this, command, ADP.Fill);
- ConnectionState originalState = ConnectionState.Open;
- // the default is MissingSchemaAction.Add, the user must explicitly
- // set MisingSchemaAction.AddWithKey to get key information back in the dataset
- if (Data.MissingSchemaAction.AddWithKey == MissingSchemaAction) {
- behavior |= CommandBehavior.KeyInfo;
- }
- try {
- QuietOpen(activeConnection, out originalState);
- behavior |= CommandBehavior.SequentialAccess;
- IDataReader dataReader = null;
- try {
- dataReader = command.ExecuteReader(behavior);
- if (null != datatables) { // delegate to next set of protected Fill methods
- rowsAddedToDataSet = Fill(datatables, dataReader, startRecord, maxRecords);
- }
- else {
- rowsAddedToDataSet = Fill(dataset, srcTable, dataReader, startRecord, maxRecords);
- }
- }
- finally {
- if (null != dataReader) {
- dataReader.Dispose();
- }
- }
- }
- finally {
- QuietClose(activeConnection, originalState);
- }
- }
- finally {
- if (restoreNullConnection) {
- command.Transaction = null;
- command.Connection = null;
- }
- }
- return rowsAddedToDataSet;
- }
- virtual protected IDataParameter GetBatchedParameter(int commandIdentifier, int parameterIndex) {
- // Called to retrieve a parameter from a specific bached command, the
- // first argument is the value that was returned by AddToBatch when it
- // was called for the command.
- throw ADP.NotSupported();
- }
- virtual protected bool GetBatchedRecordsAffected(int commandIdentifier, out int recordsAffected, out Exception error) { // SQLBU 412467
- // Called to retrieve the records affected from a specific batched command,
- // first argument is the value that was returned by AddToBatch when it
- // was called for the command.
- // default implementation always returns 1, derived classes override for otherwise
- // otherwise DbConcurrencyException will only be thrown if sum of all records in batch is 0
- // return 0 to cause Update to throw DbConcurrencyException
- recordsAffected = 1;
- error = null;
- return true;
- }
- [ EditorBrowsableAttribute(EditorBrowsableState.Advanced) ] // MDAC 69508
- override public IDataParameter[] GetFillParameters() { // V1.0.3300
- IDataParameter[] value = null;
- IDbCommand select = _IDbDataAdapter.SelectCommand;
- if (null != select) {
- IDataParameterCollection parameters = select.Parameters;
- if (null != parameters) {
- value = new IDataParameter[parameters.Count];
- parameters.CopyTo(value, 0);
- }
- }
- if (null == value) {
- value = new IDataParameter[0];
- }
- return value;
- }
- internal DataTableMapping GetTableMapping(DataTable dataTable) {
- DataTableMapping tableMapping = null;
- int index = IndexOfDataSetTable(dataTable.TableName);
- if (-1 != index) {
- tableMapping = TableMappings[index];
- }
- if (null == tableMapping) {
- if (System.Data.MissingMappingAction.Error == MissingMappingAction) {
- throw ADP.MissingTableMappingDestination(dataTable.TableName);
- }
- tableMapping = new DataTableMapping(dataTable.TableName, dataTable.TableName);
- }
- return tableMapping;
- }
- virtual protected void InitializeBatching() {
- // Called when batch updates are requested to prepare for processing
- // of a batch of commands.
- throw ADP.NotSupported();
- }
- virtual protected void OnRowUpdated(RowUpdatedEventArgs value) { // V1.0.3300
- }
- virtual protected void OnRowUpdating(RowUpdatingEventArgs value) { // V1.0.3300
- }
- private void ParameterInput(IDataParameterCollection parameters, StatementType typeIndex, DataRow row, DataTableMapping mappings) {
- Data.MissingMappingAction missingMapping = UpdateMappingAction;
- Data.MissingSchemaAction missingSchema = UpdateSchemaAction;
- foreach(IDataParameter parameter in parameters) {
- if ((null != parameter) && (0 != (ParameterDirection.Input & parameter.Direction))) {
- string columnName = parameter.SourceColumn;
- if (!ADP.IsEmpty(columnName)) {
- DataColumn dataColumn = mappings.GetDataColumn(columnName, null, row.Table, missingMapping, missingSchema);
- if (null != dataColumn) {
- DataRowVersion version = DbDataAdapter.GetParameterSourceVersion(typeIndex, parameter);
- parameter.Value = row[dataColumn, version];
- }
- else {
- parameter.Value = null;
- }
- DbParameter dbparameter = (parameter as DbParameter);
- if ((null != dbparameter) && dbparameter.SourceColumnNullMapping) {
- Debug.Assert(DbType.Int32 == parameter.DbType, "unexpected DbType");
- parameter.Value = ADP.IsNull(parameter.Value) ? ParameterValueNullValue : ParameterValueNonNullValue;
- }
- }
- }
- }
- }
- private void ParameterOutput(IDataParameter parameter, DataRow row, DataTableMapping mappings, MissingMappingAction missingMapping, MissingSchemaAction missingSchema) {
- if (0 != (ParameterDirection.Output & parameter.Direction)) {
- object value = parameter.Value;
- if (null != value) {
- // null means default, meaning we leave the current DataRow value alone
- string columnName = parameter.SourceColumn;
- if (!ADP.IsEmpty(columnName)) {
- DataColumn dataColumn = mappings.GetDataColumn(columnName, null, row.Table, missingMapping, missingSchema);
- if (null != dataColumn) {
- if (dataColumn.ReadOnly) {
- try {
- dataColumn.ReadOnly = false;
- row[dataColumn] = value;
- }
- finally {
- dataColumn.ReadOnly = true;
- }
- }
- else {
- row[dataColumn] = value;
- }
- }
- }
- }
- }
- }
- private void ParameterOutput(IDataParameterCollection parameters, DataRow row, DataTableMapping mappings) {
- Data.MissingMappingAction missingMapping = UpdateMappingAction;
- Data.MissingSchemaAction missingSchema = UpdateSchemaAction;
- foreach(IDataParameter parameter in parameters) {
- if (null != parameter) {
- ParameterOutput(parameter, row, mappings, missingMapping, missingSchema);
- }
- }
- }
- virtual protected void TerminateBatching() {
- // Called when batch updates are requested to cleanup after a batch
- // update has been completed.
- throw ADP.NotSupported();
- }
- override public int Update(DataSet dataSet) { // V1.0.3300
- //if (!TableMappings.Contains(DbDataAdapter.DefaultSourceTableName)) { // MDAC 59268
- // throw ADP.UpdateRequiresSourceTable(DbDataAdapter.DefaultSourceTableName);
- //}
- return Update(dataSet, DbDataAdapter.DefaultSourceTableName);
- }
- public int Update(DataRow[] dataRows) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.Update|API> %d#, dataRows[]\n", ObjectID);
- try {
- int rowsAffected = 0;
- if (null == dataRows) {
- throw ADP.ArgumentNull("dataRows");
- }
- else if (0 != dataRows.Length) {
- DataTable dataTable = null;
- for (int i = 0; i < dataRows.Length; ++i) {
- if ((null != dataRows[i]) && (dataTable != dataRows[i].Table)) {
- if (null != dataTable) {
- throw ADP.UpdateMismatchRowTable(i);
- }
- dataTable = dataRows[i].Table;
- }
- }
- if (null != dataTable) {
- DataTableMapping tableMapping = GetTableMapping(dataTable);
- rowsAffected = Update(dataRows, tableMapping);
- }
- }
- return rowsAffected;
- }
- finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- public int Update(DataTable dataTable) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.Update|API> %d#, dataTable", ObjectID);
- try {
- if (null == dataTable) {
- throw ADP.UpdateRequiresDataTable("dataTable");
- }
- DataTableMapping tableMapping = null;
- int index = IndexOfDataSetTable(dataTable.TableName);
- if (-1 != index) {
- tableMapping = TableMappings[index];
- }
- if (null == tableMapping) {
- if (System.Data.MissingMappingAction.Error == MissingMappingAction) {
- throw ADP.MissingTableMappingDestination(dataTable.TableName);
- }
- tableMapping = new DataTableMapping(DbDataAdapter.DefaultSourceTableName, dataTable.TableName);
- }
- return UpdateFromDataTable(dataTable, tableMapping);
- } finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- public int Update(DataSet dataSet, string srcTable) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.Update|API> %d#, dataSet, srcTable='%ls'", ObjectID, srcTable);
- try {
- if (null == dataSet) {
- throw ADP.UpdateRequiresNonNullDataSet("dataSet");
- }
- if (ADP.IsEmpty(srcTable)) {
- throw ADP.UpdateRequiresSourceTableName("srcTable");
- }
- #if DEBUG
- //ADP.TraceDataSet("Update <" + srcTable + ">", dataSet);
- #endif
- int rowsAffected = 0;
- System.Data.MissingMappingAction missingMapping = UpdateMappingAction;
- DataTableMapping tableMapping = GetTableMappingBySchemaAction(srcTable, srcTable, UpdateMappingAction);
- Debug.Assert(null != tableMapping, "null TableMapping when MissingMappingAction.Error");
- // the ad-hoc scenario of no dataTable just returns
- // ad-hoc scenario is defined as MissingSchemaAction.Add or MissingSchemaAction.Ignore
- System.Data.MissingSchemaAction schemaAction = UpdateSchemaAction;
- DataTable dataTable = tableMapping.GetDataTableBySchemaAction(dataSet, schemaAction);
- if (null != dataTable) {
- rowsAffected = UpdateFromDataTable(dataTable, tableMapping);
- }
- else if (!HasTableMappings() || (-1 == TableMappings.IndexOf(tableMapping))) {
- //throw error since the user didn't explicitly map this tableName to Ignore.
- throw ADP.UpdateRequiresSourceTable(srcTable); // MDAC 72681
- }
- return rowsAffected;
- }
- finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- virtual protected int Update(DataRow[] dataRows, DataTableMapping tableMapping) { // V1.0.3300
- IntPtr hscp;
- Bid.ScopeEnter(out hscp, "<comm.DbDataAdapter.Update|API> %d#, dataRows[], tableMapping", ObjectID);
- try {
- Debug.Assert((null != dataRows) && (0 < dataRows.Length), "Update: bad dataRows");
- Debug.Assert(null != tableMapping, "Update: bad DataTableMapping");
- // If records were affected, increment row count by one - that is number of rows affected in dataset.
- int cumulativeDataRowsAffected = 0;
- IDbConnection[] connections = new IDbConnection[5]; // one for each statementtype
- ConnectionState[] connectionStates = new ConnectionState[5]; // closed by default (== 0)
- bool useSelectConnectionState = false; // MDAC 58710
- IDbCommand tmpcmd = _IDbDataAdapter.SelectCommand;
- if (null != tmpcmd) {
- connections[0] = tmpcmd.Connection;
- if (null != connections[0]) {
- connectionStates[0] = connections[0].State;
- useSelectConnectionState = true;
- }
- }
- int maxBatchCommands = Math.Min(UpdateBatchSize, dataRows.Length);
- if (maxBatchCommands < 1) { // batch size of zero indicates one batch, no matter how large...
- maxBatchCommands = dataRows.Length;
- }
- BatchCommandInfo[] batchCommands = new BatchCommandInfo[maxBatchCommands];
- DataRow[] rowBatch = new DataRow[maxBatchCommands];
- int commandCount = 0;
- // the outer try/finally is for closing any connections we may have opened
- try {
- try {
- if (1 != maxBatchCommands) {
- InitializeBatching();
- }
- StatementType statementType = StatementType.Select;
- IDbCommand dataCommand = null;
- // for each row which is either insert, update, or delete
- foreach(DataRow dataRow in dataRows) {
- if (null == dataRow) {
- continue; // foreach DataRow
- }
- bool isCommandFromRowUpdating = false;
- // obtain the appropriate command
- switch (dataRow.RowState) {
- case DataRowState.Detached:
- case DataRowState.Unchanged:
- continue; // foreach DataRow
- case DataRowState.Added:
- statementType = StatementType.Insert;
- dataCommand = _IDbDataAdapter.InsertCommand;
- break;
- case DataRowState.Deleted:
- statementType = StatementType.Delete;
- dataCommand = _IDbDataAdapter.DeleteCommand;
- break;
- case DataRowState.Modified:
- statementType = StatementType.Update;
- dataCommand = _IDbDataAdapter.UpdateCommand;
- break;
- default:
- Debug.Assert(false, "InvalidDataRowState");
- throw ADP.InvalidDataRowState(dataRow.RowState); // out of Update without completing batch
- }
- // setup the event to be raised
- RowUpdatingEventArgs rowUpdatingEvent = CreateRowUpdatingEvent(dataRow, dataCommand, statementType, tableMapping);
- // this try/catch for any exceptions during the parameter initialization
- try {
- dataRow.RowError = null; // MDAC 67185
- if (null != dataCommand) {
- // prepare the parameters for the user who then can modify them during OnRowUpdating
- ParameterInput(dataCommand.Parameters, statementType, dataRow, tableMapping);
- }
- }
- catch (Exception e) {
- //
- if (!ADP.IsCatchableExceptionType(e)) {
- throw;
- }
- ADP.TraceExceptionForCapture(e);
- rowUpdatingEvent.Errors = e;
- rowUpdatingEvent.Status = UpdateStatus.ErrorsOccurred;
- }
- OnRowUpdating(rowUpdatingEvent); // user may throw out of Update without completing batch
- IDbCommand tmpCommand = rowUpdatingEvent.Command;
- isCommandFromRowUpdating = (dataCommand != tmpCommand);
- dataCommand = tmpCommand;
- tmpCommand = null;
- // handle the status from RowUpdating event
- UpdateStatus rowUpdatingStatus = rowUpdatingEvent.Status;
- if (UpdateStatus.Continue != rowUpdatingStatus) {
- if (UpdateStatus.ErrorsOccurred == rowUpdatingStatus) {
- UpdatingRowStatusErrors(rowUpdatingEvent, dataRow);
- continue; // foreach DataRow
- }
- else if (UpdateStatus.SkipCurrentRow == rowUpdatingStatus) {
- if (DataRowState.Unchanged == dataRow.RowState) { // MDAC 66286
- cumulativeDataRowsAffected++;
- }
- continue; // foreach DataRow
- }
- else if (UpdateStatus.SkipAllRemainingRows == rowUpdatingStatus) {
- if (DataRowState.Unchanged == dataRow.RowState) { // MDAC 66286
- cumulativeDataRowsAffected++;
- }
- break; // execute existing batch and return
- }
- else {
- throw ADP.InvalidUpdateStatus(rowUpdatingStatus); // out of Update
- }
- }
- // else onward to Append/ExecuteNonQuery/ExecuteReader
- rowUpdatingEvent = null;
- RowUpdatedEventArgs rowUpdatedEvent = null;
- if (1 == maxBatchCommands) {
- if (null != dataCommand) {
- batchCommands[0].CommandIdentifier = 0;
- batchCommands[0].ParameterCount = dataCommand.Parameters.Count;
- batchCommands[0].StatementType = statementType;
- batchCommands[0].UpdatedRowSource = dataCommand.UpdatedRowSource;
- }
- batchCommands[0].Row = dataRow;
- rowBatch[0] = dataRow; // not doing a batch update, just simplifying code...
- commandCount = 1;
- }
- else {
- Exception errors = null;
- try {
- if (null != dataCommand) {
- if (0 == (UpdateRowSource.FirstReturnedRecord & dataCommand.UpdatedRowSource)) {
- // append the command to the commandset. If an exception
- // occurs, then the user must append and continue
- batchCommands[commandCount].CommandIdentifier = AddToBatch(dataCommand);
- batchCommands[commandCount].ParameterCount = dataCommand.Parameters.Count;
- batchCommands[commandCount].Row = dataRow;
- batchCommands[commandCount].StatementType = statementType;
- batchCommands[commandCount].UpdatedRowSource = dataCommand.UpdatedRowSource;
- rowBatch[commandCount] = dataRow;
- commandCount++;
- if (commandCount < maxBatchCommands) {
- continue; // foreach DataRow
- }
- // else onward execute the batch
- }
- else {
- // do not allow the expectation that returned results will be used
- errors = ADP.ResultsNotAllowedDuringBatch();
- }
- }
- else {
- // null Command will force RowUpdatedEvent with ErrorsOccured without completing batch
- errors = ADP.UpdateRequiresCommand(statementType, isCommandFromRowUpdating);
- }
- }
- catch (Exception e) { // try/catch for RowUpdatedEventArgs
- //
- if (!ADP.IsCatchableExceptionType(e)) {
- throw;
- }
- ADP.TraceExceptionForCapture(e);
- errors = e;
- }
- if (null != errors) {
- rowUpdatedEvent = CreateRowUpdatedEvent(dataRow, dataCommand, StatementType.Batch, tableMapping);
- rowUpdatedEvent.Errors = errors;
- rowUpdatedEvent.Status = UpdateStatus.ErrorsOccurred;
- OnRowUpdated(rowUpdatedEvent); // user may throw out of Update
- if (errors != rowUpdatedEvent.Errors) { // user set the error msg and we will use it
- for(int i = 0; i < batchCommands.Length; ++i) {
- batchCommands[i].Errors = null;
- }
- }
- cumulativeDataRowsAffected += UpdatedRowStatus(rowUpdatedEvent, batchCommands, commandCount);
- if (UpdateStatus.SkipAllRemainingRows == rowUpdatedEvent.Status) {
- break;
- }
- continue; // foreach datarow
- }
- }
- rowUpdatedEvent = CreateRowUpdatedEvent(dataRow, dataCommand, statementType, tableMapping);
- // this try/catch for any exceptions during the execution, population, output parameters
- try {
- if (1 != maxBatchCommands) {
- IDbConnection connection = DbDataAdapter.GetConnection1(this);
- ConnectionState state = UpdateConnectionOpen(connection, StatementType.Batch, connections, connectionStates, useSelectConnectionState);
- rowUpdatedEvent.AdapterInit(rowBatch);
- if (ConnectionState.Open == state) {
- UpdateBatchExecute(batchCommands, commandCount, rowUpdatedEvent);
- }
- else {
- // null Connection will force RowUpdatedEvent with ErrorsOccured without completing batch
- rowUpdatedEvent.Errors = ADP.UpdateOpenConnectionRequired(StatementType.Batch, false, state);
- rowUpdatedEvent.Status = UpdateStatus.ErrorsOccurred;
- }
- }
- else if (null != dataCommand) {
- IDbConnection connection = DbDataAdapter.GetConnection4(this, dataCommand, statementType, isCommandFromRowUpdating);
- ConnectionState state = UpdateConnectionOpen(connection, statementType, connections, connectionStates, useSelectConnectionState);
- if (ConnectionState.Open == state) {
- UpdateRowExecute(rowUpdatedEvent, dataCommand, statementType);
- batchCommands[0].RecordsAffected = rowUpdatedEvent.RecordsAffected;
- batchCommands[0].Errors = null;
- }
- else {
- // null Connection will force RowUpdatedEvent with ErrorsOccured without completing batch
- rowUpdatedEvent.Errors = ADP.UpdateOpenConnectionRequired(statementType, isCommandFromRowUpdating, state);
- rowUpdatedEvent.Status = UpdateStatus.ErrorsOccurred;
- }
- }
- else {
- // null Command will force RowUpdatedEvent with ErrorsOccured without completing batch
- rowUpdatedEvent.Errors = ADP.UpdateRequiresCommand(statementType, isCommandFromRowUpdating);
- rowUpdatedEvent.Status = UpdateStatus.ErrorsOccurred;
- }
- }
- catch (Exception e) { // try/catch for RowUpdatedEventArgs
- //
- if (!ADP.IsCatchableExceptionType(e)) {
- throw;
- }
- ADP.TraceExceptionForCapture(e);
- rowUpdatedEvent.Errors = e;
- rowUpdatedEvent.Status = UpdateStatus.ErrorsOccurred;
- }
- bool clearBatchOnSkipAll = (UpdateStatus.ErrorsOccurred == rowUpdatedEvent.Status);
- {
- Exception errors = rowUpdatedEvent.Errors;
- OnRowUpdated(rowUpdatedEvent); // user may throw out of Update
- // NOTE: the contents of rowBatch are now tainted...
- if (errors != rowUpdatedEvent.Errors) { // user set the error msg and we will use it
- for(int i = 0; i < batchCommands.Length; ++i) {
- batchCommands[i].Errors = null;
- }
- }
- }
- cumulativeDataRowsAffected += UpdatedRowStatus(rowUpdatedEvent, batchCommands, commandCount);
- if (UpdateStatus.SkipAllRemainingRows == rowUpdatedEvent.Status) {
- if (clearBatchOnSkipAll && 1 != maxBatchCommands) {
- ClearBatch();
- commandCount = 0;
- }
- break; // from update
- }
- if (1 != maxBatchCommands) {
- ClearBatch();
- commandCount = 0;
- }
- for(int i = 0; i < batchCommands.Length; ++i) {
- batchCommands[i] = default(BatchCommandInfo);
- }
- commandCount = 0;
- } // foreach DataRow
- // must handle the last batch
- if (1 != maxBatchCommands && 0 < commandCount) {
- RowUpdatedEventArgs rowUpdatedEvent = CreateRowUpdatedEvent(null, dataCommand, statementType, tableMapping);
- try {
- IDbConnection connection = DbDataAdapter.GetConnection1(this);
- ConnectionState state = UpdateConnectionOpen(connection, StatementType.Batch, connections, connectionStates, useSelectConnectionState);
- DataRow[] finalRowBatch = rowBatch;
- if (commandCount < rowBatch.Length) {
- finalRowBatch = new DataRow[commandCount];
- Array.Copy(rowBatch, finalRowBatch, commandCount);
- }
- rowUpdatedEvent.AdapterInit(finalRowBatch);
- if (ConnectionState.Open == state) {
- UpdateBatchExecute(batchCommands, commandCount, rowUpdatedEvent);
- }
- else {
- // null Connection will force RowUpdatedEvent with ErrorsOccured without completing batch
- rowUpdatedEvent.Errors = ADP.UpdateOpenConnectionRequired(StatementType.Batch, false, state);
- rowUpdatedEvent.Status = UpdateStatus.ErrorsOccurred;
- }
- }
- catch (Exception e) { // try/catch for RowUpdatedEventArgs
- //
- if (!ADP.IsCatchableExceptionType(e)) {
- throw;
- }
- ADP.TraceExceptionForCapture(e);
- rowUpdatedEvent.Errors = e;
- rowUpdatedEvent.Status = UpdateStatus.ErrorsOccurred;
- }
- Exception errors = rowUpdatedEvent.Errors;
- OnRowUpdated(rowUpdatedEvent); // user may throw out of Update
- // NOTE: the contents of rowBatch are now tainted...
- if (errors != rowUpdatedEvent.Errors) { // user set the error msg and we will use it
- for(int i = 0; i < batchCommands.Length; ++i) {
- batchCommands[i].Errors = null;
- }
- }
- cumulativeDataRowsAffected += UpdatedRowStatus(rowUpdatedEvent, batchCommands, commandCount);
- }
- }
- finally {
- if (1 != maxBatchCommands) {
- TerminateBatching();
- }
- }
- }
- finally { // try/finally for connection cleanup
- for(int i = 0; i < connections.Length; ++i) {
- QuietClose(connections[i], connectionStates[i]);
- }
- }
- return cumulativeDataRowsAffected;
- }
- finally {
- Bid.ScopeLeave(ref hscp);
- }
- }
- private void UpdateBatchExecute(BatchCommandInfo[] batchCommands, int commandCount, RowUpdatedEventArgs rowUpdatedEvent) {
- try {
- // the batch execution may succeed, partially succeed and throw an exception (or not), or totally fail
- int recordsAffected = ExecuteBatch();
- rowUpdatedEvent.AdapterInit(recordsAffected);
- }
- catch(DbException e) {
- // an exception was thrown be but some part of the batch may have been succesfull
- ADP.TraceExceptionForCapture(e);
- rowUpdatedEvent.Errors = e;
- rowUpdatedEvent.Status = UpdateStatus.ErrorsOccurred;
- }
- Data.MissingMappingAction missingMapping = UpdateMappingAction;
- Data.MissingSchemaAction missingSchema = UpdateSchemaAction;
- int checkRecordsAffected = 0;
- bool hasConcurrencyViolation = false;
- List<DataRow> rows = null;
- // walk through the batch to build the sum of recordsAffected
- // determine possible indivdual messages per datarow
- // determine possible concurrency violations per datarow
- // map output parameters to the datarow
- for(int bc = 0; bc < commandCount; ++bc) {
- BatchCommandInfo batchCommand = batchCommands[bc];
- StatementType statementType = batchCommand.StatementType;
- // default implementation always returns 1, derived classes must override
- // otherwise DbConcurrencyException will only be thrown if sum of all records in batch is 0
- int rowAffected;
- if (GetBatchedRecordsAffected(batchCommand.CommandIdentifier, out rowAffected, out batchCommands[bc].Errors)) {
- batchCommands[bc].RecordsAffected = rowAffected;
- }
- if ((null == batchCommands[bc].Errors) && batchCommands[bc].RecordsAffected.HasValue) {
- // determine possible concurrency violations per datarow
- if ((StatementType.Update == statementType) || (StatementType.Delete == statementType)) {
- checkRecordsAffected++;
- if (0 == rowAffected) {
- if (null == rows) {
- rows = new List<DataRow>();
- }
- batchCommands[bc].Errors = ADP.UpdateConcurrencyViolation(batchCommands[bc].StatementType, 0, 1, new DataRow[] { rowUpdatedEvent.Rows[bc] });
- hasConcurrencyViolation = true;
- rows.Add(rowUpdatedEvent.Rows[bc]);
- }
- }
- // map output parameters to the datarow
- if (((StatementType.Insert == statementType) || (StatementType.Update == statementType))
- && (0 != (UpdateRowSource.OutputParameters & batchCommand.UpdatedRowSource)) && (0 != rowAffected)) // MDAC 71174
- {
- if (StatementType.Insert == statementType) { // MDAC 64199
- // AcceptChanges for 'added' rows so backend generated keys that are returned
- // propagte into the datatable correctly.
- rowUpdatedEvent.Rows[bc].AcceptChanges();
- }
- for(int i = 0; i < batchCommand.ParameterCount; ++i) {
- IDataParameter parameter = GetBatchedParameter(batchCommand.CommandIdentifier, i);
- ParameterOutput(parameter, batchCommand.Row, rowUpdatedEvent.TableMapping, missingMapping, missingSchema);
- }
- }
- }
- }
- if (null == rowUpdatedEvent.Errors) {
- // Only error if RecordsAffect == 0, not -1. A value of -1 means no count was received from server,
- // do not error in that situation (means 'set nocount on' was executed on server).
- if (UpdateStatus.Continue == rowUpdatedEvent.Status) {
- if ((0 < checkRecordsAffected) && ((0 == rowUpdatedEvent.RecordsAffected) || hasConcurrencyViolation)) {
- // bug50526, an exception if no records affected and attempted an Update/Delete
- Debug.Assert(null == rowUpdatedEvent.Errors, "Continue - but contains an exception");
- DataRow[] rowsInError = (null != rows) ? rows.ToArray() : rowUpdatedEvent.Rows;
- rowUpdatedEvent.Errors = ADP.UpdateConcurrencyViolation(StatementType.Batch, commandCount - rowsInError.Length, commandCount, rowsInError); // MDAC 55735
- rowUpdatedEvent.Status = UpdateStatus.ErrorsOccurred;
- }
- }
- }
- }
- private ConnectionState UpdateConnectionOpen(IDbConnection connection, StatementType statementType, IDbConnection[] connections, ConnectionState[] connectionStates, bool useSelectConnectionState) {
- Debug.Assert(null != connection, "unexpected null connection");
- Debug.Assert(null != connection, "unexpected null connection");
- int index = (int)statementType;
- if (connection != connections[index]) {
- // if the user has changed the connection on the command object
- // and we had opened that connection, close that connection
- QuietClose(connections[index], connectionStates[index]);
- connections[index] = connection;
- connectionStates[index] = ConnectionState.Closed; // required, open may throw
- QuietOpen(connection, out connectionStates[index]);
- if (useSelectConnectionState && (connections[0] == connection)) {
- connectionStates[index] = connections[0].State;
- }
- }
- return connection.State;
- }
- private int UpdateFromDataTable(DataTable dataTable, DataTableMapping tableMapping) {
- int rowsAffected = 0;
- DataRow[] dataRows = ADP.SelectAdapterRows(dataTable, false);
- if ((null != dataRows) && (0 < dataRows.Length)) {
- rowsAffected = Update(dataRows, tableMapping);
- }
- return rowsAffected;
- }
- private void UpdateRowExecute(RowUpdatedEventArgs rowUpdatedEvent, IDbCommand dataCommand, StatementType cmdIndex) {
- Debug.Assert(null != rowUpdatedEvent, "null rowUpdatedEvent");
- Debug.Assert(null != dataCommand, "null dataCommand");
- Debug.Assert(rowUpdatedEvent.Command == dataCommand, "dataCommand differs from rowUpdatedEvent");
- bool insertAcceptChanges = true;
- UpdateRowSource updatedRowSource = dataCommand.UpdatedRowSource;
- if ((StatementType.Delete == cmdIndex) || (0 == (UpdateRowSource.FirstReturnedRecord & updatedRowSource))) {
- int recordsAffected = dataCommand.ExecuteNonQuery(); // MDAC 88441
- rowUpdatedEvent.AdapterInit(recordsAffected);
- }
- else if ((StatementType.Insert == cmdIndex) || (StatementType.Update == cmdIndex)) {
- // we only care about the first row of the first result
- using(IDataReader dataReader = dataCommand.ExecuteReader(CommandBehavior.SequentialAccess)) {
- DataReaderContainer readerHandler = DataReaderContainer.Create(dataReader, ReturnProviderSpecificTypes);
- try {
- bool getData = false;
- do {
- // advance to the first row returning result set
- // determined by actually having columns in the result set
- if (0 < readerHandler.FieldCount) {
- getData = true;
- break;
- }
- } while (dataReader.NextResult());
- if (getData && (0 != dataReader.RecordsAffected)) { // MDAC 71174
- SchemaMapping mapping = new SchemaMapping(this, null, rowUpdatedEvent.Row.Table, readerHandler, false, SchemaType.Mapped, rowUpdatedEvent.TableMapping.SourceTable, true, null, null);
- if ((null != mapping.DataTable) && (null != mapping.DataValues)) {
- if (dataReader.Read()) {
- if ((StatementType.Insert == cmdIndex) && insertAcceptChanges) { // MDAC 64199
- rowUpdatedEvent.Row.AcceptChanges();
- insertAcceptChanges = false;
- }
- mapping.ApplyToDataRow(rowUpdatedEvent.Row);
- }
- }
- }
- }
- finally {
- // using Close which can optimize its { while(dataReader.NextResult()); } loop
- dataReader.Close();
- // RecordsAffected is available after Close, but don't trust it after Dispose
- int recordsAffected = dataReader.RecordsAffected;
- rowUpdatedEvent.AdapterInit(recordsAffected);
- }
- }
- }
- else {
- // StatementType.Select, StatementType.Batch
- Debug.Assert(false, "unexpected StatementType");
- }
- // map the parameter results to the dataSet
- if (((StatementType.Insert == cmdIndex) || (StatementType.Update == cmdIndex))
- && (0 != (UpdateRowSource.OutputParameters & updatedRowSource)) && (0 != rowUpdatedEvent.RecordsAffected)) { // MDAC 71174
- if ((StatementType.Insert == cmdIndex) && insertAcceptChanges) { // MDAC 64199
- rowUpdatedEvent.Row.AcceptChanges();
- }
- ParameterOutput(dataCommand.Parameters, rowUpdatedEvent.Row, rowUpdatedEvent.TableMapping);
- }
- // Only error if RecordsAffect == 0, not -1. A value of -1 means no count was received from server,
- // do not error in that situation (means 'set nocount on' was executed on server).
- switch(rowUpdatedEvent.Status) {
- case UpdateStatus.Continue:
- switch(cmdIndex) {
- case StatementType.Update:
- case StatementType.Delete:
- if (0 == rowUpdatedEvent.RecordsAffected) {
- // bug50526, an exception if no records affected and attempted an Update/Delete
- Debug.Assert(null == rowUpdatedEvent.Errors, "Continue - but contains an exception");
- rowUpdatedEvent.Errors = ADP.UpdateConcurrencyViolation(cmdIndex, rowUpdatedEvent.RecordsAffected, 1, new DataRow[] { rowUpdatedEvent.Row }); // MDAC 55735
- rowUpdatedEvent.Status = UpdateStatus.ErrorsOccurred;
- }
- break;
- }
- break;
- }
- }
- private int UpdatedRowStatus(RowUpdatedEventArgs rowUpdatedEvent, BatchCommandInfo[] batchCommands, int commandCount) {
- Debug.Assert(null != rowUpdatedEvent, "null rowUpdatedEvent");
- int cumulativeDataRowsAffected = 0;
- switch (rowUpdatedEvent.Status) {
- case UpdateStatus.Continue:
- cumulativeDataRowsAffected = UpdatedRowStatusContinue(rowUpdatedEvent, batchCommands, commandCount);
- break; // return to foreach DataRow
- case UpdateStatus.ErrorsOccurred:
- cumulativeDataRowsAffected = UpdatedRowStatusErrors(rowUpdatedEvent, batchCommands, commandCount);
- break; // no datarow affected if ErrorsOccured
- case UpdateStatus.SkipCurrentRow:
- case UpdateStatus.SkipAllRemainingRows: // cancel the Update method
- cumulativeDataRowsAffected = UpdatedRowStatusSkip(batchCommands, commandCount);
- break; // foreach DataRow without accepting changes on this row (but user may haved accepted chagnes for us)
- default:
- throw ADP.InvalidUpdateStatus(rowUpdatedEvent.Status);
- } // switch RowUpdatedEventArgs.Status
- return cumulativeDataRowsAffected;
- }
- private int UpdatedRowStatusContinue(RowUpdatedEventArgs rowUpdatedEvent, BatchCommandInfo[] batchCommands, int commandCount) {
- Debug.Assert(null != batchCommands, "null batchCommands?");
- int cumulativeDataRowsAffected = 0;
- // 1. We delay accepting the changes until after we fire RowUpdatedEvent
- // so the user has a chance to call RejectChanges for any given reason
- // 2. If the DataSource return 0 records affected, its an indication that
- // the command didn't take so we don't want to automatically
- // AcceptChanges.
- // With 'set nocount on' the count will be -1, accept changes in that case too.
- // 3. Don't accept changes if no rows were affected, the user needs
- // to know that there is a concurrency violation
- // Only accept changes if the row is not already accepted, ie detached.
- bool acdu = AcceptChangesDuringUpdate;
- for (int i = 0; i < commandCount; i++) {
- DataRow row = batchCommands[i].Row;
- if ((null == batchCommands[i].Errors) && batchCommands[i].RecordsAffected.HasValue && (0 != batchCommands[i].RecordsAffected.Value)) {
- Debug.Assert(null != row, "null dataRow?");
- if (acdu) {
- if (0 != ((DataRowState.Added|DataRowState.Deleted|DataRowState.Modified)&row.RowState)) {
- row.AcceptChanges();
- }
- }
- cumulativeDataRowsAffected++;
- }
- }
- return cumulativeDataRowsAffected;
- }
- private int UpdatedRowStatusErrors(RowUpdatedEventArgs rowUpdatedEvent, BatchCommandInfo[] batchCommands, int commandCount) {
- Debug.Assert(null != batchCommands, "null batchCommands?");
- Exception errors = rowUpdatedEvent.Errors;
- if (null == errors) {
- // user changed status to ErrorsOccured without supplying an exception message
- errors = ADP.RowUpdatedErrors();
- rowUpdatedEvent.Errors = errors;
- }
- int affected = 0;
- bool done = false;
- string message = errors.Message;
- for (int i = 0; i < commandCount; i++) {
- DataRow row = batchCommands[i].Row;
- Debug.Assert(null != row, "null dataRow?");
- if (null != batchCommands[i].Errors) { // will exist if 0 == RecordsAffected
- string rowMsg = batchCommands[i].Errors.Message;
- if (String.IsNullOrEmpty(rowMsg)) {
- rowMsg = message;
- }
- row.RowError += rowMsg;
- done = true;
- }
- }
- if (!done) { // all rows are in 'error'
- for (int i = 0; i < commandCount; i++) {
- DataRow row = batchCommands[i].Row;
- // its possible a DBConcurrencyException exists and all rows have records affected
- // via not overriding GetBatchedRecordsAffected or user setting the exception
- row.RowError += message; // MDAC 65808
- }
- }
- else {
- affected = UpdatedRowStatusContinue(rowUpdatedEvent, batchCommands, commandCount);
- }
- if (!ContinueUpdateOnError) { // MDAC 66900
- throw errors; // out of Update
- }
- return affected; // return the count of successful rows within the batch failure
- }
- private int UpdatedRowStatusSkip(BatchCommandInfo[] batchCommands, int commandCount){
- Debug.Assert(null != batchCommands, "null batchCommands?");
- int cumulativeDataRowsAffected = 0;
- for (int i = 0; i < commandCount; i++) {
- DataRow row = batchCommands[i].Row;
- Debug.Assert(null != row, "null dataRow?");
- if (0 != ((DataRowState.Detached|DataRowState.Unchanged) & row.RowState)) {
- cumulativeDataRowsAffected++; // MDAC 66286
- }
- }
- return cumulativeDataRowsAffected;
- }
- private void UpdatingRowStatusErrors(RowUpdatingEventArgs rowUpdatedEvent, DataRow dataRow) {
- Debug.Assert(null != dataRow, "null dataRow");
- Exception errors = rowUpdatedEvent.Errors;
- if (null == errors) {
- // user changed status to ErrorsOccured without supplying an exception message
- errors = ADP.RowUpdatingErrors();
- rowUpdatedEvent.Errors = errors;
- }
- string message = errors.Message;
- dataRow.RowError += message; // MDAC 65808
- if (!ContinueUpdateOnError) { // MDAC 66900
- throw errors; // out of Update
- }
- }
- static private IDbConnection GetConnection1(DbDataAdapter adapter) {
- IDbCommand command = adapter._IDbDataAdapter.SelectCommand;
- if (null == command) {
- command = adapter._IDbDataAdapter.InsertCommand;
- if (null == command) {
- command = adapter._IDbDataAdapter.UpdateCommand;
- if (null == command) {
- command = adapter._IDbDataAdapter.DeleteCommand;
- }
- }
- }
- IDbConnection connection = null;
- if (null != command) {
- connection = command.Connection;
- }
- if (null == connection) {
- throw ADP.UpdateConnectionRequired(StatementType.Batch, false);
- }
- return connection;
- }
- static private IDbConnection GetConnection3(DbDataAdapter adapter, IDbCommand command, string method) {
- Debug.Assert(null != command, "GetConnection3: null command");
- Debug.Assert(!ADP.IsEmpty(method), "missing method name");
- IDbConnection connection = command.Connection;
- if (null == connection) {
- throw ADP.ConnectionRequired_Res(method);
- }
- return connection;
- }
- static private IDbConnection GetConnection4(DbDataAdapter adapter, IDbCommand command, StatementType statementType, bool isCommandFromRowUpdating) {
- Debug.Assert(null != command, "GetConnection4: null command");
- IDbConnection connection = command.Connection;
- if (null == connection) {
- throw ADP.UpdateConnectionRequired(statementType, isCommandFromRowUpdating);
- }
- return connection;
- }
- static private DataRowVersion GetParameterSourceVersion(StatementType statementType, IDataParameter parameter) {
- switch (statementType) {
- case StatementType.Insert: return DataRowVersion.Current; // ignores parameter.SourceVersion
- case StatementType.Update: return parameter.SourceVersion;
- case StatementType.Delete: return DataRowVersion.Original; // ignores parameter.SourceVersion
- case StatementType.Select:
- case StatementType.Batch:
- throw ADP.UnwantedStatementType(statementType);
- default:
- throw ADP.InvalidStatementType(statementType);
- }
- }
- static private void QuietClose(IDbConnection connection, ConnectionState originalState) {
- // close the connection if:
- // * it was closed on first use and adapter has opened it, AND
- // * provider's implementation did not ask to keep this connection open
- if ((null != connection) && (ConnectionState.Closed == originalState)) {
- // we don't have to check the current connection state because
- // it is supposed to be safe to call Close multiple times
- connection.Close();
- }
- }
- // QuietOpen needs to appear in the try {} finally { QuietClose } block
- // otherwise a possibility exists that an exception may be thrown, i.e. ThreadAbortException
- // where we would Open the connection and not close it
- static private void QuietOpen(IDbConnection connection, out ConnectionState originalState) {
- Debug.Assert(null != connection, "QuietOpen: null connection");
- originalState = connection.State;
- if (ConnectionState.Closed == originalState) {
- connection.Open();
- }
- }
- }
- }
|