System.Data.SQLite
Check-in [4f933521a1]
Not logged in

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

Overview
Comment:Add DateTimeFormatString connection string property to allow the DateTime format string used for all parsing and formatting to be overridden. Disable use of the new connection string parsing algorithm when the No_SQLiteConnectionNewParser environment variable is set. Pursuant to [bbdda6eae2].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 4f933521a13694bc2a9cc7fb0053020f7ea75fa2
User & Date: mistachkin 2013-05-30 00:44:55
References
2013-05-30
00:47 Closed ticket [bbdda6eae2]: unable to open database file on a local network plus 4 other changes artifact: 1bc4445158 user: mistachkin
Context
2013-06-22
03:36
Update several wiki pages. check-in: ef62d192d4 user: mistachkin tags: trunk
2013-06-03
01:57
Initial phase of experimental support for implementing virtual tables in managed code. No docs, no tests, does not work yet, and may not even compile. check-in: 273b0c601f user: mistachkin tags: virtualTables
2013-05-30
00:44
Add DateTimeFormatString connection string property to allow the DateTime format string used for all parsing and formatting to be overridden. Disable use of the new connection string parsing algorithm when the No_SQLiteConnectionNewParser environment variable is set. Pursuant to [bbdda6eae2]. check-in: 4f933521a1 user: mistachkin tags: trunk
2013-05-29
23:04
Honor the DateTimeFormat and DateTimeKind connection string properties even when the BindAllAsText connection flag is in use. check-in: d81d546e99 user: mistachkin tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to Doc/Extra/environment.html.

    70     70             <td>If this environment variable is set [to anything], the native
    71     71             library pre-loading functionality will be disabled.  By default,
    72     72             the native library pre-loading will attempt to load the native
    73     73             SQLite library from architecture-specific (e.g. "x86", "amd64",
    74     74             "x64") or platform-specific (e.g. "Win32") directories that reside
    75     75             underneath the application base directory.</td>
    76     76           </tr>
           77  +        <tr valign="top">
           78  +          <td>No_SQLiteConnectionNewParser</td>
           79  +          <td>If this environment variable is set [to anything], the new
           80  +          connection string parsing algorithm will not be used.  This
           81  +          environment variable is intended for use with legacy code only.</td>
           82  +        </tr>
    77     83           <tr valign="top">
    78     84             <td>No_SQLiteFunctions</td>
    79     85             <td>If this environment variable is set [to anything], the initial
    80     86             search for types in all loaded assemblies that are tagged with the
    81     87             SQLiteFunction attribute will be skipped.  Normally, this search is
    82     88             conducted only once per application domain by the static constructor
    83     89             of the SQLiteFunction class; however, these implementation details

Changes to Doc/Extra/version.html.

    42     42       </div>
    43     43       <div id="mainSection">
    44     44       <div id="mainBody">
    45     45       <h1 class="heading">Version History</h1>
    46     46       <p><b>1.0.87.0 - June XX, 2013 <font color="red">(release scheduled)</font></b></p>
    47     47       <ul>
    48     48         <li>The DbType to type name translation needs to prioritize the Entity Framework type names. Fix for <a href="http://system.data.sqlite.org/index.html/info/47f4bac575">[47f4bac575]</a>.</li>
           49  +      <li>Add DateTimeFormatString connection string property to allow the DateTime format string used for all parsing and formatting to be overridden.</li>
           50  +      <li>Disable use of the new connection string parsing algorithm when the No_SQLiteConnectionNewParser environment variable is set. Pursuant to <a href="http://system.data.sqlite.org/index.html/info/bbdda6eae2">[bbdda6eae2]</a>.</li>
    49     51       </ul>
    50     52       <p><b>1.0.86.0 - May 23, 2013</b></p>
    51     53       <ul>
    52     54         <li>Updated to <a href="http://www.sqlite.org/releaselog/3_7_17.html">SQLite 3.7.17</a>.</li>
    53     55         <li>Disable use of the AllowPartiallyTrustedCallers attribute when compiled for the .NET Framework 4.0/4.5.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    54     56         <li>Allow semi-colons in the data source file name. Fix for <a href="http://system.data.sqlite.org/index.html/info/48a6b8e4ca">[e47b3d8346]</a>.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    55     57         <li>NULL values should be reported as type &quot;object&quot;, not &quot;DBNull&quot;. Fix for <a href="http://system.data.sqlite.org/index.html/info/48a6b8e4ca">[48a6b8e4ca]</a>.</li>

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

    73     73   #endif
    74     74   
    75     75       /// <summary>
    76     76       /// The user-defined functions registered on this connection
    77     77       /// </summary>
    78     78       protected SQLiteFunction[] _functionsArray;
    79     79   
    80         -    internal SQLite3(SQLiteDateFormats fmt, DateTimeKind kind)
    81         -      : base(fmt, kind)
           80  +    internal SQLite3(SQLiteDateFormats fmt, DateTimeKind kind, string fmtString)
           81  +      : base(fmt, kind, fmtString)
    82     82       {
    83     83       }
    84     84   
    85     85       ///////////////////////////////////////////////////////////////////////////////////////////////
    86     86   
    87     87       #region IDisposable "Pattern" Members
    88     88       private bool disposed;

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

    17     17     using System.Runtime.InteropServices;
    18     18   
    19     19     /// <summary>
    20     20     /// Alternate SQLite3 object, overriding many text behaviors to support UTF-16 (Unicode)
    21     21     /// </summary>
    22     22     internal sealed class SQLite3_UTF16 : SQLite3
    23     23     {
    24         -    internal SQLite3_UTF16(SQLiteDateFormats fmt, DateTimeKind kind)
    25         -      : base(fmt, kind)
           24  +    internal SQLite3_UTF16(SQLiteDateFormats fmt, DateTimeKind kind, string fmtString)
           25  +      : base(fmt, kind, fmtString)
    26     26       {
    27     27       }
    28     28   
    29     29       ///////////////////////////////////////////////////////////////////////////////////////////////
    30     30   
    31     31       #region IDisposable "Pattern" Members
    32     32       private bool disposed;

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

    15     15   
    16     16     /// <summary>
    17     17     /// This internal class provides the foundation of SQLite support.  It defines all the abstract members needed to implement
    18     18     /// a SQLite data provider, and inherits from SQLiteConvert which allows for simple translations of string to and from SQLite.
    19     19     /// </summary>
    20     20     internal abstract class SQLiteBase : SQLiteConvert, IDisposable
    21     21     {
    22         -    internal SQLiteBase(SQLiteDateFormats fmt, DateTimeKind kind)
    23         -      : base(fmt, kind) { }
           22  +    internal SQLiteBase(SQLiteDateFormats fmt, DateTimeKind kind, string fmtString)
           23  +      : base(fmt, kind, fmtString) { }
    24     24   
    25     25       /// <summary>
    26     26       /// Returns a string representing the active version of SQLite
    27     27       /// </summary>
    28     28       internal abstract string Version { get; }
    29     29       /// <summary>
    30     30       /// Returns an integer representing the active version of SQLite

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

   144    144     /// </item>
   145    145     /// <item>
   146    146     /// <description>DateTimeKind</description>
   147    147     /// <description><b>Unspecified</b> - Not specified as either UTC or local time.<br/><b>Utc</b> - The time represented is UTC.<br/><b>Local</b> - The time represented is local time.</description>
   148    148     /// <description>N</description>
   149    149     /// <description>Unspecified</description>
   150    150     /// </item>
          151  +  /// <item>
          152  +  /// <description>DateTimeFormatString</description>
          153  +  /// <description>The exact DateTime format string to use for all formatting and parsing of all DateTime
          154  +  /// values for this connection.</description>
          155  +  /// <description>N</description>
          156  +  /// <description>null</description>
          157  +  /// </item>
   151    158     /// <item>
   152    159     /// <description>BaseSchemaName</description>
   153    160     /// <description>Some base data classes in the framework (e.g. those that build SQL queries dynamically)
   154    161     /// assume that an ADO.NET provider cannot support an alternate catalog (i.e. database) without supporting
   155    162     /// alternate schemas as well; however, SQLite does not fit into this model.  Therefore, this value is used
   156    163     /// as a placeholder and removed prior to preparing any SQL statements that may contain it.</description>
   157    164     /// <description>N</description>
................................................................................
   308    315   
   309    316       private const SQLiteConnectionFlags DefaultFlags = SQLiteConnectionFlags.Default;
   310    317       private const SQLiteSynchronousEnum DefaultSynchronous = SQLiteSynchronousEnum.Default;
   311    318       private const SQLiteJournalModeEnum DefaultJournalMode = SQLiteJournalModeEnum.Default;
   312    319       private const IsolationLevel DefaultIsolationLevel = IsolationLevel.Serializable;
   313    320       private const SQLiteDateFormats DefaultDateTimeFormat = SQLiteDateFormats.ISO8601;
   314    321       private const DateTimeKind DefaultDateTimeKind = DateTimeKind.Unspecified;
          322  +    private const string DefaultDateTimeFormatString = null;
   315    323       private const string DefaultDataSource = null;
   316    324       private const string DefaultUri = null;
   317    325       private const string DefaultFullUri = null;
   318    326       private const string DefaultHexPassword = null;
   319    327       private const string DefaultPassword = null;
   320    328       private const int DefaultVersion = 3;
   321    329       private const int DefaultPageSize = 1024;
................................................................................
  1165   1173       /// </item>
  1166   1174       /// <item>
  1167   1175       /// <description>DateTimeKind</description>
  1168   1176       /// <description><b>Unspecified</b> - Not specified as either UTC or local time.<br/><b>Utc</b> - The time represented is UTC.<br/><b>Local</b> - The time represented is local time.</description>
  1169   1177       /// <description>N</description>
  1170   1178       /// <description>Unspecified</description>
  1171   1179       /// </item>
         1180  +    /// <item>
         1181  +    /// <description>DateTimeFormatString</description>
         1182  +    /// <description>The exact DateTime format string to use for all formatting and parsing of all DateTime
         1183  +    /// values for this connection.</description>
         1184  +    /// <description>N</description>
         1185  +    /// <description>null</description>
         1186  +    /// </item>
  1172   1187       /// <item>
  1173   1188       /// <description>BaseSchemaName</description>
  1174   1189       /// <description>Some base data classes in the framework (e.g. those that build SQL queries dynamically)
  1175   1190       /// assume that an ADO.NET provider cannot support an alternate catalog (i.e. database) without supporting
  1176   1191       /// alternate schemas as well; however, SQLite does not fit into this model.  Therefore, this value is used
  1177   1192       /// as a placeholder and removed prior to preparing any SQL statements that may contain it.</description>
  1178   1193       /// <description>N</description>
................................................................................
  1409   1424       {
  1410   1425         string s = connectionString;
  1411   1426         int n;
  1412   1427         SortedList<string, string> ls = new SortedList<string, string>(StringComparer.OrdinalIgnoreCase);
  1413   1428   
  1414   1429         // First split into semi-colon delimited values.
  1415   1430         string error = null;
  1416         -      string[] arParts = SQLiteConvert.NewSplit(s, ';', true, ref error);
         1431  +      string[] arParts;
         1432  +
         1433  +#if !PLATFORM_COMPACTFRAMEWORK
         1434  +      if (Environment.GetEnvironmentVariable("No_SQLiteConnectionNewParser") != null)
         1435  +          arParts = SQLiteConvert.Split(s, ';');
         1436  +      else
         1437  +#endif
         1438  +          arParts = SQLiteConvert.NewSplit(s, ';', true, ref error);
  1417   1439   
  1418   1440         if (arParts == null)
  1419         -          throw new ArgumentException(String.Format("Invalid ConnectionString format, cannot parse: {0}", error));
         1441  +      {
         1442  +          throw new ArgumentException(String.Format(
         1443  +              "Invalid ConnectionString format, cannot parse: {0}", (error != null) ?
         1444  +              error : "could not split connection string into properties"));
         1445  +      }
  1420   1446   
  1421   1447         int x = (arParts != null) ? arParts.Length : 0;
  1422   1448         // For each semi-colon piece, split into key and value pairs by the presence of the = sign
  1423   1449         for (n = 0; n < x; n++)
  1424   1450         {
  1425   1451           if (arParts[n] == null)
  1426   1452             continue;
................................................................................
  1866   1892   
  1867   1893               enumValue = TryParseEnum(typeof(DateTimeKind), FindKey(opts,
  1868   1894                   "DateTimeKind", DefaultDateTimeKind.ToString()), true);
  1869   1895   
  1870   1896               DateTimeKind kind = (enumValue is DateTimeKind) ?
  1871   1897                   (DateTimeKind)enumValue : DefaultDateTimeKind;
  1872   1898   
         1899  +            string dateTimeFormat = FindKey(opts, "DateTimeFormatString",
         1900  +                DefaultDateTimeFormatString);
         1901  +
  1873   1902               //
  1874   1903               // NOTE: SQLite automatically sets the encoding of the database to
  1875   1904               //       UTF16 if called from sqlite3_open16().
  1876   1905               //
  1877   1906               if (SQLiteConvert.ToBoolean(FindKey(opts, "UseUTF16Encoding",
  1878   1907                         DefaultUseUTF16Encoding.ToString())))
  1879   1908               {
  1880         -                _sql = new SQLite3_UTF16(dateFormat, kind);
         1909  +                _sql = new SQLite3_UTF16(dateFormat, kind, dateTimeFormat);
  1881   1910               }
  1882   1911               else
  1883   1912               {
  1884         -                _sql = new SQLite3(dateFormat, kind);
         1913  +                _sql = new SQLite3(dateFormat, kind, dateTimeFormat);
  1885   1914               }
  1886   1915           }
  1887   1916   
  1888   1917           SQLiteOpenFlagsEnum flags = SQLiteOpenFlagsEnum.None;
  1889   1918   
  1890   1919           if (!SQLiteConvert.ToBoolean(FindKey(opts, "FailIfMissing", DefaultFailIfMissing.ToString())))
  1891   1920             flags |= SQLiteOpenFlagsEnum.Create;
................................................................................
  2295   2324   
  2296   2325               enumValue = TryParseEnum(typeof(DateTimeKind), FindKey(opts,
  2297   2326                   "DateTimeKind", DefaultDateTimeKind.ToString()), true);
  2298   2327   
  2299   2328               DateTimeKind kind = (enumValue is DateTimeKind) ?
  2300   2329                   (DateTimeKind)enumValue : DefaultDateTimeKind;
  2301   2330   
         2331  +            string dateTimeFormat = FindKey(opts, "DateTimeFormatString",
         2332  +                DefaultDateTimeFormatString);
         2333  +
  2302   2334               //
  2303   2335               // NOTE: SQLite automatically sets the encoding of the database to
  2304   2336               //       UTF16 if called from sqlite3_open16().
  2305   2337               //
  2306   2338               if (SQLiteConvert.ToBoolean(FindKey(opts,
  2307   2339                       "UseUTF16Encoding", DefaultUseUTF16Encoding.ToString())))
  2308   2340               {
  2309         -                _sql = new SQLite3_UTF16(dateFormat, kind);
         2341  +                _sql = new SQLite3_UTF16(dateFormat, kind, dateTimeFormat);
  2310   2342               }
  2311   2343               else
  2312   2344               {
  2313         -                _sql = new SQLite3(dateFormat, kind);
         2345  +                _sql = new SQLite3(dateFormat, kind, dateTimeFormat);
  2314   2346               }
  2315   2347           }
  2316   2348           if (_sql != null) return _sql.Shutdown();
  2317   2349           throw new InvalidOperationException("Database connection not active.");
  2318   2350       }
  2319   2351   
  2320   2352       /// Enables or disabled extended result codes returned by SQLite

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

   486    486               return DateTimeKind.Unspecified;
   487    487           }
   488    488           set
   489    489           {
   490    490               this["datetimekind"] = value;
   491    491           }
   492    492       }
          493  +
          494  +    /// <summary>
          495  +    /// Gets/sets the DateTime format string used for formatting
          496  +    /// and parsing purposes.
          497  +    /// </summary>
          498  +    [Browsable(true)]
          499  +    [DefaultValue(null)]
          500  +    public string DateTimeFormatString
          501  +    {
          502  +        get
          503  +        {
          504  +            object value;
          505  +
          506  +            if (TryGetValue("datetimeformatstring", out value))
          507  +            {
          508  +                if (value is string)
          509  +                    return (string)value;
          510  +                else if (value != null)
          511  +                    return value.ToString();
          512  +            }
          513  +
          514  +            return null;
          515  +        }
          516  +        set
          517  +        {
          518  +            this["datetimeformatstring"] = value;
          519  +        }
          520  +    }
   493    521   
   494    522       /// <summary>
   495    523       /// Gets/Sets the placeholder base schema name used for
   496    524       /// .NET Framework compatibility purposes.
   497    525       /// </summary>
   498    526       [Browsable(true)]
   499    527       [DefaultValue(SQLiteConnection.DefaultBaseSchemaName)]

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

    89     89       private static readonly string _datetimeFormatLocal = _datetimeFormats[19];
    90     90   
    91     91       /// <summary>
    92     92       /// An UTF-8 Encoding instance, so we can convert strings to and from UTF-8
    93     93       /// </summary>
    94     94       private static Encoding _utf8 = new UTF8Encoding();
    95     95       /// <summary>
    96         -    /// The default DateTime format for this instance
           96  +    /// The default DateTime format for this instance.
    97     97       /// </summary>
    98     98       internal SQLiteDateFormats _datetimeFormat;
    99     99       /// <summary>
   100    100       /// The default DateTimeKind for this instance.
   101    101       /// </summary>
   102    102       internal DateTimeKind _datetimeKind;
   103    103       /// <summary>
          104  +    /// The default DateTime format string for this instance.
          105  +    /// </summary>
          106  +    internal string _datetimeFormatString = null;
          107  +    /// <summary>
   104    108       /// Initializes the conversion class
   105    109       /// </summary>
   106    110       /// <param name="fmt">The default date/time format to use for this instance</param>
   107    111       /// <param name="kind">The DateTimeKind to use.</param>
   108         -    internal SQLiteConvert(SQLiteDateFormats fmt, DateTimeKind kind)
          112  +    /// <param name="fmtString">The DateTime format string to use.</param>
          113  +    internal SQLiteConvert(
          114  +        SQLiteDateFormats fmt,
          115  +        DateTimeKind kind,
          116  +        string fmtString
          117  +        )
   109    118       {
   110    119         _datetimeFormat = fmt;
   111    120         _datetimeKind = kind;
          121  +      _datetimeFormatString = fmtString;
   112    122       }
   113    123   
   114    124       #region UTF-8 Conversion Functions
   115    125       /// <summary>
   116    126       /// Converts a string to a UTF-8 encoded byte array sized to include a null-terminating character.
   117    127       /// </summary>
   118    128       /// <param name="sourceText">The string to convert to UTF-8</param>
................................................................................
   181    191       }
   182    192   
   183    193   
   184    194       #endregion
   185    195   
   186    196       #region DateTime Conversion Functions
   187    197       /// <summary>
   188         -    /// Converts a string into a DateTime, using the current DateTimeFormat specified for the connection when it was opened.
          198  +    /// Converts a string into a DateTime, using the DateTimeFormat, DateTimeKind,
          199  +    /// and DateTimeFormatString specified for the connection when it was opened.
   189    200       /// </summary>
   190    201       /// <remarks>
   191    202       /// Acceptable ISO8601 DateTime formats are:
   192    203       /// <list type="bullet">
   193    204       /// <item><description>THHmmssK</description></item>
   194    205       /// <item><description>THHmmK</description></item>
   195    206       /// <item><description>HH:mm:ss.FFFFFFFK</description></item>
................................................................................
   218    229       /// <item><description>yyyyMMddHHmmss</description></item>
   219    230       /// <item><description>yyyyMMddHHmm</description></item>
   220    231       /// <item><description>yyyyMMddTHHmmssFFFFFFF</description></item>
   221    232       /// <item><description>yyyy-MM-dd</description></item>
   222    233       /// <item><description>yyyyMMdd</description></item>
   223    234       /// <item><description>yy-MM-dd</description></item>
   224    235       /// </list>
   225         -    /// If the string cannot be matched to one of the above formats, an exception will be thrown.
          236  +    /// If the string cannot be matched to one of the above formats -OR-
          237  +    /// the DateTimeFormatString if one was provided, an exception will
          238  +    /// be thrown.
   226    239       /// </remarks>
   227    240       /// <param name="dateText">The string containing either a long integer number of 100-nanosecond units since
   228    241       /// System.DateTime.MinValue, a Julian day double, an integer number of seconds since the Unix epoch, a
   229    242       /// culture-independent formatted date and time string, a formatted date and time string in the current
   230    243       /// culture, or an ISO8601-format string.</param>
   231    244       /// <returns>A DateTime value</returns>
   232    245       public DateTime ToDateTime(string dateText)
   233    246       {
   234         -      return ToDateTime(dateText, _datetimeFormat, _datetimeKind);
          247  +      return ToDateTime(dateText, _datetimeFormat, _datetimeKind, _datetimeFormatString);
   235    248       }
   236    249   
   237    250       /// <summary>
   238         -    /// Converts a string into a DateTime, using the specified DateTimeFormat and DateTimeKind.
          251  +    /// Converts a string into a DateTime, using the specified DateTimeFormat,
          252  +    /// DateTimeKind and DateTimeFormatString.
   239    253       /// </summary>
   240    254       /// <remarks>
   241    255       /// Acceptable ISO8601 DateTime formats are:
   242    256       /// <list type="bullet">
   243    257       /// <item><description>THHmmssK</description></item>
   244    258       /// <item><description>THHmmK</description></item>
   245    259       /// <item><description>HH:mm:ss.FFFFFFFK</description></item>
................................................................................
   268    282       /// <item><description>yyyyMMddHHmmss</description></item>
   269    283       /// <item><description>yyyyMMddHHmm</description></item>
   270    284       /// <item><description>yyyyMMddTHHmmssFFFFFFF</description></item>
   271    285       /// <item><description>yyyy-MM-dd</description></item>
   272    286       /// <item><description>yyyyMMdd</description></item>
   273    287       /// <item><description>yy-MM-dd</description></item>
   274    288       /// </list>
   275         -    /// If the string cannot be matched to one of the above formats, an exception will be thrown.
          289  +    /// If the string cannot be matched to one of the above formats -OR-
          290  +    /// the DateTimeFormatString if one was provided, an exception will
          291  +    /// be thrown.
   276    292       /// </remarks>
   277    293       /// <param name="dateText">The string containing either a long integer number of 100-nanosecond units since
   278    294       /// System.DateTime.MinValue, a Julian day double, an integer number of seconds since the Unix epoch, a
   279    295       /// culture-independent formatted date and time string, a formatted date and time string in the current
   280    296       /// culture, or an ISO8601-format string.</param>
   281    297       /// <param name="format">The SQLiteDateFormats to use.</param>
   282    298       /// <param name="kind">The DateTimeKind to use.</param>
          299  +    /// <param name="formatString">The DateTime format string to use.</param>
   283    300       /// <returns>A DateTime value</returns>
   284         -    public static DateTime ToDateTime(string dateText, SQLiteDateFormats format, DateTimeKind kind)
          301  +    public static DateTime ToDateTime(
          302  +        string dateText,
          303  +        SQLiteDateFormats format,
          304  +        DateTimeKind kind,
          305  +        string formatString
          306  +        )
   285    307       {
   286    308           switch (format)
   287    309           {
   288    310               case SQLiteDateFormats.Ticks:
   289    311                   {
   290    312                       return new DateTime(Convert.ToInt64(
   291    313                           dateText, CultureInfo.InvariantCulture), kind);
................................................................................
   299    321                   {
   300    322                       return DateTime.SpecifyKind(
   301    323                           UnixEpoch.AddSeconds(Convert.ToInt32(
   302    324                           dateText, CultureInfo.InvariantCulture)), kind);
   303    325                   }
   304    326               case SQLiteDateFormats.InvariantCulture:
   305    327                   {
   306         -                    return DateTime.SpecifyKind(DateTime.Parse(
   307         -                        dateText, DateTimeFormatInfo.InvariantInfo,
   308         -                        kind == DateTimeKind.Utc ?
   309         -                            DateTimeStyles.AdjustToUniversal :
   310         -                            DateTimeStyles.None),
   311         -                        kind);
          328  +                    if (formatString != null)
          329  +                        return DateTime.SpecifyKind(DateTime.ParseExact(
          330  +                            dateText, formatString,
          331  +                            DateTimeFormatInfo.InvariantInfo,
          332  +                            kind == DateTimeKind.Utc ?
          333  +                                DateTimeStyles.AdjustToUniversal :
          334  +                                DateTimeStyles.None),
          335  +                            kind);
          336  +                    else
          337  +                        return DateTime.SpecifyKind(DateTime.Parse(
          338  +                            dateText, DateTimeFormatInfo.InvariantInfo,
          339  +                            kind == DateTimeKind.Utc ?
          340  +                                DateTimeStyles.AdjustToUniversal :
          341  +                                DateTimeStyles.None),
          342  +                            kind);
   312    343                   }
   313    344               case SQLiteDateFormats.CurrentCulture:
   314    345                   {
   315         -                    return DateTime.SpecifyKind(DateTime.Parse(
   316         -                        dateText, DateTimeFormatInfo.CurrentInfo,
   317         -                        kind == DateTimeKind.Utc ?
   318         -                            DateTimeStyles.AdjustToUniversal :
   319         -                            DateTimeStyles.None),
   320         -                        kind);
          346  +                    if (formatString != null)
          347  +                        return DateTime.SpecifyKind(DateTime.ParseExact(
          348  +                            dateText, formatString,
          349  +                            DateTimeFormatInfo.CurrentInfo,
          350  +                            kind == DateTimeKind.Utc ?
          351  +                                DateTimeStyles.AdjustToUniversal :
          352  +                                DateTimeStyles.None),
          353  +                            kind);
          354  +                    else
          355  +                        return DateTime.SpecifyKind(DateTime.Parse(
          356  +                            dateText, DateTimeFormatInfo.CurrentInfo,
          357  +                            kind == DateTimeKind.Utc ?
          358  +                                DateTimeStyles.AdjustToUniversal :
          359  +                                DateTimeStyles.None),
          360  +                            kind);
   321    361                   }
   322    362               default: /* ISO-8601 */
   323    363                   {
   324         -                    return DateTime.SpecifyKind(DateTime.ParseExact(
   325         -                        dateText, _datetimeFormats,
   326         -                        DateTimeFormatInfo.InvariantInfo,
   327         -                        kind == DateTimeKind.Utc ?
   328         -                            DateTimeStyles.AdjustToUniversal :
   329         -                            DateTimeStyles.None),
   330         -                        kind);
          364  +                    if (formatString != null)
          365  +                        return DateTime.SpecifyKind(DateTime.ParseExact(
          366  +                            dateText, formatString,
          367  +                            DateTimeFormatInfo.InvariantInfo,
          368  +                            kind == DateTimeKind.Utc ?
          369  +                                DateTimeStyles.AdjustToUniversal :
          370  +                                DateTimeStyles.None),
          371  +                            kind);
          372  +                    else
          373  +                        return DateTime.SpecifyKind(DateTime.ParseExact(
          374  +                            dateText, _datetimeFormats,
          375  +                            DateTimeFormatInfo.InvariantInfo,
          376  +                            kind == DateTimeKind.Utc ?
          377  +                                DateTimeStyles.AdjustToUniversal :
          378  +                                DateTimeStyles.None),
          379  +                            kind);
   331    380                   }
   332    381           }
   333    382       }
   334    383   
   335    384       /// <summary>
   336    385       /// Converts a julianday value into a DateTime
   337    386       /// </summary>
................................................................................
   372    421       /// <returns>The whole number of seconds since the Unix epoch</returns>
   373    422       public static long ToUnixEpoch(DateTime value)
   374    423       {
   375    424           return (value.Subtract(UnixEpoch).Ticks / TimeSpan.TicksPerSecond);
   376    425       }
   377    426   
   378    427       /// <summary>
   379         -    /// Returns the default DateTime format string to use for the specified
   380         -    /// DateTimeKind.
          428  +    /// Returns the DateTime format string to use for the specified DateTimeKind.
          429  +    /// If <paramref name="formatString"/> is not null, it will be returned verbatim.
   381    430       /// </summary>
   382    431       /// <param name="kind">The DateTimeKind to use.</param>
          432  +    /// <param name="formatString">The DateTime format string to use.</param>
   383    433       /// <returns>
   384         -    /// The default DateTime format string to use for the specified DateTimeKind.
          434  +    /// The DateTime format string to use for the specified DateTimeKind.
   385    435       /// </returns>
   386         -    private static string GetDateTimeKindFormat(DateTimeKind kind)
          436  +    private static string GetDateTimeKindFormat(
          437  +        DateTimeKind kind,
          438  +        string formatString
          439  +        )
   387    440       {
          441  +        if (formatString != null) return formatString;
   388    442           return (kind == DateTimeKind.Utc) ? _datetimeFormatUtc : _datetimeFormatLocal;
   389    443       }
   390    444   
   391    445       /// <summary>
   392         -    /// Converts a DateTime to a string value, using the current DateTimeFormat specified for the connection when it was opened.
          446  +    /// Converts a string into a DateTime, using the DateTimeFormat, DateTimeKind,
          447  +    /// and DateTimeFormatString specified for the connection when it was opened.
   393    448       /// </summary>
   394    449       /// <param name="dateValue">The DateTime value to convert</param>
   395    450       /// <returns>Either a string containing the long integer number of 100-nanosecond units since System.DateTime.MinValue, a
   396    451       /// Julian day double, an integer number of seconds since the Unix epoch, a culture-independent formatted date and time
   397    452       /// string, a formatted date and time string in the current culture, or an ISO8601-format date/time string.</returns>
   398    453       public string ToString(DateTime dateValue)
   399    454       {
................................................................................
   402    457               case SQLiteDateFormats.Ticks:
   403    458                   return dateValue.Ticks.ToString(CultureInfo.InvariantCulture);
   404    459               case SQLiteDateFormats.JulianDay:
   405    460                   return ToJulianDay(dateValue).ToString(CultureInfo.InvariantCulture);
   406    461               case SQLiteDateFormats.UnixEpoch:
   407    462                   return ((long)(dateValue.Subtract(UnixEpoch).Ticks / TimeSpan.TicksPerSecond)).ToString();
   408    463               case SQLiteDateFormats.InvariantCulture:
   409         -                return dateValue.ToString(FullFormat, CultureInfo.InvariantCulture);
          464  +                return dateValue.ToString((_datetimeFormatString != null) ?
          465  +                    _datetimeFormatString : FullFormat, CultureInfo.InvariantCulture);
   410    466               case SQLiteDateFormats.CurrentCulture:
   411         -                return dateValue.ToString(FullFormat, CultureInfo.CurrentCulture);
          467  +                return dateValue.ToString((_datetimeFormatString != null) ?
          468  +                    _datetimeFormatString : FullFormat, CultureInfo.CurrentCulture);
   412    469               default:
   413    470                   return (dateValue.Kind == DateTimeKind.Unspecified) ?
   414    471                       DateTime.SpecifyKind(dateValue, _datetimeKind).ToString(
   415         -                        GetDateTimeKindFormat(_datetimeKind), CultureInfo.InvariantCulture) :
   416         -                    dateValue.ToString(GetDateTimeKindFormat(dateValue.Kind), CultureInfo.InvariantCulture);
          472  +                        GetDateTimeKindFormat(_datetimeKind, _datetimeFormatString),
          473  +                            CultureInfo.InvariantCulture) : dateValue.ToString(
          474  +                        GetDateTimeKindFormat(dateValue.Kind, _datetimeFormatString),
          475  +                            CultureInfo.InvariantCulture);
   417    476           }
   418    477       }
   419    478   
   420    479       /// <summary>
   421    480       /// Internal function to convert a UTF-8 encoded IntPtr of the specified length to a DateTime.
   422    481       /// </summary>
   423    482       /// <remarks>
................................................................................
   863    922         0,            // VarNumeric (21)
   864    923         DBNull.Value, // AnsiStringFixedLength (22)
   865    924         DBNull.Value, // StringFixedLength (23)
   866    925         DBNull.Value, // ?? (24)
   867    926         DBNull.Value  // Xml (25)
   868    927       };
   869    928   
          929  +    /// <summary>
          930  +    /// Determines the type name for the given database value type.
          931  +    /// </summary>
          932  +    /// <param name="typ">The database value type.</param>
          933  +    /// <returns>The type name or an empty string if it cannot be determined.</returns>
   870    934       internal static string DbTypeToTypeName(DbType typ)
   871    935       {
   872    936           lock (_syncRoot)
   873    937           {
   874    938               if (_typeNames == null)
   875    939                   _typeNames = GetSQLiteDbTypeMap();
   876    940   
................................................................................
   967   1031         TypeAffinity.Double,   // Decimal (15)
   968   1032         TypeAffinity.DateTime, // DateTime (16)
   969   1033         TypeAffinity.Null,     // ?? (17)
   970   1034         TypeAffinity.Text      // String (18)
   971   1035       };
   972   1036   
   973   1037       /// <summary>
   974         -    /// Builds and returns an array containing the database column types
         1038  +    /// Builds and returns a map containing the database column types
   975   1039       /// recognized by this provider.
   976   1040       /// </summary>
   977   1041       /// <returns>
   978         -    /// An array containing the database column types recognized by this
         1042  +    /// A map containing the database column types recognized by this
   979   1043       /// provider.
   980   1044       /// </returns>
   981   1045       private static SQLiteDbTypeMap GetSQLiteDbTypeMap()
   982   1046       {
   983   1047           return new SQLiteDbTypeMap(new SQLiteDbTypeMapping[] {
   984   1048               new SQLiteDbTypeMapping("BIGINT", DbType.Int64, false),
   985   1049               new SQLiteDbTypeMapping("BIGUINT", DbType.UInt64, false),
................................................................................
  1426   1490             if (collection == null)
  1427   1491                 throw new ArgumentNullException("collection");
  1428   1492   
  1429   1493             foreach (SQLiteDbTypeMapping item in collection)
  1430   1494                 Add(item);
  1431   1495         }
  1432   1496   
  1433         -      /////////////////////////////////////////////////////////////////////////
  1434         -
  1435         -      public new void Add(
  1436         -          string key, /* IGNORED */
  1437         -          SQLiteDbTypeMapping value
  1438         -          )
  1439         -      {
  1440         -          Add(value);
  1441         -      }
  1442         -
  1443   1497         /////////////////////////////////////////////////////////////////////////
  1444   1498   
  1445   1499         public void Add(SQLiteDbTypeMapping item)
  1446   1500         {
  1447   1501             if (item == null)
  1448   1502                 throw new ArgumentNullException("item");
  1449   1503   

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

   177    177   #endif
   178    178   
   179    179                   //
   180    180                   // NOTE: Create an instance of the SQLite wrapper class.
   181    181                   //
   182    182                   if (_sql == null)
   183    183                       _sql = new SQLite3(SQLiteDateFormats.Default,
   184         -                        DateTimeKind.Unspecified);
          184  +                        DateTimeKind.Unspecified, null);
   185    185   
   186    186                   //
   187    187                   // NOTE: Create a single "global" (i.e. per-process) callback
   188    188                   //       to register with SQLite.  This callback will pass the
   189    189                   //       event on to any registered handler.  We only want to
   190    190                   //       do this once.
   191    191                   //

Changes to Tests/basic.eagle.

   869    869   
   870    870       namespace _Dynamic${id}
   871    871       {
   872    872         public static class Test${id}
   873    873         {
   874    874           public static string GetConnectionString(
   875    875             string format,
   876         -          string kind
          876  +          string kind,
          877  +          string formatString
   877    878             )
   878    879           {
   879    880             SQLiteConnectionStringBuilder builder =
   880    881                 new SQLiteConnectionStringBuilder();
   881    882   
   882    883             builder.Add("Date Source", "test.db");
   883    884             builder.Add("DateTimeFormat", format);
   884    885             builder.Add("DateTimeKind", kind);
          886  +          builder.Add("DateTimeFormatString", formatString);
   885    887   
   886    888             return builder.ToString();
   887    889           }
   888    890   
   889    891           ///////////////////////////////////////////////////////////////////////
   890    892   
   891    893           public static void Main()
................................................................................
   896    898       }
   897    899     }] true true true results errors System.Data.SQLite.dll]
   898    900   
   899    901     list $code $results \
   900    902         [expr {[info exists errors] ? $errors : ""}] \
   901    903         [expr {$code eq "Ok" ? [catch {
   902    904           object invoke _Dynamic${id}.Test${id} GetConnectionString \
   903         -            null null
          905  +            null null null
          906  +      } result] : [set result ""]}] $result \
          907  +      [expr {$code eq "Ok" ? [catch {
          908  +        object invoke _Dynamic${id}.Test${id} GetConnectionString \
          909  +            Default null null
          910  +      } result] : [set result ""]}] $result \
          911  +      [expr {$code eq "Ok" ? [catch {
          912  +        object invoke _Dynamic${id}.Test${id} GetConnectionString \
          913  +            null Unspecified null
   904    914         } result] : [set result ""]}] $result \
   905    915         [expr {$code eq "Ok" ? [catch {
   906    916           object invoke _Dynamic${id}.Test${id} GetConnectionString \
   907         -            Default null
          917  +            ISO8601 Utc null
   908    918         } result] : [set result ""]}] $result \
   909    919         [expr {$code eq "Ok" ? [catch {
   910    920           object invoke _Dynamic${id}.Test${id} GetConnectionString \
   911         -            null Unspecified
   912         -      } result] : [set result ""]}] $result \
   913         -      [expr {$code eq "Ok" ? [catch {
   914         -        object invoke _Dynamic${id}.Test${id} GetConnectionString \
   915         -            ISO8601 Utc
          921  +            Ticks Local yyyy-MM-dd
   916    922         } result] : [set result ""]}] $result
   917    923   } -cleanup {
   918    924     unset -nocomplain result results errors code id
   919    925   } -constraints \
   920    926   {eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -match \
   921    927   regexp -result {^Ok System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 \{Date\
   922    928   Source=test\.db\} 0 \{Date Source=test\.db;DateTimeFormat=(?:Default|ISO8601)\}\
   923    929   0 \{Date Source=test\.db;DateTimeKind=Unspecified\} 0 \{Date\
   924         -Source=test\.db;DateTimeFormat=(?:Default|ISO8601);DateTimeKind=Utc\}$}}
          930  +Source=test\.db;DateTimeFormat=(?:Default|ISO8601);DateTimeKind=Utc\} 0 \{Date\
          931  +Source=test\.db;DateTimeFormat=Ticks;DateTimeKind=Local;DateTimeFormatString=yyyy-MM-dd\}$}}
   925    932   
   926    933   ###############################################################################
   927    934   
   928    935   runTest {test data-1.16 {SQLiteConnectionStringBuilder properties} -body {
   929    936     set id [object invoke Interpreter.GetActive NextId]
   930    937   
   931    938     unset -nocomplain results errors
................................................................................
   997   1004     lappend results $code [expr {[info exists errors] ? $errors : ""}]
   998   1005   
   999   1006     if {$code eq "Ok"} then {
  1000   1007       set keys [list null Version Synchronous UseUTF16Encoding Pooling \
  1001   1008                      BinaryGUID "Data Source" Uri FullUri "Default Timeout" \
  1002   1009                      Enlist FailIfMissing "Legacy Format" "Read Only" \
  1003   1010                      Password "Page Size" "Max Page Count" "Cache Size" \
  1004         -                   DateTimeFormat DateTimeKind BaseSchemaName \
  1005         -                   "Journal Mode" "Default IsolationLevel" "Foreign Keys" \
  1006         -                   Flags SetDefaults ToFullPath HexPassword]
         1011  +                   DateTimeFormat DateTimeKind DateTimeFormatString \
         1012  +                   BaseSchemaName "Journal Mode" "Default IsolationLevel" \
         1013  +                   "Foreign Keys" Flags SetDefaults ToFullPath HexPassword]
  1007   1014   
  1008   1015       set values [list null 3 Normal True False \
  1009   1016                        True test.db test.db file:test.db 60 \
  1010   1017                        False True False True \
  1011   1018                        secret 4096 1024 8192 \
  1012         -                     UnixEpoch Utc sqlite_schema \
         1019  +                     UnixEpoch Utc yyyy-MM-dd sqlite_schema \
  1013   1020                        Memory Serializable False \
  1014   1021                        Default False False 736563726574]
  1015   1022   
  1016   1023       set propertyNames [list null Version SyncMode UseUTF16Encoding Pooling \
  1017   1024                               BinaryGUID DataSource Uri FullUri DefaultTimeout \
  1018   1025                               Enlist FailIfMissing LegacyFormat ReadOnly \
  1019   1026                               Password PageSize MaxPageCount CacheSize \
  1020         -                            DateTimeFormat DateTimeKind BaseSchemaName \
  1021         -                            JournalMode DefaultIsolationLevel ForeignKeys \
  1022         -                            Flags SetDefaults ToFullPath HexPassword]
         1027  +                            DateTimeFormat DateTimeKind DateTimeFormatString \
         1028  +                            BaseSchemaName JournalMode DefaultIsolationLevel \
         1029  +                            ForeignKeys Flags SetDefaults ToFullPath \
         1030  +                            HexPassword]
  1023   1031   
  1024   1032       foreach key $keys value $values propertyName $propertyNames {
  1025   1033         set code [catch {
  1026   1034           object invoke _Dynamic${id}.Test${id} GetConnectionString \
  1027   1035               $key $value $propertyName
  1028   1036         } result]
  1029   1037   
................................................................................
  1042   1050   UseUTF16Encoding=True\} 0 \{False, Pooling=False\} 0 \{True, BinaryGUID=True\}\
  1043   1051   0 \{test\.db, Data Source=test\.db\} 0 \{test\.db, Uri=test\.db\} 0\
  1044   1052   \{file:test.db, FullUri=file:test\.db\} 0 \{60, Default Timeout=60\} 0 \{False,\
  1045   1053   Enlist=False\} 0 \{True, FailIfMissing=True\} 0 \{False, Legacy Format=False\}\
  1046   1054   0 \{True, Read Only=True\} 0 \{secret, Password=secret\} 0 \{4096, Page\
  1047   1055   Size=4096\} 0 \{1024, Max Page Count=1024\} 0 \{8192, Cache Size=8192\} 0\
  1048   1056   \{UnixEpoch, DateTimeFormat=UnixEpoch\} 0 \{Utc, DateTimeKind=Utc\} 0\
  1049         -\{sqlite_schema, BaseSchemaName=sqlite_schema\} 0 \{Memory, Journal\
  1050         -Mode=Memory\} 0 \{Serializable, Default IsolationLevel=Serializable\} 0\
  1051         -\{False, Foreign Keys=False\} 0 \{(?:Default|LogCallbackException),\
         1057  +\{yyyy-MM-dd, DateTimeFormatString=yyyy-MM-dd\} 0 \{sqlite_schema,\
         1058  +BaseSchemaName=sqlite_schema\} 0 \{Memory, Journal Mode=Memory\} 0\
         1059  +\{Serializable, Default IsolationLevel=Serializable\} 0 \{False, Foreign\
         1060  +Keys=False\} 0 \{(?:Default|LogCallbackException),\
  1052   1061   Flags=(?:Default|LogCallbackException)\} 0 \{False, SetDefaults=False\} 0\
  1053   1062   \{False, ToFullPath=False\} 0 {736563726574, HexPassword=736563726574}$}}
  1054   1063   
  1055   1064   ###############################################################################
  1056   1065   
  1057   1066   runTest {test data-1.17 {SQLiteConvert ToDateTime (Julian Day)} -body {
  1058   1067     set dateTime [object invoke -create System.Data.SQLite.SQLiteConvert \
................................................................................
  1465   1474     #
  1466   1475     shutdownSQLite $test_channel
  1467   1476   
  1468   1477     #
  1469   1478     # NOTE: Create an instance of the core SQLite library interop wrapper class.
  1470   1479     #
  1471   1480     set sqlite3 [object create -flags +NonPublic System.Data.SQLite.SQLite3 \
  1472         -      Default Unspecified]
         1481  +      Default Unspecified null]
  1473   1482   } -body {
  1474   1483     set result(rc1) [object invoke -flags +NonPublic $sqlite3 SetMemoryStatus \
  1475   1484         false]
  1476   1485   
  1477   1486     set result(before) [object invoke -flags +NonPublic $sqlite3 MemoryUsed]
  1478   1487   
  1479   1488     set result(ptr1) [object invoke -create -flags +NonPublic \

Changes to readme.htm.

   187    187   <h2><b>Version History</b></h2>
   188    188   
   189    189   <p>
   190    190       <b>1.0.87.0 - June XX, 2013 <font color="red">(release scheduled)</font></b>
   191    191   </p>
   192    192   <ul>
   193    193       <li>The DbType to type name translation needs to prioritize the Entity Framework type names. Fix for [47f4bac575].</li>
          194  +    <li>Add DateTimeFormatString connection string property to allow the DateTime format string used for all parsing and formatting to be overridden.</li>
          195  +    <li>Disable use of the new connection string parsing algorithm when the No_SQLiteConnectionNewParser environment variable is set. Pursuant to [bbdda6eae2].</li>
   194    196   </ul>
   195    197   <p>
   196    198       <b>1.0.86.0 - May 23, 2013</b>
   197    199   </p>
   198    200   <ul>
   199    201       <li>Updated to <a href="http://www.sqlite.org/releaselog/3_7_17.html">SQLite 3.7.17</a>.</li>
   200    202       <li>Disable use of the AllowPartiallyTrustedCallers attribute when compiled for the .NET Framework 4.0/4.5.&nbsp;<b>** Potentially Incompatible Change **</b></li>

Changes to www/news.wiki.

     3      3   <b>Version History</b>
     4      4   
     5      5   <p>
     6      6       <b>1.0.87.0 - June XX, 2013 <font color="red">(release scheduled)</font></b>
     7      7   </p>
     8      8   <ul>
     9      9       <li>The DbType to type name translation needs to prioritize the Entity Framework type names. Fix for [47f4bac575].</li>
           10  +    <li>Add DateTimeFormatString connection string property to allow the DateTime format string used for all parsing and formatting to be overridden.</li>
           11  +    <li>Disable use of the new connection string parsing algorithm when the No_SQLiteConnectionNewParser environment variable is set. Pursuant to [bbdda6eae2].</li>
    10     12   </ul>
    11     13   <p>
    12     14       <b>1.0.86.0 - May 23, 2013</b>
    13     15   </p>
    14     16   <ul>
    15     17       <li>Updated to [http://www.sqlite.org/releaselog/3_7_17.html|SQLite 3.7.17].</li>
    16     18       <li>Disable use of the AllowPartiallyTrustedCallers attribute when compiled for the .NET Framework 4.0/4.5.&nbsp;<b>** Potentially Incompatible Change **</b></li>