Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch tkt-8d928c3e88 Excluding Merge-Ins
This is equivalent to a diff from c2e4f24377 to 45312da90e
2015-01-14
| ||
21:26 | Address all the LINQ issues mentioned in ticket [8d928c3e88]. Make the storage schema (SSDL) files more consistent with their provider names. check-in: 9ff0f0adf0 user: mistachkin tags: trunk | |
2015-01-13
| ||
04:08 | Fix extra single quotes around the formatted DateTime values in the LINQ assembly. Use GetSettingValue to access the new environment variables. Closed-Leaf check-in: 45312da90e user: mistachkin tags: tkt-8d928c3e88 | |
03:39 | In the LINQ assembly, when surrounding single quotes are required for a formatted DateTime value, be sure to escape contained single quotes. check-in: b999c9c818 user: mistachkin tags: tkt-8d928c3e88 | |
03:34 | Merge updates from trunk. check-in: a15efc1fd5 user: mistachkin tags: tkt-8d928c3e88 | |
03:34 | Attempt to make the 'legacy' NuGet package configuration transform work the same as the EF6 one. check-in: c2e4f24377 user: mistachkin tags: trunk | |
03:30 | Remove a comment that is no longer accurate. check-in: 812281ccef user: mistachkin tags: trunk | |
Changes to Doc/Extra/Provider/environment.html.
︙ | ︙ | |||
76 77 78 79 80 81 82 83 84 85 86 87 88 89 | </font> </p> <table width="80%" cellpadding="0" cellspacing="0"> <tr valign="top"> <th>Name</th> <th>Description</th> </tr> <tr valign="top"> <td>Force_SQLiteLog</td> <td>If this environment variable is set [to anything], the SQLite logging subsystem may be initialized in a non-default application domain. By default, this is not allowed due to the potential for application domain unloading issues.</td> </tr> | > > > > > > > > > > > | 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 | </font> </p> <table width="80%" cellpadding="0" cellspacing="0"> <tr valign="top"> <th>Name</th> <th>Description</th> </tr> <tr valign="top"> <td>AppendManifestToken_SQLiteProviderManifest</td> <td>If this environment variable is set [to anything], it will be used by the System.Data.SQLite.Linq.SQLiteProviderManifest class (and the System.Data.SQLite.EF6.SQLiteProviderManifest class) to modify future provider manifest tokens by appending the value of the environment variable to the existing provider manifest token, if any. Typically, in order for the constructed provider manifest token to be syntactically correct, the environment variable value [to be appended] must begin with a semicolon.</td> </tr> <tr valign="top"> <td>Force_SQLiteLog</td> <td>If this environment variable is set [to anything], the SQLite logging subsystem may be initialized in a non-default application domain. By default, this is not allowed due to the potential for application domain unloading issues.</td> </tr> |
︙ | ︙ | |||
149 150 151 152 153 154 155 156 157 158 159 160 161 162 | <td>PROCESSOR_ARCHITECTURE</td> <td>This environment variable is normally set by the operating system itself and should reflect the native processor architecture of the current process (e.g. a 32-bit x86 application running on a 64-bit x64 operating system should have the value "x86"). </td> </tr> <tr valign="top"> <td>TypeName_SQLiteProviderServices</td> <td>If this environment variable is set [to anything], it will be used by the System.Data.SQLite.SQLiteFactory class as the type name containing the System.Data.Common.DbProviderServices implementation that should be used.</td> </tr> | > > > > > > | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | <td>PROCESSOR_ARCHITECTURE</td> <td>This environment variable is normally set by the operating system itself and should reflect the native processor architecture of the current process (e.g. a 32-bit x86 application running on a 64-bit x64 operating system should have the value "x86"). </td> </tr> <tr valign="top"> <td>SQLite_ForceLogPrepare</td> <td>If this environment variable is set [to anything], all calls to prepare a SQL query will be logged, regardless of the flags for the associated connection.</td> </tr> <tr valign="top"> <td>TypeName_SQLiteProviderServices</td> <td>If this environment variable is set [to anything], it will be used by the System.Data.SQLite.SQLiteFactory class as the type name containing the System.Data.Common.DbProviderServices implementation that should be used.</td> </tr> |
︙ | ︙ |
Changes to Doc/Extra/Provider/version.html.
︙ | ︙ | |||
51 52 53 54 55 56 57 58 59 60 61 62 63 64 | <li>Defer disposing of connections created by the static SQLiteCommand.Execute method when a data reader is returned. Fix for <a href="http://system.data.sqlite.org/index.html/info/daeaf3150a">[daeaf3150a]</a>.</li> <li>Wrap SELECT statements in parenthesis if they have an ORDER BY, LIMIT, or OFFSET clause and a compound operator is involved. Fix for <a href="http://system.data.sqlite.org/index.html/info/0a32885109">[0a32885109]</a>.</li> <li>In the SQLiteDataReader.VerifyType method, remove duplicate "if" statement for the DbType.SByte value and move the remaining "if" to the Int64 affinity. Fix for <a href="http://system.data.sqlite.org/index.html/info/c5cc2fb334">[c5cc2fb334]</a>. <b>** Potentially Incompatible Change **</b></li> <li>Handle Julian Day values that fall outside of the supported range for OLE Automation dates. Fix for <a href="http://system.data.sqlite.org/index.html/info/3e783eecbe">[3e783eecbe]</a>. <b>** Potentially Incompatible Change **</b></li> <li>Make sure the interop files are copied when publishing a project that refers to a NuGet package containing them. Fix for <a href="http://system.data.sqlite.org/index.html/info/e796ac82c1">[e796ac82c1]</a>. <b>** Potentially Incompatible Change **</b></li> <li>Make sure the interop files are copied before the PostBuildEvent. Fix for <a href="http://system.data.sqlite.org/index.html/info/f16c93a932">[f16c93a932]</a>. <b>** Potentially Incompatible Change **</b></li> <li>Modify GetSchemaTable method to avoid setting SchemaTableColumn.IsKey column to true when more than one table is referenced. Fix for <a href="http://system.data.sqlite.org/index.html/info/47c6fa04d3">[47c6fa04d3]</a>. <b>** Potentially Incompatible Change **</b></li> </ul> <p><b>1.0.94.0 - September 9, 2014</b></p> <ul> <li>Updated to <a href="http://www.sqlite.org/releaselog/3_8_6.html">SQLite 3.8.6</a>.</li> <li>Updated to <a href="http://www.nuget.org/packages/EntityFramework/6.1.1">Entity Framework 6.1.1</a>.</li> <li>Refactor and simplify NuGet packages in order to support per-solution SQLite interop assembly files. <b>** Potentially Incompatible Change **</b></li> <li>Add RefreshFlags method to the SQLiteDataReader class to forcibly refresh its connection flags.</li> | > > > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | <li>Defer disposing of connections created by the static SQLiteCommand.Execute method when a data reader is returned. Fix for <a href="http://system.data.sqlite.org/index.html/info/daeaf3150a">[daeaf3150a]</a>.</li> <li>Wrap SELECT statements in parenthesis if they have an ORDER BY, LIMIT, or OFFSET clause and a compound operator is involved. Fix for <a href="http://system.data.sqlite.org/index.html/info/0a32885109">[0a32885109]</a>.</li> <li>In the SQLiteDataReader.VerifyType method, remove duplicate "if" statement for the DbType.SByte value and move the remaining "if" to the Int64 affinity. Fix for <a href="http://system.data.sqlite.org/index.html/info/c5cc2fb334">[c5cc2fb334]</a>. <b>** Potentially Incompatible Change **</b></li> <li>Handle Julian Day values that fall outside of the supported range for OLE Automation dates. Fix for <a href="http://system.data.sqlite.org/index.html/info/3e783eecbe">[3e783eecbe]</a>. <b>** Potentially Incompatible Change **</b></li> <li>Make sure the interop files are copied when publishing a project that refers to a NuGet package containing them. Fix for <a href="http://system.data.sqlite.org/index.html/info/e796ac82c1">[e796ac82c1]</a>. <b>** Potentially Incompatible Change **</b></li> <li>Make sure the interop files are copied before the PostBuildEvent. Fix for <a href="http://system.data.sqlite.org/index.html/info/f16c93a932">[f16c93a932]</a>. <b>** Potentially Incompatible Change **</b></li> <li>Modify GetSchemaTable method to avoid setting SchemaTableColumn.IsKey column to true when more than one table is referenced. Fix for <a href="http://system.data.sqlite.org/index.html/info/47c6fa04d3">[47c6fa04d3]</a>. <b>** Potentially Incompatible Change **</b></li> <li>Add AppendManifestToken_SQLiteProviderManifest environment variable to enable better integration between LINQ and the underlying store connection.</li> <li>Add SQLite_ForceLogPrepare environment variable to force logging of all prepared SQL regardless of the flags for the associated connection.</li> <li>Honor the DateTimeFormat, DateTimeKind, DateTimeFormatString, BinaryGUID connection string and/or provider manifest token properties from within the LINQ assembly. Fix for <a href="http://system.data.sqlite.org/index.html/info/8d928c3e88">[8d928c3e88]</a>. <b>** Potentially Incompatible Change **</b></li> </ul> <p><b>1.0.94.0 - September 9, 2014</b></p> <ul> <li>Updated to <a href="http://www.sqlite.org/releaselog/3_8_6.html">SQLite 3.8.6</a>.</li> <li>Updated to <a href="http://www.nuget.org/packages/EntityFramework/6.1.1">Entity Framework 6.1.1</a>.</li> <li>Refactor and simplify NuGet packages in order to support per-solution SQLite interop assembly files. <b>** Potentially Incompatible Change **</b></li> <li>Add RefreshFlags method to the SQLiteDataReader class to forcibly refresh its connection flags.</li> |
︙ | ︙ |
Changes to System.Data.SQLite.Linq/Resources/SQLiteProviderServices.StoreSchemaDefinition.EF6.ssdl.
︙ | ︙ | |||
273 274 275 276 277 278 279 | <AssociationSet Name="STableConstraints" Association="Self.TableTableConstraint" > <End Role="Parent" EntitySet="STables"/> <End Role="Constraint" EntitySet="SConstraints"/> </AssociationSet> <AssociationSet Name="SConstraintConstraintColumns" Association="Self.ConstraintConstraintColumn" > <End Role="ConstraintColumn" EntitySet="SConstraintColumns"/> <End Role="Constraint" EntitySet="SConstraints"/> | | | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | <AssociationSet Name="STableConstraints" Association="Self.TableTableConstraint" > <End Role="Parent" EntitySet="STables"/> <End Role="Constraint" EntitySet="SConstraints"/> </AssociationSet> <AssociationSet Name="SConstraintConstraintColumns" Association="Self.ConstraintConstraintColumn" > <End Role="ConstraintColumn" EntitySet="SConstraintColumns"/> <End Role="Constraint" EntitySet="SConstraints"/> </AssociationSet> <AssociationSet Name="SConstraintForeignKeys" Association="Self.ConstraintForeignKey" > <End Role="ForeignKey" EntitySet="SForeignKeys"/> <End Role="Constraint" EntitySet="SForeignKeyConstraints"/> </AssociationSet> <AssociationSet Name="SFromForeignKeyColumns" Association="Self.FromForeignKeyColumn" > <End Role="ForeignKey" EntitySet="SForeignKeys"/> <End Role="Column" EntitySet="STableColumns"/> |
︙ | ︙ | |||
475 476 477 478 479 480 481 | <EntityType Name="CheckConstraint"> <Key> <PropertyRef Name="Id" /> </Key> <Property Name="Id" Nullable="false" Type="nvarchar" /> <Property Name="Expression" Nullable="true" Type="nvarchar" /> </EntityType> | | | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 | <EntityType Name="CheckConstraint"> <Key> <PropertyRef Name="Id" /> </Key> <Property Name="Id" Nullable="false" Type="nvarchar" /> <Property Name="Expression" Nullable="true" Type="nvarchar" /> </EntityType> <EntityType Name="ConstraintColumn"> <Key> <PropertyRef Name="ConstraintId" /> <PropertyRef Name="ColumnId" /> </Key> <Property Name="ConstraintId" Nullable="false" Type="nvarchar" /> <Property Name="ColumnId" Nullable="false" Type="nvarchar" /> |
︙ | ︙ |
Changes to System.Data.SQLite.Linq/Resources/SQLiteProviderServices.StoreSchemaDefinition.Linq.ssdl.
1 | <?xml version="1.0" encoding="utf-8"?> | | | 1 2 3 4 5 6 7 8 9 | <?xml version="1.0" encoding="utf-8"?> <Schema Namespace="EFSQLite" Provider="System.Data.SQLite.Linq" ProviderManifestToken="ISO8601" Alias="Self" xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl"> <EntityContainer Name="Schema"> <EntitySet Name="STables" EntityType="Self.Table"> <DefiningQuery> SELECT '[' || TABLE_NAME || ']' COLLATE NOCASE [Id] , TABLE_CATALOG [CatalogName] , TABLE_SCHEMA [SchemaName] |
︙ | ︙ | |||
273 274 275 276 277 278 279 | <AssociationSet Name="STableConstraints" Association="Self.TableTableConstraint" > <End Role="Parent" EntitySet="STables"/> <End Role="Constraint" EntitySet="SConstraints"/> </AssociationSet> <AssociationSet Name="SConstraintConstraintColumns" Association="Self.ConstraintConstraintColumn" > <End Role="ConstraintColumn" EntitySet="SConstraintColumns"/> <End Role="Constraint" EntitySet="SConstraints"/> | | | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | <AssociationSet Name="STableConstraints" Association="Self.TableTableConstraint" > <End Role="Parent" EntitySet="STables"/> <End Role="Constraint" EntitySet="SConstraints"/> </AssociationSet> <AssociationSet Name="SConstraintConstraintColumns" Association="Self.ConstraintConstraintColumn" > <End Role="ConstraintColumn" EntitySet="SConstraintColumns"/> <End Role="Constraint" EntitySet="SConstraints"/> </AssociationSet> <AssociationSet Name="SConstraintForeignKeys" Association="Self.ConstraintForeignKey" > <End Role="ForeignKey" EntitySet="SForeignKeys"/> <End Role="Constraint" EntitySet="SForeignKeyConstraints"/> </AssociationSet> <AssociationSet Name="SFromForeignKeyColumns" Association="Self.FromForeignKeyColumn" > <End Role="ForeignKey" EntitySet="SForeignKeys"/> <End Role="Column" EntitySet="STableColumns"/> |
︙ | ︙ | |||
475 476 477 478 479 480 481 | <EntityType Name="CheckConstraint"> <Key> <PropertyRef Name="Id" /> </Key> <Property Name="Id" Nullable="false" Type="nvarchar" /> <Property Name="Expression" Nullable="true" Type="nvarchar" /> </EntityType> | | | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 | <EntityType Name="CheckConstraint"> <Key> <PropertyRef Name="Id" /> </Key> <Property Name="Id" Nullable="false" Type="nvarchar" /> <Property Name="Expression" Nullable="true" Type="nvarchar" /> </EntityType> <EntityType Name="ConstraintColumn"> <Key> <PropertyRef Name="ConstraintId" /> <PropertyRef Name="ColumnId" /> </Key> <Property Name="ConstraintId" Nullable="false" Type="nvarchar" /> <Property Name="ColumnId" Nullable="false" Type="nvarchar" /> |
︙ | ︙ |
Changes to System.Data.SQLite.Linq/SQL Generation/SqlBuilder.cs.
︙ | ︙ | |||
97 98 99 100 101 102 103 104 105 106 107 108 109 110 | else { ISqlFragment sqlFragment = (o as ISqlFragment); if (null != sqlFragment) { sqlFragment.WriteSql(writer, sqlGenerator); } else { throw new InvalidOperationException(); } } } } | > > > > | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | else { ISqlFragment sqlFragment = (o as ISqlFragment); if (null != sqlFragment) { sqlFragment.WriteSql(writer, sqlGenerator); } else if (o is char) { writer.Write((char)o); } else { throw new InvalidOperationException(); } } } } |
︙ | ︙ |
Changes to System.Data.SQLite.Linq/SQL Generation/SqlGenerator.cs.
︙ | ︙ | |||
116 117 118 119 120 121 122 | /// Renaming issues. /// When rows or columns are renamed, we produce names that are unique globally /// with respect to the query. The names are derived from the original names, /// with an integer as a suffix. e.g. CustomerId will be renamed to CustomerId1, /// CustomerId2 etc. /// /// Since the names generated are globally unique, they will not conflict when the | | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | /// Renaming issues. /// When rows or columns are renamed, we produce names that are unique globally /// with respect to the query. The names are derived from the original names, /// with an integer as a suffix. e.g. CustomerId will be renamed to CustomerId1, /// CustomerId2 etc. /// /// Since the names generated are globally unique, they will not conflict when the /// columns of a JOIN SELECT statement are joined with another JOIN. /// /// </para> /// /// <para> /// Record flattening. /// SQL server does not have the concept of records. However, a join statement /// produces records. We have to flatten the record accesses into a simple |
︙ | ︙ | |||
434 435 436 437 438 439 440 | return functionNameToOperatorDictionary; } #endregion #region Constructor /// <summary> | | | 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | return functionNameToOperatorDictionary; } #endregion #region Constructor /// <summary> /// Basic constructor. /// </summary> private SqlGenerator(SQLiteProviderManifest manifest) { _manifest = manifest; } #endregion |
︙ | ︙ | |||
462 463 464 465 466 467 468 | //Handle Query DbQueryCommandTree queryCommandTree = tree as DbQueryCommandTree; if (queryCommandTree != null) { SqlGenerator sqlGen = new SqlGenerator(manifest); parameters = null; | | | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 | //Handle Query DbQueryCommandTree queryCommandTree = tree as DbQueryCommandTree; if (queryCommandTree != null) { SqlGenerator sqlGen = new SqlGenerator(manifest); parameters = null; string sql = sqlGen.GenerateSql((DbQueryCommandTree)tree); return sql; } //Handle Function DbFunctionCommandTree DbFunctionCommandTree = tree as DbFunctionCommandTree; |
︙ | ︙ | |||
871 872 873 874 875 876 877 | switch (typeKind) { case PrimitiveTypeKind.Int32: result.Append(e.Value.ToString()); break; case PrimitiveTypeKind.Binary: | < | < > > > > > > > > | > > > > > > | 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 | switch (typeKind) { case PrimitiveTypeKind.Int32: result.Append(e.Value.ToString()); break; case PrimitiveTypeKind.Binary: ToBlobLiteral((byte[])e.Value, result); break; case PrimitiveTypeKind.Boolean: result.Append((bool)e.Value ? "1" : "0"); break; case PrimitiveTypeKind.Byte: result.Append(e.Value.ToString()); break; case PrimitiveTypeKind.DateTime: bool needQuotes = NeedSingleQuotes(_manifest._dateTimeFormat); string dateString = SQLiteConvert.ToString( (System.DateTime)e.Value, _manifest._dateTimeFormat, _manifest._dateTimeKind, _manifest._dateTimeFormatString); if (needQuotes) { result.Append(EscapeSingleQuote( dateString, false /* IsUnicode */)); } else { result.Append(dateString); } break; case PrimitiveTypeKind.Decimal: string strDecimal = ((Decimal)e.Value).ToString(CultureInfo.InvariantCulture); // if the decimal value has no decimal part, cast as decimal to preserve type // if the number has precision > int64 max precision, it will be handled as decimal by sql server // and does not need cast. if precision is lest then 20, then cast using Max(literal precision, sql default precision) |
︙ | ︙ | |||
919 920 921 922 923 924 925 | break; case PrimitiveTypeKind.Double: result.Append(((Double)e.Value).ToString(CultureInfo.InvariantCulture)); break; case PrimitiveTypeKind.Guid: | > > > > > > | > | 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 | break; case PrimitiveTypeKind.Double: result.Append(((Double)e.Value).ToString(CultureInfo.InvariantCulture)); break; case PrimitiveTypeKind.Guid: { object value = e.Value; if (_manifest._binaryGuid && (value is Guid)) ToBlobLiteral(((Guid)value).ToByteArray(), result); else result.Append(EscapeSingleQuote(e.Value.ToString(), false /* IsUnicode */)); } break; case PrimitiveTypeKind.Int16: result.Append(e.Value.ToString()); break; case PrimitiveTypeKind.Int64: |
︙ | ︙ | |||
1123 1124 1125 1126 1127 1128 1129 | /// Lambda functions are not supported. /// The functions supported are: /// <list type="number"> /// <item>Canonical Functions - We recognize these by their dataspace, it is DataSpace.CSpace</item> /// <item>Store Functions - We recognize these by the BuiltInAttribute and not being Canonical</item> /// <item>User-defined Functions - All the rest except for Lambda functions</item> /// </list> | | | 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 | /// Lambda functions are not supported. /// The functions supported are: /// <list type="number"> /// <item>Canonical Functions - We recognize these by their dataspace, it is DataSpace.CSpace</item> /// <item>Store Functions - We recognize these by the BuiltInAttribute and not being Canonical</item> /// <item>User-defined Functions - All the rest except for Lambda functions</item> /// </list> /// We handle Canonical and Store functions the same way: If they are in the list of functions /// that need special handling, we invoke the appropriate handler, otherwise we translate them to /// FunctionName(arg1, arg2, ..., argn). /// We translate user-defined functions to NamespaceName.FunctionName(arg1, arg2, ..., argn). /// </summary> /// <param name="e"></param> /// <returns>A <see cref="SqlBuilder"/></returns> public override ISqlFragment Visit(DbFunctionExpression e) |
︙ | ︙ | |||
1174 1175 1176 1177 1178 1179 1180 | } /// <summary> /// <see cref="Visit(DbFilterExpression)"/> for general details. /// We modify both the GroupBy and the Select fields of the SqlSelectStatement. /// GroupBy gets just the keys without aliases, /// and Select gets the keys and the aggregates with aliases. | | | | | | | | | | | | | | | | | | | 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 | } /// <summary> /// <see cref="Visit(DbFilterExpression)"/> for general details. /// We modify both the GroupBy and the Select fields of the SqlSelectStatement. /// GroupBy gets just the keys without aliases, /// and Select gets the keys and the aggregates with aliases. /// /// Whenever there exists at least one aggregate with an argument that is not is not a simple /// <see cref="DbPropertyExpression"/> over <see cref="DbVariableReferenceExpression"/>, /// we create a nested query in which we alias the arguments to the aggregates. /// That is due to the following two limitations of Sql Server: /// <list type="number"> /// <item>If an expression being aggregated contains an outer reference, then that outer /// reference must be the only column referenced in the expression </item> /// <item>Sql Server cannot perform an aggregate function on an expression containing /// an aggregate or a subquery. </item> /// </list> /// /// The default translation, without inner query is: /// /// SELECT /// kexp1 AS key1, kexp2 AS key2,... kexpn AS keyn, /// aggf1(aexpr1) AS agg1, .. aggfn(aexprn) AS aggn /// FROM input AS a /// GROUP BY kexp1, kexp2, .. kexpn /// /// When we inject an innner query, the equivalent translation is: /// /// SELECT /// key1 AS key1, key2 AS key2, .. keyn AS keys, /// aggf1(agg1) AS agg1, aggfn(aggn) AS aggn /// FROM ( /// SELECT /// kexp1 AS key1, kexp2 AS key2,... kexpn AS keyn, /// aexpr1 AS agg1, .. aexprn AS aggn /// FROM input AS a /// ) as a /// GROUP BY key1, key2, keyn /// /// </summary> /// <param name="e"></param> /// <returns>A <see cref="SqlSelectStatement"/></returns> public override ISqlFragment Visit(DbGroupByExpression e) { Symbol fromSymbol; //SqlSelectStatement result = VisitInputExpression(e.Input.Expression, |
︙ | ︙ | |||
1236 1237 1238 1239 1240 1241 1242 | symbolTable.Add(e.Input.GroupVariableName, fromSymbol); // The enumerator is shared by both the keys and the aggregates, // so, we do not close it in between. RowType groupByType = MetadataHelpers.GetEdmType<RowType>(MetadataHelpers.GetEdmType<CollectionType>(e.ResultType).TypeUsage); | | | 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 | symbolTable.Add(e.Input.GroupVariableName, fromSymbol); // The enumerator is shared by both the keys and the aggregates, // so, we do not close it in between. RowType groupByType = MetadataHelpers.GetEdmType<RowType>(MetadataHelpers.GetEdmType<CollectionType>(e.ResultType).TypeUsage); //Whenever there exists at least one aggregate with an argument that is not simply a PropertyExpression // over a VarRefExpression, we need a nested query in which we alias the arguments to the aggregates. bool needsInnerQuery = NeedsInnerQuery(e.Aggregates); SqlSelectStatement result; if (needsInnerQuery) { //Create the inner query |
︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 | // The inner query contains the default translation Key AS Alias innerQuery.Select.Append(separator); innerQuery.Select.AppendLine(); innerQuery.Select.Append(keySql); innerQuery.Select.Append(" AS "); innerQuery.Select.Append(alias); | | | 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 | // The inner query contains the default translation Key AS Alias innerQuery.Select.Append(separator); innerQuery.Select.AppendLine(); innerQuery.Select.Append(keySql); innerQuery.Select.Append(" AS "); innerQuery.Select.Append(alias); //The outer resulting query projects over the key aliased in the inner query: // fromSymbol.Alias AS Alias result.Select.Append(separator); result.Select.AppendLine(); result.Select.Append(fromSymbol); result.Select.Append("."); result.Select.Append(alias); result.Select.Append(" AS "); |
︙ | ︙ | |||
1462 1463 1464 1465 1466 1467 1468 | public override ISqlFragment Visit(DbLikeExpression e) { SqlBuilder result = new SqlBuilder(); result.Append(e.Argument.Accept(this)); result.Append(" LIKE "); result.Append(e.Pattern.Accept(this)); | | | 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 | public override ISqlFragment Visit(DbLikeExpression e) { SqlBuilder result = new SqlBuilder(); result.Append(e.Argument.Accept(this)); result.Append(" LIKE "); result.Append(e.Pattern.Accept(this)); // if the ESCAPE expression is a DbNullExpression, then that's tantamount to // not having an ESCAPE at all if (e.Escape.ExpressionKind != DbExpressionKind.Null) { result.Append(" ESCAPE "); result.Append(e.Escape.Accept(this)); } |
︙ | ︙ | |||
1812 1813 1814 1815 1816 1817 1818 | throw new NotSupportedException(); } /// <summary> /// For Sql9 it translates to: /// SELECT Y.x1, Y.x2, ..., Y.xn /// FROM ( | | | | | 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 | throw new NotSupportedException(); } /// <summary> /// For Sql9 it translates to: /// SELECT Y.x1, Y.x2, ..., Y.xn /// FROM ( /// SELECT X.x1, X.x2, ..., X.xn, row_number() OVER (ORDER BY sk1, sk2, ...) AS [row_number] /// FROM input as X /// ) as Y /// WHERE Y.[row_number] > count /// ORDER BY sk1, sk2, ... /// </summary> /// <param name="e"></param> /// <returns>A <see cref="SqlBuilder"/></returns> public override ISqlFragment Visit(DbSkipExpression e) { Debug.Assert(e.Count is DbConstantExpression || e.Count is DbParameterReferenceExpression, "DbLimitExpression.Count is of invalid expression type"); |
︙ | ︙ | |||
2615 2616 2617 2618 2619 2620 2621 | throw new InvalidOperationException("Special handling should be called only for functions in the list of special functions"); return handlers[e.Function.Name](this, e); } /// <summary> /// Handles functions that are translated into TSQL operators. | | | | 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 | throw new InvalidOperationException("Special handling should be called only for functions in the list of special functions"); return handlers[e.Function.Name](this, e); } /// <summary> /// Handles functions that are translated into TSQL operators. /// The given function should have one or two arguments. /// Functions with one arguemnt are translated into /// op arg /// Functions with two arguments are translated into /// arg0 op arg1 /// Also, the arguments can be optionaly enclosed in parethesis /// </summary> /// <param name="e"></param> /// <param name="parenthesiseArguments">Whether the arguments should be enclosed in parethesis</param> |
︙ | ︙ | |||
2687 2688 2689 2690 2691 2692 2693 | } private static ISqlFragment HandleGetDateFunction(SqlGenerator sqlgen, DbFunctionExpression e) { SqlBuilder result = new SqlBuilder(); Debug.Assert(e.Arguments.Count == 0, "Canonical getdate function should have no arguments"); | | | | 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 | } private static ISqlFragment HandleGetDateFunction(SqlGenerator sqlgen, DbFunctionExpression e) { SqlBuilder result = new SqlBuilder(); Debug.Assert(e.Arguments.Count == 0, "Canonical getdate function should have no arguments"); switch (sqlgen._manifest._dateTimeFormat) { case SQLiteDateFormats.Ticks: result.Append("(STRFTIME('%s', 'now') * 10000000 + 621355968000000000)"); break; case SQLiteDateFormats.JulianDay: result.Append("CAST(STRFTIME('%J', 'now') AS double)"); break; default: result.Append("STRFTIME('%Y-%m-%d %H:%M:%S', 'now')"); break; } return result; } private static ISqlFragment HandleGetUtcDateFunction(SqlGenerator sqlgen, DbFunctionExpression e) { SqlBuilder result = new SqlBuilder(); Debug.Assert(e.Arguments.Count == 0, "Canonical getutcdate function should have no arguments"); switch (sqlgen._manifest._dateTimeFormat) { case SQLiteDateFormats.Ticks: result.Append("(STRFTIME('%s', 'now', 'utc') * 10000000 + 621355968000000000)"); break; case SQLiteDateFormats.JulianDay: result.Append("CAST(STRFTIME('%J', 'now', 'utc') AS double)"); break; |
︙ | ︙ | |||
2767 2768 2769 2770 2771 2772 2773 | { result.Append("CAST(STRFTIME('"); // expand the datepart literal as tsql kword result.Append(trans); result.Append("', "); | | | | 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 | { result.Append("CAST(STRFTIME('"); // expand the datepart literal as tsql kword result.Append(trans); result.Append("', "); switch (sqlgen._manifest._dateTimeFormat) { case SQLiteDateFormats.Ticks: result.Append(String.Format("(({0} - 621355968000000000) / 10000000.0)", e.Arguments[1].Accept(sqlgen))); break; default: result.Append(e.Arguments[1].Accept(sqlgen)); break; } result.Append(") AS integer)"); } else { result.Append("CAST(SUBSTR(STRFTIME('%f', "); switch (sqlgen._manifest._dateTimeFormat) { case SQLiteDateFormats.Ticks: result.Append(String.Format("(({0} - 621355968000000000) / 10000000.0)", e.Arguments[1].Accept(sqlgen))); break; default: result.Append(e.Arguments[1].Accept(sqlgen)); break; |
︙ | ︙ | |||
2810 2811 2812 2813 2814 2815 2816 | /// <param name="e"></param> /// <returns></returns> private static ISqlFragment HandleCanonicalFunctionDateAdd(SqlGenerator sqlgen, DbFunctionExpression e) { SqlBuilder result = new SqlBuilder(); Debug.Assert(e.Arguments.Count == 2, "Canonical datepart functions should have exactly two arguments"); | | | | | | 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 | /// <param name="e"></param> /// <returns></returns> private static ISqlFragment HandleCanonicalFunctionDateAdd(SqlGenerator sqlgen, DbFunctionExpression e) { SqlBuilder result = new SqlBuilder(); Debug.Assert(e.Arguments.Count == 2, "Canonical datepart functions should have exactly two arguments"); switch (sqlgen._manifest._dateTimeFormat) { case SQLiteDateFormats.Ticks: result.Append(String.Format("(STRFTIME('%s', JULIANDAY({1}) + ({0} / 86400.0)) * 10000000 + 621355968000000000)", e.Arguments[0].Accept(sqlgen), e.Arguments[1].Accept(sqlgen))); break; case SQLiteDateFormats.JulianDay: result.Append(String.Format("CAST(STRFTIME('%J', JULIANDAY({1}) + ({0} / 86400.0)) AS double)", e.Arguments[0].Accept(sqlgen), e.Arguments[1].Accept(sqlgen))); break; default: result.Append(String.Format("STRFTIME('%Y-%m-%d %H:%M:%S', JULIANDAY({1}) + ({0} / 86400.0))", e.Arguments[0].Accept(sqlgen), e.Arguments[1].Accept(sqlgen))); break; } return result; } /// <summary> /// DateSubtract(datetime1, datetime2) -> DATEDIFF ( seconds , startdate , enddate ) /// </summary> /// <param name="sqlgen"></param> /// <param name="e"></param> /// <returns></returns> private static ISqlFragment HandleCanonicalFunctionDateSubtract(SqlGenerator sqlgen, DbFunctionExpression e) { SqlBuilder result = new SqlBuilder(); Debug.Assert(e.Arguments.Count == 2, "Canonical datepart functions should have exactly two arguments"); switch (sqlgen._manifest._dateTimeFormat) { case SQLiteDateFormats.Ticks: result.Append(String.Format("CAST((({0} - 621355968000000000) / 10000000.0) - (({1} - 621355968000000000) / 10000000.0) * 86400.0 AS integer)", e.Arguments[0].Accept(sqlgen), e.Arguments[1].Accept(sqlgen))); break; default: result.Append(String.Format("CAST((JULIANDAY({1}) - JULIANDAY({0})) * 86400.0 AS integer)", e.Arguments[0].Accept(sqlgen), e.Arguments[1].Accept(sqlgen))); break; } return result; } /// <summary> /// Handler for canonical functions for extracting date parts. /// For example: /// Year(date) -> DATEPART( year, date) /// </summary> /// <param name="sqlgen"></param> /// <param name="e"></param> /// <returns></returns> private static ISqlFragment HandleCanonicalFunctionDatepart(SqlGenerator sqlgen, DbFunctionExpression e) |
︙ | ︙ | |||
2873 2874 2875 2876 2877 2878 2879 | SqlBuilder result = new SqlBuilder(); result.Append("CAST(STRFTIME('"); result.Append(trans); result.Append("', "); Debug.Assert(e.Arguments.Count == 1, "Canonical datepart functions should have exactly one argument"); | | | 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 | SqlBuilder result = new SqlBuilder(); result.Append("CAST(STRFTIME('"); result.Append(trans); result.Append("', "); Debug.Assert(e.Arguments.Count == 1, "Canonical datepart functions should have exactly one argument"); switch (sqlgen._manifest._dateTimeFormat) { case SQLiteDateFormats.Ticks: result.Append(String.Format("(({0} - 621355968000000000) / 10000000.0)", e.Arguments[0].Accept(sqlgen))); break; default: result.Append(e.Arguments[0].Accept(sqlgen)); break; |
︙ | ︙ | |||
3310 3311 3312 3313 3314 3315 3316 | { symbolTable.Add(inputVarName, fromSymbol); } } /// <summary> /// Translates a list of SortClauses. | | | 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 | { symbolTable.Add(inputVarName, fromSymbol); } } /// <summary> /// Translates a list of SortClauses. /// Used in the translation of OrderBy /// </summary> /// <param name="orderByClause">The SqlBuilder to which the sort keys should be appended</param> /// <param name="sortKeys"></param> void AddSortKeys(SqlBuilder orderByClause, IList<DbSortClause> sortKeys) { string separator = ""; foreach (DbSortClause sortClause in sortKeys) |
︙ | ︙ | |||
3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 | selectStatement.From.AppendLine(); selectStatement.From.Append(") "); return selectStatement; } /// <summary> /// Before we embed a string literal in a SQL string, we should /// convert all ' to '', and enclose the whole string in single quotes. /// </summary> /// <param name="s"></param> /// <param name="isUnicode"></param> /// <returns>The escaped sql string.</returns> private static string EscapeSingleQuote(string s, bool isUnicode) { return "'" + s.Replace("'", "''") + "'"; } /// <summary> | > > > > > > > > > > > > > > > > > > > | | | 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 | selectStatement.From.AppendLine(); selectStatement.From.Append(") "); return selectStatement; } /// <summary> /// Determines if values of the specified <see cref="SQLiteDateFormats" /> /// require wrapping in single quotes. /// </summary> /// <param name="format"> /// The <see cref="SQLiteDateFormats" /> format. /// </param> /// <returns> /// Non-zero if single quotes are required for a value in the specified /// <see cref="SQLiteDateFormats" />. /// </returns> private static bool NeedSingleQuotes( SQLiteDateFormats format ) { return format != SQLiteDateFormats.Ticks && format != SQLiteDateFormats.JulianDay && format != SQLiteDateFormats.UnixEpoch; } /// <summary> /// Before we embed a string literal in a SQL string, we should /// convert all ' to '', and enclose the whole string in single quotes. /// </summary> /// <param name="s"></param> /// <param name="isUnicode"></param> /// <returns>The escaped sql string.</returns> private static string EscapeSingleQuote(string s, bool isUnicode) { return "'" + s.Replace("'", "''") + "'"; } /// <summary> /// Returns the sql primitive/native type name. /// It will include size, precision or scale depending on type information present in the /// type facets /// </summary> /// <param name="type"></param> /// <returns></returns> private string GetSqlPrimitiveType(TypeUsage type) { PrimitiveType primitiveType = MetadataHelpers.GetEdmType<PrimitiveType>(type); |
︙ | ︙ | |||
3563 3564 3565 3566 3567 3568 3569 | /// <returns></returns> private ISqlFragment HandleCountExpression(DbExpression e) { ISqlFragment result; if (e.ExpressionKind == DbExpressionKind.Constant) { | | | 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 | /// <returns></returns> private ISqlFragment HandleCountExpression(DbExpression e) { ISqlFragment result; if (e.ExpressionKind == DbExpressionKind.Constant) { //For constant expression we should not cast the value, // thus we don't go throught the default DbConstantExpression handling SqlBuilder sqlBuilder = new SqlBuilder(); sqlBuilder.Append(((DbConstantExpression)e).Value.ToString()); result = sqlBuilder; } else { |
︙ | ︙ | |||
3648 3649 3650 3651 3652 3653 3654 | /// <returns></returns> bool IsCompatible(SqlSelectStatement result, DbExpressionKind expressionKind) { switch (expressionKind) { case DbExpressionKind.Distinct: return result.Top == null | | | 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 | /// <returns></returns> bool IsCompatible(SqlSelectStatement result, DbExpressionKind expressionKind) { switch (expressionKind) { case DbExpressionKind.Distinct: return result.Top == null // The projection after distinct may not project all // columns used in the Order By && result.OrderBy.IsEmpty; case DbExpressionKind.Filter: return result.Select.IsEmpty && result.Where.IsEmpty && result.GroupBy.IsEmpty |
︙ | ︙ | |||
3771 3772 3773 3774 3775 3776 3777 | /// For the rest, we need to treat them as there was a dummy /// <code> /// -- originally {expression} /// -- change that to /// SELECT * /// FROM {expression} as c /// </code> | | | 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 | /// For the rest, we need to treat them as there was a dummy /// <code> /// -- originally {expression} /// -- change that to /// SELECT * /// FROM {expression} as c /// </code> /// /// DbLimitExpression needs to start the statement but not add the default columns /// </summary> /// <param name="e"></param> /// <param name="addDefaultColumns"></param> /// <returns></returns> SqlSelectStatement VisitExpressionEnsureSqlStatement(DbExpression e, bool addDefaultColumns) { |
︙ | ︙ | |||
3957 3958 3959 3960 3961 3962 3963 | // Should we actually support this? //result.Append(QuoteIdentifier((string)function.MetadataProperties["Schema"].Value ?? "dbo")); //result.Append("."); result.Append(QuoteIdentifier(storeFunctionName)); } } | > > > > > > > > > > > > > > > > > > | > | > > > | > | > | | > | | > | | | | 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 | // Should we actually support this? //result.Append(QuoteIdentifier((string)function.MetadataProperties["Schema"].Value ?? "dbo")); //result.Append("."); result.Append(QuoteIdentifier(storeFunctionName)); } } /// <summary> /// Appends the literal BLOB string representation of the specified /// byte array to the <see cref="SqlBuilder" />. /// </summary> /// <param name="bytes"> /// The byte array to be formatted as a literal BLOB string. /// </param> /// <param name="builder"> /// The <see cref="SqlBuilder" /> object to use. If null, an exception /// will be thrown. /// </param> private static void ToBlobLiteral( byte[] bytes, SqlBuilder builder ) { if (builder == null) throw new ArgumentNullException("builder"); if (bytes == null) { builder.Append("NULL"); /* TODO: Reasonable? */ return; } builder.Append(" X'"); for (int index = 0; index < bytes.Length; index++) { builder.Append(hexDigits[(bytes[index] & 0xF0) >> 4]); builder.Append(hexDigits[bytes[index] & 0x0F]); } builder.Append("' "); } /// <summary> /// Helper method for the Group By visitor /// Returns true if at least one of the aggregates in the given list /// has an argument that is not a <see cref="DbPropertyExpression"/> /// over <see cref="DbVariableReferenceExpression"/> /// </summary> /// <param name="aggregates"></param> /// <returns></returns> static bool NeedsInnerQuery(IList<DbAggregate> aggregates) { foreach (DbAggregate aggregate in aggregates) { Debug.Assert(aggregate.Arguments.Count == 1); if (!IsPropertyOverVarRef(aggregate.Arguments[0])) { return true; } } return false; } /// <summary> /// Determines whether the given expression is a <see cref="DbPropertyExpression"/> /// over <see cref="DbVariableReferenceExpression"/> /// </summary> /// <param name="expression"></param> /// <returns></returns> static bool IsPropertyOverVarRef(DbExpression expression) { DbPropertyExpression propertyExpression = expression as DbPropertyExpression; if (propertyExpression == null) { return false; } DbVariableReferenceExpression varRefExpression = propertyExpression.Instance as DbVariableReferenceExpression; if (varRefExpression == null) { return false; } return true; } #endregion private class KeyFieldExpressionComparer : IEqualityComparer<DbExpression> { // Fields internal static readonly SqlGenerator.KeyFieldExpressionComparer Singleton = new SqlGenerator.KeyFieldExpressionComparer(); // Methods private KeyFieldExpressionComparer() |
︙ | ︙ |
Changes to System.Data.SQLite.Linq/SQLiteProviderManifest.cs.
︙ | ︙ | |||
8 9 10 11 12 13 14 | #if USE_ENTITY_FRAMEWORK_6 namespace System.Data.SQLite.EF6 #else namespace System.Data.SQLite.Linq #endif { using System; | | | | > > | > > | > | > > > | | > > > > | > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #if USE_ENTITY_FRAMEWORK_6 namespace System.Data.SQLite.EF6 #else namespace System.Data.SQLite.Linq #endif { using System; using System.Collections.Generic; using System.IO; using System.Reflection; #if !PLATFORM_COMPACTFRAMEWORK using System.Text; #endif using System.Xml; #if USE_ENTITY_FRAMEWORK_6 using System.Data.Entity.Core; using System.Data.Entity.Core.Common; using System.Data.Entity.Core.Metadata.Edm; #else using System.Data.Common; using System.Data.Metadata.Edm; #endif /// <summary> /// The Provider Manifest for SQL Server /// </summary> internal sealed class SQLiteProviderManifest : DbXmlEnabledProviderManifest { internal SQLiteDateFormats _dateTimeFormat; internal DateTimeKind _dateTimeKind; internal string _dateTimeFormatString; internal bool _binaryGuid; /// <summary> /// Constructs the provider manifest. /// </summary> /// <remarks> /// Previously, the manifest token was interpreted as a <see cref="SQLiteDateFormats" />, /// because the <see cref="DateTime" /> functions are vastly different depending on the /// connection was opened. However, the manifest token may specify a connection string /// instead. WARNING: Only the "DateTimeFormat", "DateTimeKind", "DateTimeFormatString", /// and "BinaryGUID" connection parameters are extracted from it. All other connection /// parameters, if any are present, are silently ignored. /// </remarks> /// <param name="manifestToken"> /// A token used to infer the capabilities of the store. /// </param> public SQLiteProviderManifest(string manifestToken) : base(GetProviderManifest()) { SetFromOptions(ParseProviderManifestToken(GetProviderManifestToken(manifestToken))); } private static XmlReader GetProviderManifest() { return GetXmlResource("System.Data.SQLite.SQLiteProviderServices.ProviderManifest.xml"); } /// <summary> /// Determines and returns the effective provider manifest token to use, /// based on the specified provider manifest token and the environment, /// if applicable. /// </summary> /// <param name="manifestToken"> /// The original provider manifest token passed to the constructor for this /// class. /// </param> /// <returns> /// The effective provider manifest token. /// </returns> private static string GetProviderManifestToken( string manifestToken ) { #if !PLATFORM_COMPACTFRAMEWORK string value = UnsafeNativeMethods.GetSettingValue( "AppendManifestToken_SQLiteProviderManifest", null); if (String.IsNullOrEmpty(value)) return manifestToken; int capacity = value.Length; if (manifestToken != null) capacity += manifestToken.Length; StringBuilder builder = new StringBuilder(capacity); builder.Append(manifestToken); builder.Append(value); return builder.ToString(); #else // // NOTE: The .NET Compact Framework lacks environment variable support. // Therefore, just return the original provider manifest token // verbatim in this case. // return manifestToken; #endif } /// <summary> /// Attempts to parse a provider manifest token. It must contain either a /// legacy string that specifies the <see cref="SQLiteDateFormats" /> value /// -OR- string that uses the standard connection string syntax; otherwise, /// the results are undefined. /// </summary> /// <param name="manifestToken"> /// The manifest token to parse. /// </param> /// <returns> /// The dictionary containing the connection string parameters. /// </returns> private static SortedList<string, string> ParseProviderManifestToken( string manifestToken ) { return SQLiteConnection.ParseConnectionString(manifestToken, false, true); } /// <summary> /// Attempts to set the provider manifest options from the specified /// connection string parameters. An exception may be thrown if one /// or more of the connection string parameter values do not conform /// to the expected type. /// </summary> /// <param name="opts"> /// The dictionary containing the connection string parameters. /// </param> internal void SetFromOptions( SortedList<string, string> opts ) { _dateTimeFormat = SQLiteConnection.DefaultDateTimeFormat; _dateTimeKind = SQLiteConnection.DefaultDateTimeKind; _dateTimeFormatString = SQLiteConnection.DefaultDateTimeFormatString; _binaryGuid = /* SQLiteConnection.DefaultBinaryGUID; */ false; /* COMPAT: Legacy. */ if (opts == null) return; #if !PLATFORM_COMPACTFRAMEWORK string[] names = Enum.GetNames(typeof(SQLiteDateFormats)); #else string[] names = { SQLiteDateFormats.Ticks.ToString(), SQLiteDateFormats.ISO8601.ToString(), SQLiteDateFormats.JulianDay.ToString(), SQLiteDateFormats.UnixEpoch.ToString(), SQLiteDateFormats.InvariantCulture.ToString(), SQLiteDateFormats.CurrentCulture.ToString(), "Default" }; #endif foreach (string name in names) { if (String.IsNullOrEmpty(name)) continue; object value = SQLiteConnection.FindKey(opts, name, null); if (value == null) continue; _dateTimeFormat = (SQLiteDateFormats)Enum.Parse( typeof(SQLiteDateFormats), name, true); } object enumValue; enumValue = SQLiteConnection.TryParseEnum( typeof(SQLiteDateFormats), SQLiteConnection.FindKey( opts, "DateTimeFormat", null), true); if (enumValue is SQLiteDateFormats) _dateTimeFormat = (SQLiteDateFormats)enumValue; enumValue = SQLiteConnection.TryParseEnum( typeof(DateTimeKind), SQLiteConnection.FindKey( opts, "DateTimeKind", null), true); if (enumValue is DateTimeKind) _dateTimeKind = (DateTimeKind)enumValue; string stringValue = SQLiteConnection.FindKey( opts, "DateTimeFormatString", null); if (stringValue != null) _dateTimeFormatString = stringValue; stringValue = SQLiteConnection.FindKey( opts, "BinaryGUID", null); if (stringValue != null) _binaryGuid = SQLiteConvert.ToBoolean(stringValue); } /// <summary> /// Returns manifest information for the provider /// </summary> /// <param name="informationType">The name of the information to be retrieved.</param> /// <returns>An XmlReader at the begining of the information requested.</returns> protected override XmlReader GetDbInformation(string informationType) |
︙ | ︙ |
Changes to System.Data.SQLite.Linq/SQLiteProviderServices.cs.
︙ | ︙ | |||
8 9 10 11 12 13 14 | #if USE_ENTITY_FRAMEWORK_6 namespace System.Data.SQLite.EF6 #else namespace System.Data.SQLite.Linq #endif { using System; | | | | | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #if USE_ENTITY_FRAMEWORK_6 namespace System.Data.SQLite.EF6 #else namespace System.Data.SQLite.Linq #endif { using System; using System.Collections.Generic; using System.Data.Common; using System.Diagnostics; using System.Globalization; using System.Text; #if USE_ENTITY_FRAMEWORK_6 using System.Data.Entity.Core.Common; using System.Data.Entity.Core.Metadata.Edm; using System.Data.Entity.Core.Common.CommandTrees; #else using System.Data.Metadata.Edm; |
︙ | ︙ | |||
106 107 108 109 110 111 112 | command.Dispose(); throw; } } protected override string GetDbProviderManifestToken(DbConnection connection) { | | | < | | < < < | < < | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | command.Dispose(); throw; } } protected override string GetDbProviderManifestToken(DbConnection connection) { if (connection == null) throw new ArgumentNullException("connection"); if (String.IsNullOrEmpty(connection.ConnectionString)) throw new ArgumentNullException("ConnectionString"); return connection.ConnectionString; } protected override DbProviderManifest GetDbProviderManifest(string versionHint) { return new SQLiteProviderManifest(versionHint); } |
︙ | ︙ |
Changes to System.Data.SQLite/Configurations/System.Data.SQLite.dll.config.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?xml version="1.0"?> <!-- * * System.Data.SQLite.dll.config - * * Written by Joe Mistachkin. * Released to the public domain, use at your own risk! * --> <configuration> <appSettings> <!-- NOTE: If this configuration variable is set [to anything], the SQLite logging subsystem may be initialized in a non-default application domain. By default, this is not allowed due to the potential for application domain unloading issues. --> <!-- | > > > > > > > > > > > > > > | 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 | <?xml version="1.0"?> <!-- * * System.Data.SQLite.dll.config - * * Written by Joe Mistachkin. * Released to the public domain, use at your own risk! * --> <configuration> <appSettings> <!-- NOTE: If this environment variable is set [to anything], it will be used by the System.Data.SQLite.Linq.SQLiteProviderManifest class (and the System.Data.SQLite.EF6.SQLiteProviderManifest class) to modify future provider manifest tokens by appending the value of the environment variable to the existing provider manifest token, if any. Typically, in order for the constructed provider manifest token to be syntactically correct, the environment variable value [to be appended] must begin with a semicolon. --> <!-- <add key="AppendManifestToken_SQLiteProviderManifest" value="" /> --> <!-- NOTE: If this configuration variable is set [to anything], the SQLite logging subsystem may be initialized in a non-default application domain. By default, this is not allowed due to the potential for application domain unloading issues. --> <!-- |
︙ | ︙ | |||
103 104 105 106 107 108 109 110 111 112 113 114 115 116 | architecture of the current process (e.g. a 32-bit x86 application running on a 64-bit x64 operating system should have the value "x86"). --> <!-- <add key="PROCESSOR_ARCHITECTURE" value="%PROCESSOR_ARCHITECTURE%" /> --> <!-- NOTE: If this environment variable is set [to anything], it will be used by the System.Data.SQLite.SQLiteFactory class as the type name containing the System.Data.Common.DbProviderServices implementation that should be used. --> | > > > > > > > > > | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | architecture of the current process (e.g. a 32-bit x86 application running on a 64-bit x64 operating system should have the value "x86"). --> <!-- <add key="PROCESSOR_ARCHITECTURE" value="%PROCESSOR_ARCHITECTURE%" /> --> <!-- NOTE: If this environment variable is set [to anything], all calls to prepare a SQL query will be logged, regardless of the flags for the associated connection. --> <!-- <add key="SQLite_ForceLogPrepare" value="1" /> --> <!-- NOTE: If this environment variable is set [to anything], it will be used by the System.Data.SQLite.SQLiteFactory class as the type name containing the System.Data.Common.DbProviderServices implementation that should be used. --> |
︙ | ︙ |
Changes to System.Data.SQLite/SQLite3.cs.
︙ | ︙ | |||
883 884 885 886 887 888 889 890 891 892 893 894 895 896 | internal override string GetLastError(string defValue) { string result = SQLiteBase.GetLastError(_sql, _sql); if (String.IsNullOrEmpty(result)) result = defValue; return result; } internal override SQLiteStatement Prepare(SQLiteConnection cnn, string strSql, SQLiteStatement previous, uint timeoutMS, ref string strRemain) { if (!String.IsNullOrEmpty(strSql)) { // // NOTE: SQLite does not support the concept of separate schemas | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 | internal override string GetLastError(string defValue) { string result = SQLiteBase.GetLastError(_sql, _sql); if (String.IsNullOrEmpty(result)) result = defValue; return result; } /////////////////////////////////////////////////////////////////////////////////////////////// #region Query Diagnostics Support #if !PLATFORM_COMPACTFRAMEWORK /// <summary> /// This field is used to keep track of whether or not the /// "SQLite_ForceLogPrepare" environment variable has been queried. If so, /// it will only be non-zero if the environment variable was present. /// </summary> private static bool? forceLogPrepare = null; /////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Determines if all calls to prepare a SQL query will be logged, /// regardless of the flags for the associated connection. /// </summary> /// <returns> /// Non-zero to log all calls to prepare a SQL query. /// </returns> private static bool ForceLogPrepare() { lock (syncRoot) { if (forceLogPrepare == null) { if (UnsafeNativeMethods.GetSettingValue( "SQLite_ForceLogPrepare", null) != null) { forceLogPrepare = true; } else { forceLogPrepare = false; } } return (bool)forceLogPrepare; } } #endif #endregion /////////////////////////////////////////////////////////////////////////////////////////////// internal override SQLiteStatement Prepare(SQLiteConnection cnn, string strSql, SQLiteStatement previous, uint timeoutMS, ref string strRemain) { if (!String.IsNullOrEmpty(strSql)) { // // NOTE: SQLite does not support the concept of separate schemas |
︙ | ︙ | |||
911 912 913 914 915 916 917 | "{0}.", baseSchemaName), String.Empty); } } SQLiteConnectionFlags flags = (cnn != null) ? cnn.Flags : SQLiteConnectionFlags.Default; | > > > > | | 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 | "{0}.", baseSchemaName), String.Empty); } } SQLiteConnectionFlags flags = (cnn != null) ? cnn.Flags : SQLiteConnectionFlags.Default; if ( #if !PLATFORM_COMPACTFRAMEWORK ForceLogPrepare() || #endif ((flags & SQLiteConnectionFlags.LogPrepare) == SQLiteConnectionFlags.LogPrepare)) { if ((strSql == null) || (strSql.Length == 0) || (strSql.Trim().Length == 0)) SQLiteLog.LogMessage("Preparing {<nothing>}..."); else SQLiteLog.LogMessage(String.Format( CultureInfo.CurrentCulture, "Preparing {{{0}}}...", strSql)); } |
︙ | ︙ |
Changes to System.Data.SQLite/SQLiteConnection.cs.
︙ | ︙ | |||
348 349 350 351 352 353 354 | internal const IsolationLevel DeferredIsolationLevel = IsolationLevel.ReadCommitted; internal const IsolationLevel ImmediateIsolationLevel = IsolationLevel.Serializable; private const SQLiteConnectionFlags DefaultFlags = SQLiteConnectionFlags.Default; private const SQLiteSynchronousEnum DefaultSynchronous = SQLiteSynchronousEnum.Default; private const SQLiteJournalModeEnum DefaultJournalMode = SQLiteJournalModeEnum.Default; private const IsolationLevel DefaultIsolationLevel = IsolationLevel.Serializable; | | | | | | 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 | internal const IsolationLevel DeferredIsolationLevel = IsolationLevel.ReadCommitted; internal const IsolationLevel ImmediateIsolationLevel = IsolationLevel.Serializable; private const SQLiteConnectionFlags DefaultFlags = SQLiteConnectionFlags.Default; private const SQLiteSynchronousEnum DefaultSynchronous = SQLiteSynchronousEnum.Default; private const SQLiteJournalModeEnum DefaultJournalMode = SQLiteJournalModeEnum.Default; private const IsolationLevel DefaultIsolationLevel = IsolationLevel.Serializable; internal const SQLiteDateFormats DefaultDateTimeFormat = SQLiteDateFormats.Default; internal const DateTimeKind DefaultDateTimeKind = DateTimeKind.Unspecified; internal const string DefaultDateTimeFormatString = null; private const string DefaultDataSource = null; private const string DefaultUri = null; private const string DefaultFullUri = null; private const string DefaultHexPassword = null; private const string DefaultPassword = null; private const int DefaultVersion = 3; private const int DefaultPageSize = 1024; private const int DefaultMaxPageCount = 0; private const int DefaultCacheSize = 2000; private const int DefaultMaxPoolSize = 100; private const int DefaultConnectionTimeout = 30; private const bool DefaultNoSharedFlags = false; private const bool DefaultFailIfMissing = false; private const bool DefaultReadOnly = false; internal const bool DefaultBinaryGUID = true; private const bool DefaultUseUTF16Encoding = false; private const bool DefaultToFullPath = true; private const bool DefaultPooling = false; // TODO: Maybe promote this to static property? private const bool DefaultLegacyFormat = false; private const bool DefaultForeignKeys = false; private const bool DefaultEnlist = true; private const bool DefaultSetDefaults = true; |
︙ | ︙ | |||
1195 1196 1197 1198 1199 1200 1201 | if (handle.IsClosed) throw new InvalidOperationException("The connection handle is closed."); } /////////////////////////////////////////////////////////////////////////////////////////////// | > > > > > > > > > > > > > > > > > > > > | | > | | 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 | if (handle.IsClosed) throw new InvalidOperationException("The connection handle is closed."); } /////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Parses a connection string into component parts using the custom /// connection string parser. An exception may be thrown if the syntax /// of the connection string is incorrect. /// </summary> /// <param name="connectionString"> /// The connection string to parse. /// </param> /// <param name="parseViaFramework"> /// Non-zero to parse the connection string using the algorithm provided /// by the framework itself. This is not applicable when running on the /// .NET Compact Framework. /// </param> /// <param name="allowNameOnly"> /// Non-zero if names are allowed without values. /// </param> /// <returns> /// The list of key/value pairs corresponding to the parameters specified /// within the connection string. /// </returns> internal static SortedList<string, string> ParseConnectionString( string connectionString, bool parseViaFramework, bool allowNameOnly ) { return parseViaFramework ? ParseConnectionStringViaFramework(connectionString, false) : ParseConnectionString(connectionString, allowNameOnly); } /////////////////////////////////////////////////////////////////////////////////////////////// private void SetupSQLiteBase(SortedList<string, string> opts) { object enumValue; |
︙ | ︙ | |||
1886 1887 1888 1889 1890 1891 1892 | else if (path.StartsWith ("/", StringComparison.OrdinalIgnoreCase)) return path; else throw new InvalidOperationException ("Invalid connection string: invalid URI"); } /// <summary> | | | > | > > > > > | > > > | > > > | 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 | else if (path.StartsWith ("/", StringComparison.OrdinalIgnoreCase)) return path; else throw new InvalidOperationException ("Invalid connection string: invalid URI"); } /// <summary> /// Parses a connection string into component parts using the custom /// connection string parser. An exception may be thrown if the syntax /// of the connection string is incorrect. /// </summary> /// <param name="connectionString"> /// The connection string to parse. /// </param> /// <param name="allowNameOnly"> /// Non-zero if names are allowed without values. /// </param> /// <returns> /// The list of key/value pairs corresponding to the parameters specified /// within the connection string. /// </returns> private static SortedList<string, string> ParseConnectionString( string connectionString, bool allowNameOnly ) { string s = connectionString; int n; SortedList<string, string> ls = new SortedList<string, string>(StringComparer.OrdinalIgnoreCase); // First split into semi-colon delimited values. string error = null; |
︙ | ︙ | |||
1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 | if (arParts[n].Length == 0) continue; int indexOf = arParts[n].IndexOf('='); if (indexOf != -1) ls.Add(UnwrapString(arParts[n].Substring(0, indexOf).Trim()), UnwrapString(arParts[n].Substring(indexOf + 1).Trim())); else throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Invalid ConnectionString format for part \"{0}\", no equal sign found", arParts[n])); } return ls; } /// <summary> /// Parses a connection string using the built-in (i.e. framework provided) /// connection string parser class and returns the key/value pairs. An /// exception may be thrown if the connection string is invalid or cannot be /// parsed. When compiled for the .NET Compact Framework, the custom /// connection string parser is always used instead because the framework /// provided one is unavailable there. /// </summary> /// <param name="connectionString"> /// The connection string to parse. /// </param> /// <param name="strict"> /// Non-zero to throw an exception if any connection string values are not of | > > | > | | 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 | if (arParts[n].Length == 0) continue; int indexOf = arParts[n].IndexOf('='); if (indexOf != -1) ls.Add(UnwrapString(arParts[n].Substring(0, indexOf).Trim()), UnwrapString(arParts[n].Substring(indexOf + 1).Trim())); else if (allowNameOnly) ls.Add(UnwrapString(arParts[n].Trim()), String.Empty); else throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Invalid ConnectionString format for part \"{0}\", no equal sign found", arParts[n])); } return ls; } /// <summary> /// Parses a connection string using the built-in (i.e. framework provided) /// connection string parser class and returns the key/value pairs. An /// exception may be thrown if the connection string is invalid or cannot be /// parsed. When compiled for the .NET Compact Framework, the custom /// connection string parser is always used instead because the framework /// provided one is unavailable there. /// </summary> /// <param name="connectionString"> /// The connection string to parse. /// </param> /// <param name="strict"> /// Non-zero to throw an exception if any connection string values are not of /// the <see cref="String" /> type. This is not applicable when running on /// the .NET Compact Framework. /// </param> /// <returns>The list of key/value pairs.</returns> private static SortedList<string, string> ParseConnectionStringViaFramework( string connectionString, bool strict ) { #if !PLATFORM_COMPACTFRAMEWORK DbConnectionStringBuilder connectionStringBuilder = new DbConnectionStringBuilder(); |
︙ | ︙ | |||
1995 1996 1997 1998 1999 2000 2001 | return result; #else // // NOTE: On the .NET Compact Framework, always use our custom connection // string parser as the built-in (i.e. framework provided) one is // unavailable. // | | | 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 | return result; #else // // NOTE: On the .NET Compact Framework, always use our custom connection // string parser as the built-in (i.e. framework provided) one is // unavailable. // return ParseConnectionString(connectionString, false); #endif } #if !PLATFORM_COMPACTFRAMEWORK /// <summary> /// Manual distributed transaction enlistment support /// </summary> |
︙ | ︙ | |||
2402 2403 2404 2405 2406 2407 2408 | if (_connectionState != ConnectionState.Closed) throw new InvalidOperationException(); Close(); SortedList<string, string> opts = ParseConnectionString( | | | 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 | if (_connectionState != ConnectionState.Closed) throw new InvalidOperationException(); Close(); SortedList<string, string> opts = ParseConnectionString( _connectionString, _parseViaFramework, false); OnChanged(this, new ConnectionEventArgs( SQLiteConnectionEventType.ConnectionString, null, null, null, null, null, _connectionString, new object[] { opts })); object enumValue; |
︙ | ︙ |
Changes to Tests/basic.eagle.
︙ | ︙ | |||
2257 2258 2259 2260 2261 2262 2263 | "OneTwo=ThreeFour" "\"OneTwo\"=\"ThreeFour\"" \ "One Two=Three Four" "\"One Two\"=\"Three Four\"" \ "OneTwo=ThreeFour;" "\"OneTwo\"=\"ThreeFour\";" \ "One Two=Three Four;" "\"One Two\"=\"Three Four\";"] foreach string $strings { set list [object invoke -flags +NonPublic \ | | > | 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 | "OneTwo=ThreeFour" "\"OneTwo\"=\"ThreeFour\"" \ "One Two=Three Four" "\"One Two\"=\"Three Four\"" \ "OneTwo=ThreeFour;" "\"OneTwo\"=\"ThreeFour\";" \ "One Two=Three Four;" "\"One Two\"=\"Three Four\";"] foreach string $strings { set list [object invoke -flags +NonPublic \ System.Data.SQLite.SQLiteConnection ParseConnectionString \ $string false] object foreach -alias pair $list { lappend result [list [$pair Key] [$pair Value]] } } set result |
︙ | ︙ |
Added Tests/tkt-8d928c3e88.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 | ############################################################################### # # tkt-8d928c3e88.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 runSQLiteTestFilesPrologue ############################################################################### runTest {test tkt-8d928c3e88-1.1 {LINQ w/BinaryGUID=false} -body { # # NOTE: Re-copy the reference database file used for this unit test to the # build directory in case it has been changed by a previous test run. # file copy -force $northwindEfDbFile \ [file join [getBuildDirectory] [file tail $northwindEfDbFile]] set result [list] set output "" set code [catch { testClrExec $testLinqExeFile [list -eventflags Wait -directory \ [file dirname $testLinqExeFile] -nocarriagereturns -stdout output \ -success 0] -binaryguid false } error] tlog "---- BEGIN STDOUT OUTPUT\n" tlog $output tlog "\n---- END STDOUT OUTPUT\n" lappend result $code if {$code == 0} then { lappend result [string trim $output] } else { lappend result [string trim $error] } set result } -cleanup { unset -nocomplain code output error result } -constraints {eagle monoToDo SQLite file_System.Data.SQLite.dll testExec\ file_System.Data.SQLite.Linq.dll file_testlinq.exe file_northwindEF.db} \ -result {0 2d3d2d3d-2d3d-2d3d-2d3d-2d3d2d3d2d3d}} ############################################################################### runTest {test tkt-8d928c3e88-1.2 {LINQ w/BinaryGUID=true} -body { # # NOTE: Re-copy the reference database file used for this unit test to the # build directory in case it has been changed by a previous test run. # file copy -force $northwindEfDbFile \ [file join [getBuildDirectory] [file tail $northwindEfDbFile]] set result [list] set output "" set code [catch { testClrExec $testLinqExeFile [list -eventflags Wait -directory \ [file dirname $testLinqExeFile] -nocarriagereturns -stdout output \ -success 0] -binaryguid true } error] tlog "---- BEGIN STDOUT OUTPUT\n" tlog $output tlog "\n---- END STDOUT OUTPUT\n" lappend result $code if {$code == 0} then { lappend result [string trim $output] } else { lappend result [string trim $error] } set result } -cleanup { unset -nocomplain code output error result } -constraints {eagle monoToDo SQLite file_System.Data.SQLite.dll testExec\ file_System.Data.SQLite.Linq.dll file_testlinq.exe file_northwindEF.db} \ -result {0 =-=-=-=--=-=-=-=}} ############################################################################### runTest {test tkt-8d928c3e88-2.1 {LINQ w/DateTimeFormat=Ticks} -body { # # NOTE: Re-copy the reference database file used for this unit test to the # build directory in case it has been changed by a previous test run. # file copy -force $northwindEfDbFile \ [file join [getBuildDirectory] [file tail $northwindEfDbFile]] set result [list] set output "" set code [catch { testClrExec $testLinqExeFile [list -eventflags Wait -directory \ [file dirname $testLinqExeFile] -nocarriagereturns -stdout output \ -success 0] -datetime2 Ticks } error] tlog "---- BEGIN STDOUT OUTPUT\n" tlog $output tlog "\n---- END STDOUT OUTPUT\n" lappend result $code if {$code == 0} then { lappend result [string trim $output] } else { lappend result [string trim $error] } set result } -cleanup { unset -nocomplain code output error result } -constraints {eagle monoToDo SQLite file_System.Data.SQLite.dll testExec\ file_System.Data.SQLite.Linq.dll file_testlinq.exe file_northwindEF.db} \ -match regexp -result \ {\sWHERE \[Extent1\]\.\[OrderDate\] < 629876736000000000\s}} ############################################################################### runTest {test tkt-8d928c3e88-2.2 {LINQ w/DateTimeFormat=JulianDay} -body { # # NOTE: Re-copy the reference database file used for this unit test to the # build directory in case it has been changed by a previous test run. # file copy -force $northwindEfDbFile \ [file join [getBuildDirectory] [file tail $northwindEfDbFile]] set result [list] set output "" set code [catch { testClrExec $testLinqExeFile [list -eventflags Wait -directory \ [file dirname $testLinqExeFile] -nocarriagereturns -stdout output \ -success 0] -datetime2 JulianDay } error] tlog "---- BEGIN STDOUT OUTPUT\n" tlog $output tlog "\n---- END STDOUT OUTPUT\n" lappend result $code if {$code == 0} then { lappend result [string trim $output] } else { lappend result [string trim $error] } set result } -cleanup { unset -nocomplain code output error result } -constraints {eagle monoToDo SQLite file_System.Data.SQLite.dll testExec\ file_System.Data.SQLite.Linq.dll file_testlinq.exe file_northwindEF.db} \ -match regexp -result {\sWHERE \[Extent1\]\.\[OrderDate\] < 2450449\.5\s}} ############################################################################### runTest {test tkt-8d928c3e88-2.3 {LINQ w/DateTimeFormat=UnixEpoch} -body { # # NOTE: Re-copy the reference database file used for this unit test to the # build directory in case it has been changed by a previous test run. # file copy -force $northwindEfDbFile \ [file join [getBuildDirectory] [file tail $northwindEfDbFile]] set result [list] set output "" set code [catch { testClrExec $testLinqExeFile [list -eventflags Wait -directory \ [file dirname $testLinqExeFile] -nocarriagereturns -stdout output \ -success 0] -datetime2 UnixEpoch } error] tlog "---- BEGIN STDOUT OUTPUT\n" tlog $output tlog "\n---- END STDOUT OUTPUT\n" lappend result $code if {$code == 0} then { lappend result [string trim $output] } else { lappend result [string trim $error] } set result } -cleanup { unset -nocomplain code output error result } -constraints {eagle monoToDo SQLite file_System.Data.SQLite.dll testExec\ file_System.Data.SQLite.Linq.dll file_testlinq.exe file_northwindEF.db} \ -match regexp -result {\sWHERE \[Extent1\]\.\[OrderDate\] < 852076800\s}} ############################################################################### runTest {test tkt-8d928c3e88-2.4 {LINQ w/DateTimeFormat=ISO8601} -body { # # NOTE: Re-copy the reference database file used for this unit test to the # build directory in case it has been changed by a previous test run. # file copy -force $northwindEfDbFile \ [file join [getBuildDirectory] [file tail $northwindEfDbFile]] set result [list] set output "" set code [catch { testClrExec $testLinqExeFile [list -eventflags Wait -directory \ [file dirname $testLinqExeFile] -nocarriagereturns -stdout output \ -success 0] -datetime2 ISO8601 } error] tlog "---- BEGIN STDOUT OUTPUT\n" tlog $output tlog "\n---- END STDOUT OUTPUT\n" lappend result $code if {$code == 0} then { lappend result [string trim $output] } else { lappend result [string trim $error] } set result } -cleanup { unset -nocomplain code output error result } -constraints {eagle monoToDo SQLite file_System.Data.SQLite.dll testExec\ file_System.Data.SQLite.Linq.dll file_testlinq.exe file_northwindEF.db} \ -match regexp -result \ {\sWHERE \[Extent1\]\.\[OrderDate\] < '1997-01-01 00:00:00'\s}} ############################################################################### runSQLiteTestFilesEpilogue runSQLiteTestEpilogue runTestEpilogue |
Changes to Tests/tkt-e47b3d8346.eagle.
︙ | ︙ | |||
23 24 25 26 27 28 29 | runTest {test tkt-e47b3d8346-1.1 {parse semi-colon in data source} -setup { unset -nocomplain result list pair } -body { set result [list] set list [object invoke -flags +NonPublic \ System.Data.SQLite.SQLiteConnection ParseConnectionString \ | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | runTest {test tkt-e47b3d8346-1.1 {parse semi-colon in data source} -setup { unset -nocomplain result list pair } -body { set result [list] set list [object invoke -flags +NonPublic \ System.Data.SQLite.SQLiteConnection ParseConnectionString \ {Data Source="C:\full\path\to\file.db;more.data.here";} false] object foreach -alias pair $list { lappend result [list [$pair Key] [$pair Value]] } set result } -cleanup { |
︙ | ︙ |
Changes to readme.htm.
︙ | ︙ | |||
218 219 220 221 222 223 224 225 226 227 228 229 230 231 | <li>Defer disposing of connections created by the static SQLiteCommand.Execute method when a data reader is returned. Fix for [daeaf3150a].</li> <li>Wrap SELECT statements in parenthesis if they have an ORDER BY, LIMIT, or OFFSET clause and a compound operator is involved. Fix for [0a32885109].</li> <li>In the SQLiteDataReader.VerifyType method, remove duplicate "if" statement for the DbType.SByte value and move the remaining "if" to the Int64 affinity. Fix for [c5cc2fb334]. <b>** Potentially Incompatible Change **</b></li> <li>Handle Julian Day values that fall outside of the supported range for OLE Automation dates. Fix for [3e783eecbe]. <b>** Potentially Incompatible Change **</b></li> <li>Make sure the interop files are copied when publishing a project that refers to a NuGet package containing them. Fix for [e796ac82c1]. <b>** Potentially Incompatible Change **</b></li> <li>Make sure the interop files are copied before the PostBuildEvent. Fix for [f16c93a932]. <b>** Potentially Incompatible Change **</b></li> <li>Modify GetSchemaTable method to avoid setting SchemaTableColumn.IsKey column to true when more than one table is referenced. Fix for [47c6fa04d3]. <b>** Potentially Incompatible Change **</b></li> </ul> <p> <b>1.0.94.0 - September 9, 2014</b> </p> <ul> <li>Updated to <a href="http://www.sqlite.org/releaselog/3_8_6.html">SQLite 3.8.6</a>.</li> <li>Updated to <a href="http://www.nuget.org/packages/EntityFramework/6.1.1">Entity Framework 6.1.1</a>.</li> | > > > | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | <li>Defer disposing of connections created by the static SQLiteCommand.Execute method when a data reader is returned. Fix for [daeaf3150a].</li> <li>Wrap SELECT statements in parenthesis if they have an ORDER BY, LIMIT, or OFFSET clause and a compound operator is involved. Fix for [0a32885109].</li> <li>In the SQLiteDataReader.VerifyType method, remove duplicate "if" statement for the DbType.SByte value and move the remaining "if" to the Int64 affinity. Fix for [c5cc2fb334]. <b>** Potentially Incompatible Change **</b></li> <li>Handle Julian Day values that fall outside of the supported range for OLE Automation dates. Fix for [3e783eecbe]. <b>** Potentially Incompatible Change **</b></li> <li>Make sure the interop files are copied when publishing a project that refers to a NuGet package containing them. Fix for [e796ac82c1]. <b>** Potentially Incompatible Change **</b></li> <li>Make sure the interop files are copied before the PostBuildEvent. Fix for [f16c93a932]. <b>** Potentially Incompatible Change **</b></li> <li>Modify GetSchemaTable method to avoid setting SchemaTableColumn.IsKey column to true when more than one table is referenced. Fix for [47c6fa04d3]. <b>** Potentially Incompatible Change **</b></li> <li>Add AppendManifestToken_SQLiteProviderManifest environment variable to enable better integration between LINQ and the underlying store connection.</li> <li>Add SQLite_ForceLogPrepare environment variable to force logging of all prepared SQL regardless of the flags for the associated connection.</li> <li>Honor the DateTimeFormat, DateTimeKind, DateTimeFormatString, BinaryGUID connection string and/or provider manifest token properties from within the LINQ assembly. Fix for [8d928c3e88]. <b>** Potentially Incompatible Change **</b></li> </ul> <p> <b>1.0.94.0 - September 9, 2014</b> </p> <ul> <li>Updated to <a href="http://www.sqlite.org/releaselog/3_8_6.html">SQLite 3.8.6</a>.</li> <li>Updated to <a href="http://www.nuget.org/packages/EntityFramework/6.1.1">Entity Framework 6.1.1</a>.</li> |
︙ | ︙ |
Changes to testlinq/Program.cs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /******************************************************** * ADO.NET 2.0 Data Provider for SQLite Version 3.X * Written by Robert Simpson (robert@blackcastlesoft.com) * * Released to the public domain, use at your own risk! ********************************************************/ using System; using System.Diagnostics; using System.Linq; using System.Text; using System.Transactions; #if USE_ENTITY_FRAMEWORK_6 using System.Data.Entity.Core.Objects; #else using System.Data.Objects; #endif namespace testlinq { class Program { | > > > > | 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 | /******************************************************** * ADO.NET 2.0 Data Provider for SQLite Version 3.X * Written by Robert Simpson (robert@blackcastlesoft.com) * * Released to the public domain, use at your own risk! ********************************************************/ using System; using System.Data.Common; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Text; using System.Transactions; #if USE_ENTITY_FRAMEWORK_6 using System.Data.Entity.Core.EntityClient; using System.Data.Entity.Core.Objects; #else using System.Data.EntityClient; using System.Data.Objects; #endif namespace testlinq { class Program { |
︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 66 67 68 69 70 | case "old": { return OldTests(); } case "datetime": { return DateTimeTest(); } case "skip": { int pageSize = 0; if (args.Length > 1) { | > > > > > > > > > > | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | case "old": { return OldTests(); } case "datetime": { return DateTimeTest(); } case "datetime2": { string dateTimeFormat = null; if (args.Length > 1) dateTimeFormat = args[1]; DateTimeTest2(dateTimeFormat); return 0; } case "skip": { int pageSize = 0; if (args.Length > 1) { |
︙ | ︙ | |||
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | return EFTransactionTest(value); } case "update": { return UpdateTest(); } default: { Console.WriteLine("unknown test \"{0}\"", arg); return 1; } } } // // NOTE: Used to test the fix for ticket [8b7d179c3c]. // private static int SkipTest(int pageSize) { using (northwindEFEntities db = new northwindEFEntities()) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | return EFTransactionTest(value); } case "update": { return UpdateTest(); } case "binaryguid": { bool value = false; if (args.Length > 1) { if (!bool.TryParse(args[1], out value)) { Console.WriteLine( "cannot parse \"{0}\" as boolean", args[1]); return 1; } } return BinaryGuidTest(value); } default: { Console.WriteLine("unknown test \"{0}\"", arg); return 1; } } } /// <summary> /// Attempts to obtain the underlying store connection /// (a <see cref="DbConnection" />) from the specified /// <see cref="EntityConnection" />. /// </summary> /// <param name="entityConnection"> /// The <see cref="EntityConnection" /> to use. /// </param> /// <returns> /// The <see cref="DbConnection" /> -OR- null if it /// cannot be determined. /// </returns> private static DbConnection GetStoreConnection( EntityConnection entityConnection ) { // // NOTE: No entity connection, no store connection. // if (entityConnection == null) return null; // // HACK: We need the underlying store connection and // the legacy versions of the .NET Framework do // not expose it; therefore, attempt to grab it // by force. // FieldInfo fieldInfo = typeof(EntityConnection).GetField( "_storeConnection", BindingFlags.Instance | BindingFlags.NonPublic); // // NOTE: If the field is not found, just return null. // if (fieldInfo == null) return null; return fieldInfo.GetValue(entityConnection) as DbConnection; } // // NOTE: Used to test the fix for ticket [8b7d179c3c]. // private static int SkipTest(int pageSize) { using (northwindEFEntities db = new northwindEFEntities()) |
︙ | ︙ | |||
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 | Console.WriteLine( "inserted {0} updated {1}", counts[0], counts[1]); } return 0; } private static int DateTimeTest() { using (northwindEFEntities db = new northwindEFEntities()) { DateTime dateTime = new DateTime(1997, 1, 1, 0, 0, 0, DateTimeKind.Local); int c1 = db.Orders.Where(i => i.OrderDate == new DateTime(1997, 1, 1, 0, 0, 0, DateTimeKind.Local)).Count(); int c2 = db.Orders.Where(i => i.OrderDate == dateTime).Count(); return c1 == c2 ? 0 : 1; } } private static int OldTests() { using (northwindEFEntities db = new northwindEFEntities()) { { string entitySQL = "SELECT VALUE o FROM Orders AS o WHERE SQLite.DatePart('yyyy', o.OrderDate) = 1997 ORDER BY o.OrderID;"; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Console.WriteLine( "inserted {0} updated {1}", counts[0], counts[1]); } return 0; } // // NOTE: Used to test the BinaryGUID fix (i.e. BLOB literal formatting // of GUID values when the BinaryGUID connection property has been // enabled). // private static int BinaryGuidTest(bool binaryGuid) { Environment.SetEnvironmentVariable( "AppendManifestToken_SQLiteProviderManifest", String.Format(";BinaryGUID={0};", binaryGuid)); using (northwindEFEntities db = new northwindEFEntities()) { string sql = "SELECT VALUE GUID " + "'2d3d2d3d-2d3d-2d3d-2d3d-2d3d2d3d2d3d' " + "FROM Orders AS o WHERE o.OrderID = 10248;"; ObjectQuery<string> query = db.CreateQuery<string>(sql); foreach (string s in query) Console.WriteLine(s); } Environment.SetEnvironmentVariable( "AppendManifestToken_SQLiteProviderManifest", null); return 0; } private static int DateTimeTest() { using (northwindEFEntities db = new northwindEFEntities()) { DateTime dateTime = new DateTime(1997, 1, 1, 0, 0, 0, DateTimeKind.Local); int c1 = db.Orders.Where(i => i.OrderDate == new DateTime(1997, 1, 1, 0, 0, 0, DateTimeKind.Local)).Count(); int c2 = db.Orders.Where(i => i.OrderDate == dateTime).Count(); return c1 == c2 ? 0 : 1; } } private static void DateTimeTest2( string dateTimeFormat ) { TraceListener listener = new ConsoleTraceListener(); Trace.Listeners.Add(listener); Environment.SetEnvironmentVariable("SQLite_ForceLogPrepare", "1"); if (dateTimeFormat != null) { Environment.SetEnvironmentVariable( "AppendManifestToken_SQLiteProviderManifest", String.Format(";DateTimeFormat={0};", dateTimeFormat)); } using (northwindEFEntities db = new northwindEFEntities()) { db.Orders.Where(i => i.OrderDate < new DateTime(1997, 1, 1, 0, 0, 0, DateTimeKind.Local)).Count(); } if (dateTimeFormat != null) { Environment.SetEnvironmentVariable( "AppendManifestToken_SQLiteProviderManifest", null); } Environment.SetEnvironmentVariable("SQLite_ForceLogPrepare", null); Trace.Listeners.Remove(listener); } private static int OldTests() { using (northwindEFEntities db = new northwindEFEntities()) { { string entitySQL = "SELECT VALUE o FROM Orders AS o WHERE SQLite.DatePart('yyyy', o.OrderDate) = 1997 ORDER BY o.OrderID;"; |
︙ | ︙ |
Changes to www/news.wiki.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <li>Defer disposing of connections created by the static SQLiteCommand.Execute method when a data reader is returned. Fix for [daeaf3150a].</li> <li>Wrap SELECT statements in parenthesis if they have an ORDER BY, LIMIT, or OFFSET clause and a compound operator is involved. Fix for [0a32885109].</li> <li>In the SQLiteDataReader.VerifyType method, remove duplicate "if" statement for the DbType.SByte value and move the remaining "if" to the Int64 affinity. Fix for [c5cc2fb334]. <b>** Potentially Incompatible Change **</b></li> <li>Handle Julian Day values that fall outside of the supported range for OLE Automation dates. Fix for [3e783eecbe]. <b>** Potentially Incompatible Change **</b></li> <li>Make sure the interop files are copied when publishing a project that refers to a NuGet package containing them. Fix for [e796ac82c1]. <b>** Potentially Incompatible Change **</b></li> <li>Make sure the interop files are copied before the PostBuildEvent. Fix for [f16c93a932]. <b>** Potentially Incompatible Change **</b></li> <li>Modify GetSchemaTable method to avoid setting SchemaTableColumn.IsKey column to true when more than one table is referenced. Fix for [47c6fa04d3]. <b>** Potentially Incompatible Change **</b></li> </ul> <p> <b>1.0.94.0 - September 9, 2014</b> </p> <ul> <li>Updated to [http://www.sqlite.org/releaselog/3_8_6.html|SQLite 3.8.6].</li> <li>Updated to [http://www.nuget.org/packages/EntityFramework/6.1.1|Entity Framework 6.1.1].</li> | > > > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <li>Defer disposing of connections created by the static SQLiteCommand.Execute method when a data reader is returned. Fix for [daeaf3150a].</li> <li>Wrap SELECT statements in parenthesis if they have an ORDER BY, LIMIT, or OFFSET clause and a compound operator is involved. Fix for [0a32885109].</li> <li>In the SQLiteDataReader.VerifyType method, remove duplicate "if" statement for the DbType.SByte value and move the remaining "if" to the Int64 affinity. Fix for [c5cc2fb334]. <b>** Potentially Incompatible Change **</b></li> <li>Handle Julian Day values that fall outside of the supported range for OLE Automation dates. Fix for [3e783eecbe]. <b>** Potentially Incompatible Change **</b></li> <li>Make sure the interop files are copied when publishing a project that refers to a NuGet package containing them. Fix for [e796ac82c1]. <b>** Potentially Incompatible Change **</b></li> <li>Make sure the interop files are copied before the PostBuildEvent. Fix for [f16c93a932]. <b>** Potentially Incompatible Change **</b></li> <li>Modify GetSchemaTable method to avoid setting SchemaTableColumn.IsKey column to true when more than one table is referenced. Fix for [47c6fa04d3]. <b>** Potentially Incompatible Change **</b></li> <li>Add AppendManifestToken_SQLiteProviderManifest environment variable to enable better integration between LINQ and the underlying store connection.</li> <li>Add SQLite_ForceLogPrepare environment variable to force logging of all prepared SQL regardless of the flags for the associated connection.</li> <li>Honor the DateTimeFormat, DateTimeKind, DateTimeFormatString, BinaryGUID connection string and/or provider manifest token properties from within the LINQ assembly. Fix for [8d928c3e88]. <b>** Potentially Incompatible Change **</b></li> </ul> <p> <b>1.0.94.0 - September 9, 2014</b> </p> <ul> <li>Updated to [http://www.sqlite.org/releaselog/3_8_6.html|SQLite 3.8.6].</li> <li>Updated to [http://www.nuget.org/packages/EntityFramework/6.1.1|Entity Framework 6.1.1].</li> |
︙ | ︙ |