System.Data.SQLite

Login
This project makes use of Eagle, provided by Mistachkin Systems.
Eagle: Secure Software Automation

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch customDataTypes Excluding Merge-Ins

This is equivalent to a diff from f1e6c7c76b to 3ab3245ae4

2016-06-20
20:50
Make it possible to customize the bound parameter and data reader value handling on a per-connection, per-database type name basis. check-in: 599dfac7d8 user: mistachkin tags: trunk
20:45
Pickup the SQLite core library 3.13 docs from upstream. check-in: 34d41e04cf user: mistachkin tags: trunk
20:35
Fix compilation with the .NET Compact Framework. Closed-Leaf check-in: 3ab3245ae4 user: mistachkin tags: customDataTypes
20:30
Reorganize the new connection flags. check-in: d1e833bf59 user: mistachkin tags: customDataTypes
2016-06-19
06:44
Merge updates from trunk. check-in: 16ef12980e user: mistachkin tags: customDataTypes
06:42
Fix some test constraints. check-in: f1e6c7c76b user: mistachkin tags: trunk
2016-06-18
21:34
Add IsReadOnly method to the SQLiteConnection class. check-in: c4f8b9e65b user: mistachkin tags: trunk

Changes to Doc/Extra/Provider/version.html.

44
45
46
47
48
49
50


51
52
53
54
55
56
57
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59







+
+







    <div id="mainBody">
    <h1 class="heading">Version History</h1>
    <p><b>1.0.102.0 - June XX, 2016 <font color="red">(release scheduled)</font></b></p>
    <ul>
      <li>Updated to <a href="https://www.sqlite.org/releaselog/3_13_0.html">SQLite 3.13.0</a>.</li>
      <li>Update the SQLiteConnection.EnableExtensions method to make use of the new SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION option, when available.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>Prevent the SQLiteCommand.ExecuteScalar method from throwing an exception when there are no result columns.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>Support per-connection customization for binding parameters and reading values, based on the database type name.</li>
      <li>Add TypeName property to the SQLiteParameter class.</li>
      <li>Add VerifyOnly method to the SQLiteCommand class.</li>
      <li>Add IsReadOnly method to the SQLiteConnection class.</li>
    </ul>
    <p><b>1.0.101.0 - April 19, 2016</b></p>
    <ul>
      <li>Updated to <a href="https://www.sqlite.org/releaselog/3_12_2.html">SQLite 3.12.2</a>.</li>
      <li>Add binary package release for Mono on POSIX.</li>

Changes to Setup/data/verify.lst.

846
847
848
849
850
851
852

853
854
855
856
857
858
859
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860







+







  Tests/tkt-e1b2e0f769.eagle
  Tests/tkt-e30b820248.eagle
  Tests/tkt-e47b3d8346.eagle
  Tests/tkt-ef2216192d.eagle
  Tests/tkt-f2c47a01eb.eagle
  Tests/tkt-f8dbab8baf.eagle
  Tests/tkt-fe50b8c2e8.eagle
  Tests/types.eagle
  Tests/version.eagle
  Tests/vtab.eagle
  tools/
  tools/install/
  tools/install/Installer.2005.csproj
  tools/install/Installer.2008.csproj
  tools/install/Installer.2010.csproj

Changes to System.Data.SQLite/SQLiteBase.cs.

1156
1157
1158
1159
1160
1161
1162































1163
1164
1165
1166
1167
1168
1169
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








      /// <summary>
      /// When returning column values as a <see cref="String" />, skip
      /// verifying their affinity.
      /// </summary>
      NoVerifyTextAffinity = 0x200000000,

      /// <summary>
      /// Enable using per-connection mappings between type names and
      /// <see cref="SQLiteBindValueCallback" /> values.  Also see the
      /// <see cref="SQLiteConnection.ClearTypeCallbacks" />,
      /// <see cref="SQLiteConnection.TryGetTypeCallbacks" />, and
      /// <see cref="SQLiteConnection.SetTypeCallbacks" /> methods.
      /// </summary>
      UseConnectionBindValueCallbacks = 0x400000000,

      /// <summary>
      /// Enable using per-connection mappings between type names and
      /// <see cref="SQLiteReadValueCallback" /> values.  Also see the
      /// <see cref="SQLiteConnection.ClearTypeCallbacks" />,
      /// <see cref="SQLiteConnection.TryGetTypeCallbacks" />, and
      /// <see cref="SQLiteConnection.SetTypeCallbacks" /> methods.
      /// </summary>
      UseConnectionReadValueCallbacks = 0x800000000,

      /// <summary>
      /// If the database type name has not been explicitly set for the
      /// parameter specified, fallback to using the parameter name.
      /// </summary>
      UseParameterNameForTypeName = 0x1000000000,

      /// <summary>
      /// If the database type name has not been explicitly set for the
      /// parameter specified, fallback to using the database type name
      /// associated with the <see cref="DbType" /> value.
      /// </summary>
      UseParameterDbTypeForTypeName = 0x2000000000,

      /// <summary>
      /// When binding parameter values or returning column values, always
      /// treat them as though they were plain text (i.e. no numeric,
      /// date/time, or other conversions should be attempted).
      /// </summary>
      BindAndGetAllAsText = BindAllAsText | GetAllAsText,

1187
1188
1189
1190
1191
1192
1193













1194
1195
1196
1197
1198
1199
1200
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244







+
+
+
+
+
+
+
+
+
+
+
+
+







      /// date/time, or other conversions should be attempted) and always
      /// use the invariant culture when converting their values to strings
      /// or from strings.
      /// </summary>
      ConvertAndBindAndGetAllAsInvariantText = BindAndGetAllAsText |
                                               ConvertAndBindInvariantText,

      /// <summary>
      /// Enables use of all per-connection value handling callbacks.
      /// </summary>
      UseConnectionAllValueCallbacks = UseConnectionBindValueCallbacks |
                                       UseConnectionReadValueCallbacks,

      /// <summary>
      /// Enables use of all applicable <see cref="SQLiteParameter" />
      /// properties as fallbacks for the database type name.
      /// </summary>
      UseParameterAnythingForTypeName = UseParameterNameForTypeName |
                                        UseParameterDbTypeForTypeName,

      /// <summary>
      /// Enable all logging.
      /// </summary>
#if INTEROP_VIRTUAL_TABLE
      LogAll = LogPrepare | LogPreBind | LogBind |
               LogCallbackException | LogBackup | LogModuleError |
               LogModuleException,

Changes to System.Data.SQLite/SQLiteConnection.cs.

17
18
19
20
21
22
23







































































































































































































































































































































































































































































































































































































































































































































24
25
26
27
28
29
30
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







  using System.Reflection;
  using System.Runtime.InteropServices;
  using System.IO;
  using System.Text;

  /////////////////////////////////////////////////////////////////////////////////////////////////

  /// <summary>
  /// This class represents a single value to be returned
  /// from the <see cref="SQLiteDataReader" /> class via
  /// its <see cref="SQLiteDataReader.GetBoolean" />,
  /// <see cref="SQLiteDataReader.GetByte" />,
  /// <see cref="SQLiteDataReader.GetBytes" />,
  /// <see cref="SQLiteDataReader.GetChar" />,
  /// <see cref="SQLiteDataReader.GetChars" />,
  /// <see cref="SQLiteDataReader.GetDateTime" />,
  /// <see cref="SQLiteDataReader.GetDecimal" />,
  /// <see cref="SQLiteDataReader.GetDouble" />,
  /// <see cref="SQLiteDataReader.GetFloat" />,
  /// <see cref="SQLiteDataReader.GetGuid" />,
  /// <see cref="SQLiteDataReader.GetInt16" />,
  /// <see cref="SQLiteDataReader.GetInt32" />,
  /// <see cref="SQLiteDataReader.GetInt64" />,
  /// <see cref="SQLiteDataReader.GetString" />, or
  /// <see cref="SQLiteDataReader.GetValue" /> method.  If the value of the
  /// associated public field of this class is null upon returning from the
  /// callback, the null value will only be used if the return type for the
  /// <see cref="SQLiteDataReader" /> method called is not a value type.
  /// If the value to be returned from the <see cref="SQLiteDataReader" />
  /// method is unsuitable (e.g. null with a value type), an exception will
  /// be thrown.
  /// </summary>
  public sealed class SQLiteDataReaderValue
  {
      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetBoolean" /> method -OR- null to
      /// indicate an error.
      /// </summary>
      public bool? BooleanValue;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetByte" /> method -OR- null to
      /// indicate an error.
      /// </summary>
      public byte? ByteValue;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetBytes" /> method.
      /// </summary>
      public byte[] BytesValue;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetChar" /> method -OR- null to
      /// indicate an error.
      /// </summary>
      public char? CharValue;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetChars" /> method.
      /// </summary>
      public char[] CharsValue;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetDateTime" /> method -OR- null to
      /// indicate an error.
      /// </summary>
      public DateTime? DateTimeValue;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetDecimal" /> method -OR- null to
      /// indicate an error.
      /// </summary>
      public decimal? DecimalValue;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetDouble" /> method -OR- null to
      /// indicate an error.
      /// </summary>
      public double? DoubleValue;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetFloat" /> method -OR- null to
      /// indicate an error.
      /// </summary>
      public float? FloatValue;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetGuid" /> method -OR- null to
      /// indicate an error.
      /// </summary>
      public Guid? GuidValue;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetInt16" /> method -OR- null to
      /// indicate an error.
      /// </summary>
      public short? Int16Value;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetInt32" /> method -OR- null to
      /// indicate an error.
      /// </summary>
      public int? Int32Value;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetInt64" /> method -OR- null to
      /// indicate an error.
      /// </summary>
      public long? Int64Value;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetString" /> method.
      /// </summary>
      public string StringValue;

      /// <summary>
      /// The value to be returned from the
      /// <see cref="SQLiteDataReader.GetValue" /> method.
      /// </summary>
      public object Value;
  }

  /////////////////////////////////////////////////////////////////////////////////////////////////

  /// <summary>
  /// This class represents the parameters that are provided
  /// to the <see cref="SQLiteDataReader.GetBytes" /> and
  /// <see cref="SQLiteDataReader.GetChars" /> methods, with
  /// the exception of the column index (provided separately).
  /// </summary>
  public class SQLiteReadArrayEventArgs : EventArgs
  {
      #region Private Data
      /// <summary>
      /// Provides the underlying storage for the
      /// <see cref="DataOffset" /> property.
      /// </summary>
      private long dataOffset;

      /// <summary>
      /// Provides the underlying storage for the
      /// <see cref="ByteBuffer" /> property.
      /// </summary>
      private byte[] byteBuffer;

      /// <summary>
      /// Provides the underlying storage for the
      /// <see cref="CharBuffer" /> property.
      /// </summary>
      private char[] charBuffer;

      /// <summary>
      /// Provides the underlying storage for the
      /// <see cref="BufferOffset" /> property.
      /// </summary>
      private int bufferOffset;

      /// <summary>
      /// Provides the underlying storage for the
      /// <see cref="Length" /> property.
      /// </summary>
      private int length;
      #endregion

      /////////////////////////////////////////////////////////////////////////

      #region Private Constructors
      /// <summary>
      /// Constructs an instance of this class to pass into a user-defined
      /// callback associated with the <see cref="SQLiteDataReader.GetBytes" />
      /// method.
      /// </summary>
      /// <param name="dataOffset">
      /// The value that was originally specified for the "dataOffset"
      /// parameter to the <see cref="SQLiteDataReader.GetBytes" /> or
      /// <see cref="SQLiteDataReader.GetChars" /> methods.
      /// </param>
      /// <param name="byteBuffer">
      /// The value that was originally specified for the "buffer"
      /// parameter to the <see cref="SQLiteDataReader.GetBytes" />
      /// method.
      /// </param>
      /// <param name="bufferOffset">
      /// The value that was originally specified for the "bufferOffset"
      /// parameter to the <see cref="SQLiteDataReader.GetBytes" /> or
      /// <see cref="SQLiteDataReader.GetChars" /> methods.
      /// </param>
      /// <param name="length">
      /// The value that was originally specified for the "length"
      /// parameter to the <see cref="SQLiteDataReader.GetBytes" /> or
      /// <see cref="SQLiteDataReader.GetChars" /> methods.
      /// </param>
      internal SQLiteReadArrayEventArgs(
          long dataOffset,
          byte[] byteBuffer,
          int bufferOffset,
          int length
          )
      {
          this.dataOffset = dataOffset;
          this.byteBuffer = byteBuffer;
          this.bufferOffset = bufferOffset;
          this.length = length;
      }

      /////////////////////////////////////////////////////////////////////////

      /// <summary>
      /// Constructs an instance of this class to pass into a user-defined
      /// callback associated with the <see cref="SQLiteDataReader.GetChars" />
      /// method.
      /// </summary>
      /// <param name="dataOffset">
      /// The value that was originally specified for the "dataOffset"
      /// parameter to the <see cref="SQLiteDataReader.GetBytes" /> or
      /// <see cref="SQLiteDataReader.GetChars" /> methods.
      /// </param>
      /// <param name="charBuffer">
      /// The value that was originally specified for the "buffer"
      /// parameter to the <see cref="SQLiteDataReader.GetChars" />
      /// method.
      /// </param>
      /// <param name="bufferOffset">
      /// The value that was originally specified for the "bufferOffset"
      /// parameter to the <see cref="SQLiteDataReader.GetBytes" /> or
      /// <see cref="SQLiteDataReader.GetChars" /> methods.
      /// </param>
      /// <param name="length">
      /// The value that was originally specified for the "length"
      /// parameter to the <see cref="SQLiteDataReader.GetBytes" /> or
      /// <see cref="SQLiteDataReader.GetChars" /> methods.
      /// </param>
      internal SQLiteReadArrayEventArgs(
          long dataOffset,
          char[] charBuffer,
          int bufferOffset,
          int length
          )
      {
          this.dataOffset = dataOffset;
          this.charBuffer = charBuffer;
          this.bufferOffset = bufferOffset;
          this.length = length;
      }
      #endregion

      /////////////////////////////////////////////////////////////////////////

      #region Public Properties
      /// <summary>
      /// The value that was originally specified for the "dataOffset"
      /// parameter to the <see cref="SQLiteDataReader.GetBytes" /> or
      /// <see cref="SQLiteDataReader.GetChars" /> methods.
      /// </summary>
      public long DataOffset
      {
          get { return dataOffset; }
          set { dataOffset = value; }
      }

      /////////////////////////////////////////////////////////////////////////

      /// <summary>
      /// The value that was originally specified for the "buffer"
      /// parameter to the <see cref="SQLiteDataReader.GetBytes" />
      /// method.
      /// </summary>
      public byte[] ByteBuffer
      {
          get { return byteBuffer; }
      }

      /////////////////////////////////////////////////////////////////////////

      /// <summary>
      /// The value that was originally specified for the "buffer"
      /// parameter to the <see cref="SQLiteDataReader.GetChars" />
      /// method.
      /// </summary>
      public char[] CharBuffer
      {
          get { return charBuffer; }
      }

      /////////////////////////////////////////////////////////////////////////

      /// <summary>
      /// The value that was originally specified for the "bufferOffset"
      /// parameter to the <see cref="SQLiteDataReader.GetBytes" /> or
      /// <see cref="SQLiteDataReader.GetChars" /> methods.
      /// </summary>
      public int BufferOffset
      {
          get { return bufferOffset; }
          set { bufferOffset = value; }
      }

      /////////////////////////////////////////////////////////////////////////

      /// <summary>
      /// The value that was originally specified for the "length"
      /// parameter to the <see cref="SQLiteDataReader.GetBytes" /> or
      /// <see cref="SQLiteDataReader.GetChars" /> methods.
      /// </summary>
      public int Length
      {
          get { return length; }
          set { length = value; }
      }
      #endregion
  }

  /////////////////////////////////////////////////////////////////////////////////////////////////

  /// <summary>
  /// This class represents the parameters and return values for the
  /// <see cref="SQLiteDataReader.GetBoolean" />,
  /// <see cref="SQLiteDataReader.GetByte" />,
  /// <see cref="SQLiteDataReader.GetBytes" />,
  /// <see cref="SQLiteDataReader.GetChar" />,
  /// <see cref="SQLiteDataReader.GetChars" />,
  /// <see cref="SQLiteDataReader.GetDateTime" />,
  /// <see cref="SQLiteDataReader.GetDecimal" />,
  /// <see cref="SQLiteDataReader.GetDouble" />,
  /// <see cref="SQLiteDataReader.GetFloat" />,
  /// <see cref="SQLiteDataReader.GetGuid" />,
  /// <see cref="SQLiteDataReader.GetInt16" />,
  /// <see cref="SQLiteDataReader.GetInt32" />,
  /// <see cref="SQLiteDataReader.GetInt64" />,
  /// <see cref="SQLiteDataReader.GetString" />, and
  /// <see cref="SQLiteDataReader.GetValue" /> methods.
  /// </summary>
  public class SQLiteReadValueEventArgs : EventArgs
  {
      #region Private Data
      /// <summary>
      /// Provides the underlying storage for the
      /// <see cref="MethodName" /> property.
      /// </summary>
      private string methodName;

      /// <summary>
      /// Provides the underlying storage for the
      /// <see cref="ArrayEventArgs" /> property.
      /// </summary>
      private SQLiteReadArrayEventArgs arrayEventArgs;

      /// <summary>
      /// Provides the underlying storage for the
      /// <see cref="Value" /> property.
      /// </summary>
      private SQLiteDataReaderValue value;
      #endregion

      /////////////////////////////////////////////////////////////////////////

      #region Private Constructors
      /// <summary>
      /// Constructs a new instance of this class.  Depending on the method
      /// being called, the <paramref name="arrayEventArgs" /> and/or
      /// <paramref name="value" /> parameters may be null.
      /// </summary>
      /// <param name="methodName">
      /// The name of the <see cref="SQLiteDataReader" /> method that was
      /// responsible for invoking this callback.
      /// </param>
      /// <param name="arrayEventArgs">
      /// If the <see cref="SQLiteDataReader.GetBytes" /> or
      /// <see cref="SQLiteDataReader.GetChars" /> method is being called,
      /// this object will contain the array related parameters for that
      /// method.
      /// </param>
      /// <param name="value">
      /// This may be used by the callback to set the return value for the
      /// called <see cref="SQLiteDataReader" /> method.
      /// </param>
      internal SQLiteReadValueEventArgs(
          string methodName,
          SQLiteReadArrayEventArgs arrayEventArgs,
          SQLiteDataReaderValue value
          )
      {
          this.methodName = methodName;
          this.arrayEventArgs = arrayEventArgs;
          this.value = value;
      }
      #endregion

      /////////////////////////////////////////////////////////////////////////

      #region Public Properties
      /// <summary>
      /// The name of the <see cref="SQLiteDataReader" /> method that was
      /// responsible for invoking this callback.
      /// </summary>
      public string MethodName
      {
          get { return methodName; }
      }

      /////////////////////////////////////////////////////////////////////////

      /// <summary>
      /// If the <see cref="SQLiteDataReader.GetBytes" /> or
      /// <see cref="SQLiteDataReader.GetChars" /> method is being called,
      /// this object will contain the array related parameters for that
      /// method.
      /// </summary>
      public SQLiteReadArrayEventArgs ArrayEventArgs
      {
          get { return arrayEventArgs; }
      }

      /////////////////////////////////////////////////////////////////////////

      /// <summary>
      /// This may be used by the callback to set the return value for the
      /// called <see cref="SQLiteDataReader" /> method.
      /// </summary>
      public SQLiteDataReaderValue Value
      {
          get { return value; }
      }
      #endregion
  }

  /////////////////////////////////////////////////////////////////////////////////////////////////

  /// <summary>
  /// This represents a method that will be called in response to a request to
  /// bind a parameter to a command.  If an exception is thrown, it will cause
  /// the parameter binding operation to fail -AND- it will continue to unwind
  /// the call stack.
  /// </summary>
  /// <param name="convert">
  /// The <see cref="SQLiteConvert" /> instance in use.
  /// </param>
  /// <param name="command">
  /// The <see cref="SQLiteCommand" /> instance in use.
  /// </param>
  /// <param name="flags">
  /// The flags associated with the <see cref="SQLiteConnection" /> instance
  /// in use.
  /// </param>
  /// <param name="parameter">
  /// The <see cref="SQLiteParameter" /> instance being bound to the command.
  /// </param>
  /// <param name="typeName">
  /// The database type name associated with this callback.
  /// </param>
  /// <param name="index">
  /// The ordinal of the parameter being bound to the command.
  /// </param>
  /// <param name="userData">
  /// The data originally used when registering this callback.
  /// </param>
  /// <param name="complete">
  /// Non-zero if the default handling for the parameter binding call should
  /// be skipped (i.e. the parameter should not be bound at all).  Great care
  /// should be used when setting this to non-zero.
  /// </param>
  public delegate void SQLiteBindValueCallback(
      SQLiteConvert convert,
      SQLiteCommand command,
      SQLiteConnectionFlags flags,
      SQLiteParameter parameter,
      string typeName,
      int index,
      object userData,
      out bool complete
  );

  /////////////////////////////////////////////////////////////////////////////////////////////////

  /// <summary>
  /// This represents a method that will be called in response to a request
  /// to read a value from a data reader.  If an exception is thrown, it will
  /// cause the data reader operation to fail -AND- it will continue to unwind
  /// the call stack.
  /// </summary>
  /// <param name="convert">
  /// The <see cref="SQLiteConvert" /> instance in use.
  /// </param>
  /// <param name="dataReader">
  /// The <see cref="SQLiteDataReader" /> instance in use.
  /// </param>
  /// <param name="flags">
  /// The flags associated with the <see cref="SQLiteConnection" /> instance
  /// in use.
  /// </param>
  /// <param name="eventArgs">
  /// The parameter and return type data for the column being read from the
  /// data reader.
  /// </param>
  /// <param name="typeName">
  /// The database type name associated with this callback.
  /// </param>
  /// <param name="index">
  /// The zero based index of the column being read from the data reader.
  /// </param>
  /// <param name="userData">
  /// The data originally used when registering this callback.
  /// </param>
  /// <param name="complete">
  /// Non-zero if the default handling for the data reader call should be
  /// skipped.  If this is set to non-zero and the necessary return value
  /// is unavailable or unsuitable, an exception will be thrown.
  /// </param>
  public delegate void SQLiteReadValueCallback(
      SQLiteConvert convert,
      SQLiteDataReader dataReader,
      SQLiteConnectionFlags flags,
      SQLiteReadValueEventArgs eventArgs,
      string typeName,
      int index,
      object userData,
      out bool complete
  );

  /////////////////////////////////////////////////////////////////////////////////////////////////

  /// <summary>
  /// This class represents the custom data type handling callbacks
  /// for a single type name.
  /// </summary>
  public sealed class SQLiteTypeCallbacks
  {
      #region Private Data
      /// <summary>
      /// Provides the underlying storage for the
      /// <see cref="TypeName" /> property.
      /// </summary>
      private string typeName;

      /// <summary>
      /// Provides the underlying storage for the
      /// <see cref="BindValueCallback" /> property.
      /// </summary>
      private SQLiteBindValueCallback bindValueCallback;

      /// <summary>
      /// Provides the underlying storage for the
      /// <see cref="ReadValueCallback" /> property.
      /// </summary>
      private SQLiteReadValueCallback readValueCallback;

      /// <summary>
      /// Provides the underlying storage for the
      /// <see cref="BindValueUserData" /> property.
      /// </summary>
      private object bindValueUserData;

      /// <summary>
      /// Provides the underlying storage for the
      /// <see cref="ReadValueUserData" /> property.
      /// </summary>
      private object readValueUserData;
      #endregion

      /////////////////////////////////////////////////////////////////////////

      #region Private Constructors
      /// <summary>
      /// Constructs an instance of this class.
      /// </summary>
      /// <param name="bindValueCallback">
      /// The custom paramater binding callback.  This parameter may be null.
      /// </param>
      /// <param name="readValueCallback">
      /// The custom data reader value callback.  This parameter may be null.
      /// </param>
      /// <param name="bindValueUserData">
      /// The extra data to pass into the parameter binding callback.  This
      /// parameter may be null.
      /// </param>
      /// <param name="readValueUserData">
      /// The extra data to pass into the data reader value callback.  This
      /// parameter may be null.
      /// </param>
      private SQLiteTypeCallbacks(
          SQLiteBindValueCallback bindValueCallback,
          SQLiteReadValueCallback readValueCallback,
          object bindValueUserData,
          object readValueUserData
          )
      {
          this.bindValueCallback = bindValueCallback;
          this.readValueCallback = readValueCallback;
          this.bindValueUserData = bindValueUserData;
          this.readValueUserData = readValueUserData;
      }
      #endregion

      /////////////////////////////////////////////////////////////////////////

      #region Static "Factory" Methods
      /// <summary>
      /// Creates an instance of the <see cref="SQLiteTypeCallbacks" /> class.
      /// </summary>
      /// <param name="bindValueCallback">
      /// The custom paramater binding callback.  This parameter may be null.
      /// </param>
      /// <param name="readValueCallback">
      /// The custom data reader value callback.  This parameter may be null.
      /// </param>
      /// <param name="bindValueUserData">
      /// The extra data to pass into the parameter binding callback.  This
      /// parameter may be null.
      /// </param>
      /// <param name="readValueUserData">
      /// The extra data to pass into the data reader value callback.  This
      /// parameter may be null.
      /// </param>
      public static SQLiteTypeCallbacks Create(
          SQLiteBindValueCallback bindValueCallback,
          SQLiteReadValueCallback readValueCallback,
          object bindValueUserData,
          object readValueUserData
          )
      {
          return new SQLiteTypeCallbacks(
              bindValueCallback, readValueCallback, bindValueUserData,
              readValueUserData);
      }
      #endregion

      /////////////////////////////////////////////////////////////////////////

      #region Public Properties
      /// <summary>
      /// The database type name that the callbacks contained in this class
      /// will apply to.  This value may not be null.
      /// </summary>
      public string TypeName
      {
          get { return typeName; }
          internal set { typeName = value; }
      }

      /////////////////////////////////////////////////////////////////////////

      /// <summary>
      /// The custom paramater binding callback.  This value may be null.
      /// </summary>
      public SQLiteBindValueCallback BindValueCallback
      {
          get { return bindValueCallback; }
      }

      /////////////////////////////////////////////////////////////////////////

      /// <summary>
      /// The custom data reader value callback.  This value may be null.
      /// </summary>
      public SQLiteReadValueCallback ReadValueCallback
      {
          get { return readValueCallback; }
      }

      /////////////////////////////////////////////////////////////////////////

      /// <summary>
      /// The extra data to pass into the parameter binding callback.  This
      /// value may be null.
      /// </summary>
      public object BindValueUserData
      {
          get { return bindValueUserData; }
      }

      /////////////////////////////////////////////////////////////////////////

      /// <summary>
      /// The extra data to pass into the data reader value callback.  This
      /// value may be null.
      /// </summary>
      public object ReadValueUserData
      {
          get { return readValueUserData; }
      }
      #endregion
  }

  /////////////////////////////////////////////////////////////////////////////////////////////////

  /// <summary>
  /// This class represents the mappings between database type names
  /// and their associated custom data type handling callbacks.
  /// </summary>
  internal sealed class SQLiteTypeCallbacksMap
      : Dictionary<string, SQLiteTypeCallbacks>
  {
      /// <summary>
      /// Constructs an (empty) instance of this class.
      /// </summary>
      public SQLiteTypeCallbacksMap()
          : base(new TypeNameStringComparer())
      {
          // do nothing.
      }
  }

  /////////////////////////////////////////////////////////////////////////////////////////////////

  /// <summary>
  /// Event data for connection event handlers.
  /// </summary>
  public class ConnectionEventArgs : EventArgs
  {
      /// <summary>
      /// The type of event being raised.
674
675
676
677
678
679
680






681
682
683
684
685
686
687
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404







+
+
+
+
+
+








    /// <summary>
    /// The per-connection mappings between type names and <see cref="DbType" />
    /// values.  These mappings override the corresponding global mappings.
    /// </summary>
    internal SQLiteDbTypeMap _typeNames;

    /// <summary>
    /// The per-connection mappings between type names and optional callbacks
    /// for parameter binding and value reading.
    /// </summary>
    private SQLiteTypeCallbacksMap _typeCallbacks;

    /// <summary>
    /// The base SQLite object to interop with
    /// </summary>
    internal SQLiteBase _sql;
    /// <summary>
    /// The database filename minus path and extension
    /// </summary>
898
899
900
901
902
903
904

905
906
907
908
909
910
911
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629







+







      }
#endif

      _cachedSettings = new Dictionary<string, object>(
          new TypeNameStringComparer());

      _typeNames = new SQLiteDbTypeMap();
      _typeCallbacks = new SQLiteTypeCallbacksMap();
      _parseViaFramework = parseViaFramework;
      _flags = SQLiteConnectionFlags.None;
      _defaultDbType = null;
      _defaultTypeName = null;
      _vfsName = null;
      _connectionState = ConnectionState.Closed;
      _connectionString = null;
1380
1381
1382
1383
1384
1385
1386
































































































1387
1388
1389
1390
1391
1392
1393
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








            _typeNames.Add(new SQLiteDbTypeMapping(typeName, dataType, primary));
        }

        return result;
    }
    #endregion

    ///////////////////////////////////////////////////////////////////////////////////////////////

    #region Per-Connection Type Callbacks
    /// <summary>
    /// Clears the per-connection type callbacks.
    /// </summary>
    /// <returns>
    /// The total number of per-connection type callbacks cleared.
    /// </returns>
    public int ClearTypeCallbacks()
    {
        CheckDisposed();

        int result = -1; /* NO CALLBACKS */

        if (_typeCallbacks != null)
        {
            result = _typeCallbacks.Count;
            _typeCallbacks.Clear();
        }

        return result;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Attempts to get the per-connection type callbacks for the specified
    /// database type name.
    /// </summary>
    /// <param name="typeName">
    /// The database type name.
    /// </param>
    /// <param name="callbacks">
    /// Upon success, this parameter will contain the object holding the
    /// callbacks for the database type name.  Upon failure, this parameter
    /// will be null.
    /// </param>
    /// <returns>
    /// Non-zero upon success; otherwise, zero.
    /// </returns>
    public bool TryGetTypeCallbacks(
        string typeName,
        out SQLiteTypeCallbacks callbacks
        )
    {
        if (typeName == null)
            throw new ArgumentNullException("typeName");

        if (_typeCallbacks == null)
        {
            callbacks = null;
            return false;
        }

        return _typeCallbacks.TryGetValue(typeName, out callbacks);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Sets, resets, or clears the per-connection type callbacks for the
    /// specified database type name.
    /// </summary>
    /// <param name="typeName">
    /// The database type name.
    /// </param>
    /// <param name="callbacks">
    /// The object holding the callbacks for the database type name.  If
    /// this parameter is null, any callbacks for the database type name
    /// will be removed if they are present.
    /// </param>
    /// <returns>
    /// Non-zero if callbacks were set or removed; otherwise, zero.
    /// </returns>
    public bool SetTypeCallbacks(
        string typeName,
        SQLiteTypeCallbacks callbacks
        )
    {
        if (typeName == null)
            throw new ArgumentNullException("typeName");

        if (_typeCallbacks == null)
            return false;

        if (callbacks == null)
            return _typeCallbacks.Remove(typeName);

        callbacks.TypeName = typeName;
        _typeCallbacks[typeName] = callbacks;

        return true;
    }
    #endregion

    ///////////////////////////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Attempts to bind the specified <see cref="SQLiteFunction" /> object
    /// instance to this connection.
    /// </summary>

Changes to System.Data.SQLite/SQLiteDataReader.cs.

424
425
426
427
428
429
430
431
432































































433
434
435
436
437
438
439
440

















441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457

















458
459
460
461
462
463
464
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561









+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







                if (typ == DbType.Binary) return affinity;
                if (typ == DbType.String) return affinity;
                break;
        }

        throw new InvalidCastException();
    }

    /// <summary>
    /// Invokes the data reader value callback configured for the database
    /// type name associated with the specified column.  If no data reader
    /// value callback is available for the database type name, do nothing.
    /// </summary>
    /// <param name="index">
    /// The index of the column being read.
    /// </param>
    /// <param name="eventArgs">
    /// The extra event data to pass into the callback.
    /// </param>
    /// <param name="complete">
    /// Non-zero if the default handling for the data reader call should be
    /// skipped.  If this is set to non-zero and the necessary return value
    /// is unavailable or unsuitable, an exception will be thrown.
    /// </param>
    private void InvokeReadValueCallback(
        int index,
        SQLiteReadValueEventArgs eventArgs,
        out bool complete
        )
    {
        complete = false;
        SQLiteConnectionFlags oldFlags = _flags;
        _flags &= ~SQLiteConnectionFlags.UseConnectionReadValueCallbacks;

        try
        {
            string typeName = GetDataTypeName(index);

            if (typeName == null)
                return;

            SQLiteConnection connection = GetConnection(this);

            if (connection == null)
                return;

            SQLiteTypeCallbacks callbacks;

            if (!connection.TryGetTypeCallbacks(typeName, out callbacks) ||
                (callbacks == null))
            {
                return;
            }

            SQLiteReadValueCallback callback = callbacks.ReadValueCallback;

            if (callback == null)
                return;

            object userData = callbacks.ReadValueUserData;

            callback(
                _activeStatement._sql, this, oldFlags, eventArgs, typeName,
                index, userData, out complete); /* throw */
        }
        finally
        {
            _flags |= SQLiteConnectionFlags.UseConnectionReadValueCallbacks;
        }
    }

    /// <summary>
    /// Retrieves the column as a boolean value
    /// </summary>
    /// <param name="i">The index of the column.</param>
    /// <returns>bool</returns>
    public override bool GetBoolean(int i)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetBoolean", null, value), out complete);

            if (complete)
            {
                if (value.BooleanValue == null)
                    throw new SQLiteException("missing boolean return value");

                return (bool)value.BooleanValue;
            }
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetBoolean(i - PrivateVisibleFieldCount);

        VerifyType(i, DbType.Boolean);
        return Convert.ToBoolean(GetValue(i), CultureInfo.CurrentCulture);
    }

    /// <summary>
    /// Retrieves the column as a single byte value
    /// </summary>
    /// <param name="i">The index of the column.</param>
    /// <returns>byte</returns>
    public override byte GetByte(int i)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetByte", null, value), out complete);

            if (complete)
            {
                if (value.ByteValue == null)
                    throw new SQLiteException("missing byte return value");

                return (byte)value.ByteValue;
            }
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetByte(i - PrivateVisibleFieldCount);

        VerifyType(i, DbType.Byte);
        return Convert.ToByte(_activeStatement._sql.GetInt32(_activeStatement, i));
    }
475
476
477
478
479
480
481




































482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498

















499
500
501
502
503
504
505
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    /// <remarks>
    /// To determine the number of bytes in the column, pass a null value for the buffer.  The total length will be returned.
    /// </remarks>
    public override long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteReadArrayEventArgs eventArgs = new SQLiteReadArrayEventArgs(
                fieldOffset, buffer, bufferoffset, length);

            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetBytes", eventArgs, value), out complete);

            if (complete)
            {
                byte[] bytes = value.BytesValue;

                if (bytes != null)
                {
#if !PLATFORM_COMPACTFRAMEWORK
                    Array.Copy(bytes, /* throw */
                        eventArgs.DataOffset, eventArgs.ByteBuffer,
                        eventArgs.BufferOffset, eventArgs.Length);
#else
                    Array.Copy(bytes, /* throw */
                        (int)eventArgs.DataOffset, eventArgs.ByteBuffer,
                        eventArgs.BufferOffset, eventArgs.Length);
#endif

                    return eventArgs.Length;
                }
                else
                {
                    return -1;
                }
            }
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetBytes(i - PrivateVisibleFieldCount, fieldOffset, buffer, bufferoffset, length);

        VerifyType(i, DbType.Binary);
        return _activeStatement._sql.GetBytes(_activeStatement, i, (int)fieldOffset, buffer, bufferoffset, length);
    }

    /// <summary>
    /// Returns the column as a single character
    /// </summary>
    /// <param name="i">The index of the column.</param>
    /// <returns>char</returns>
    public override char GetChar(int i)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetChar", null, value), out complete);

            if (complete)
            {
                if (value.CharValue == null)
                    throw new SQLiteException("missing character return value");

                return (char)value.CharValue;
            }
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetChar(i - PrivateVisibleFieldCount);

        VerifyType(i, DbType.SByte);
        return Convert.ToChar(_activeStatement._sql.GetInt32(_activeStatement, i));
    }
516
517
518
519
520
521
522




































523
524
525
526
527
528
529
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    /// <remarks>
    /// To determine the number of characters in the column, pass a null value for the buffer.  The total length will be returned.
    /// </remarks>
    public override long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteReadArrayEventArgs eventArgs = new SQLiteReadArrayEventArgs(
                fieldoffset, buffer, bufferoffset, length);

            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetChars", eventArgs, value), out complete);

            if (complete)
            {
                char[] chars = value.CharsValue;

                if (chars != null)
                {
#if !PLATFORM_COMPACTFRAMEWORK
                    Array.Copy(chars, /* throw */
                        eventArgs.DataOffset, eventArgs.CharBuffer,
                        eventArgs.BufferOffset, eventArgs.Length);
#else
                    Array.Copy(chars, /* throw */
                        (int)eventArgs.DataOffset, eventArgs.CharBuffer,
                        eventArgs.BufferOffset, eventArgs.Length);
#endif

                    return eventArgs.Length;
                }
                else
                {
                    return -1;
                }
            }
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetChars(i - PrivateVisibleFieldCount, fieldoffset, buffer, bufferoffset, length);

        if ((_flags & SQLiteConnectionFlags.NoVerifyTextAffinity) != SQLiteConnectionFlags.NoVerifyTextAffinity)
            VerifyType(i, DbType.String);

551
552
553
554
555
556
557

















558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574

















575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591

















592
593
594
595
596
597
598
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    /// </summary>
    /// <param name="i">The index of the column.</param>
    /// <returns>DateTime</returns>
    public override DateTime GetDateTime(int i)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetDateTime", null, value), out complete);

            if (complete)
            {
                if (value.DateTimeValue == null)
                    throw new SQLiteException("missing date/time return value");

                return (DateTime)value.DateTimeValue;
            }
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetDateTime(i - PrivateVisibleFieldCount);

        VerifyType(i, DbType.DateTime);
        return _activeStatement._sql.GetDateTime(_activeStatement, i);
    }

    /// <summary>
    /// Retrieve the column as a decimal value
    /// </summary>
    /// <param name="i">The index of the column.</param>
    /// <returns>decimal</returns>
    public override decimal GetDecimal(int i)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetDecimal", null, value), out complete);

            if (complete)
            {
                if (value.DecimalValue == null)
                    throw new SQLiteException("missing decimal return value");

                return (decimal)value.DecimalValue;
            }
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetDecimal(i - PrivateVisibleFieldCount);

        VerifyType(i, DbType.Decimal);
        return Decimal.Parse(_activeStatement._sql.GetText(_activeStatement, i), NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent | NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture);
    }

    /// <summary>
    /// Returns the column as a double
    /// </summary>
    /// <param name="i">The index of the column.</param>
    /// <returns>double</returns>
    public override double GetDouble(int i)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetDouble", null, value), out complete);

            if (complete)
            {
                if (value.DoubleValue == null)
                    throw new SQLiteException("missing double return value");

                return (double)value.DoubleValue;
            }
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetDouble(i - PrivateVisibleFieldCount);

        VerifyType(i, DbType.Double);
        return _activeStatement._sql.GetDouble(_activeStatement, i);
    }
617
618
619
620
621
622
623

















624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640

















641
642
643
644
645
646
647
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    /// </summary>
    /// <param name="i">The index of the column.</param>
    /// <returns>float</returns>
    public override float GetFloat(int i)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetFloat", null, value), out complete);

            if (complete)
            {
                if (value.FloatValue == null)
                    throw new SQLiteException("missing float return value");

                return (float)value.FloatValue;
            }
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetFloat(i - PrivateVisibleFieldCount);

        VerifyType(i, DbType.Single);
        return Convert.ToSingle(_activeStatement._sql.GetDouble(_activeStatement, i));
    }

    /// <summary>
    /// Returns the column as a Guid
    /// </summary>
    /// <param name="i">The index of the column.</param>
    /// <returns>Guid</returns>
    public override Guid GetGuid(int i)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetGuid", null, value), out complete);

            if (complete)
            {
                if (value.GuidValue == null)
                    throw new SQLiteException("missing guid return value");

                return (Guid)value.GuidValue;
            }
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetGuid(i - PrivateVisibleFieldCount);

        TypeAffinity affinity = VerifyType(i, DbType.Guid);
        if (affinity == TypeAffinity.Blob)
        {
658
659
660
661
662
663
664

















665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681

















682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698

















699
700
701
702
703
704
705
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    /// </summary>
    /// <param name="i">The index of the column.</param>
    /// <returns>Int16</returns>
    public override Int16 GetInt16(int i)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetInt16", null, value), out complete);

            if (complete)
            {
                if (value.Int16Value == null)
                    throw new SQLiteException("missing int16 return value");

                return (Int16)value.Int16Value;
            }
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetInt16(i - PrivateVisibleFieldCount);

        VerifyType(i, DbType.Int16);
        return Convert.ToInt16(_activeStatement._sql.GetInt32(_activeStatement, i));
    }

    /// <summary>
    /// Retrieves the column as an int
    /// </summary>
    /// <param name="i">The index of the column.</param>
    /// <returns>Int32</returns>
    public override Int32 GetInt32(int i)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetInt32", null, value), out complete);

            if (complete)
            {
                if (value.Int32Value == null)
                    throw new SQLiteException("missing int32 return value");

                return (Int32)value.Int32Value;
            }
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetInt32(i - PrivateVisibleFieldCount);

        VerifyType(i, DbType.Int32);
        return _activeStatement._sql.GetInt32(_activeStatement, i);
    }

    /// <summary>
    /// Retrieves the column as a long
    /// </summary>
    /// <param name="i">The index of the column.</param>
    /// <returns>Int64</returns>
    public override Int64 GetInt64(int i)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetInt64", null, value), out complete);

            if (complete)
            {
                if (value.Int64Value == null)
                    throw new SQLiteException("missing int64 return value");

                return (Int64)value.Int64Value;
            }
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetInt64(i - PrivateVisibleFieldCount);

        VerifyType(i, DbType.Int64);
        return _activeStatement._sql.GetInt64(_activeStatement, i);
    }
1228
1229
1230
1231
1232
1233
1234












1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253












1254
1255
1256
1257
1258
1259
1260
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606







+
+
+
+
+
+
+
+
+
+
+
+



















+
+
+
+
+
+
+
+
+
+
+
+







    /// </summary>
    /// <param name="i">The index of the column.</param>
    /// <returns>string</returns>
    public override string GetString(int i)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetString", null, value), out complete);

            if (complete)
                return value.StringValue;
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetString(i - PrivateVisibleFieldCount);

        if ((_flags & SQLiteConnectionFlags.NoVerifyTextAffinity) != SQLiteConnectionFlags.NoVerifyTextAffinity)
            VerifyType(i, DbType.String);

        return _activeStatement._sql.GetText(_activeStatement, i);
    }

    /// <summary>
    /// Retrieves the column as an object corresponding to the underlying datatype of the column
    /// </summary>
    /// <param name="i">The index of the column.</param>
    /// <returns>object</returns>
    public override object GetValue(int i)
    {
        CheckDisposed();
        VerifyForGet();

        if ((_flags & SQLiteConnectionFlags.UseConnectionReadValueCallbacks) == SQLiteConnectionFlags.UseConnectionReadValueCallbacks)
        {
            SQLiteDataReaderValue value = new SQLiteDataReaderValue();
            bool complete;

            InvokeReadValueCallback(i, new SQLiteReadValueEventArgs(
                "GetValue", null, value), out complete);

            if (complete)
                return value.Value;
        }

        if (i >= PrivateVisibleFieldCount && _keyInfo != null)
            return _keyInfo.GetValue(i - PrivateVisibleFieldCount);

        SQLiteType typ = GetSQLiteType(_flags, i);

        if (((_flags & SQLiteConnectionFlags.DetectTextAffinity) == SQLiteConnectionFlags.DetectTextAffinity) &&

Changes to System.Data.SQLite/SQLiteParameter.cs.

50
51
52
53
54
55
56





57
58
59
60
61
62
63
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68







+
+
+
+
+







    /// The data size, unused by SQLite
    /// </summary>
    private int            _dataSize;

    private bool           _nullable;
    private bool           _nullMapping;

    /// <summary>
    /// The database type name associated with this parameter, if any.
    /// </summary>
    private string         _typeName;

    /// <summary>
    /// Constructor used when creating for use with a specific command.
    /// </summary>
    /// <param name="command">
    /// The command associated with this parameter.
    /// </param>
    internal SQLiteParameter(
472
473
474
475
476
477
478















479
480
481
482
483
484
485
486
487
488
489
490
491
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+













      set
      {
        _objValue = value;
        if (_dbType == UnknownDbType && _objValue != null && _objValue != DBNull.Value) // If the DbType has never been assigned, try to glean one from the value's datatype
          _dbType = SQLiteConvert.TypeToDbType(_objValue.GetType());
      }
    }

    /// <summary>
    /// The database type name associated with this parameter, if any.
    /// </summary>
    public string TypeName
    {
        get
        {
            return _typeName;
        }
        set
        {
            _typeName = value;
        }
    }

    /// <summary>
    /// Clones a parameter
    /// </summary>
    /// <returns>A new, unassociated SQLiteParameter</returns>
    public object Clone()
    {
      SQLiteParameter newparam = new SQLiteParameter(this);

      return newparam;
    }
  }
}

Changes to System.Data.SQLite/SQLiteStatement.cs.

233
234
235
236
237
238
239







































































































































240
241
242
243
244
245
246
247
248
249










250
251
252
253
254
255
256
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+










+
+
+
+
+
+
+
+
+
+








      int x = _paramNames.Length;
      for (int n = 0; n < x; n++)
      {
        BindParameter(n + 1, _paramValues[n]);
      }
    }

    /// <summary>
    /// This method attempts to query the database connection associated with
    /// the statement in use.  If the underlying command or connection is
    /// unavailable, a null value will be returned.
    /// </summary>
    /// <returns>
    /// The connection object -OR- null if it is unavailable.
    /// </returns>
    private static SQLiteConnection GetConnection(
        SQLiteStatement statement
        )
    {
        try
        {
            if (statement != null)
            {
                SQLiteCommand command = statement._command;

                if (command != null)
                {
                    SQLiteConnection connection = command.Connection;

                    if (connection != null)
                        return connection;
                }
            }
        }
        catch (ObjectDisposedException)
        {
            // do nothing.
        }

        return null;
    }

    /// <summary>
    /// Invokes the parameter binding callback configured for the database
    /// type name associated with the specified column.  If no parameter
    /// binding callback is available for the database type name, do
    /// nothing.
    /// </summary>
    /// <param name="index">
    /// The index of the column being read.
    /// </param>
    /// <param name="parameter">
    /// The <see cref="SQLiteParameter" /> instance being bound to the
    /// command.
    /// </param>
    /// <param name="complete">
    /// Non-zero if the default handling for the parameter binding call
    /// should be skipped (i.e. the parameter should not be bound at all).
    /// Great care should be used when setting this to non-zero.
    /// </param>
    private void InvokeBindValueCallback(
        int index,
        SQLiteParameter parameter,
        out bool complete
        )
    {
        complete = false;
        SQLiteConnectionFlags oldFlags = _flags;
        _flags &= ~SQLiteConnectionFlags.UseConnectionBindValueCallbacks;

        try
        {
            if (parameter == null)
                return;

            SQLiteConnection connection = GetConnection(this);

            if (connection == null)
                return;

            //
            // NOTE: First, always look for an explicitly set database type
            //       name.
            //
            string typeName = parameter.TypeName;

            if (typeName == null)
            {
                //
                // NOTE: Are we allowed to fallback to using the parameter name
                //       as the basis for looking up the binding callback?
                //
                if ((_flags & SQLiteConnectionFlags.UseParameterNameForTypeName)
                        == SQLiteConnectionFlags.UseParameterNameForTypeName)
                {
                    typeName = parameter.ParameterName;
                }
            }

            if (typeName == null)
            {
                //
                // NOTE: Are we allowed to fallback to using the database type
                //       name translated from the DbType as the basis for looking
                //       up the binding callback?
                //
                if ((_flags & SQLiteConnectionFlags.UseParameterDbTypeForTypeName)
                        == SQLiteConnectionFlags.UseParameterDbTypeForTypeName)
                {
                    typeName = SQLiteConvert.DbTypeToTypeName(
                        connection, parameter.DbType, _flags);
                }
            }

            if (typeName == null)
                return;

            SQLiteTypeCallbacks callbacks;

            if (!connection.TryGetTypeCallbacks(typeName, out callbacks) ||
                (callbacks == null))
            {
                return;
            }

            SQLiteBindValueCallback callback = callbacks.BindValueCallback;

            if (callback == null)
                return;

            object userData = callbacks.BindValueUserData;

            callback(
                _sql, _command, oldFlags, parameter, typeName, index,
                userData, out complete); /* throw */
        }
        finally
        {
            _flags |= SQLiteConnectionFlags.UseConnectionBindValueCallbacks;
        }
    }

    /// <summary>
    /// Perform the bind operation for an individual parameter
    /// </summary>
    /// <param name="index">The index of the parameter to bind</param>
    /// <param name="param">The parameter we're binding</param>
    private void BindParameter(int index, SQLiteParameter param)
    {
      if (param == null)
        throw new SQLiteException("Insufficient parameters supplied to the command");

      if ((_flags & SQLiteConnectionFlags.UseConnectionBindValueCallbacks) == SQLiteConnectionFlags.UseConnectionBindValueCallbacks)
      {
          bool complete;

          InvokeBindValueCallback(index, param, out complete);

          if (complete)
              return;
      }

      object obj = param.Value;
      DbType objType = param.DbType;

      if ((obj != null) && (objType == DbType.Object))
          objType = SQLiteConvert.TypeToDbType(obj.GetType());

Added Tests/types.eagle.























































































































































































































































































































































































































































































































































































































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
###############################################################################
#
# types.eagle --
#
# Written by Joe Mistachkin.
# Released to the public domain, use at your own risk!
#
###############################################################################

package require Eagle
package require Eagle.Library
package require Eagle.Test

runTestPrologue

###############################################################################

package require System.Data.SQLite.Test
runSQLiteTestPrologue

###############################################################################

proc bindValueCallback1 {
        convert command flags parameter typeName index userData
        completeVarName } {
  lappend ::log(bind) [list convert [isObjectHandle $convert]]
  lappend ::log(bind) [list command [isObjectHandle $command]]
  lappend ::log(bind) [list flags [getStringFromObjectHandle $flags]]
  lappend ::log(bind) [list parameter [isObjectHandle $parameter]]
  lappend ::log(bind) [list typeName [getStringFromObjectHandle $typeName]]
  lappend ::log(bind) [list index [getStringFromObjectHandle $index]]
  lappend ::log(bind) [list userData [getStringFromObjectHandle $userData]]

  if {[getStringFromObjectHandle $userData] == 3} then {
    upvar 1 $completeVarName complete; unset complete
    error "parameter binding canceled"
  }

  if {[getStringFromObjectHandle $userData] == 2} then {
    $parameter DbType String
    $parameter Value custom
  }

  if {[getStringFromObjectHandle $userData] == 1} then {
    upvar 1 $completeVarName complete
    set complete [object invoke -create System.Boolean Parse True]
  }
}

###############################################################################

proc readValueCallback1 {
        convert dataReader flags eventArgs typeName index userData
        completeVarName } {
  lappend ::log(read) [list convert [isObjectHandle $convert]]
  lappend ::log(read) [list dataReader [isObjectHandle $dataReader]]
  lappend ::log(read) [list flags [getStringFromObjectHandle $flags]]
  lappend ::log(read) [list eventArgs [isObjectHandle $eventArgs]]
  lappend ::log(read) [list typeName [getStringFromObjectHandle $typeName]]
  lappend ::log(read) [list index [getStringFromObjectHandle $index]]
  lappend ::log(read) [list userData [getStringFromObjectHandle $userData]]

  if {[getStringFromObjectHandle $userData] == 3} then {
    upvar 1 $completeVarName complete; unset complete
    error "reading of value canceled"
  }

  if {[getStringFromObjectHandle $userData] == 1} then {
    upvar 1 $completeVarName complete
    set complete [object invoke -create System.Boolean Parse True]
  }
}

###############################################################################

runTest {test types-1.1 {type callbacks management} -setup {
  setupDb [set fileName types-1.1.db]
} -body {
  set connection [getDbConnection]

  set result [list]

  lappend result [$connection ClearTypeCallbacks]

  set typeCallbacks(1) [object invoke \
      System.Data.SQLite.SQLiteTypeCallbacks Create \
      null null null null]

  set typeCallbacks(2) null

  lappend result [$connection SetTypeCallbacks TEST $typeCallbacks(1)]
  lappend result [$connection TryGetTypeCallbacks TEST typeCallbacks(2)]
  lappend result [$connection ClearTypeCallbacks]
  lappend result [$connection SetTypeCallbacks TEST $typeCallbacks(1)]
  lappend result [expr {$typeCallbacks(1) eq $typeCallbacks(2)}]

  set result
} -cleanup {
  freeDbConnection

  cleanupDb $fileName

  unset -nocomplain typeCallbacks
  unset -nocomplain result connection db fileName
} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite} -result {0 True True 1 True True}}

###############################################################################

set readArgs [list \
    convert dataReader flags eventArgs typeName index userData \
    completeVarName]

set params [list \
    [list Boolean    GetBoolean    false   BooleanValue    true    0] \
    [list Byte       GetByte       false   ByteValue       true    0] \
    [list Byte       GetBytes      true    BytesValue      false   0] \
    [list Char       GetChar       false   CharValue       true    0] \
    [list Char       GetChars      true    CharsValue      false   0] \
    [list DateTime   GetDateTime   false   DateTimeValue   true    0] \
    [list Decimal    GetDecimal    false   DecimalValue    true    0] \
    [list Double     GetDouble     false   DoubleValue     true    0] \
    [list Single     GetFloat      false   FloatValue      true    0] \
    [list Guid       GetGuid       false   GuidValue       true    \
        00000000-0000-0000-0000-000000000000] \
    [list Int16      GetInt16      false   Int16Value      true    0] \
    [list Int32      GetInt32      false   Int32Value      true    0] \
    [list Int64      GetInt64      false   Int64Value      true    0] \
    [list String     GetString     false   StringValue     false   null] \
    [list Object     GetValue      false   Value           false   null]]

###############################################################################

set expectedResults [list \
    {False False True False False False False False} \
    {0 0 1 0 0 0 0 0} \
    {0 1 48 1 49 3 {49 46 50} 5 {116 104 114\
        101 101} 1 4 27 {50 48 49 54 45 48 54\
        45 49 57 32 49 57 58 53 48 58 48 52 46\
        49 50 51 52 53 54 55} 36 {55 52 102 49\
        102 52 48 50 45 100 100 101 102 45 52\
        48 50 55 45 97 55 56 102 45 51 56 52 55\
        102 97 57 55 98 56 51 48}} \
    "<NUL> <NUL> \x01 <NUL> <NUL> <NUL> <NUL> <NUL>" \
    "0 1 0 1 1 3 {1 . 2} 1 t 1 \x04 1 2 1 7" \
    {{0001-01-01 00:00:00Z} {0001-01-01 00:00:00Z}\
        {0001-01-01 00:00:00Z} {0001-01-01 00:00:00Z}\
        {0001-01-01 00:00:00Z} {0001-01-01 00:00:00Z}\
        {2016-06-19 19:50:04.1234567Z} {0001-01-01\
        00:00:00Z}} \
    {0 0 1 1.2 0 0 0 0} \
    {0 0 1 1.2 0 0 0 0} \
    {0 0 1 1.2 0 0 0 0} \
    {00000000-0000-0000-0000-000000000000\
        00000000-0000-0000-0000-000000000000\
        00000000-0000-0000-0000-000000000000\
        00000000-0000-0000-0000-000000000000\
        00000000-0000-0000-0000-000000000000\
        00060504-0000-0000-0000-000000000000\
        00000000-0000-0000-0000-000000000000\
        74f1f402-ddef-4027-a78f-3847fa97b830} \
    {0 0 1 0 0 0 0 0} \
    {0 0 1 0 0 0 0 0} \
    {0 0 1 0 0 0 0 0} \
    "<NUL> <NUL> <NUL> <NUL> three \x04\x05\x06\
        {2016-06-19 19:50:04.1234567}\
        74f1f402-ddef-4027-a78f-3847fa97b830" \
    {{} 0 1 1.2 three {4 5 6} {2016-06-19\
        19:50:04.1234567}\
        74f1f402-ddef-4027-a78f-3847fa97b830}]

###############################################################################

set savedDateTimeFormat [object invoke Interpreter.GetActive DateTimeFormat]
if {![isObjectHandle $savedDateTimeFormat]} then {set savedDateTimeFormat null}
object invoke Interpreter.GetActive DateTimeFormat [getDateTimeFormat]

###############################################################################

for {set i 0} {$i < [llength $params]} {incr i} {
  foreach {
    typeName methodName isArray propertyName isRequired value
  } [lindex $params $i] break

  set expectedResult [lindex $expectedResults $i]

  #############################################################################

  proc readValueCallback2 $readArgs [subst {
    if {$isArray} then {
      if {\[catch {
        set dataOffset \[\$eventArgs ArrayEventArgs.DataOffset\]

        set buffer \[\$eventArgs -create [appendArgs ArrayEventArgs. \
            $typeName Buffer]\]

        set bufferOffset \[\$eventArgs ArrayEventArgs.BufferOffset\]
        set length \[\$eventArgs ArrayEventArgs.Length\]

        set readValue \[\$dataReader \[\$eventArgs MethodName\] \
            \$index \$dataOffset \$buffer \$bufferOffset \$length\]

        \$eventArgs \[appendArgs Value. $propertyName\] \$readValue
      } error\]} then {
        set readValue \[\$dataReader -tostring GetValue \$index\]

        if {"$typeName" eq "Char"} then {
          set string \[object create -alias String \$readValue\]
          set buffer \[\$string -create -alias ToCharArray]
        } else {
          set buffer \[object invoke -create -alias \
              System.Text.Encoding.UTF8 GetBytes \$readValue\]
        }

        \$eventArgs \[appendArgs Value. $propertyName\] \$buffer
        \$eventArgs ArrayEventArgs.Length \[\$buffer Length\]
      } else {
        set buffer \[\$eventArgs -create [appendArgs ArrayEventArgs. \
            $typeName Buffer]\]

        \$eventArgs \[appendArgs Value. $propertyName\] \$buffer
      }
    } else {
      if {\[catch {
        set readValue \[\$dataReader \[\$eventArgs MethodName\] \$index\]

        if {"$typeName" eq "Char"} then {
          set readValue \[object invoke -create Char Parse \$readValue\]
        }

        \$eventArgs \[appendArgs Value. $propertyName\] \$readValue
      } error\]} then {
        \$eventArgs \[appendArgs Value. $propertyName\] {$value}
      }
    }

    upvar 1 \$completeVarName complete
    set complete \[object invoke -create System.Boolean Parse True\]
  }]

  #############################################################################

  runTest {test [appendArgs types-2. $i] [appendArgs $methodName " callback"] \
      -setup [subst -nocommands {
    set typeName {$typeName}
    set methodName {$methodName}
    set isArray {$isArray}

    setupDb [set fileName [appendArgs types-2. $i .db]] "" "" "" \
        UseConnectionReadValueCallbacks
  }] -body {
    sql execute $db {
      CREATE TABLE t1(x INTEGER, y SPECIAL);
      INSERT INTO t1 (x, y) VALUES(1, NULL);
      INSERT INTO t1 (x, y) VALUES(2, 0);
      INSERT INTO t1 (x, y) VALUES(3, 1);
      INSERT INTO t1 (x, y) VALUES(4, 1.2);
      INSERT INTO t1 (x, y) VALUES(5, 'three');
      INSERT INTO t1 (x, y) VALUES(6, X'040506');
      INSERT INTO t1 (x, y) VALUES(7, '2016-06-19 19:50:04.1234567');
      INSERT INTO t1 (x, y) VALUES(8, '74f1f402-ddef-4027-a78f-3847fa97b830');
    }

    set callback {-callbackflags +Default readValueCallback2}
    set connection [getDbConnection]

    set result [list]

    set typeCallbacks [object invoke -marshalflags +DynamicCallback \
        System.Data.SQLite.SQLiteTypeCallbacks Create null $callback \
        null null]

    $connection SetTypeCallbacks SPECIAL $typeCallbacks

    set dataReader [sql execute -execute reader -format datareader \
        -alias $db "SELECT y FROM t1 ORDER BY x;"]

    while {[$dataReader Read]} {
      if {$isArray} then {
        set buffer [object invoke \
            -create Array CreateInstance $typeName 100]

        if {[catch {
          $dataReader $methodName 0 0 $buffer 0 1
        } value] == 0} then {
          lappend result $value

          if {$value > 0} then {
            set list [object create -alias StringList $buffer]

            lappend result [object invoke StringList GetRange \
                $list 0 [expr {$value - 1}] false]
          }
        } else {
          lappend result [list error(array) $::errorCode]
        }
      } else {
        if {[catch {
          $dataReader $methodName 0
        } value] == 0} then {
          if {$value eq "\x00"} then {
            lappend result <NUL>
          } else {
            lappend result [getStringFromObjectHandle $value]
          }
        } else {
          lappend result [list error(value) $::errorCode]
        }
      }
    }

    set result
  } -cleanup {
    catch {object removecallback $callback}

    unset -nocomplain dataReader
    freeDbConnection

    cleanupDb $fileName

    unset -nocomplain buffer typeCallbacks callback value list
    unset -nocomplain result connection db fileName
    unset -nocomplain typeName methodName isArray
  } -constraints {eagle command.object monoBug28 command.sql compile.DATA\
SQLite System.Data.SQLite} -result $expectedResult}

  rename readValueCallback2 ""
}

###############################################################################

object invoke Interpreter.GetActive DateTimeFormat $savedDateTimeFormat
unset -nocomplain savedDateTimeFormat

###############################################################################

unset -nocomplain i readArgs params typeName methodName isArray propertyName \
    isRequired expectedResults expectedResult

###############################################################################

runTest {test types-3.1 {bind callback (incomplete)} -setup {
  unset -nocomplain log

  setupDb [set fileName types-3.1.db] "" "" "" \
      "UseConnectionBindValueCallbacks UseParameterNameForTypeName"
} -body {
  sql execute $db {
    CREATE TABLE t1(x SPECIAL);
  }

  set callback {-callbackflags +Default bindValueCallback1}
  set connection [getDbConnection]

  set typeCallbacks [object invoke -marshalflags +DynamicCallback \
      System.Data.SQLite.SQLiteTypeCallbacks Create $callback null \
      0 null]

  $connection SetTypeCallbacks SPECIAL $typeCallbacks

  sql execute $db {
    INSERT INTO t1 (x) VALUES(?);
  } [list Special Int64 1234]

  set result [list]

  lappend result [expr {
    [info exists log(bind)] ? $log(bind) : "<MISSING>"
  }]

  lappend result [sql execute -execute reader -format list $db \
      "SELECT * FROM t1 ORDER BY x;"]

  set result
} -cleanup {
  catch {object removecallback $callback}

  freeDbConnection

  cleanupDb $fileName

  unset -nocomplain result typeCallbacks callback log connection db fileName
} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite} -result {{{convert true} {command true} {flags\
{UseConnectionBindValueCallbacks, UseParameterNameForTypeName}} {parameter\
true} {typeName Special} {index 1} {userData 0}} 1234}}

###############################################################################

runTest {test types-3.2 {bind callback (complete)} -setup {
  unset -nocomplain log

  setupDb [set fileName types-3.2.db] "" "" "" \
      "UseConnectionBindValueCallbacks UseParameterNameForTypeName"
} -body {
  sql execute $db {
    CREATE TABLE t1(x SPECIAL);
  }

  set callback {-callbackflags +Default bindValueCallback1}
  set connection [getDbConnection]

  set typeCallbacks [object invoke -marshalflags +DynamicCallback \
      System.Data.SQLite.SQLiteTypeCallbacks Create $callback null \
      1 null]

  $connection SetTypeCallbacks SPECIAL $typeCallbacks

  sql execute $db {
    INSERT INTO t1 (x) VALUES(?);
  } [list Special Int64 5678]

  set result [list]

  lappend result [expr {
    [info exists log(bind)] ? $log(bind) : "<MISSING>"
  }]

  lappend result [sql execute -execute reader -format list $db \
      "SELECT * FROM t1 ORDER BY x;"]

  set result
} -cleanup {
  catch {object removecallback $callback}

  freeDbConnection

  cleanupDb $fileName

  unset -nocomplain result typeCallbacks callback log connection db fileName
} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite} -result {{{convert true} {command true} {flags\
{UseConnectionBindValueCallbacks, UseParameterNameForTypeName}} {parameter\
true} {typeName Special} {index 1} {userData 1}} {}}}

###############################################################################

runTest {test types-3.3 {bind callback (modify/incomplete)} -setup {
  unset -nocomplain log

  setupDb [set fileName types-3.3.db] "" "" "" \
      "UseConnectionBindValueCallbacks UseParameterNameForTypeName"
} -body {
  sql execute $db {
    CREATE TABLE t1(x SPECIAL);
  }

  set callback {-callbackflags +Default bindValueCallback1}
  set connection [getDbConnection]

  set typeCallbacks [object invoke -marshalflags +DynamicCallback \
      System.Data.SQLite.SQLiteTypeCallbacks Create $callback null \
      2 null]

  $connection SetTypeCallbacks SPECIAL $typeCallbacks

  sql execute $db {
    INSERT INTO t1 (x) VALUES(?);
  } [list Special Int64 9999]

  set result [list]

  lappend result [expr {
    [info exists log(bind)] ? $log(bind) : "<MISSING>"
  }]

  lappend result [sql execute -execute reader -format list $db \
      "SELECT * FROM t1 ORDER BY x;"]

  set result
} -cleanup {
  catch {object removecallback $callback}

  freeDbConnection

  cleanupDb $fileName

  unset -nocomplain result typeCallbacks callback log connection db fileName
} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite} -result {{{convert true} {command true} {flags\
{UseConnectionBindValueCallbacks, UseParameterNameForTypeName}} {parameter\
true} {typeName Special} {index 1} {userData 2}} custom}}

###############################################################################

runTest {test types-4.1 {read callback (exception)} -setup {
  unset -nocomplain log

  setupDb [set fileName types-4.1.db] "" "" "" \
      UseConnectionReadValueCallbacks
} -body {
  sql execute $db {
    CREATE TABLE t1(x SPECIAL);
    INSERT INTO t1 (x) VALUES(8888);
  }

  set callback {-callbackflags {+Default ThrowOnError} readValueCallback1}
  set connection [getDbConnection]

  set typeCallbacks [object invoke -marshalflags +DynamicCallback \
      System.Data.SQLite.SQLiteTypeCallbacks Create null $callback \
      null 3]

  $connection SetTypeCallbacks SPECIAL $typeCallbacks

  set result [list]

  lappend result [catch {
    sql execute -execute reader -format list $db {SELECT * FROM t1 ORDER BY x;}
  } error]

  lappend result [extractSystemDataSQLiteExceptionMessage $error]

  lappend result [catch {
    sql execute -execute scalar $db {SELECT COUNT(*) FROM t1;}
  } error]

  lappend result [extractSystemDataSQLiteExceptionMessage $error]
  lappend result [expr {[info exists log(read)] ? $log(read) : "<MISSING>"}]

  set result
} -cleanup {
  catch {object removecallback $callback}

  freeDbConnection

  cleanupDb $fileName

  unset -nocomplain error result typeCallbacks callback log connection db \
      fileName
} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite} -result {1 {reading of value canceled} 0 1 {{convert true}\
{dataReader true} {flags UseConnectionReadValueCallbacks} {eventArgs true}\
{typeName SPECIAL} {index 0} {userData 3}}}}

###############################################################################

runTest {test types-5.1 {bind callback (exception)} -setup {
  unset -nocomplain log

  setupDb [set fileName types-5.1.db] "" "" "" \
      "UseConnectionBindValueCallbacks UseParameterNameForTypeName"
} -body {
  sql execute $db {
    CREATE TABLE t1(x SPECIAL);
  }

  set callback {-callbackflags {+Default ThrowOnError} bindValueCallback1}
  set connection [getDbConnection]

  set typeCallbacks [object invoke -marshalflags +DynamicCallback \
      System.Data.SQLite.SQLiteTypeCallbacks Create $callback null \
      3 null]

  $connection SetTypeCallbacks SPECIAL $typeCallbacks

  catch {
    sql execute $db {
      INSERT INTO t1 (x) VALUES(?);
    } [list Special Int64 4321]
  }

  set result [list]

  lappend result [expr {
    [info exists log(bind)] ? $log(bind) : "<MISSING>"
  }]

  lappend result [sql execute -execute reader -format list $db \
      "SELECT * FROM t1 ORDER BY x;"]

  set result
} -cleanup {
  catch {object removecallback $callback}

  freeDbConnection

  cleanupDb $fileName

  unset -nocomplain result typeCallbacks callback log connection db fileName
} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite} -result {{{convert true} {command true} {flags\
{UseConnectionBindValueCallbacks, UseParameterNameForTypeName}} {parameter\
true} {typeName Special} {index 1} {userData 3}} {}}}

###############################################################################

catch {eval object dispose [info objects System#Boolean#*]}

###############################################################################

rename readValueCallback1 ""
rename bindValueCallback1 ""

###############################################################################

runSQLiteTestEpilogue
runTestEpilogue

Changes to lib/System.Data.SQLite/common.eagle.

1823
1824
1825
1826
1827
1828
1829











































































































1830
1831
1832
1833
1834
1835
1836
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







        #       System.Data.SQLite, and suitable for round-tripping with the
        #       DateTime class of the framework.  If this value is changed,
        #       various tests may fail.
        #
        return "yyyy-MM-dd HH:mm:ss.FFFFFFFK"
      }
    }

    proc getProperties { object varName } {
      upvar 1 $varName properties

      set count 0
      set names [list]

      if {[isObjectHandle $object] && $object ne "null"} then {
        eval lappend names [object members \
            -membertypes Property -nameonly $object]

        eval lappend names [object members \
            -membertypes Field -nameonly $object]
      }

      foreach name $names {
        if {[catch {
          object invoke -objectflags +NoDispose $object $name
        } value] == 0} then {
          if {[isObjectHandle $value] && $value ne "null"} then {
            set error null; object invoke -flags +NonPublic \
                -marshalflags +NoHandle Interpreter.GetActive \
                AddObjectReference Ok $value error

            lappend properties(objects) [list $name $value]
          } else {
            lappend properties(values) [list $name $value]
          }

          incr count
        } else {
          lappend properties(errors) [list $name $::errorCode]
        }
      }

      return $count
    }

    proc getAllProperties { object varName } {
      upvar 1 $varName properties
      set value $object

      while {true} {
        if {![info exists properties(seenObjects)] || \
            $value ni $properties(seenObjects)} then {
          getProperties $value properties
          lappend properties(seenObjects) $value
        }

        if {![info exists properties(objects)]} then {
          break
        }

        if {[llength $properties(objects)] == 0} then {
          unset properties(objects); break
        }

        set value [lindex [lindex $properties(objects) 0] end]
        set properties(objects) [lrange $properties(objects) 1 end]
      }

      if {[info exists properties(seenObjects)]} then {
        foreach value $properties(seenObjects) {
          if {$value eq $object} continue
          catch {object dispose $value}
        }

        unset properties(seenObjects)
      }
    }

    proc getVariables { varNames {objects false} } {
      set result [list]

      foreach varName $varNames {
        if {[uplevel 1 [list array exists $varName]]} then {
          set arrayName $varName

          foreach elementName [uplevel 1 [list array names $arrayName]] {
            set name [appendArgs $arrayName ( $elementName )]
            set varValue [uplevel 1 [list set $name]]

            if {$objects && [isObjectHandle $varValue]} then {
              unset -nocomplain properties
              getAllProperties $varValue properties

              lappend result [list $name [array get properties]]
            } else {
              lappend result [list $name $varValue]
            }
          }
        } else {
          set varValue [uplevel 1 [list set $varName]]

          if {$objects && [isObjectHandle $varValue]} then {
            unset -nocomplain properties
            getAllProperties $varValue properties

            lappend result [list $varName [array get properties]]
          } else {
            lappend result [list $varName $varValue]
          }
        }
      }

      return $result
    }

    proc enumerableToList { enumerable } {
      set result [list]

      if {[string length $enumerable] == 0 || $enumerable eq "null"} then {
        return $result
      }
2006
2007
2008
2009
2010
2011
2012
2013


2014
2015
2016
2017
2018
2019
2020
2113
2114
2115
2116
2117
2118
2119

2120
2121
2122
2123
2124
2125
2126
2127
2128







-
+
+







      #
      # NOTE: If the string conforms to format of the normal exception
      #       error strings, extract and return only the error message
      #       portion itself.
      #
      set patterns [list \
      {System\.Data\.SQLite\.SQLiteException \(0x80004005\): (.+?)  (?: )?at} \
      {System\.Data\.SQLite\.SQLiteException: (.+?)  (?: )?at}]
      {System\.Data\.SQLite\.SQLiteException: (.+?)  (?: )?at} \
      {Eagle\._Components\.Public\.ScriptException: (.+?)  (?: )?at}]

      foreach pattern $patterns {
        if {[regexp -- $pattern $value dummy message]} then {
          set message [string map [list \r\n \n] [string trim $message]]
          set lines [split $message \n]

          if {[llength $lines] == 2} then {
2080
2081
2082
2083
2084
2085
2086







2087
2088
2089
2090
2091
2092
2093
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208







+
+
+
+
+
+
+







            ![array exists ::dataSource]} then {
          set database [appendArgs "data source \"" $::dataSource \"]
        } else {
          set database <unknown>
        }
      }

      #
      # NOTE: Even though there is only one source of flags so far, they
      #       must be combined using the correct syntax for enumerated
      #       flag values for the .NET Framework.
      #
      set flags [combineFlags $flags ""]

      #
      # NOTE: Show (and log) the local connection flags and the associated
      #       data source or file name.
      #
      if {!$quiet} then {
        if {![info exists ::no(emitLocalFlags)] && \
            (![info exists ::no(emitLocalFlagsIfNone)] || \

Changes to readme.htm.

211
212
213
214
215
216
217


218
219
220
221
222
223
224
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226







+
+







<p>
    <b>1.0.102.0 - June XX, 2016 <font color="red">(release scheduled)</font></b>
</p>
<ul>
    <li>Updated to <a href="https://www.sqlite.org/releaselog/3_13_0.html">SQLite 3.13.0</a>.</li>
    <li>Update the SQLiteConnection.EnableExtensions method to make use of the new SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION option, when available.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Prevent the SQLiteCommand.ExecuteScalar method from throwing an exception when there are no result columns.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Support per-connection customization for binding parameters and reading values, based on the database type name.</li>
    <li>Add TypeName property to the SQLiteParameter class.</li>
    <li>Add VerifyOnly method to the SQLiteCommand class.</li>
    <li>Add IsReadOnly method to the SQLiteConnection class.</li>
</ul>
<p>
    <b>1.0.101.0 - April 19, 2016</b>
</p>
<ul>

Changes to www/news.wiki.

1
2
3
4
5
6
7
8
9
10
11


12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20











+
+







<title>News</title>

<b>Version History</b>

<p>
    <b>1.0.102.0 - June XX, 2016 <font color="red">(release scheduled)</font></b>
</p>
<ul>
    <li>Updated to [https://www.sqlite.org/releaselog/3_13_0.html|SQLite 3.13.0].</li>
    <li>Update the SQLiteConnection.EnableExtensions method to make use of the new SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION option, when available.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Prevent the SQLiteCommand.ExecuteScalar method from throwing an exception when there are no result columns.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Support per-connection customization for binding parameters and reading values, based on the database type name.</li>
    <li>Add TypeName property to the SQLiteParameter class.</li>
    <li>Add VerifyOnly method to the SQLiteCommand class.</li>
    <li>Add IsReadOnly method to the SQLiteConnection class.</li>
</ul>
<p>
    <b>1.0.101.0 - April 19, 2016</b>
</p>
<ul>