Diff of /System.Data.SQLite/SQLiteDataReader.cs [51a8cf] .. [d2857c]  Maximize  Restore

Switch to unified view

a/System.Data.SQLite/SQLiteDataReader.cs b/System.Data.SQLite/SQLiteDataReader.cs
1
/********************************************************
1
/********************************************************
2
 * ADO.NET 2.0 Data Provider for SQLite Version 3.X
2
 * ADO.NET 2.0 Data Provider for SQLite Version 3.X
3
 * Written by Robert Simpson (robert@blackcastlesoft.com)
3
 * Written by Robert Simpson (robert@blackcastlesoft.com)
4
 * 
4
 * 
5
 * Released to the public domain, use at your own risk!
5
 * Released to the public domain, use at your own risk!
6
 ********************************************************/
6
 ********************************************************/

7
7
8
using System.Collections;
9
using System.Data.Common;
10
using System.Globalization;
11
8
namespace System.Data.SQLite
12
namespace System.Data.SQLite

9
{
13
{

10
  using System;
11
  using System.Data;
12
  using System.Data.Common;
13
  using System.Collections.Generic;
14
  using System.Globalization;
15
  using System.Reflection;
16
17
  /// <summary>
18
  /// SQLite implementation of DbDataReader.
19
  /// </summary>
20
  public sealed class SQLiteDataReader : DbDataReader
21
  {
22
    /// <summary>
14
    /// <summary>

23
    /// Underlying command this reader is attached to
15
    /// SQLite implementation of DbDataReader.
24
    /// </summary>
16
    /// </summary>

25
    private SQLiteCommand _command;
17
    public sealed class SQLiteDataReader : DbDataReader
18
    {
26
    /// <summary>
19
        /// <summary>

20
        /// The behavior of the datareader
21
        /// </summary>
22
        private readonly CommandBehavior _commandBehavior;
23
24
        /// <summary>
25
        /// Current statement being Read()
26
        /// </summary>
27
        private SQLiteStatement _activeStatement;
28
29
        /// <summary>
27
    /// Index of the current statement in the command being processed
30
        /// Index of the current statement in the command being processed

28
    /// </summary>
31
        /// </summary>

29
    private int _activeStatementIndex;
32
        private int _activeStatementIndex;

33
30
    /// <summary>
34
        /// <summary>

31
    /// Current statement being Read()
35
        /// Underlying command this reader is attached to
32
    /// </summary>
36
        /// </summary>

33
    private SQLiteStatement _activeStatement;
37
        private SQLiteCommand _command;
38
34
    /// <summary>
39
        /// <summary>

35
    /// State of the current statement being processed.
40
        /// If set, then dispose of the command object when the reader is finished
36
    /// -1 = First Step() executed, so the first Read() will be ignored
37
    ///  0 = Actively reading
38
    ///  1 = Finished reading
39
    ///  2 = Non-row-returning statement, no records
40
    /// </summary>
41
        /// </summary>

41
    private int _readingState;
42
        internal bool _disposeCommand;
43
42
    /// <summary>
44
        /// <summary>

43
    /// Number of records affected by the insert/update statements executed on the command
44
    /// </summary>
45
    private int _rowsAffected;
46
    /// <summary>
47
    /// Count of fields (columns) in the row-returning statement currently being processed
45
        /// Count of fields (columns) in the row-returning statement currently being processed

48
    /// </summary>
46
        /// </summary>

49
    private int _fieldCount;
47
        private int _fieldCount;

48
50
    /// <summary>
49
        /// <summary>

51
    /// Datatypes of active fields (columns) in the current statement, used for type-restricting data
50
        /// Datatypes of active fields (columns) in the current statement, used for type-restricting data

52
    /// </summary>
51
        /// </summary>

53
    private SQLiteType[] _fieldTypeArray;
52
        private SQLiteType[] _fieldTypeArray;

54
53
55
    /// <summary>
54
        /// <summary>

56
    /// The behavior of the datareader
57
    /// </summary>
58
    private CommandBehavior _commandBehavior;
59
60
    /// <summary>
61
    /// If set, then dispose of the command object when the reader is finished
62
    /// </summary>
63
    internal bool _disposeCommand;
64
65
    /// <summary>
66
    /// An array of rowid's for the active statement if CommandBehavior.KeyInfo is specified
55
        /// An array of rowid's for the active statement if CommandBehavior.KeyInfo is specified

67
    /// </summary>
56
        /// </summary>

68
    private SQLiteKeyReader _keyInfo;
57
        private SQLiteKeyReader _keyInfo;

69
58
59
        /// <summary>
60
        /// State of the current statement being processed.
61
        /// -1 = First Step() executed, so the first Read() will be ignored
62
        ///  0 = Actively reading
63
        ///  1 = Finished reading
64
        ///  2 = Non-row-returning statement, no records
65
        /// </summary>
66
        private int _readingState;
67
68
        /// <summary>
69
        /// Number of records affected by the insert/update statements executed on the command
70
        /// </summary>
71
        private int _rowsAffected;
72
70
    internal long _version; // Matches the version of the connection
73
        internal long _version; // Matches the version of the connection

71
74
72
    /// <summary>
75
        /// <summary>

73
    /// Internal constructor, initializes the datareader and sets up to begin executing statements
76
        /// Internal constructor, initializes the datareader and sets up to begin executing statements

74
    /// </summary>
77
        /// </summary>

75
    /// <param name="cmd">The SQLiteCommand this data reader is for</param>
78
        /// <param name="cmd">The SQLiteCommand this data reader is for</param>

76
    /// <param name="behave">The expected behavior of the data reader</param>
79
        /// <param name="behave">The expected behavior of the data reader</param>

77
    internal SQLiteDataReader(SQLiteCommand cmd, CommandBehavior behave)
80
        internal SQLiteDataReader(SQLiteCommand cmd, CommandBehavior behave)

78
    {
81
        {
79
      _command = cmd;
82
            _command = cmd;

80
      _version = _command.Connection._version;
83
            _version = _command.Connection._version;

81
84
82
      _commandBehavior = behave;
85
            _commandBehavior = behave;

83
      _activeStatementIndex = -1;
86
            _activeStatementIndex = -1;

84
      _rowsAffected = -1;
87
            _rowsAffected = -1;

85
88
86
      if (_command != null)
89
            if (_command != null)

87
        NextResult();
90
                NextResult();

88
    }
91
        }
89
92
93
        /// <summary>
94
        /// Not implemented.  Returns 0
95
        /// </summary>
96
        public override int Depth
97
        {
98
            get
99
            {
100
                CheckClosed();
101
                return 0;
102
            }
103
        }
104
105
        /// <summary>
106
        /// Returns the number of columns in the current resultset
107
        /// </summary>
108
        public override int FieldCount
109
        {
110
            get
111
            {
112
                CheckClosed();
113
                if (_keyInfo == null)
114
                    return _fieldCount;
115
116
                return _fieldCount + _keyInfo.Count;
117
            }
118
        }
119
120
        /// <summary>
121
        /// Returns the number of visible fielsd in the current resultset
122
        /// </summary>
123
        public override int VisibleFieldCount
124
        {
125
            get
126
            {
127
                CheckClosed();
128
                return _fieldCount;
129
            }
130
        }
131
132
        /// <summary>
133
        /// Returns True if the resultset has rows that can be fetched
134
        /// </summary>
135
        public override bool HasRows
136
        {
137
            get
138
            {
139
                CheckClosed();
140
                return (_readingState != 1);
141
            }
142
        }
143
144
        /// <summary>
145
        /// Returns True if the data reader is closed
146
        /// </summary>
147
        public override bool IsClosed
148
        {
149
            get { return (_command == null); }
150
        }
151
152
        /// <summary>
153
        /// Retrieve the count of records affected by an update/insert command.  Only valid once the data reader is closed!
154
        /// </summary>
155
        public override int RecordsAffected
156
        {
157
            get { return (_rowsAffected < 0) ? 0 : _rowsAffected; }
158
        }
159
160
        /// <summary>
161
        /// Indexer to retrieve data from a column given its name
162
        /// </summary>
163
        /// <param name="name">The name of the column to retrieve data for</param>
164
        /// <returns>The value contained in the column</returns>
165
        public override object this[string name]
166
        {
167
            get { return GetValue(GetOrdinal(name)); }
168
        }
169
170
        /// <summary>
171
        /// Indexer to retrieve data from a column given its i
172
        /// </summary>
173
        /// <param name="i">The index of the column to retrieve</param>
174
        /// <returns>The value contained in the column</returns>
175
        public override object this[int i]
176
        {
177
            get { return GetValue(i); }
178
        }
179
90
    internal void Cancel()
180
        internal void Cancel()

91
    {
181
        {
92
      _version = 0;
182
            _version = 0;

93
    }
183
        }
94
184
95
    /// <summary>
185
        /// <summary>

96
    /// Closes the datareader, potentially closing the connection as well if CommandBehavior.CloseConnection was specified.
186
        /// Closes the datareader, potentially closing the connection as well if CommandBehavior.CloseConnection was specified.

97
    /// </summary>
187
        /// </summary>

98
    public override void Close()
188
        public override void Close()

99
    {
100
      try
101
      {
102
        if (_command != null)
103
        {
189
        {

104
          try
105
          {
106
            try
190
            try

107
            {
191
            {

108
              // Make sure we've not been canceled
109
              if (_version != 0)
192
                if (_command != null)

110
              {
111
                try
112
                {
193
                {

113
                  while (NextResult())
194
                    try
114
                  {
195
                    {

196
                        try
197
                        {
198
                            // Make sure we've not been canceled
199
                            if (_version != 0)
200
                            {
201
                                try
202
                                {
203
                                    while (NextResult())
204
                                    {
205
                                    }
206
                                }
207
                                catch (SQLiteException)
208
                                {
209
                                }
210
                            }
211
                            _command.ClearDataReader();
212
                        }
213
                        finally
214
                        {
215
                            // If the datareader's behavior includes closing the connection, then do so here.
216
                            if ((_commandBehavior & CommandBehavior.CloseConnection) != 0 && _command.Connection != null)
217
                                _command.Connection.Close();
218
                        }
115
                  }
219
                    }

220
                    finally
221
                    {
222
                        if (_disposeCommand)
223
                            _command.Dispose();
224
                    }
116
                }
225
                }

117
                catch(SQLiteException)
226
118
                {
227
                _command = null;
119
                }
228
                _activeStatement = null;
120
              }
229
                _fieldTypeArray = null;
121
              _command.ClearDataReader();
122
            }
230
            }

123
            finally
231
            finally

124
            {
232
            {

125
              // If the datareader's behavior includes closing the connection, then do so here.
233
                if (_keyInfo != null)
126
              if ((_commandBehavior & CommandBehavior.CloseConnection) != 0 && _command.Connection != null)
234
                {
127
                _command.Connection.Close();
235
                    _keyInfo.Dispose();
236
                    _keyInfo = null;
237
                }
128
            }
238
            }

129
          }
130
          finally
131
          {
132
            if (_disposeCommand)
133
              _command.Dispose();
134
          }
135
        }
239
        }

136
240
137
        _command = null;
138
        _activeStatement = null;
139
        _fieldTypeArray = null;
140
      }
141
      finally
142
      {
143
        if (_keyInfo != null)
144
        {
145
          _keyInfo.Dispose();
146
          _keyInfo = null;
147
        }
148
      }
149
    }
150
151
    /// <summary>
241
        /// <summary>

152
    /// Throw an error if the datareader is closed
242
        /// Throw an error if the datareader is closed

153
    /// </summary>
243
        /// </summary>

154
    private void CheckClosed()
244
        private void CheckClosed()

155
    {
245
        {
156
      if (_command == null)
246
            if (_command == null)

157
        throw new InvalidOperationException("DataReader has been closed");
247
                throw new InvalidOperationException("DataReader has been closed");

158
248
159
      if (_version == 0)
249
            if (_version == 0)

160
        throw new SQLiteException((int)SQLiteErrorCode.Abort, "Execution was aborted by the user");
250
                throw new SQLiteException((int) SQLiteErrorCode.Abort, "Execution was aborted by the user");

161
251
162
      if (_command.Connection.State != ConnectionState.Open || _command.Connection._version != _version)
252
            if (_command.Connection.State != ConnectionState.Open || _command.Connection._version != _version)

163
        throw new InvalidOperationException("Connection was closed, statement was terminated");
253
                throw new InvalidOperationException("Connection was closed, statement was terminated");

164
    }
254
        }
165
255
166
    /// <summary>
256
        /// <summary>

167
    /// Throw an error if a row is not loaded
257
        /// Throw an error if a row is not loaded

168
    /// </summary>
258
        /// </summary>

169
    private void CheckValidRow()
259
        private void CheckValidRow()

170
    {
260
        {
171
      if (_readingState != 0)
261
            if (_readingState != 0)

172
        throw new InvalidOperationException("No current row");
262
                throw new InvalidOperationException("No current row");

173
    }
263
        }
174
264
175
    /// <summary>
265
        /// <summary>

176
    /// Enumerator support
266
        /// Enumerator support

177
    /// </summary>
267
        /// </summary>

178
    /// <returns>Returns a DbEnumerator object.</returns>
268
        /// <returns>Returns a DbEnumerator object.</returns>

179
    public override Collections.IEnumerator GetEnumerator()
269
        public override IEnumerator GetEnumerator()

180
    {
270
        {
181
      return new DbEnumerator(this, ((_commandBehavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection));
271
            return new DbEnumerator(this,
182
    }
272
                                    ((_commandBehavior & CommandBehavior.CloseConnection) ==
183
273
                                     CommandBehavior.CloseConnection));
274
        }
275
184
    /// <summary>
276
        /// <summary>

185
    /// Not implemented.  Returns 0
186
    /// </summary>
187
    public override int Depth
188
    {
189
      get
190
      {
191
        CheckClosed();
192
        return 0;
193
      }
194
    }
195
196
    /// <summary>
197
    /// Returns the number of columns in the current resultset
198
    /// </summary>
199
    public override int FieldCount
200
    {
201
      get
202
      {
203
        CheckClosed();
204
        if (_keyInfo == null)
205
          return _fieldCount;
206
207
        return _fieldCount + _keyInfo.Count;
208
      }
209
    }
210
211
    /// <summary>
212
    /// Returns the number of visible fielsd in the current resultset
213
    /// </summary>
214
    public override int VisibleFieldCount
215
    {
216
      get
217
      {
218
        CheckClosed();
219
        return _fieldCount;
220
      }
221
    }
222
223
    /// <summary>
224
    /// SQLite is inherently un-typed.  All datatypes in SQLite are natively strings.  The definition of the columns of a table
277
        /// SQLite is inherently un-typed.  All datatypes in SQLite are natively strings.  The definition of the columns of a table

225
    /// and the affinity of returned types are all we have to go on to type-restrict data in the reader.
278
        /// and the affinity of returned types are all we have to go on to type-restrict data in the reader.

226
    /// 
279
        /// 

227
    /// This function attempts to verify that the type of data being requested of a column matches the datatype of the column.  In
280
        /// This function attempts to verify that the type of data being requested of a column matches the datatype of the column.  In

228
    /// the case of columns that are not backed into a table definition, we attempt to match up the affinity of a column (int, double, string or blob)
281
        /// the case of columns that are not backed into a table definition, we attempt to match up the affinity of a column (int, double, string or blob)

229
    /// to a set of known types that closely match that affinity.  It's not an exact science, but its the best we can do.
282
        /// to a set of known types that closely match that affinity.  It's not an exact science, but its the best we can do.

230
    /// </summary>
283
        /// </summary>

231
    /// <returns>
284
        /// <returns>

232
    /// This function throws an InvalidTypeCast() exception if the requested type doesn't match the column's definition or affinity.
285
        /// This function throws an InvalidTypeCast() exception if the requested type doesn't match the column's definition or affinity.

233
    /// </returns>
286
        /// </returns>

234
    /// <param name="i">The index of the column to type-check</param>
287
        /// <param name="i">The index of the column to type-check</param>

235
    /// <param name="typ">The type we want to get out of the column</param>
288
        /// <param name="typ">The type we want to get out of the column</param>

236
    private TypeAffinity VerifyType(int i, DbType typ)
289
        private TypeAffinity VerifyType(int i, DbType typ)

237
    {
290
        {
238
      CheckClosed();
291
            CheckClosed();

239
      CheckValidRow();
292
            CheckValidRow();

240
      TypeAffinity affinity = GetSQLiteType(i).Affinity;
293
            TypeAffinity affinity = GetSQLiteType(i).Affinity;

241
294
242
      switch (affinity)
295
            switch (affinity)

243
      {
296
            {
244
        case TypeAffinity.Int64:
297
                case TypeAffinity.Int64:

245
          if (typ == DbType.Int16) return affinity;
298
                    if (typ == DbType.Int16) return affinity;

246
          if (typ == DbType.Int32) return affinity;
299
                    if (typ == DbType.Int32) return affinity;

247
          if (typ == DbType.Int64) return affinity;
300
                    if (typ == DbType.Int64) return affinity;

248
          if (typ == DbType.Boolean) return affinity;
301
                    if (typ == DbType.Boolean) return affinity;

249
          if (typ == DbType.Byte) return affinity;
302
                    if (typ == DbType.Byte) return affinity;

250
          if (typ == DbType.DateTime) return affinity;
303
                    if (typ == DbType.DateTime) return affinity;

251
          if (typ == DbType.Single) return affinity;
304
                    if (typ == DbType.Single) return affinity;

252
          if (typ == DbType.Double) return affinity;
305
                    if (typ == DbType.Double) return affinity;

253
          if (typ == DbType.Decimal) return affinity;
306
                    if (typ == DbType.Decimal) return affinity;

254
          break;
307
                    break;

255
        case TypeAffinity.Double:
308
                case TypeAffinity.Double:

256
          if (typ == DbType.Single) return affinity;
309
                    if (typ == DbType.Single) return affinity;

257
          if (typ == DbType.Double) return affinity;
310
                    if (typ == DbType.Double) return affinity;

258
          if (typ == DbType.Decimal) return affinity;
311
                    if (typ == DbType.Decimal) return affinity;

259
          if (typ == DbType.DateTime) return affinity;
312
                    if (typ == DbType.DateTime) return affinity;

260
          break;
313
                    break;

261
        case TypeAffinity.Text:
314
                case TypeAffinity.Text:

262
          if (typ == DbType.SByte) return affinity;
315
                    if (typ == DbType.SByte) return affinity;

263
          if (typ == DbType.String) return affinity;
316
                    if (typ == DbType.String) return affinity;

264
          if (typ == DbType.SByte) return affinity;
317
                    if (typ == DbType.SByte) return affinity;

265
          if (typ == DbType.Guid) return affinity;
318
                    if (typ == DbType.Guid) return affinity;

266
          if (typ == DbType.DateTime) return affinity;
319
                    if (typ == DbType.DateTime) return affinity;

267
          if (typ == DbType.Decimal) return affinity;
320
                    if (typ == DbType.Decimal) return affinity;

268
          break;
321
                    break;

269
        case TypeAffinity.Blob:
322
                case TypeAffinity.Blob:

270
          if (typ == DbType.Guid) return affinity;
323
                    if (typ == DbType.Guid) return affinity;

271
          if (typ == DbType.String) return affinity;
324
                    if (typ == DbType.String) return affinity;

272
          if (typ == DbType.Binary) return affinity;
325
                    if (typ == DbType.Binary) return affinity;

273
          break;
326
                    break;

274
      }
327
            }
275
328
276
      throw new InvalidCastException();
329
            throw new InvalidCastException();

277
    }
330
        }
278
331
279
    /// <summary>
332
        /// <summary>

280
    /// Retrieves the column as a boolean value
333
        /// Retrieves the column as a boolean value

281
    /// </summary>
334
        /// </summary>

282
    /// <param name="i">The index of the column to retrieve</param>
335
        /// <param name="i">The index of the column to retrieve</param>

283
    /// <returns>bool</returns>
336
        /// <returns>bool</returns>

284
    public override bool GetBoolean(int i)
337
        public override bool GetBoolean(int i)

285
    {
338
        {
286
      if (i >= VisibleFieldCount && _keyInfo != null)
339
            if (i >= VisibleFieldCount && _keyInfo != null)

287
        return _keyInfo.GetBoolean(i - VisibleFieldCount);
340
                return _keyInfo.GetBoolean(i - VisibleFieldCount);

288
341
289
      VerifyType(i, DbType.Boolean);
342
            VerifyType(i, DbType.Boolean);

290
      return Convert.ToBoolean(GetValue(i), CultureInfo.CurrentCulture);
343
            return Convert.ToBoolean(GetValue(i), CultureInfo.CurrentCulture);

291
    }
344
        }
292
345
293
    /// <summary>
346
        /// <summary>

294
    /// Retrieves the column as a single byte value
347
        /// Retrieves the column as a single byte value

295
    /// </summary>
348
        /// </summary>

296
    /// <param name="i">The index of the column to retrieve</param>
349
        /// <param name="i">The index of the column to retrieve</param>

297
    /// <returns>byte</returns>
350
        /// <returns>byte</returns>

298
    public override byte GetByte(int i)
351
        public override byte GetByte(int i)

299
    {
352
        {
300
      if (i >= VisibleFieldCount && _keyInfo != null)
353
            if (i >= VisibleFieldCount && _keyInfo != null)

301
        return _keyInfo.GetByte(i - VisibleFieldCount);
354
                return _keyInfo.GetByte(i - VisibleFieldCount);

302
355
303
      VerifyType(i, DbType.Byte);
356
            VerifyType(i, DbType.Byte);

304
      return Convert.ToByte(_activeStatement._sql.GetInt32(_activeStatement, i));
357
            return Convert.ToByte(_activeStatement._sql.GetInt32(_activeStatement, i));

305
    }
358
        }
306
359
307
    /// <summary>
360
        /// <summary>

308
    /// Retrieves a column as an array of bytes (blob)
361
        /// Retrieves a column as an array of bytes (blob)

309
    /// </summary>
362
        /// </summary>

310
    /// <param name="i">The index of the column to retrieve</param>
363
        /// <param name="i">The index of the column to retrieve</param>

311
    /// <param name="fieldOffset">The zero-based index of where to begin reading the data</param>
364
        /// <param name="fieldOffset">The zero-based index of where to begin reading the data</param>

312
    /// <param name="buffer">The buffer to write the bytes into</param>
365
        /// <param name="buffer">The buffer to write the bytes into</param>

313
    /// <param name="bufferoffset">The zero-based index of where to begin writing into the array</param>
366
        /// <param name="bufferoffset">The zero-based index of where to begin writing into the array</param>

314
    /// <param name="length">The number of bytes to retrieve</param>
367
        /// <param name="length">The number of bytes to retrieve</param>

315
    /// <returns>The actual number of bytes written into the array</returns>
368
        /// <returns>The actual number of bytes written into the array</returns>

316
    /// <remarks>
369
        /// <remarks>

317
    /// To determine the number of bytes in the column, pass a null value for the buffer.  The total length will be returned.
370
        /// To determine the number of bytes in the column, pass a null value for the buffer.  The total length will be returned.

318
    /// </remarks>
371
        /// </remarks>

319
    public override long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
372
        public override long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)

320
    {
373
        {
321
      if (i >= VisibleFieldCount && _keyInfo != null)
374
            if (i >= VisibleFieldCount && _keyInfo != null)

322
        return _keyInfo.GetBytes(i - VisibleFieldCount, fieldOffset, buffer, bufferoffset, length);
375
                return _keyInfo.GetBytes(i - VisibleFieldCount, fieldOffset, buffer, bufferoffset, length);

323
376
324
      VerifyType(i, DbType.Binary);
377
            VerifyType(i, DbType.Binary);

325
      return _activeStatement._sql.GetBytes(_activeStatement, i, (int)fieldOffset, buffer, bufferoffset, length);
378
            return _activeStatement._sql.GetBytes(_activeStatement, i, (int) fieldOffset, buffer, bufferoffset, length);

326
    }
379
        }
327
380
328
    /// <summary>
381
        /// <summary>

329
    /// Returns the column as a single character
382
        /// Returns the column as a single character

330
    /// </summary>
383
        /// </summary>

331
    /// <param name="i">The index of the column to retrieve</param>
384
        /// <param name="i">The index of the column to retrieve</param>

332
    /// <returns>char</returns>
385
        /// <returns>char</returns>

333
    public override char GetChar(int i)
386
        public override char GetChar(int i)

334
    {
387
        {
335
      if (i >= VisibleFieldCount && _keyInfo != null)
388
            if (i >= VisibleFieldCount && _keyInfo != null)

336
        return _keyInfo.GetChar(i - VisibleFieldCount);
389
                return _keyInfo.GetChar(i - VisibleFieldCount);

337
390
338
      VerifyType(i, DbType.SByte);
391
            VerifyType(i, DbType.SByte);

339
      return Convert.ToChar(_activeStatement._sql.GetInt32(_activeStatement, i));
392
            return Convert.ToChar(_activeStatement._sql.GetInt32(_activeStatement, i));

340
    }
393
        }
341
394
342
    /// <summary>
395
        /// <summary>

343
    /// Retrieves a column as an array of chars (blob)
396
        /// Retrieves a column as an array of chars (blob)

344
    /// </summary>
397
        /// </summary>

345
    /// <param name="i">The index of the column to retrieve</param>
398
        /// <param name="i">The index of the column to retrieve</param>

346
    /// <param name="fieldoffset">The zero-based index of where to begin reading the data</param>
399
        /// <param name="fieldoffset">The zero-based index of where to begin reading the data</param>

347
    /// <param name="buffer">The buffer to write the characters into</param>
400
        /// <param name="buffer">The buffer to write the characters into</param>

348
    /// <param name="bufferoffset">The zero-based index of where to begin writing into the array</param>
401
        /// <param name="bufferoffset">The zero-based index of where to begin writing into the array</param>

349
    /// <param name="length">The number of bytes to retrieve</param>
402
        /// <param name="length">The number of bytes to retrieve</param>

350
    /// <returns>The actual number of characters written into the array</returns>
403
        /// <returns>The actual number of characters written into the array</returns>

351
    /// <remarks>
404
        /// <remarks>

352
    /// To determine the number of characters in the column, pass a null value for the buffer.  The total length will be returned.
405
        /// To determine the number of characters in the column, pass a null value for the buffer.  The total length will be returned.

353
    /// </remarks>
406
        /// </remarks>

354
    public override long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
407
        public override long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)

355
    {
408
        {
356
      if (i >= VisibleFieldCount && _keyInfo != null)
409
            if (i >= VisibleFieldCount && _keyInfo != null)

357
        return _keyInfo.GetChars(i - VisibleFieldCount, fieldoffset, buffer, bufferoffset, length);
410
                return _keyInfo.GetChars(i - VisibleFieldCount, fieldoffset, buffer, bufferoffset, length);

358
411
359
      VerifyType(i, DbType.String);
412
            VerifyType(i, DbType.String);

360
      return _activeStatement._sql.GetChars(_activeStatement, i, (int)fieldoffset, buffer, bufferoffset, length);
413
            return _activeStatement._sql.GetChars(_activeStatement, i, (int) fieldoffset, buffer, bufferoffset, length);

361
    }
414
        }
362
415
363
    /// <summary>
416
        /// <summary>

364
    /// Retrieves the name of the back-end datatype of the column
417
        /// Retrieves the name of the back-end datatype of the column

365
    /// </summary>
418
        /// </summary>

366
    /// <param name="i">The index of the column to retrieve</param>
419
        /// <param name="i">The index of the column to retrieve</param>

367
    /// <returns>string</returns>
420
        /// <returns>string</returns>

368
    public override string GetDataTypeName(int i)
421
        public override string GetDataTypeName(int i)

369
    {
422
        {
370
      if (i >= VisibleFieldCount && _keyInfo != null)
423
            if (i >= VisibleFieldCount && _keyInfo != null)

371
        return _keyInfo.GetDataTypeName(i - VisibleFieldCount);
424
                return _keyInfo.GetDataTypeName(i - VisibleFieldCount);

372
425
373
      SQLiteType typ = GetSQLiteType(i);
426
            SQLiteType typ = GetSQLiteType(i);

374
      if (typ.Type == DbType.Object) return SQLiteConvert.SQLiteTypeToType(typ).Name;
427
            if (typ.Type == DbType.Object) return SQLiteConvert.SQLiteTypeToType(typ).Name;

375
      return _activeStatement._sql.ColumnType(_activeStatement, i, out typ.Affinity);
428
            return _activeStatement._sql.ColumnType(_activeStatement, i, out typ.Affinity);

376
    }
429
        }
377
430
378
    /// <summary>
431
        /// <summary>

379
    /// Retrieve the column as a date/time value
432
        /// Retrieve the column as a date/time value

380
    /// </summary>
433
        /// </summary>

381
    /// <param name="i">The index of the column to retrieve</param>
434
        /// <param name="i">The index of the column to retrieve</param>

382
    /// <returns>DateTime</returns>
435
        /// <returns>DateTime</returns>

383
    public override DateTime GetDateTime(int i)
436
        public override DateTime GetDateTime(int i)

384
    {
437
        {
385
      if (i >= VisibleFieldCount && _keyInfo != null)
438
            if (i >= VisibleFieldCount && _keyInfo != null)

386
        return _keyInfo.GetDateTime(i - VisibleFieldCount);
439
                return _keyInfo.GetDateTime(i - VisibleFieldCount);

387
440
388
      VerifyType(i, DbType.DateTime);
441
            VerifyType(i, DbType.DateTime);

389
      return _activeStatement._sql.GetDateTime(_activeStatement, i);
442
            return _activeStatement._sql.GetDateTime(_activeStatement, i);

390
    }
443
        }
391
444
392
    /// <summary>
445
        /// <summary>

393
    /// Retrieve the column as a decimal value
446
        /// Retrieve the column as a decimal value

394
    /// </summary>
447
        /// </summary>

395
    /// <param name="i">The index of the column to retrieve</param>
448
        /// <param name="i">The index of the column to retrieve</param>

396
    /// <returns>decimal</returns>
449
        /// <returns>decimal</returns>

397
    public override decimal GetDecimal(int i)
450
        public override decimal GetDecimal(int i)

398
    {
451
        {
399
      if (i >= VisibleFieldCount && _keyInfo != null)
452
            if (i >= VisibleFieldCount && _keyInfo != null)

400
        return _keyInfo.GetDecimal(i - VisibleFieldCount);
453
                return _keyInfo.GetDecimal(i - VisibleFieldCount);

401
454
402
      VerifyType(i, DbType.Decimal);
455
            VerifyType(i, DbType.Decimal);

403
      return Decimal.Parse(_activeStatement._sql.GetText(_activeStatement, i), NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent | NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture);
456
            return Decimal.Parse(_activeStatement._sql.GetText(_activeStatement, i),
404
    }
457
                                 NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent |
405
458
                                 NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture);
459
        }
460
406
    /// <summary>
461
        /// <summary>

407
    /// Returns the column as a double
462
        /// Returns the column as a double

408
    /// </summary>
463
        /// </summary>

409
    /// <param name="i">The index of the column to retrieve</param>
464
        /// <param name="i">The index of the column to retrieve</param>

410
    /// <returns>double</returns>
465
        /// <returns>double</returns>

411
    public override double GetDouble(int i)
466
        public override double GetDouble(int i)

412
    {
467
        {
413
      if (i >= VisibleFieldCount && _keyInfo != null)
468
            if (i >= VisibleFieldCount && _keyInfo != null)

414
        return _keyInfo.GetDouble(i - VisibleFieldCount);
469
                return _keyInfo.GetDouble(i - VisibleFieldCount);

415
470
416
      VerifyType(i, DbType.Double);
471
            VerifyType(i, DbType.Double);

417
      return _activeStatement._sql.GetDouble(_activeStatement, i);
472
            return _activeStatement._sql.GetDouble(_activeStatement, i);

418
    }
473
        }
419
474
420
    /// <summary>
475
        /// <summary>

421
    /// Returns the .NET type of a given column
476
        /// Returns the .NET type of a given column

422
    /// </summary>
477
        /// </summary>

423
    /// <param name="i">The index of the column to retrieve</param>
478
        /// <param name="i">The index of the column to retrieve</param>

424
    /// <returns>Type</returns>
479
        /// <returns>Type</returns>

425
    public override Type GetFieldType(int i)
480
        public override Type GetFieldType(int i)

426
    {
481
        {
427
      if (i >= VisibleFieldCount && _keyInfo != null)
482
            if (i >= VisibleFieldCount && _keyInfo != null)

428
        return _keyInfo.GetFieldType(i - VisibleFieldCount);
483
                return _keyInfo.GetFieldType(i - VisibleFieldCount);

429
484
430
      return SQLiteConvert.SQLiteTypeToType(GetSQLiteType(i));
485
            return SQLiteConvert.SQLiteTypeToType(GetSQLiteType(i));

431
    }
486
        }
432
487
433
    /// <summary>
488
        /// <summary>

434
    /// Returns a column as a float value
489
        /// Returns a column as a float value

435
    /// </summary>
490
        /// </summary>

436
    /// <param name="i">The index of the column to retrieve</param>
491
        /// <param name="i">The index of the column to retrieve</param>

437
    /// <returns>float</returns>
492
        /// <returns>float</returns>

438
    public override float GetFloat(int i)
493
        public override float GetFloat(int i)

439
    {
494
        {
440
      if (i >= VisibleFieldCount && _keyInfo != null)
495
            if (i >= VisibleFieldCount && _keyInfo != null)

441
        return _keyInfo.GetFloat(i - VisibleFieldCount);
496
                return _keyInfo.GetFloat(i - VisibleFieldCount);

442
497
443
      VerifyType(i, DbType.Single);
498
            VerifyType(i, DbType.Single);

444
      return Convert.ToSingle(_activeStatement._sql.GetDouble(_activeStatement, i));
499
            return Convert.ToSingle(_activeStatement._sql.GetDouble(_activeStatement, i));

445
    }
500
        }
446
501
447
    /// <summary>
502
        /// <summary>

448
    /// Returns the column as a Guid
503
        /// Returns the column as a Guid

449
    /// </summary>
504
        /// </summary>

450
    /// <param name="i">The index of the column to retrieve</param>
505
        /// <param name="i">The index of the column to retrieve</param>

451
    /// <returns>Guid</returns>
506
        /// <returns>Guid</returns>

452
    public override Guid GetGuid(int i)
507
        public override Guid GetGuid(int i)

453
    {
508
        {
454
      if (i >= VisibleFieldCount && _keyInfo != null)
509
            if (i >= VisibleFieldCount && _keyInfo != null)

455
        return _keyInfo.GetGuid(i - VisibleFieldCount);
510
                return _keyInfo.GetGuid(i - VisibleFieldCount);

456
511
457
      TypeAffinity affinity = VerifyType(i, DbType.Guid);
512
            TypeAffinity affinity = VerifyType(i, DbType.Guid);

458
      if (affinity == TypeAffinity.Blob)
513
            if (affinity == TypeAffinity.Blob)

459
      {
514
            {
460
        byte[] buffer = new byte[16];
515
                var buffer = new byte[16];

461
        _activeStatement._sql.GetBytes(_activeStatement, i, 0, buffer, 0, 16);
516
                _activeStatement._sql.GetBytes(_activeStatement, i, 0, buffer, 0, 16);

462
        return new Guid(buffer);
517
                return new Guid(buffer);

463
      }
518
            }
464
      else
519
            else

465
        return new Guid(_activeStatement._sql.GetText(_activeStatement, i));
520
                return new Guid(_activeStatement._sql.GetText(_activeStatement, i));

466
    }
521
        }
467
522
468
    /// <summary>
523
        /// <summary>

469
    /// Returns the column as a short
524
        /// Returns the column as a short

470
    /// </summary>
525
        /// </summary>

471
    /// <param name="i">The index of the column to retrieve</param>
526
        /// <param name="i">The index of the column to retrieve</param>

472
    /// <returns>Int16</returns>
527
        /// <returns>Int16</returns>

473
    public override Int16 GetInt16(int i)
528
        public override Int16 GetInt16(int i)

474
    {
529
        {
475
      if (i >= VisibleFieldCount && _keyInfo != null)
530
            if (i >= VisibleFieldCount && _keyInfo != null)

476
        return _keyInfo.GetInt16(i - VisibleFieldCount);
531
                return _keyInfo.GetInt16(i - VisibleFieldCount);

477
532
478
      VerifyType(i, DbType.Int16);
533
            VerifyType(i, DbType.Int16);

479
      return Convert.ToInt16(_activeStatement._sql.GetInt32(_activeStatement, i));
534
            return Convert.ToInt16(_activeStatement._sql.GetInt32(_activeStatement, i));

480
    }
535
        }
481
536
482
    /// <summary>
537
        /// <summary>

483
    /// Retrieves the column as an int
538
        /// Retrieves the column as an int

484
    /// </summary>
539
        /// </summary>

485
    /// <param name="i">The index of the column to retrieve</param>
540
        /// <param name="i">The index of the column to retrieve</param>

486
    /// <returns>Int32</returns>
541
        /// <returns>Int32</returns>

487
    public override Int32 GetInt32(int i)
542
        public override Int32 GetInt32(int i)

488
    {
543
        {
489
      if (i >= VisibleFieldCount && _keyInfo != null)
544
            if (i >= VisibleFieldCount && _keyInfo != null)

490
        return _keyInfo.GetInt32(i - VisibleFieldCount);
545
                return _keyInfo.GetInt32(i - VisibleFieldCount);

491
546
492
      VerifyType(i, DbType.Int32);
547
            VerifyType(i, DbType.Int32);

493
      return _activeStatement._sql.GetInt32(_activeStatement, i);
548
            return _activeStatement._sql.GetInt32(_activeStatement, i);

494
    }
549
        }
495
550
496
    /// <summary>
551
        /// <summary>

497
    /// Retrieves the column as a long
552
        /// Retrieves the column as a long

498
    /// </summary>
553
        /// </summary>

499
    /// <param name="i">The index of the column to retrieve</param>
554
        /// <param name="i">The index of the column to retrieve</param>

500
    /// <returns>Int64</returns>
555
        /// <returns>Int64</returns>

501
    public override Int64 GetInt64(int i)
556
        public override Int64 GetInt64(int i)

502
    {
557
        {
503
      if (i >= VisibleFieldCount && _keyInfo != null)
558
            if (i >= VisibleFieldCount && _keyInfo != null)

504
        return _keyInfo.GetInt64(i - VisibleFieldCount);
559
                return _keyInfo.GetInt64(i - VisibleFieldCount);

505
560
506
      VerifyType(i, DbType.Int64);
561
            VerifyType(i, DbType.Int64);

507
      return _activeStatement._sql.GetInt64(_activeStatement, i);
562
            return _activeStatement._sql.GetInt64(_activeStatement, i);

508
    }
563
        }
509
564
510
    /// <summary>
565
        /// <summary>

511
    /// Retrieves the name of the column
566
        /// Retrieves the name of the column

512
    /// </summary>
567
        /// </summary>

513
    /// <param name="i">The index of the column to retrieve</param>
568
        /// <param name="i">The index of the column to retrieve</param>

514
    /// <returns>string</returns>
569
        /// <returns>string</returns>

515
    public override string GetName(int i)
570
        public override string GetName(int i)

516
    {
571
        {
517
      if (i >= VisibleFieldCount && _keyInfo != null)
572
            if (i >= VisibleFieldCount && _keyInfo != null)

518
        return _keyInfo.GetName(i - VisibleFieldCount);
573
                return _keyInfo.GetName(i - VisibleFieldCount);

519
574
520
      return _activeStatement._sql.ColumnName(_activeStatement, i);
575
            return _activeStatement._sql.ColumnName(_activeStatement, i);

521
    }
576
        }
522
577
523
    /// <summary>
578
        /// <summary>

524
    /// Retrieves the i of a column, given its name
579
        /// Retrieves the i of a column, given its name

525
    /// </summary>
580
        /// </summary>

526
    /// <param name="name">The name of the column to retrieve</param>
581
        /// <param name="name">The name of the column to retrieve</param>

527
    /// <returns>The int i of the column</returns>
582
        /// <returns>The int i of the column</returns>

528
    public override int GetOrdinal(string name)
583
        public override int GetOrdinal(string name)

529
    {
584
        {
530
      CheckClosed();
585
            CheckClosed();

531
      int r = _activeStatement._sql.ColumnIndex(_activeStatement, name);
586
            int r = _activeStatement._sql.ColumnIndex(_activeStatement, name);

532
      if (r == -1 && _keyInfo != null)
587
            if (r == -1 && _keyInfo != null)

533
      {
588
            {
534
        r = _keyInfo.GetOrdinal(name);
589
                r = _keyInfo.GetOrdinal(name);

535
        if (r > -1) r += VisibleFieldCount;
590
                if (r > -1) r += VisibleFieldCount;

591
            }
592
593
            return r;
536
      }
594
        }

537
595
538
      return r;
539
    }
540
541
    /// <summary>
596
        /// <summary>

542
    /// Schema information in SQLite is difficult to map into .NET conventions, so a lot of work must be done
597
        /// Schema information in SQLite is difficult to map into .NET conventions, so a lot of work must be done

543
    /// to gather the necessary information so it can be represented in an ADO.NET manner.
598
        /// to gather the necessary information so it can be represented in an ADO.NET manner.

544
    /// </summary>
599
        /// </summary>

545
    /// <returns>Returns a DataTable containing the schema information for the active SELECT statement being processed.</returns>
600
        /// <returns>Returns a DataTable containing the schema information for the active SELECT statement being processed.</returns>

546
    public override DataTable GetSchemaTable()
601
        public override DataTable GetSchemaTable()

547
    {
602
        {
548
      return GetSchemaTable(true, false);
603
            return GetSchemaTable(true, false);

549
    }
604
        }
550
605
551
    internal DataTable GetSchemaTable(bool wantUniqueInfo, bool wantDefaultValue)
606
        internal DataTable GetSchemaTable(bool wantUniqueInfo, bool wantDefaultValue)

552
    {
607
        {
553
      CheckClosed();
608
            CheckClosed();

554
609
555
      DataTable tbl = new DataTable("SchemaTable");
610
            var tbl = new DataTable("SchemaTable");

556
      DataTable tblIndexes = null;
611
            DataTable tblIndexes = null;

557
      DataTable tblIndexColumns;
612
            DataTable tblIndexColumns;

558
      DataRow row;
613
            DataRow row;

559
      string temp;
614
            string temp;

560
      string strCatalog = "";
615
            string strCatalog = "";

561
      string strTable = "";
616
            string strTable = "";

562
      string strColumn = "";
617
            string strColumn = "";

563
618
564
      tbl.Locale = CultureInfo.InvariantCulture;
619
            tbl.Locale = CultureInfo.InvariantCulture;

565
      tbl.Columns.Add(SchemaTableColumn.ColumnName, typeof(String));
620
            tbl.Columns.Add(SchemaTableColumn.ColumnName, typeof (String));

566
      tbl.Columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(int));
621
            tbl.Columns.Add(SchemaTableColumn.ColumnOrdinal, typeof (int));

567
      tbl.Columns.Add(SchemaTableColumn.ColumnSize, typeof(int));
622
            tbl.Columns.Add(SchemaTableColumn.ColumnSize, typeof (int));

568
      tbl.Columns.Add(SchemaTableColumn.NumericPrecision, typeof(short));
623
            tbl.Columns.Add(SchemaTableColumn.NumericPrecision, typeof (short));

569
      tbl.Columns.Add(SchemaTableColumn.NumericScale, typeof(short));
624
            tbl.Columns.Add(SchemaTableColumn.NumericScale, typeof (short));

570
      tbl.Columns.Add(SchemaTableColumn.IsUnique, typeof(Boolean));
625
            tbl.Columns.Add(SchemaTableColumn.IsUnique, typeof (Boolean));

571
      tbl.Columns.Add(SchemaTableColumn.IsKey, typeof(Boolean));
626
            tbl.Columns.Add(SchemaTableColumn.IsKey, typeof (Boolean));

572
      tbl.Columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(string));
627
            tbl.Columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof (string));

573
      tbl.Columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(String));
628
            tbl.Columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof (String));

574
      tbl.Columns.Add(SchemaTableColumn.BaseColumnName, typeof(String));
629
            tbl.Columns.Add(SchemaTableColumn.BaseColumnName, typeof (String));

575
      tbl.Columns.Add(SchemaTableColumn.BaseSchemaName, typeof(String));
630
            tbl.Columns.Add(SchemaTableColumn.BaseSchemaName, typeof (String));

576
      tbl.Columns.Add(SchemaTableColumn.BaseTableName, typeof(String));
631
            tbl.Columns.Add(SchemaTableColumn.BaseTableName, typeof (String));

577
      tbl.Columns.Add(SchemaTableColumn.DataType, typeof(Type));
632
            tbl.Columns.Add(SchemaTableColumn.DataType, typeof (Type));

578
      tbl.Columns.Add(SchemaTableColumn.AllowDBNull, typeof(Boolean));
633
            tbl.Columns.Add(SchemaTableColumn.AllowDBNull, typeof (Boolean));

579
      tbl.Columns.Add(SchemaTableColumn.ProviderType, typeof(int));
634
            tbl.Columns.Add(SchemaTableColumn.ProviderType, typeof (int));

580
      tbl.Columns.Add(SchemaTableColumn.IsAliased, typeof(Boolean));
635
            tbl.Columns.Add(SchemaTableColumn.IsAliased, typeof (Boolean));

581
      tbl.Columns.Add(SchemaTableColumn.IsExpression, typeof(Boolean));
636
            tbl.Columns.Add(SchemaTableColumn.IsExpression, typeof (Boolean));

582
      tbl.Columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(Boolean));
637
            tbl.Columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof (Boolean));

583
      tbl.Columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(Boolean));
638
            tbl.Columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof (Boolean));

584
      tbl.Columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(Boolean));
639
            tbl.Columns.Add(SchemaTableOptionalColumn.IsHidden, typeof (Boolean));

585
      tbl.Columns.Add(SchemaTableColumn.IsLong, typeof(Boolean));
640
            tbl.Columns.Add(SchemaTableColumn.IsLong, typeof (Boolean));

586
      tbl.Columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(Boolean));
641
            tbl.Columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof (Boolean));

587
      tbl.Columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(Type));
642
            tbl.Columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof (Type));

588
      tbl.Columns.Add(SchemaTableOptionalColumn.DefaultValue, typeof(object));
643
            tbl.Columns.Add(SchemaTableOptionalColumn.DefaultValue, typeof (object));

589
      tbl.Columns.Add("DataTypeName", typeof(string));
644
            tbl.Columns.Add("DataTypeName", typeof (string));

590
      tbl.Columns.Add("CollationType", typeof(string));
645
            tbl.Columns.Add("CollationType", typeof (string));

591
      tbl.BeginLoadData();
646
            tbl.BeginLoadData();

592
647
593
      for (int n = 0; n < _fieldCount; n++)
648
            for (int n = 0; n < _fieldCount; n++)

594
      {
595
        row = tbl.NewRow();
596
597
        DbType typ = GetSQLiteType(n).Type;
598
599
        // Default settings for the column
600
        row[SchemaTableColumn.ColumnName] = GetName(n);
601
        row[SchemaTableColumn.ColumnOrdinal] = n;
602
        row[SchemaTableColumn.ColumnSize] = SQLiteConvert.DbTypeToColumnSize(typ);
603
        row[SchemaTableColumn.NumericPrecision] = SQLiteConvert.DbTypeToNumericPrecision(typ);
604
        row[SchemaTableColumn.NumericScale] = SQLiteConvert.DbTypeToNumericScale(typ);
605
        row[SchemaTableColumn.ProviderType] = GetSQLiteType(n).Type;
606
        row[SchemaTableColumn.IsLong] = false;
607
        row[SchemaTableColumn.AllowDBNull] = true;
608
        row[SchemaTableOptionalColumn.IsReadOnly] = false;
609
        row[SchemaTableOptionalColumn.IsRowVersion] = false;
610
        row[SchemaTableColumn.IsUnique] = false;
611
        row[SchemaTableColumn.IsKey] = false;
612
        row[SchemaTableOptionalColumn.IsAutoIncrement] = false;
613
        row[SchemaTableColumn.DataType] = GetFieldType(n);
614
        row[SchemaTableOptionalColumn.IsHidden] = false;
615
616
        strColumn = _command.Connection._sql.ColumnOriginalName(_activeStatement, n);
617
        if (String.IsNullOrEmpty(strColumn) == false) row[SchemaTableColumn.BaseColumnName] = strColumn;
618
619
        row[SchemaTableColumn.IsExpression] = String.IsNullOrEmpty(strColumn);
620
        row[SchemaTableColumn.IsAliased] = (String.Compare(GetName(n), strColumn, StringComparison.OrdinalIgnoreCase) != 0);
621
622
        temp = _command.Connection._sql.ColumnTableName(_activeStatement, n);
623
        if (String.IsNullOrEmpty(temp) == false) row[SchemaTableColumn.BaseTableName] = temp;
624
625
        temp = _command.Connection._sql.ColumnDatabaseName(_activeStatement, n);
626
        if (String.IsNullOrEmpty(temp) == false) row[SchemaTableOptionalColumn.BaseCatalogName] = temp;
627
628
        string dataType = null;
629
        // If we have a table-bound column, extract the extra information from it
630
        if (String.IsNullOrEmpty(strColumn) == false)
631
        {
632
          string collSeq;
633
          bool bNotNull;
634
          bool bPrimaryKey;
635
          bool bAutoIncrement;
636
          string[] arSize;
637
638
          // Get the column meta data
639
          _command.Connection._sql.ColumnMetaData(
640
            (string)row[SchemaTableOptionalColumn.BaseCatalogName],
641
            (string)row[SchemaTableColumn.BaseTableName],
642
            strColumn,
643
            out dataType, out collSeq, out bNotNull, out bPrimaryKey, out bAutoIncrement);
644
645
          if (bNotNull || bPrimaryKey) row[SchemaTableColumn.AllowDBNull] = false;
646
647
          row[SchemaTableColumn.IsKey] = bPrimaryKey;
648
          row[SchemaTableOptionalColumn.IsAutoIncrement] = bAutoIncrement;
649
          row["CollationType"] = collSeq;
650
651
          // For types like varchar(50) and such, extract the size
652
          arSize = dataType.Split('(');
653
          if (arSize.Length > 1)
654
          {
655
            dataType = arSize[0];
656
            arSize = arSize[1].Split(')');
657
            if (arSize.Length > 1)
658
            {
649
            {

659
              arSize = arSize[0].Split(',', '.');
650
                row = tbl.NewRow();
660
              if (GetSQLiteType(n).Type == DbType.String || GetSQLiteType(n).Type == DbType.Binary)
651
661
              {
652
                DbType typ = GetSQLiteType(n).Type;
662
                row[SchemaTableColumn.ColumnSize] = Convert.ToInt32(arSize[0], CultureInfo.InvariantCulture);
653
663
              }
654
                // Default settings for the column
664
              else
655
                row[SchemaTableColumn.ColumnName] = GetName(n);
665
              {
656
                row[SchemaTableColumn.ColumnOrdinal] = n;
666
                row[SchemaTableColumn.NumericPrecision] = Convert.ToInt32(arSize[0], CultureInfo.InvariantCulture);
657
                row[SchemaTableColumn.ColumnSize] = SQLiteConvert.DbTypeToColumnSize(typ);
667
                if (arSize.Length > 1)
658
                row[SchemaTableColumn.NumericPrecision] = SQLiteConvert.DbTypeToNumericPrecision(typ);
668
                  row[SchemaTableColumn.NumericScale] = Convert.ToInt32(arSize[1], CultureInfo.InvariantCulture);
659
                row[SchemaTableColumn.NumericScale] = SQLiteConvert.DbTypeToNumericScale(typ);
669
              }
660
                row[SchemaTableColumn.ProviderType] = GetSQLiteType(n).Type;
670
            }
661
                row[SchemaTableColumn.IsLong] = false;
671
          }
662
                row[SchemaTableColumn.AllowDBNull] = true;
672
663
                row[SchemaTableOptionalColumn.IsReadOnly] = false;
673
          if (wantDefaultValue)
664
                row[SchemaTableOptionalColumn.IsRowVersion] = false;
674
          {
665
                row[SchemaTableColumn.IsUnique] = false;
675
            // Determine the default value for the column, which sucks because we have to query the schema for each column
666
                row[SchemaTableColumn.IsKey] = false;
676
            using (SQLiteCommand cmdTable = new SQLiteCommand(String.Format(CultureInfo.InvariantCulture, "PRAGMA [{0}].TABLE_INFO([{1}])",
667
                row[SchemaTableOptionalColumn.IsAutoIncrement] = false;
668
                row[SchemaTableColumn.DataType] = GetFieldType(n);
677
              row[SchemaTableOptionalColumn.BaseCatalogName],
669
                row[SchemaTableOptionalColumn.IsHidden] = false;

670
671
                strColumn = _command.Connection._sql.ColumnOriginalName(_activeStatement, n);
672
                if (String.IsNullOrEmpty(strColumn) == false) row[SchemaTableColumn.BaseColumnName] = strColumn;
673
674
                row[SchemaTableColumn.IsExpression] = String.IsNullOrEmpty(strColumn);
678
              row[SchemaTableColumn.BaseTableName]
675
                row[SchemaTableColumn.IsAliased] =

679
              ), _command.Connection))
676
                    (String.Compare(GetName(n), strColumn, StringComparison.OrdinalIgnoreCase) != 0);
680
            using (DbDataReader rdTable = cmdTable.ExecuteReader())
677
681
            {
678
                temp = _command.Connection._sql.ColumnTableName(_activeStatement, n);
682
              // Find the matching column
679
                if (String.IsNullOrEmpty(temp) == false) row[SchemaTableColumn.BaseTableName] = temp;
683
              while (rdTable.Read())
680
684
              {
681
                temp = _command.Connection._sql.ColumnDatabaseName(_activeStatement, n);
685
                if (String.Compare((string)row[SchemaTableColumn.BaseColumnName], rdTable.GetString(1), StringComparison.OrdinalIgnoreCase) == 0)
682
                if (String.IsNullOrEmpty(temp) == false) row[SchemaTableOptionalColumn.BaseCatalogName] = temp;
683
684
                string dataType = null;
685
                // If we have a table-bound column, extract the extra information from it
686
                if (String.IsNullOrEmpty(strColumn) == false)
686
                {
687
                {

688
                    string collSeq;
689
                    bool bNotNull;
690
                    bool bPrimaryKey;
691
                    bool bAutoIncrement;
692
                    string[] arSize;
693
694
                    // Get the column meta data
695
                    _command.Connection._sql.ColumnMetaData(
696
                        (string) row[SchemaTableOptionalColumn.BaseCatalogName],
697
                        (string) row[SchemaTableColumn.BaseTableName],
698
                        strColumn,
699
                        out dataType, out collSeq, out bNotNull, out bPrimaryKey, out bAutoIncrement);
700
701
                    if (bNotNull || bPrimaryKey) row[SchemaTableColumn.AllowDBNull] = false;
702
703
                    row[SchemaTableColumn.IsKey] = bPrimaryKey;
704
                    row[SchemaTableOptionalColumn.IsAutoIncrement] = bAutoIncrement;
705
                    row["CollationType"] = collSeq;
706
707
                    // For types like varchar(50) and such, extract the size
708
                    arSize = dataType.Split('(');
709
                    if (arSize.Length > 1)
710
                    {
711
                        dataType = arSize[0];
712
                        arSize = arSize[1].Split(')');
713
                        if (arSize.Length > 1)
714
                        {
715
                            arSize = arSize[0].Split(',', '.');
716
                            if (GetSQLiteType(n).Type == DbType.String || GetSQLiteType(n).Type == DbType.Binary)
717
                            {
718
                                row[SchemaTableColumn.ColumnSize] = Convert.ToInt32(arSize[0],
719
                                                                                    CultureInfo.InvariantCulture);
720
                            }
721
                            else
722
                            {
723
                                row[SchemaTableColumn.NumericPrecision] = Convert.ToInt32(arSize[0],
724
                                                                                          CultureInfo.InvariantCulture);
725
                                if (arSize.Length > 1)
726
                                    row[SchemaTableColumn.NumericScale] = Convert.ToInt32(arSize[1],
727
                                                                                          CultureInfo.InvariantCulture);
728
                            }
729
                        }
730
                    }
731
732
                    if (wantDefaultValue)
733
                    {
734
                        // Determine the default value for the column, which sucks because we have to query the schema for each column
735
                        using (
736
                            var cmdTable =
737
                                new SQLiteCommand(
738
                                    String.Format(CultureInfo.InvariantCulture, "PRAGMA [{0}].TABLE_INFO([{1}])",
739
                                                  row[SchemaTableOptionalColumn.BaseCatalogName],
740
                                                  row[SchemaTableColumn.BaseTableName]
741
                                        ), _command.Connection))
742
                        using (DbDataReader rdTable = cmdTable.ExecuteReader())
743
                        {
744
                            // Find the matching column
745
                            while (rdTable.Read())
746
                            {
747
                                if (
748
                                    String.Compare((string) row[SchemaTableColumn.BaseColumnName], rdTable.GetString(1),
749
                                                   StringComparison.OrdinalIgnoreCase) == 0)
750
                                {
687
                  if (rdTable.IsDBNull(4) == false)
751
                                    if (rdTable.IsDBNull(4) == false)

688
                    row[SchemaTableOptionalColumn.DefaultValue] = rdTable[4];
752
                                        row[SchemaTableOptionalColumn.DefaultValue] = rdTable[4];

689
753
754
                                    break;
755
                                }
756
                            }
757
                        }
690
                  break;
758
                    }

759
760
                    // Determine IsUnique properly, which is a pain in the butt!
761
                    if (wantUniqueInfo)
762
                    {
763
                        if ((string) row[SchemaTableOptionalColumn.BaseCatalogName] != strCatalog
764
                            || (string) row[SchemaTableColumn.BaseTableName] != strTable)
765
                        {
766
                            strCatalog = (string) row[SchemaTableOptionalColumn.BaseCatalogName];
767
                            strTable = (string) row[SchemaTableColumn.BaseTableName];
768
769
                            tblIndexes = _command.Connection.GetSchema("Indexes", new[]
770
                                                                                      {
771
                                                                                          (string)
772
                                                                                          row[
773
                                                                                              SchemaTableOptionalColumn.
774
                                                                                                  BaseCatalogName],
775
                                                                                          null,
776
                                                                                          (string)
777
                                                                                          row[
778
                                                                                              SchemaTableColumn.
779
                                                                                                  BaseTableName],
780
                                                                                          null
781
                                                                                      });
782
                        }
783
784
                        foreach (DataRow rowIndexes in tblIndexes.Rows)
785
                        {
786
                            tblIndexColumns = _command.Connection.GetSchema("IndexColumns", new[]
787
                                                                                                {
788
                                                                                                    (string)
789
                                                                                                    row[
790
                                                                                                        SchemaTableOptionalColumn
791
                                                                                                            .
792
                                                                                                            BaseCatalogName
793
                                                                                                        ],
794
                                                                                                    null,
795
                                                                                                    (string)
796
                                                                                                    row[
797
                                                                                                        SchemaTableColumn
798
                                                                                                            .
799
                                                                                                            BaseTableName
800
                                                                                                        ],
801
                                                                                                    (string)
802
                                                                                                    rowIndexes[
803
                                                                                                        "INDEX_NAME"],
804
                                                                                                    null
805
                                                                                                });
806
                            foreach (DataRow rowColumnIndex in tblIndexColumns.Rows)
807
                            {
808
                                if (
809
                                    String.Compare((string) rowColumnIndex["COLUMN_NAME"], strColumn,
810
                                                   StringComparison.OrdinalIgnoreCase) == 0)
811
                                {
812
                                    if (tblIndexColumns.Rows.Count == 1 &&
813
                                        (bool) row[SchemaTableColumn.AllowDBNull] == false)
814
                                        row[SchemaTableColumn.IsUnique] = rowIndexes["UNIQUE"];
815
816
                                    // If its an integer primary key and the only primary key in the table, then its a rowid alias and is autoincrement
817
                                    // NOTE:  Currently commented out because this is not always the desired behavior.  For example, a 1:1 relationship with
818
                                    //        another table, where the other table is autoincrement, but this one is not, and uses the rowid from the other.
819
                                    //        It is safer to only set Autoincrement on tables where we're SURE the user specified AUTOINCREMENT, even if its a rowid column.
820
821
                                    if (tblIndexColumns.Rows.Count == 1 && (bool) rowIndexes["PRIMARY_KEY"] &&
822
                                        String.IsNullOrEmpty(dataType) == false &&
823
                                        String.Compare(dataType, "integer", StringComparison.OrdinalIgnoreCase) == 0)
824
                                    {
825
                                        //  row[SchemaTableOptionalColumn.IsAutoIncrement] = true;
826
                                    }
827
828
                                    break;
829
                                }
830
                            }
831
                        }
832
                    }
833
834
                    if (String.IsNullOrEmpty(dataType))
835
                    {
836
                        TypeAffinity affin;
837
                        dataType = _activeStatement._sql.ColumnType(_activeStatement, n, out affin);
838
                    }
839
840
                    if (String.IsNullOrEmpty(dataType) == false)
841
                        row["DataTypeName"] = dataType;
691
                }
842
                }

692
              }
843
                tbl.Rows.Add(row);
693
            }
844
            }

694
          }
845
695
696
          // Determine IsUnique properly, which is a pain in the butt!
697
          if (wantUniqueInfo)
698
          {
699
            if ((string)row[SchemaTableOptionalColumn.BaseCatalogName] != strCatalog
700
              || (string)row[SchemaTableColumn.BaseTableName] != strTable)
701
            {
702
              strCatalog = (string)row[SchemaTableOptionalColumn.BaseCatalogName];
703
              strTable = (string)row[SchemaTableColumn.BaseTableName];
704
705
              tblIndexes = _command.Connection.GetSchema("Indexes", new string[] {
706
                (string)row[SchemaTableOptionalColumn.BaseCatalogName],
707
                null,
708
                (string)row[SchemaTableColumn.BaseTableName],
709
                null });
710
            }
711
712
            foreach (DataRow rowIndexes in tblIndexes.Rows)
713
            {
714
              tblIndexColumns = _command.Connection.GetSchema("IndexColumns", new string[] {
715
                (string)row[SchemaTableOptionalColumn.BaseCatalogName],
716
                null,
717
                (string)row[SchemaTableColumn.BaseTableName],
718
                (string)rowIndexes["INDEX_NAME"],
719
                null
720
                });
721
              foreach (DataRow rowColumnIndex in tblIndexColumns.Rows)
722
              {
723
                if (String.Compare((string)rowColumnIndex["COLUMN_NAME"], strColumn, StringComparison.OrdinalIgnoreCase) == 0)
724
                {
725
                  if (tblIndexColumns.Rows.Count == 1 && (bool)row[SchemaTableColumn.AllowDBNull] == false)
726
                    row[SchemaTableColumn.IsUnique] = rowIndexes["UNIQUE"];
727
728
                  // If its an integer primary key and the only primary key in the table, then its a rowid alias and is autoincrement
729
                  // NOTE:  Currently commented out because this is not always the desired behavior.  For example, a 1:1 relationship with
730
                  //        another table, where the other table is autoincrement, but this one is not, and uses the rowid from the other.
731
                  //        It is safer to only set Autoincrement on tables where we're SURE the user specified AUTOINCREMENT, even if its a rowid column.
732
733
                  if (tblIndexColumns.Rows.Count == 1 && (bool)rowIndexes["PRIMARY_KEY"] == true && String.IsNullOrEmpty(dataType) == false &&
734
                    String.Compare(dataType, "integer", StringComparison.OrdinalIgnoreCase) == 0)
735
                  {
736
                    //  row[SchemaTableOptionalColumn.IsAutoIncrement] = true;
737
                  }
738
739
                  break;
740
                }
741
              }
742
            }
743
          }
744
745
          if (String.IsNullOrEmpty(dataType))
746
          {
747
            TypeAffinity affin;
748
            dataType = _activeStatement._sql.ColumnType(_activeStatement, n, out affin);
749
          }
750
751
          if (String.IsNullOrEmpty(dataType) == false)
752
            row["DataTypeName"] = dataType;
753
        }
754
        tbl.Rows.Add(row);
755
      }
756
757
      if (_keyInfo != null)
758
        _keyInfo.AppendSchemaTable(tbl);
759
760
      tbl.AcceptChanges();
761
      tbl.EndLoadData();
762
763
      return tbl;
764
    }
765
766
    /// <summary>
767
    /// Retrieves the column as a string
768
    /// </summary>
769
    /// <param name="i">The index of the column to retrieve</param>
770
    /// <returns>string</returns>
771
    public override string GetString(int i)
772
    {
773
      if (i >= VisibleFieldCount && _keyInfo != null)
774
        return _keyInfo.GetString(i - VisibleFieldCount);
775
776
      VerifyType(i, DbType.String);
777
      return _activeStatement._sql.GetText(_activeStatement, i);
778
    }
779
780
    /// <summary>
781
    /// Retrieves the column as an object corresponding to the underlying datatype of the column
782
    /// </summary>
783
    /// <param name="i">The index of the column to retrieve</param>
784
    /// <returns>object</returns>
785
    public override object GetValue(int i)
786
    {
787
      if (i >= VisibleFieldCount && _keyInfo != null)
788
        return _keyInfo.GetValue(i - VisibleFieldCount);
789
790
      SQLiteType typ = GetSQLiteType(i);
791
792
      return _activeStatement._sql.GetValue(_activeStatement, i, typ);
793
    }
794
795
    /// <summary>
796
    /// Retreives the values of multiple columns, up to the size of the supplied array
797
    /// </summary>
798
    /// <param name="values">The array to fill with values from the columns in the current resultset</param>
799
    /// <returns>The number of columns retrieved</returns>
800
    public override int GetValues(object[] values)
801
    {
802
      int nMax = FieldCount;
803
      if (values.Length < nMax) nMax = values.Length;
804
805
      for (int n = 0; n < nMax; n++)
806
      {
807
        values[n] = GetValue(n);
808
      }
809
810
      return nMax;
811
    }
812
813
    /// <summary>
814
    /// Returns True if the resultset has rows that can be fetched
815
    /// </summary>
816
    public override bool HasRows
817
    {
818
      get
819
      {
820
        CheckClosed();
821
        return (_readingState != 1);
822
      }
823
    }
824
825
    /// <summary>
826
    /// Returns True if the data reader is closed
827
    /// </summary>
828
    public override bool IsClosed
829
    {
830
      get { return (_command == null); }
831
    }
832
833
    /// <summary>
834
    /// Returns True if the specified column is null
835
    /// </summary>
836
    /// <param name="i">The index of the column to retrieve</param>
837
    /// <returns>True or False</returns>
838
    public override bool IsDBNull(int i)
839
    {
840
      if (i >= VisibleFieldCount && _keyInfo != null)
841
        return _keyInfo.IsDBNull(i - VisibleFieldCount);
842
843
      return _activeStatement._sql.IsNull(_activeStatement, i);
844
    }
845
846
    /// <summary>
847
    /// Moves to the next resultset in multiple row-returning SQL command.
848
    /// </summary>
849
    /// <returns>True if the command was successful and a new resultset is available, False otherwise.</returns>
850
    public override bool NextResult()
851
    {
852
      CheckClosed();
853
854
      SQLiteStatement stmt = null;
855
      int fieldCount;
856
857
      while (true)
858
      {
859
        if (_activeStatement != null && stmt == null)
860
        {
861
          // Reset the previously-executed statement
862
          _activeStatement._sql.Reset(_activeStatement);
863
864
          // If we're only supposed to return a single rowset, step through all remaining statements once until
865
          // they are all done and return false to indicate no more resultsets exist.
866
          if ((_commandBehavior & CommandBehavior.SingleResult) != 0)
867
          {
868
            for (; ; )
869
            {
870
              stmt = _command.GetStatement(_activeStatementIndex + 1);
871
              if (stmt == null) break;
872
              _activeStatementIndex++;
873
874
              stmt._sql.Step(stmt);
875
              if (stmt._sql.ColumnCount(stmt) == 0)
876
              {
877
                if (_rowsAffected == -1) _rowsAffected = 0;
878
                _rowsAffected += stmt._sql.Changes;
879
              }
880
              stmt._sql.Reset(stmt); // Gotta reset after every step to release any locks and such!
881
            }
882
            return false;
883
          }
884
        }
885
886
        // Get the next statement to execute
887
        stmt = _command.GetStatement(_activeStatementIndex + 1);
888
889
        // If we've reached the end of the statements, return false, no more resultsets
890
        if (stmt == null)
891
          return false;
892
893
        // If we were on a current resultset, set the state to "done reading" for it
894
        if (_readingState < 1)
895
          _readingState = 1;
896
897
        _activeStatementIndex++;
898
899
        fieldCount = stmt._sql.ColumnCount(stmt);
900
901
        // If the statement is not a select statement or we're not retrieving schema only, then perform the initial step
902
        if ((_commandBehavior & CommandBehavior.SchemaOnly) == 0 || fieldCount == 0)
903
        {
904
          if (stmt._sql.Step(stmt))
905
          {
906
            _readingState = -1;
907
          }
908
          else if (fieldCount == 0) // No rows returned, if fieldCount is zero, skip to the next statement
909
          {
910
            if (_rowsAffected == -1) _rowsAffected = 0;
911
            _rowsAffected += stmt._sql.Changes;
912
            stmt._sql.Reset(stmt);
913
            continue; // Skip this command and move to the next, it was not a row-returning resultset
914
          }
915
          else // No rows, fieldCount is non-zero so stop here
916
          {
917
            _readingState = 1; // This command returned columns but no rows, so return true, but HasRows = false and Read() returns false
918
          }
919
        }
920
921
        // Ahh, we found a row-returning resultset eligible to be returned!
922
        _activeStatement = stmt;
923
        _fieldCount = fieldCount;
924
        _fieldTypeArray = null;
925
926
        if ((_commandBehavior & CommandBehavior.KeyInfo) != 0)
927
          LoadKeyInfo();
928
929
        return true;
930
      }
931
    }
932
933
    /// <summary>
934
    /// Retrieves the SQLiteType for a given column, and caches it to avoid repetetive interop calls.
935
    /// </summary>
936
    /// <param name="i">The index of the column to retrieve</param>
937
    /// <returns>A SQLiteType structure</returns>
938
    private SQLiteType GetSQLiteType(int i)
939
    {
940
      SQLiteType typ;
941
942
      // Initialize the field types array if not already initialized
943
      if (_fieldTypeArray == null)
944
        _fieldTypeArray = new SQLiteType[VisibleFieldCount];
945
946
      // Initialize this column's field type instance
947
      if (_fieldTypeArray[i] == null) _fieldTypeArray[i] = new SQLiteType();
948
949
      typ = _fieldTypeArray[i];
950
951
      // If not initialized, then fetch the declared column datatype and attempt to convert it 
952
      // to a known DbType.
953
      if (typ.Affinity == TypeAffinity.Uninitialized)
954
        typ.Type = SQLiteConvert.TypeNameToDbType(_activeStatement._sql.ColumnType(_activeStatement, i, out typ.Affinity));
955
      else
956
        typ.Affinity = _activeStatement._sql.ColumnAffinity(_activeStatement, i);
957
958
      return typ;
959
    }
960
961
    /// <summary>
962
    /// Reads the next row from the resultset
963
    /// </summary>
964
    /// <returns>True if a new row was successfully loaded and is ready for processing</returns>
965
    public override bool Read()
966
    {
967
      CheckClosed();
968
969
      if (_readingState == -1) // First step was already done at the NextResult() level, so don't step again, just return true.
970
      {
971
        _readingState = 0;
972
        return true;
973
      }
974
      else if (_readingState == 0) // Actively reading rows
975
      {
976
        // Don't read a new row if the command behavior dictates SingleRow.  We've already read the first row.
977
        if ((_commandBehavior & CommandBehavior.SingleRow) == 0)
978
        {
979
          if (_activeStatement._sql.Step(_activeStatement) == true)
980
          {
981
            if (_keyInfo != null)
846
            if (_keyInfo != null)

982
              _keyInfo.Reset();
847
                _keyInfo.AppendSchemaTable(tbl);
983
848
849
            tbl.AcceptChanges();
850
            tbl.EndLoadData();
851
984
            return true;
852
            return tbl;

985
          }
986
        }
853
        }

987
854
988
        _readingState = 1; // Finished reading rows
989
      }
990
991
      return false;
992
    }
993
994
    /// <summary>
855
        /// <summary>

995
    /// Retrieve the count of records affected by an update/insert command.  Only valid once the data reader is closed!
856
        /// Retrieves the column as a string
996
    /// </summary>
857
        /// </summary>

997
    public override int RecordsAffected
998
    {
999
      get { return (_rowsAffected < 0) ? 0 : _rowsAffected; }
1000
    }
1001
1002
    /// <summary>
1003
    /// Indexer to retrieve data from a column given its name
1004
    /// </summary>
1005
    /// <param name="name">The name of the column to retrieve data for</param>
1006
    /// <returns>The value contained in the column</returns>
1007
    public override object this[string name]
1008
    {
1009
      get { return GetValue(GetOrdinal(name)); }
1010
    }
1011
1012
    /// <summary>
1013
    /// Indexer to retrieve data from a column given its i
1014
    /// </summary>
1015
    /// <param name="i">The index of the column to retrieve</param>
858
        /// <param name="i">The index of the column to retrieve</param>

1016
    /// <returns>The value contained in the column</returns>
859
        /// <returns>string</returns>
860
        public override string GetString(int i)
861
        {
862
            if (i >= VisibleFieldCount && _keyInfo != null)
863
                return _keyInfo.GetString(i - VisibleFieldCount);
864
865
            VerifyType(i, DbType.String);
866
            return _activeStatement._sql.GetText(_activeStatement, i);
867
        }
868
869
        /// <summary>
870
        /// Retrieves the column as an object corresponding to the underlying datatype of the column
871
        /// </summary>
872
        /// <param name="i">The index of the column to retrieve</param>
873
        /// <returns>object</returns>
1017
    public override object this[int i]
874
        public override object GetValue(int i)

1018
    {
875
        {
1019
      get { return GetValue(i); }
876
            if (i >= VisibleFieldCount && _keyInfo != null)
1020
    }
877
                return _keyInfo.GetValue(i - VisibleFieldCount);
1021
878
879
            SQLiteType typ = GetSQLiteType(i);
880
881
            return _activeStatement._sql.GetValue(_activeStatement, i, typ);
882
        }
883
884
        /// <summary>
885
        /// Retreives the values of multiple columns, up to the size of the supplied array
886
        /// </summary>
887
        /// <param name="values">The array to fill with values from the columns in the current resultset</param>
888
        /// <returns>The number of columns retrieved</returns>
889
        public override int GetValues(object[] values)
890
        {
891
            int nMax = FieldCount;
892
            if (values.Length < nMax) nMax = values.Length;
893
894
            for (int n = 0; n < nMax; n++)
895
            {
896
                values[n] = GetValue(n);
897
            }
898
899
            return nMax;
900
        }
901
902
        /// <summary>
903
        /// Returns True if the specified column is null
904
        /// </summary>
905
        /// <param name="i">The index of the column to retrieve</param>
906
        /// <returns>True or False</returns>
907
        public override bool IsDBNull(int i)
908
        {
909
            if (i >= VisibleFieldCount && _keyInfo != null)
910
                return _keyInfo.IsDBNull(i - VisibleFieldCount);
911
912
            return _activeStatement._sql.IsNull(_activeStatement, i);
913
        }
914
915
        /// <summary>
916
        /// Moves to the next resultset in multiple row-returning SQL command.
917
        /// </summary>
918
        /// <returns>True if the command was successful and a new resultset is available, False otherwise.</returns>
919
        public override bool NextResult()
920
        {
921
            CheckClosed();
922
923
            SQLiteStatement stmt = null;
924
            int fieldCount;
925
926
            while (true)
927
            {
928
                if (_activeStatement != null && stmt == null)
929
                {
930
                    // Reset the previously-executed statement
931
                    _activeStatement._sql.Reset(_activeStatement);
932
933
                    // If we're only supposed to return a single rowset, step through all remaining statements once until
934
                    // they are all done and return false to indicate no more resultsets exist.
935
                    if ((_commandBehavior & CommandBehavior.SingleResult) != 0)
936
                    {
937
                        for (;;)
938
                        {
939
                            stmt = _command.GetStatement(_activeStatementIndex + 1);
940
                            if (stmt == null) break;
941
                            _activeStatementIndex++;
942
943
                            stmt._sql.Step(stmt);
944
                            if (stmt._sql.ColumnCount(stmt) == 0)
945
                            {
946
                                if (_rowsAffected == -1) _rowsAffected = 0;
947
                                _rowsAffected += stmt._sql.Changes;
948
                            }
949
                            stmt._sql.Reset(stmt); // Gotta reset after every step to release any locks and such!
950
                        }
951
                        return false;
952
                    }
953
                }
954
955
                // Get the next statement to execute
956
                stmt = _command.GetStatement(_activeStatementIndex + 1);
957
958
                // If we've reached the end of the statements, return false, no more resultsets
959
                if (stmt == null)
960
                    return false;
961
962
                // If we were on a current resultset, set the state to "done reading" for it
963
                if (_readingState < 1)
964
                    _readingState = 1;
965
966
                _activeStatementIndex++;
967
968
                fieldCount = stmt._sql.ColumnCount(stmt);
969
970
                // If the statement is not a select statement or we're not retrieving schema only, then perform the initial step
971
                if ((_commandBehavior & CommandBehavior.SchemaOnly) == 0 || fieldCount == 0)
972
                {
973
                    if (stmt._sql.Step(stmt))
974
                    {
975
                        _readingState = -1;
976
                    }
977
                    else if (fieldCount == 0) // No rows returned, if fieldCount is zero, skip to the next statement
978
                    {
979
                        if (_rowsAffected == -1) _rowsAffected = 0;
980
                        _rowsAffected += stmt._sql.Changes;
981
                        stmt._sql.Reset(stmt);
982
                        continue; // Skip this command and move to the next, it was not a row-returning resultset
983
                    }
984
                    else // No rows, fieldCount is non-zero so stop here
985
                    {
986
                        _readingState = 1;
987
                            // This command returned columns but no rows, so return true, but HasRows = false and Read() returns false
988
                    }
989
                }
990
991
                // Ahh, we found a row-returning resultset eligible to be returned!
992
                _activeStatement = stmt;
993
                _fieldCount = fieldCount;
994
                _fieldTypeArray = null;
995
996
                if ((_commandBehavior & CommandBehavior.KeyInfo) != 0)
997
                    LoadKeyInfo();
998
999
                return true;
1000
            }
1001
        }
1002
1003
        /// <summary>
1004
        /// Retrieves the SQLiteType for a given column, and caches it to avoid repetetive interop calls.
1005
        /// </summary>
1006
        /// <param name="i">The index of the column to retrieve</param>
1007
        /// <returns>A SQLiteType structure</returns>
1008
        private SQLiteType GetSQLiteType(int i)
1009
        {
1010
            SQLiteType typ;
1011
1012
            // Initialize the field types array if not already initialized
1013
            if (_fieldTypeArray == null)
1014
                _fieldTypeArray = new SQLiteType[VisibleFieldCount];
1015
1016
            // Initialize this column's field type instance
1017
            if (_fieldTypeArray[i] == null) _fieldTypeArray[i] = new SQLiteType();
1018
1019
            typ = _fieldTypeArray[i];
1020
1021
            // If not initialized, then fetch the declared column datatype and attempt to convert it 
1022
            // to a known DbType.
1023
            if (typ.Affinity == TypeAffinity.Uninitialized)
1024
                typ.Type =
1025
                    SQLiteConvert.TypeNameToDbType(_activeStatement._sql.ColumnType(_activeStatement, i,
1026
                                                                                    out typ.Affinity));
1027
            else
1028
                typ.Affinity = _activeStatement._sql.ColumnAffinity(_activeStatement, i);
1029
1030
            return typ;
1031
        }
1032
1033
        /// <summary>
1034
        /// Reads the next row from the resultset
1035
        /// </summary>
1036
        /// <returns>True if a new row was successfully loaded and is ready for processing</returns>
1037
        public override bool Read()
1038
        {
1039
            CheckClosed();
1040
1041
            if (_readingState == -1)
1042
                // First step was already done at the NextResult() level, so don't step again, just return true.
1043
            {
1044
                _readingState = 0;
1045
                return true;
1046
            }
1047
            else if (_readingState == 0) // Actively reading rows
1048
            {
1049
                // Don't read a new row if the command behavior dictates SingleRow.  We've already read the first row.
1050
                if ((_commandBehavior & CommandBehavior.SingleRow) == 0)
1051
                {
1052
                    if (_activeStatement._sql.Step(_activeStatement))
1053
                    {
1054
                        if (_keyInfo != null)
1055
                            _keyInfo.Reset();
1056
1057
                        return true;
1058
                    }
1059
                }
1060
1061
                _readingState = 1; // Finished reading rows
1062
            }
1063
1064
            return false;
1065
        }
1066
1022
    private void LoadKeyInfo()
1067
        private void LoadKeyInfo()

1023
    {
1068
        {
1024
      if (_keyInfo != null)
1069
            if (_keyInfo != null)

1025
        _keyInfo.Dispose();
1070
                _keyInfo.Dispose();

1026
1071
1027
      _keyInfo = new SQLiteKeyReader(_command.Connection, this, _activeStatement);
1072
            _keyInfo = new SQLiteKeyReader(_command.Connection, this, _activeStatement);

1073
        }
1028
    }
1074
    }

1029
  }
1075
}
1030
}

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks