Index: System.Data.SQLite.Linq/SQL
==================================================================
--- System.Data.SQLite.Linq/SQL
+++ System.Data.SQLite.Linq/SQL
@@ -1,359 +1,717 @@
-/********************************************************
- * 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!
- ********************************************************/
+//---------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+//---------------------------------------------------------------------
namespace System.Data.SQLite
{
using System;
using System.Collections.Generic;
- using System.Data;
- using System.Data.Common.CommandTrees;
- using System.Data.Entity;
- using System.Runtime.CompilerServices;
-
- internal class SqlChecker : DbExpressionVisitor
- {
- private static Type sql8rewriter;
-
- static SqlChecker()
- {
- sql8rewriter = Type.GetType("System.Data.SqlClient.SqlGen.Sql8ExpressionRewriter, System.Data.Entity, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", false);
- }
-
- private SqlChecker()
- {
+ using System.Diagnostics;
+ using System.Globalization;
+ using System.IO;
+ using System.Text;
+ using System.Data;
+ using System.Data.Common;
+ using System.Data.Metadata.Edm;
+ using System.Data.Common.CommandTrees;
+ using System.Data.Common.Utils;
+ using System.Data.Mapping.Update.Internal;
+
+ ///
+ /// Class generating SQL for a DML command tree.
+ ///
+ internal static class DmlSqlGenerator
+ {
+ private static readonly int s_commandTextBuilderInitialCapacity = 256;
+
+ internal static string GenerateUpdateSql(DbUpdateCommandTree tree, out List parameters)
+ {
+ StringBuilder commandText = new StringBuilder(s_commandTextBuilderInitialCapacity);
+ ExpressionTranslator translator = new ExpressionTranslator(commandText, tree, null != tree.Returning, "UpdateFunction");
+
+ // update [schemaName].[tableName]
+ commandText.Append("UPDATE ");
+ tree.Target.Expression.Accept(translator);
+ commandText.AppendLine();
+
+ // set c1 = ..., c2 = ..., ...
+ bool first = true;
+ commandText.Append("SET ");
+ foreach (DbSetClause setClause in tree.SetClauses)
+ {
+ if (first) { first = false; }
+ else { commandText.Append(", "); }
+ setClause.Property.Accept(translator);
+ commandText.Append(" = ");
+ setClause.Value.Accept(translator);
+ }
+
+ if (first)
+ {
+ // If first is still true, it indicates there were no set
+ // clauses. Introduce a fake set clause so that:
+ // - we acquire the appropriate locks
+ // - server-gen columns (e.g. timestamp) get recomputed
+ //
+ // We use the following pattern:
+ //
+ // update Foo
+ // set @i = 0
+ // where ...
+ DbParameter parameter = translator.CreateParameter(default(Int32), DbType.Int32);
+ commandText.Append(parameter.ParameterName);
+ commandText.Append(" = 0");
+ }
+ commandText.AppendLine();
+
+ // where c1 = ..., c2 = ...
+ commandText.Append("WHERE ");
+ tree.Predicate.Accept(translator);
+ commandText.AppendLine();
+
+ // generate returning sql
+ GenerateReturningSql(commandText, tree, translator, tree.Returning);
+
+ parameters = translator.Parameters;
+ return commandText.ToString();
+ }
+
+ internal static string GenerateDeleteSql(DbDeleteCommandTree tree, out List parameters)
+ {
+ StringBuilder commandText = new StringBuilder(s_commandTextBuilderInitialCapacity);
+ ExpressionTranslator translator = new ExpressionTranslator(commandText, tree, false, "DeleteFunction");
+
+ // delete [schemaName].[tableName]
+ commandText.Append("DELETE FROM ");
+ tree.Target.Expression.Accept(translator);
+ commandText.AppendLine();
+
+ // where c1 = ... AND c2 = ...
+ commandText.Append("WHERE ");
+ tree.Predicate.Accept(translator);
+
+ parameters = translator.Parameters;
+
+ commandText.AppendLine(";");
+ return commandText.ToString();
+ }
+
+ internal static string GenerateInsertSql(DbInsertCommandTree tree, out List parameters)
+ {
+ StringBuilder commandText = new StringBuilder(s_commandTextBuilderInitialCapacity);
+ ExpressionTranslator translator = new ExpressionTranslator(commandText, tree, null != tree.Returning, "InsertFunction");
+
+ // insert [schemaName].[tableName]
+ commandText.Append("INSERT INTO ");
+ tree.Target.Expression.Accept(translator);
+
+ if (tree.SetClauses.Count > 0)
+ {
+ // (c1, c2, c3, ...)
+ commandText.Append("(");
+ bool first = true;
+ foreach (DbSetClause setClause in tree.SetClauses)
+ {
+ if (first) { first = false; }
+ else { commandText.Append(", "); }
+ setClause.Property.Accept(translator);
+ }
+ commandText.AppendLine(")");
+
+ // values c1, c2, ...
+ first = true;
+ commandText.Append(" VALUES (");
+ foreach (DbSetClause setClause in tree.SetClauses)
+ {
+ if (first) { first = false; }
+ else { commandText.Append(", "); }
+ setClause.Value.Accept(translator);
+
+ translator.RegisterMemberValue(setClause.Property, setClause.Value);
+ }
+ commandText.AppendLine(");");
+ }
+ else // No columns specified. Insert an empty row containing default values by inserting null into the rowid
+ {
+ commandText.AppendLine(" DEFAULT VALUES;");
+ }
+
+ // generate returning sql
+ GenerateReturningSql(commandText, tree, translator, tree.Returning);
+
+ parameters = translator.Parameters;
+ return commandText.ToString();
+ }
+
+ // Generates T-SQL describing a member
+ // Requires: member must belong to an entity type (a safe requirement for DML
+ // SQL gen, where we only access table columns)
+ private static string GenerateMemberTSql(EdmMember member)
+ {
+ return SqlGenerator.QuoteIdentifier(member.Name);
+ }
+
+ ///
+ /// Generates SQL fragment returning server-generated values.
+ /// Requires: translator knows about member values so that we can figure out
+ /// how to construct the key predicate.
+ ///
+ /// Sample SQL:
+ ///
+ /// select IdentityValue
+ /// from dbo.MyTable
+ /// where @@ROWCOUNT > 0 and IdentityValue = scope_identity()
+ ///
+ /// or
+ ///
+ /// select TimestamptValue
+ /// from dbo.MyTable
+ /// where @@ROWCOUNT > 0 and Id = 1
+ ///
+ /// Note that we filter on rowcount to ensure no rows are returned if no rows were modified.
+ ///
+ ///
+ /// Builder containing command text
+ /// Modification command tree
+ /// Translator used to produce DML SQL statement
+ /// for the tree
+ /// Returning expression. If null, the method returns
+ /// immediately without producing a SELECT statement.
+ private static void GenerateReturningSql(StringBuilder commandText, DbModificationCommandTree tree,
+ ExpressionTranslator translator, DbExpression returning)
+ {
+ // Nothing to do if there is no Returning expression
+ if (null == returning) { return; }
+
+ // select
+ commandText.Append("SELECT ");
+ returning.Accept(translator);
+ commandText.AppendLine();
+
+ // from
+ commandText.Append("FROM ");
+ tree.Target.Expression.Accept(translator);
+ commandText.AppendLine();
+
+ // where
+ commandText.Append("WHERE last_rows_affected() > 0");
+ EntitySetBase table = ((DbScanExpression)tree.Target.Expression).Target;
+ bool identity = false;
+ foreach (EdmMember keyMember in table.ElementType.KeyMembers)
+ {
+ commandText.Append(" AND ");
+ commandText.Append(GenerateMemberTSql(keyMember));
+ commandText.Append(" = ");
+
+ // retrieve member value sql. the translator remembers member values
+ // as it constructs the DML statement (which precedes the "returning"
+ // SQL)
+ DbParameter value;
+ if (translator.MemberValues.TryGetValue(keyMember, out value))
+ {
+ commandText.Append(value.ParameterName);
+ }
+ else
+ {
+ // if no value is registered for the key member, it means it is an identity
+ // which can be retrieved using the scope_identity() function
+ if (identity)
+ {
+ // there can be only one server generated key
+ throw new NotSupportedException(string.Format("Server generated keys are only supported for identity columns. More than one key column is marked as server generated in table '{0}'.", table.Name));
+ }
+ commandText.AppendLine("last_insert_rowid();");
+ identity = true;
+ }
+ }
}
///
- /// SQLite doesn't support things like SKIP and a few other things. So determine if the query has to be rewritten
- ///
- ///
- /// Microsoft went to all the trouble of making things like SKIP work on Sql Server 2000 by doing a rewrite of the commandtree.
- /// However, all that fancy stuff is hidden from us. Thanks to reflection however, we can go ahead and use the Sql 2000 rewriter code
- /// they made.
- ///
- /// The tree to inspect for a rewrite
- /// Returns a new query tree if it needs rewriting
- internal static DbQueryCommandTree Rewrite(DbQueryCommandTree tree)
- {
- SqlChecker visitor = new SqlChecker();
- if (tree.Query.Accept(visitor))
- {
- tree = sql8rewriter.InvokeMember("Rewrite", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Static, null, null, new object[] { tree }) as DbQueryCommandTree;
- }
- return tree;
- }
-
- public override bool Visit(DbAndExpression expression)
- {
- return VisitBinaryExpression(expression);
- }
-
- public override bool Visit(DbApplyExpression expression)
- {
- throw new NotSupportedException("apply expression");
- }
-
- public override bool Visit(DbArithmeticExpression expression)
- {
- return VisitExpressionList(expression.Arguments);
- }
-
- public override bool Visit(DbCaseExpression expression)
- {
- bool flag1 = VisitExpressionList(expression.When);
- bool flag2 = VisitExpressionList(expression.Then);
- bool flag3 = VisitExpression(expression.Else);
-
- return (flag1 || flag2 || flag3);
- }
-
- public override bool Visit(DbCastExpression expression)
- {
- return VisitUnaryExpression(expression);
- }
-
- public override bool Visit(DbComparisonExpression expression)
- {
- return VisitBinaryExpression(expression);
- }
-
- public override bool Visit(DbConstantExpression expression)
- {
- return false;
- }
-
- public override bool Visit(DbCrossJoinExpression expression)
- {
- return VisitExpressionBindingList(expression.Inputs);
- }
-
- public override bool Visit(DbDerefExpression expression)
- {
- return VisitUnaryExpression(expression);
- }
-
- public override bool Visit(DbDistinctExpression expression)
- {
- return VisitUnaryExpression(expression);
- }
-
- public override bool Visit(DbElementExpression expression)
- {
- return VisitUnaryExpression(expression);
- }
-
- public override bool Visit(DbEntityRefExpression expression)
- {
- return VisitUnaryExpression(expression);
- }
-
- public override bool Visit(DbExceptExpression expression)
- {
- VisitExpression(expression.Left);
- VisitExpression(expression.Right);
- return true;
- }
-
- public override bool Visit(DbExpression expression)
- {
- throw new NotSupportedException(expression.GetType().FullName);
- }
-
- public override bool Visit(DbFilterExpression expression)
- {
- bool flag1 = VisitExpressionBinding(expression.Input);
- bool flag2 = VisitExpression(expression.Predicate);
-
- return (flag1 || flag2);
- }
-
- public override bool Visit(DbFunctionExpression expression)
- {
- return VisitExpressionList(expression.Arguments);
- }
-
- public override bool Visit(DbGroupByExpression expression)
- {
- bool flag1 = VisitExpression(expression.Input.Expression);
- bool flag2 = VisitExpressionList(expression.Keys);
- bool flag3 = VisitAggregateList(expression.Aggregates);
-
- return (flag1 || flag2 || flag3);
- }
-
- public override bool Visit(DbIntersectExpression expression)
- {
- VisitExpression(expression.Left);
- VisitExpression(expression.Right);
- return true;
- }
-
- public override bool Visit(DbIsEmptyExpression expression)
- {
- return VisitUnaryExpression(expression);
- }
-
- public override bool Visit(DbIsNullExpression expression)
- {
- return VisitUnaryExpression(expression);
- }
-
- public override bool Visit(DbIsOfExpression expression)
- {
- return VisitUnaryExpression(expression);
- }
-
- public override bool Visit(DbJoinExpression expression)
- {
- bool flag1 = VisitExpressionBinding(expression.Left);
- bool flag2 = VisitExpressionBinding(expression.Right);
- bool flag3 = VisitExpression(expression.JoinCondition);
- return (flag1 || flag2 || flag3);
- }
-
- public override bool Visit(DbLikeExpression expression)
- {
- bool flag1 = VisitExpression(expression.Argument);
- bool flag2 = VisitExpression(expression.Pattern);
- bool flag3 = VisitExpression(expression.Escape);
- return (flag1 || flag2 || flag3);
- }
-
- public override bool Visit(DbLimitExpression expression)
- {
- return VisitExpression(expression.Argument);
- }
-
- public override bool Visit(DbNewInstanceExpression expression)
- {
- return VisitExpressionList(expression.Arguments);
- }
-
- public override bool Visit(DbNotExpression expression)
- {
- return VisitUnaryExpression(expression);
- }
-
- public override bool Visit(DbNullExpression expression)
- {
- return false;
- }
-
- public override bool Visit(DbOfTypeExpression expression)
- {
- return VisitUnaryExpression(expression);
- }
-
- public override bool Visit(DbOrExpression expression)
- {
- return VisitBinaryExpression(expression);
- }
-
- public override bool Visit(DbParameterReferenceExpression expression)
- {
- return false;
- }
-
- public override bool Visit(DbProjectExpression expression)
- {
- bool flag1 = VisitExpressionBinding(expression.Input);
- bool flag2 = VisitExpression(expression.Projection);
- return (flag1 || flag2);
- }
-
- public override bool Visit(DbPropertyExpression expression)
- {
- return VisitExpression(expression.Instance);
- }
-
- public override bool Visit(DbQuantifierExpression expression)
- {
- bool flag1 = VisitExpressionBinding(expression.Input);
- bool flag2 = VisitExpression(expression.Predicate);
- return (flag1 || flag2);
- }
-
- public override bool Visit(DbRefExpression expression)
- {
- return VisitUnaryExpression(expression);
- }
-
- public override bool Visit(DbRefKeyExpression expression)
- {
- return VisitUnaryExpression(expression);
- }
-
- public override bool Visit(DbRelationshipNavigationExpression expression)
- {
- return VisitExpression(expression.NavigationSource);
- }
-
- public override bool Visit(DbScanExpression expression)
- {
- return false;
- }
-
- public override bool Visit(DbSkipExpression expression)
- {
- VisitExpressionBinding(expression.Input);
- VisitSortClauseList(expression.SortOrder);
- VisitExpression(expression.Count);
- return true;
- }
-
- public override bool Visit(DbSortExpression expression)
- {
- bool flag1 = VisitExpressionBinding(expression.Input);
- bool flag2 = VisitSortClauseList(expression.SortOrder);
- return (flag1 || flag2);
- }
-
- public override bool Visit(DbTreatExpression expression)
- {
- return VisitUnaryExpression(expression);
- }
-
- public override bool Visit(DbUnionAllExpression expression)
- {
- return VisitBinaryExpression(expression);
- }
-
- public override bool Visit(DbVariableReferenceExpression expression)
- {
- return false;
- }
-
- private bool VisitAggregate(DbAggregate aggregate)
- {
- return VisitExpressionList(aggregate.Arguments);
- }
-
- private bool VisitAggregateList(IList list)
- {
- return VisitList(new ListElementHandler(VisitAggregate), list);
- }
-
- private bool VisitBinaryExpression(DbBinaryExpression expr)
- {
- bool flag1 = VisitExpression(expr.Left);
- bool flag2 = VisitExpression(expr.Right);
- return (flag1 || flag2);
- }
-
- private bool VisitExpression(DbExpression expression)
- {
- if (expression == null)
- {
- return false;
- }
- return expression.Accept(this);
- }
-
- private bool VisitExpressionBinding(DbExpressionBinding expressionBinding)
- {
- return VisitExpression(expressionBinding.Expression);
- }
-
- private bool VisitExpressionBindingList(IList list)
- {
- return VisitList(new ListElementHandler(VisitExpressionBinding), list);
- }
-
- private bool VisitExpressionList(IList list)
- {
- return VisitList(new ListElementHandler(VisitExpression), list);
- }
-
- private static bool VisitList(ListElementHandler handler, IList list)
- {
- bool flag = false;
- foreach (TElementType local in list)
- {
- bool flag2 = handler(local);
- flag = flag || flag2;
- }
- return flag;
- }
-
- private bool VisitSortClause(DbSortClause sortClause)
- {
- return VisitExpression(sortClause.Expression);
- }
-
- private bool VisitSortClauseList(IList list)
- {
- return VisitList(new ListElementHandler(VisitSortClause), list);
- }
-
- private bool VisitUnaryExpression(DbUnaryExpression expr)
- {
- return VisitExpression(expr.Argument);
- }
-
- private delegate bool ListElementHandler(TElementType element);
- }
-}
+ /// Lightweight expression translator for DML expression trees, which have constrained
+ /// scope and support.
+ ///
+ private class ExpressionTranslator : DbExpressionVisitor
+ {
+ ///
+ /// Initialize a new expression translator populating the given string builder
+ /// with command text. Command text builder and command tree must not be null.
+ ///
+ /// Command text with which to populate commands
+ /// Command tree generating SQL
+ /// Indicates whether the translator should preserve
+ /// member values while compiling t-SQL (only needed for server generation)
+ internal ExpressionTranslator(StringBuilder commandText, DbModificationCommandTree commandTree,
+ bool preserveMemberValues, string kind)
+ {
+ Debug.Assert(null != commandText);
+ Debug.Assert(null != commandTree);
+ _kind = kind;
+ _commandText = commandText;
+ _commandTree = commandTree;
+ _parameters = new List();
+ _memberValues = preserveMemberValues ? new Dictionary() :
+ null;
+ }
+
+ private readonly StringBuilder _commandText;
+ private readonly DbModificationCommandTree _commandTree;
+ private readonly List _parameters;
+ private readonly Dictionary _memberValues;
+ private int parameterNameCount = 0;
+ private string _kind;
+
+ internal List Parameters { get { return _parameters; } }
+ internal Dictionary MemberValues { get { return _memberValues; } }
+
+ // generate parameter (name based on parameter ordinal)
+ internal SQLiteParameter CreateParameter(object value, TypeUsage type)
+ {
+ PrimitiveTypeKind primitiveType = MetadataHelpers.GetPrimitiveTypeKind(type);
+ DbType dbType = MetadataHelpers.GetDbType(primitiveType);
+ return CreateParameter(value, dbType);
+ }
+
+ // Creates a new parameter for a value in this expression translator
+ internal SQLiteParameter CreateParameter(object value, DbType dbType)
+ {
+ string parameterName = string.Concat("@p", parameterNameCount.ToString(CultureInfo.InvariantCulture));
+ parameterNameCount++;
+ SQLiteParameter parameter = new SQLiteParameter(parameterName, value);
+ parameter.DbType = dbType;
+ _parameters.Add(parameter);
+ return parameter;
+ }
+
+ #region Basics
+
+ public override void Visit(DbApplyExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+
+ VisitExpressionBindingPre(expression.Input);
+ if (expression.Apply != null)
+ {
+ VisitExpression(expression.Apply.Expression);
+ }
+ VisitExpressionBindingPost(expression.Input);
+ }
+
+ public override void Visit(DbArithmeticExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitExpressionList(expression.Arguments);
+ }
+
+ public override void Visit(DbCaseExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitExpressionList(expression.When);
+ VisitExpressionList(expression.Then);
+ VisitExpression(expression.Else);
+ }
+
+ public override void Visit(DbCastExpression expression)
+ {
+ VisitUnaryExpression(expression);
+ }
+
+ public override void Visit(DbCrossJoinExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ foreach (DbExpressionBinding binding in expression.Inputs)
+ {
+ VisitExpressionBindingPre(binding);
+ }
+ foreach (DbExpressionBinding binding2 in expression.Inputs)
+ {
+ VisitExpressionBindingPost(binding2);
+ }
+ }
+
+ public override void Visit(DbDerefExpression expression)
+ {
+ VisitUnaryExpression(expression);
+ }
+
+ public override void Visit(DbDistinctExpression expression)
+ {
+ VisitUnaryExpression(expression);
+ }
+
+ public override void Visit(DbElementExpression expression)
+ {
+ VisitUnaryExpression(expression);
+ }
+
+ public override void Visit(DbEntityRefExpression expression)
+ {
+ VisitUnaryExpression(expression);
+ }
+
+ public override void Visit(DbExceptExpression expression)
+ {
+ VisitBinary(expression);
+ }
+
+ protected virtual void VisitBinary(DbBinaryExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ this.VisitExpression(expression.Left);
+ this.VisitExpression(expression.Right);
+ }
+
+ public override void Visit(DbExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ throw new NotSupportedException("DbExpression");
+ }
+
+ public override void Visit(DbFilterExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitExpressionBindingPre(expression.Input);
+ VisitExpression(expression.Predicate);
+ VisitExpressionBindingPost(expression.Input);
+ }
+
+ public override void Visit(DbFunctionExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitExpressionList(expression.Arguments);
+ //if (expression.IsLambda)
+ //{
+ // VisitLambdaFunctionPre(expression.Function, expression.LambdaBody);
+ // VisitExpression(expression.LambdaBody);
+ // VisitLambdaFunctionPost(expression.Function, expression.LambdaBody);
+ //}
+ }
+
+ public override void Visit(DbGroupByExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitGroupExpressionBindingPre(expression.Input);
+ VisitExpressionList(expression.Keys);
+ VisitGroupExpressionBindingMid(expression.Input);
+ VisitAggregateList(expression.Aggregates);
+ VisitGroupExpressionBindingPost(expression.Input);
+ }
+
+ public override void Visit(DbIntersectExpression expression)
+ {
+ VisitBinary(expression);
+ }
+
+ public override void Visit(DbIsEmptyExpression expression)
+ {
+ VisitUnaryExpression(expression);
+ }
+
+ public override void Visit(DbIsOfExpression expression)
+ {
+ VisitUnaryExpression(expression);
+ }
+
+ public override void Visit(DbJoinExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitExpressionBindingPre(expression.Left);
+ VisitExpressionBindingPre(expression.Right);
+ VisitExpression(expression.JoinCondition);
+ VisitExpressionBindingPost(expression.Left);
+ VisitExpressionBindingPost(expression.Right);
+ }
+
+ public override void Visit(DbLikeExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitExpression(expression.Argument);
+ VisitExpression(expression.Pattern);
+ VisitExpression(expression.Escape);
+ }
+
+ public override void Visit(DbLimitExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitExpression(expression.Argument);
+ VisitExpression(expression.Limit);
+ }
+
+ public override void Visit(DbOfTypeExpression expression)
+ {
+ VisitUnaryExpression(expression);
+ }
+
+ public override void Visit(DbParameterReferenceExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ }
+
+ public override void Visit(DbProjectExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitExpressionBindingPre(expression.Input);
+ VisitExpression(expression.Projection);
+ VisitExpressionBindingPost(expression.Input);
+ }
+
+ public override void Visit(DbQuantifierExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitExpressionBindingPre(expression.Input);
+ VisitExpression(expression.Predicate);
+ VisitExpressionBindingPost(expression.Input);
+ }
+
+ public override void Visit(DbRefExpression expression)
+ {
+ VisitUnaryExpression(expression);
+ }
+
+ public override void Visit(DbRefKeyExpression expression)
+ {
+ VisitUnaryExpression(expression);
+ }
+
+ public override void Visit(DbRelationshipNavigationExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitExpression(expression.NavigationSource);
+ }
+
+ public override void Visit(DbSkipExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitExpressionBindingPre(expression.Input);
+ foreach (DbSortClause clause in expression.SortOrder)
+ {
+ VisitExpression(clause.Expression);
+ }
+ VisitExpressionBindingPost(expression.Input);
+ VisitExpression(expression.Count);
+ }
+
+ public override void Visit(DbSortExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitExpressionBindingPre(expression.Input);
+ for (int i = 0; i < expression.SortOrder.Count; i++)
+ {
+ VisitExpression(expression.SortOrder[i].Expression);
+ }
+ VisitExpressionBindingPost(expression.Input);
+ }
+
+ public override void Visit(DbTreatExpression expression)
+ {
+ VisitUnaryExpression(expression);
+ }
+
+ public override void Visit(DbUnionAllExpression expression)
+ {
+ VisitBinary(expression);
+ }
+
+ public override void Visit(DbVariableReferenceExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ }
+
+ public virtual void VisitAggregate(DbAggregate aggregate)
+ {
+ if (aggregate == null) throw new ArgumentException("aggregate");
+ VisitExpressionList(aggregate.Arguments);
+ }
+
+ public virtual void VisitAggregateList(IList aggregates)
+ {
+ if (aggregates == null) throw new ArgumentException("aggregates");
+ for (int i = 0; i < aggregates.Count; i++)
+ {
+ VisitAggregate(aggregates[i]);
+ }
+ }
+
+ public virtual void VisitExpression(DbExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ expression.Accept(this);
+ }
+
+ protected virtual void VisitExpressionBindingPost(DbExpressionBinding binding)
+ {
+ }
+
+ protected virtual void VisitExpressionBindingPre(DbExpressionBinding binding)
+ {
+ if (binding == null) throw new ArgumentException("binding");
+ VisitExpression(binding.Expression);
+ }
+
+ public virtual void VisitExpressionList(IList expressionList)
+ {
+ if (expressionList == null) throw new ArgumentException("expressionList");
+ for (int i = 0; i < expressionList.Count; i++)
+ {
+ VisitExpression(expressionList[i]);
+ }
+ }
+
+ protected virtual void VisitGroupExpressionBindingMid(DbGroupExpressionBinding binding)
+ {
+ }
+
+ protected virtual void VisitGroupExpressionBindingPost(DbGroupExpressionBinding binding)
+ {
+ }
+
+ protected virtual void VisitGroupExpressionBindingPre(DbGroupExpressionBinding binding)
+ {
+ if (binding == null) throw new ArgumentException("binding");
+ VisitExpression(binding.Expression);
+ }
+
+ protected virtual void VisitLambdaFunctionPost(EdmFunction function, DbExpression body)
+ {
+ }
+
+ protected virtual void VisitLambdaFunctionPre(EdmFunction function, DbExpression body)
+ {
+ if (function == null) throw new ArgumentException("function");
+ if (body == null) throw new ArgumentException("body");
+ }
+
+ //internal virtual void VisitRelatedEntityReference(DbRelatedEntityRef relatedEntityRef)
+ //{
+ // VisitExpression(relatedEntityRef.TargetEntityReference);
+ //}
+
+ //internal virtual void VisitRelatedEntityReferenceList(IList relatedEntityReferences)
+ //{
+ // for (int i = 0; i < relatedEntityReferences.Count; i++)
+ // {
+ // VisitRelatedEntityReference(relatedEntityReferences[i]);
+ // }
+ //}
+
+ protected virtual void VisitUnaryExpression(DbUnaryExpression expression)
+ {
+ if (expression == null) throw new ArgumentException("expression");
+ VisitExpression(expression.Argument);
+ }
+ #endregion
+
+ public override void Visit(DbAndExpression expression)
+ {
+ VisitBinary(expression, " AND ");
+ }
+
+ public override void Visit(DbOrExpression expression)
+ {
+ VisitBinary(expression, " OR ");
+ }
+
+ public override void Visit(DbComparisonExpression expression)
+ {
+ Debug.Assert(expression.ExpressionKind == DbExpressionKind.Equals,
+ "only equals comparison expressions are produced in DML command trees in V1");
+
+ VisitBinary(expression, " = ");
+
+ RegisterMemberValue(expression.Left, expression.Right);
+ }
+
+ ///
+ /// Call this method to register a property value pair so the translator "remembers"
+ /// the values for members of the row being modified. These values can then be used
+ /// to form a predicate for server-generation (based on the key of the row)
+ ///
+ /// DbExpression containing the column reference (property expression).
+ /// DbExpression containing the value of the column.
+ internal void RegisterMemberValue(DbExpression propertyExpression, DbExpression value)
+ {
+ if (null != _memberValues)
+ {
+ // register the value for this property
+ Debug.Assert(propertyExpression.ExpressionKind == DbExpressionKind.Property,
+ "DML predicates and setters must be of the form property = value");
+
+ // get name of left property
+ EdmMember property = ((DbPropertyExpression)propertyExpression).Property;
+
+ // don't track null values
+ if (value.ExpressionKind != DbExpressionKind.Null)
+ {
+ Debug.Assert(value.ExpressionKind == DbExpressionKind.Constant,
+ "value must either constant or null");
+ // retrieve the last parameter added (which describes the parameter)
+ _memberValues[property] = _parameters[_parameters.Count - 1];
+ }
+ }
+ }
+
+ public override void Visit(DbIsNullExpression expression)
+ {
+ expression.Argument.Accept(this);
+ _commandText.Append(" IS NULL");
+ }
+
+ public override void Visit(DbNotExpression expression)
+ {
+ _commandText.Append("NOT (");
+ expression.Accept(this);
+ _commandText.Append(")");
+ }
+
+ public override void Visit(DbConstantExpression expression)
+ {
+ SQLiteParameter parameter = CreateParameter(expression.Value, expression.ResultType);
+ _commandText.Append(parameter.ParameterName);
+ }
+
+ public override void Visit(DbScanExpression expression)
+ {
+ string definingQuery = MetadataHelpers.TryGetValueForMetadataProperty(expression.Target, "DefiningQuery");
+ if (definingQuery != null)
+ {
+ throw new NotSupportedException(String.Format("Unable to update the EntitySet '{0}' because it has a DefiningQuery and no <{1}> element exists in the element to support the current operation.", expression.Target.Name, _kind));
+ }
+ _commandText.Append(SqlGenerator.GetTargetTSql(expression.Target));
+ }
+
+ public override void Visit(DbPropertyExpression expression)
+ {
+ _commandText.Append(GenerateMemberTSql(expression.Property));
+ }
+
+ public override void Visit(DbNullExpression expression)
+ {
+ _commandText.Append("NULL");
+ }
+
+ public override void Visit(DbNewInstanceExpression expression)
+ {
+ // assumes all arguments are self-describing (no need to use aliases
+ // because no renames are ever used in the projection)
+ bool first = true;
+ foreach (DbExpression argument in expression.Arguments)
+ {
+ if (first) { first = false; }
+ else { _commandText.Append(", "); }
+ argument.Accept(this);
+ }
+ }
+
+ private void VisitBinary(DbBinaryExpression expression, string separator)
+ {
+ _commandText.Append("(");
+ expression.Left.Accept(this);
+ _commandText.Append(separator);
+ expression.Right.Accept(this);
+ _commandText.Append(")");
+ }
+ }
+ }
+}
+
Index: testce/testce.csproj
==================================================================
--- testce/testce.csproj
+++ testce/testce.csproj
@@ -9,12 +9,12 @@
Properties
test
testce
{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
PocketPC
- b2c48bd2-963d-4549-9169-1fa021dce484
- 5.02
+ 3C41C503-53EF-4c2a-8DD4-A8217CAD115E
+ 4.20
testce
v2.0
@@ -21,11 +21,11 @@
%25CSIDL_PROGRAM_FILES%25
2.0
- Windows Mobile 6 Professional SDK
+ Pocket PC 2003
true
@@ -61,10 +61,11 @@
False
False
+ True
False
Index: testlinq/northwindEF.db
==================================================================
--- testlinq/northwindEF.db
+++ testlinq/northwindEF.db
cannot compute difference between binary files
Index: tools/install/InstallDesigner.cs
==================================================================
--- tools/install/InstallDesigner.cs
+++ tools/install/InstallDesigner.cs
@@ -293,10 +293,25 @@
subkey.SetValue(null, path);
}
}
}
}
+
+ for (int n = 0; n < compactFrameworks.Length; n++)
+ {
+ using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\.NETCompactFramework\\v3.5.0.0\\{0}\\AssemblyFoldersEx", compactFrameworks[n]), true))
+ {
+
+ if (key != null)
+ {
+ using (RegistryKey subkey = key.CreateSubKey("SQLite", RegistryKeyPermissionCheck.ReadWriteSubTree))
+ {
+ subkey.SetValue(null, path);
+ }
+ }
+ }
+ }
}
for (int n = 0; n < 2; n++)
{
// Add factory support to the machine.config file.
@@ -356,20 +371,24 @@
{
try
{
Registry.LocalMachine.DeleteSubKey("Software\\Microsoft\\.NETFramework\\v2.0.50727\\AssemblyFoldersEx\\SQLite");
- for (int n = 0; n < compactFrameworks.Length; n++)
- {
- using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\.NETCompactFramework\\v2.0.0.0\\{0}\\DataProviders", compactFrameworks[n]), true))
- {
- try
- {
- if (key != null) key.DeleteSubKey(standardDataProviderGuid.ToString("B"));
- }
- catch
- {
+ string[] versions = { "v2.0.0.0", "v3.5.0.0" };
+ for (int x = 0; x < versions.Length; x++)
+ {
+ for (int n = 0; n < compactFrameworks.Length; n++)
+ {
+ using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\.NETCompactFramework\\{1}\\{0}\\DataProviders", compactFrameworks[n], versions[x]), true))
+ {
+ try
+ {
+ if (key != null) key.DeleteSubKey(standardDataProviderGuid.ToString("B"));
+ }
+ catch
+ {
+ }
}
}
}
for (int n = 0; n < compactFrameworks.Length; n++)
@@ -473,12 +492,12 @@
{
}
finally
{
File.Delete(tempPath);
- if (File.Exists(Path.GetFullPath("System.Data.SQLite.Linq.DLL")) == true)
- AssemblyCache.InstallAssembly(Path.GetFullPath("System.Data.SQLite.Linq.DLL"), null, AssemblyCommitFlags.Default);
+ if (File.Exists(Path.GetFullPath("..\\System.Data.SQLite.Linq.DLL")) == true)
+ AssemblyCache.InstallAssembly(Path.GetFullPath("..\\System.Data.SQLite.Linq.DLL"), null, AssemblyCommitFlags.Default);
AssemblyCache.InstallAssembly(Path.GetFullPath("SQLite.Designer.DLL"), null, AssemblyCommitFlags.Default);
AssemblyCache.InstallAssembly(SQLiteLocation, null, AssemblyCommitFlags.Default);
}
}
@@ -634,21 +653,26 @@
//}
//catch
//{
//}
- for (int n = 0; n < compactFrameworks.Length; n++)
- {
- using (RegistryKey key = Registry.LocalMachine.OpenSubKey(String.Format("Software\\Microsoft\\.NETCompactFramework\\v2.0.0.0\\{0}\\DataProviders", compactFrameworks[n]), true))
- {
- if (key != null)
- {
- using (RegistryKey subkey = key.CreateSubKey(standardDataProviderGuid.ToString("B"), RegistryKeyPermissionCheck.ReadWriteSubTree))
- {
- subkey.SetValue(null, ".NET Framework Data Provider for SQLite");
- subkey.SetValue("InvariantName", "System.Data.SQLite");
- subkey.SetValue("RuntimeAssembly", "System.Data.SQLite.DLL");
+ string[] versions = { "v2.0.0.0", "v3.5.0.0" };
+
+ for (int x = 0; x < versions.Length; x++)
+ {
+ for (int n = 0; n < compactFrameworks.Length; n++)
+ {
+ using (RegistryKey key = Registry.LocalMachine.CreateSubKey(String.Format("Software\\Microsoft\\.NETCompactFramework\\{1}\\{0}\\DataProviders", compactFrameworks[n], versions[x])))
+ {
+ if (key != null)
+ {
+ using (RegistryKey subkey = key.CreateSubKey(standardDataProviderGuid.ToString("B"), RegistryKeyPermissionCheck.ReadWriteSubTree))
+ {
+ subkey.SetValue(null, ".NET Framework Data Provider for SQLite");
+ subkey.SetValue("InvariantName", "System.Data.SQLite");
+ subkey.SetValue("RuntimeAssembly", "System.Data.SQLite.DLL");
+ }
}
}
}
}
Index: tools/install/Properties/Resources.Designer.cs
==================================================================
--- tools/install/Properties/Resources.Designer.cs
+++ tools/install/Properties/Resources.Designer.cs
@@ -1,9 +1,9 @@
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
-// Runtime Version:2.0.50727.1433
+// Runtime Version:2.0.50727.3053
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
//------------------------------------------------------------------------------
Index: tools/install/Properties/Resources.resx
==================================================================
--- tools/install/Properties/Resources.resx
+++ tools/install/Properties/Resources.resx
@@ -117,8 +117,8 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- ..\Resources\System.Data.SQLite.DLL;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ ..\Resources\System.Data.SQLite.dll;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Index: tools/install/install.csproj
==================================================================
--- tools/install/install.csproj
+++ tools/install/install.csproj
@@ -1,10 +1,10 @@
Debug
AnyCPU
- 9.0.30428
+ 9.0.30729
2.0
{71EED886-B5BF-488E-A4AA-1403E393D224}
WinExe
Properties
install
@@ -73,29 +73,27 @@
InstallDesigner.cs
+
+ True
+ True
+ Resources.resx
+
Designer
InstallDesigner.cs
ResXFileCodeGenerator
Resources.Designer.cs
- Designer
-
- True
- Resources.resx
- True
-
-
False
.NET Framework 2.0 %28x86%29
@@ -112,10 +110,11 @@
false
+