@ -2,17 +2,21 @@
using System ;
using System ;
using System.Collections.Generic ;
using System.Collections.Generic ;
using System.Diagnostics.CodeAnalysis ;
using EntityFrameworkCore.Jet.Data ;
using EntityFrameworkCore.Jet.Data ;
using System.Linq ;
using System.Linq ;
using System.Linq.Expressions ;
using System.Linq.Expressions ;
using EntityFrameworkCore.Jet.Infrastructure.Internal ;
using EntityFrameworkCore.Jet.Infrastructure.Internal ;
using JetBrains.Annotations ;
using Microsoft.EntityFrameworkCore.Storage ;
using Microsoft.EntityFrameworkCore.Storage ;
using EntityFrameworkCore.Jet.Utilities ;
using EntityFrameworkCore.Jet.Utilities ;
using Microsoft.EntityFrameworkCore ;
using Microsoft.EntityFrameworkCore.Diagnostics ;
using Microsoft.EntityFrameworkCore.Diagnostics ;
using Microsoft.EntityFrameworkCore.Infrastructure ;
using Microsoft.EntityFrameworkCore.Infrastructure ;
using Microsoft.EntityFrameworkCore.Query ;
using Microsoft.EntityFrameworkCore.Query ;
using Microsoft.EntityFrameworkCore.Query.SqlExpressions ;
using Microsoft.EntityFrameworkCore.Query.SqlExpressions ;
using ExpressionExtensions = Microsoft . EntityFrameworkCore . Internal . ExpressionExtensions ;
using Microsoft.EntityFrameworkCore.Metadata ;
using Microsoft.EntityFrameworkCore.Metadata.Internal ;
namespace EntityFrameworkCore.Jet.Query.Sql.Internal
namespace EntityFrameworkCore.Jet.Query.Sql.Internal
{
{
@ -24,36 +28,40 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal
{
{
private static readonly Dictionary < string , string > _convertMappings = new Dictionary < string , string >
private static readonly Dictionary < string , string > _convertMappings = new Dictionary < string , string >
{
{
{ nameof ( Boolean ) , "CBOOL" } ,
{ nameof ( Boolean ) , "CBOOL" } ,
{ nameof ( Byte ) , "CBYTE" } ,
{ nameof ( Byte ) , "CBYTE" } ,
{ nameof ( SByte ) , "CINT" } ,
{ nameof ( SByte ) , "CINT" } ,
{ nameof ( Int16 ) , "CINT" } ,
{ nameof ( Int16 ) , "CINT" } ,
{ nameof ( Int32 ) , "CLNG" } ,
{ nameof ( Int32 ) , "CLNG" } ,
{ nameof ( Single ) , "CSNG" } ,
{ nameof ( Single ) , "CSNG" } ,
{ nameof ( Double ) , "CDBL" } ,
{ nameof ( Double ) , "CDBL" } ,
{ nameof ( Decimal ) , "CCUR" } ,
{ nameof ( Decimal ) , "CCUR" } ,
{ nameof ( DateTime ) , "CDATE" } ,
{ nameof ( DateTime ) , "CDATE" } ,
} ;
} ;
private readonly ITypeMappingSource _typeMappingSource ;
private readonly ITypeMappingSource _typeMappingSource ;
private readonly IJetOptions _options ;
private readonly IJetOptions _options ;
private readonly ISqlGenerationHelper _sqlGenerationHelper ;
private readonly ISqlGenerationHelper _sqlGenerationHelper ;
//private readonly JetSqlExpressionFactory _sqlExpressionFactory;
private CoreTypeMapping _boolTypeMapping ;
private CoreTypeMapping _boolTypeMapping ;
/// <summary>
/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
/// </summary>
public JetQuerySqlGenerator (
public JetQuerySqlGenerator (
[NotNull] QuerySqlGeneratorDependencies dependencies ,
[JetBrains.Annotations.NotNull] QuerySqlGeneratorDependencies dependencies ,
ITypeMappingSource typeMappingSource ,
//ISqlExpressionFactory sqlExpressionFactory,
[JetBrains.Annotations.NotNull] ITypeMappingSource typeMappingSource ,
IJetOptions options )
IJetOptions options )
: base ( dependencies )
: base ( dependencies )
{
{
//_sqlExpressionFactory = (JetSqlExpressionFactory)sqlExpressionFactory;
_typeMappingSource = typeMappingSource ;
_typeMappingSource = typeMappingSource ;
_options = options ;
_options = options ;
_sqlGenerationHelper = dependencies . SqlGenerationHelper ;
_sqlGenerationHelper = dependencies . SqlGenerationHelper ;
_boolTypeMapping = _typeMappingSource . FindMapping ( typeof ( bool ) ) ;
_boolTypeMapping = _typeMappingSource . FindMapping ( typeof ( bool ) ) ;
//_jetSqlExpressionFactory = jetSqlExpressionFactory;
}
}
protected override Expression VisitSelect ( SelectExpression selectExpression )
protected override Expression VisitSelect ( SelectExpression selectExpression )
@ -65,7 +73,7 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal
if ( IsNonComposedSetOperation ( selectExpression ) )
if ( IsNonComposedSetOperation ( selectExpression ) )
{
{
// Naked set operation
// Naked set operation
GenerateSetOperation ( ( SetOperationBase ) selectExpression . Tables [ 0 ] ) ;
GenerateSetOperation ( ( SetOperationBase ) selectExpression . Tables [ 0 ] ) ;
return selectExpression ;
return selectExpression ;
}
}
@ -112,7 +120,8 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal
0 ,
0 ,
selectExpression
selectExpression
. Tables
. Tables
. Count ( t = > ! ( t is CrossJoinExpression | | t is CrossApplyExpression ) ) - maxTablesWithoutBrackets ) ) ) ;
. Count ( t = > ! ( t is CrossJoinExpression | | t is CrossApplyExpression ) ) -
maxTablesWithoutBrackets ) ) ) ;
for ( var index = 0 ; index < selectExpression . Tables . Count ; index + + )
for ( var index = 0 ; index < selectExpression . Tables . Count ; index + + )
{
{
@ -126,7 +135,8 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal
if ( isApplyExpression )
if ( isApplyExpression )
{
{
throw new InvalidOperationException ( "Jet does not support APPLY statements. Switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync() if needed." ) ;
throw new InvalidOperationException (
"Jet does not support APPLY statements. Switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync() if needed." ) ;
}
}
if ( index > 0 )
if ( index > 0 )
@ -202,7 +212,8 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal
& & selectExpression . Projection . Count = = setOperation . Source1 . Projection . Count
& & selectExpression . Projection . Count = = setOperation . Source1 . Projection . Count
& & selectExpression . Projection . Select (
& & selectExpression . Projection . Select (
( pe , index ) = > pe . Expression is ColumnExpression column
( pe , index ) = > pe . Expression is ColumnExpression column
& & string . Equals ( column . Table . Alias , setOperation . Alias , StringComparison . OrdinalIgnoreCase )
& & string . Equals ( column . Table . Alias , setOperation . Alias ,
StringComparison . OrdinalIgnoreCase )
& & string . Equals (
& & string . Equals (
column . Name , setOperation . Source1 . Projection [ index ]
column . Name , setOperation . Source1 . Projection [ index ]
. Alias , StringComparison . OrdinalIgnoreCase ) )
. Alias , StringComparison . OrdinalIgnoreCase ) )
@ -252,10 +263,10 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal
{
{
Check . NotNull ( sqlBinaryExpression , nameof ( sqlBinaryExpression ) ) ;
Check . NotNull ( sqlBinaryExpression , nameof ( sqlBinaryExpression ) ) ;
/ * if ( sqlBinaryExpression . OperatorType = = ExpressionType . Coalesce )
if ( sqlBinaryExpression . OperatorType = = ExpressionType . Coalesce )
{
{
Visit (
//Visit (
_sqlExpressionFactory . Case (
/ * _sqlExpressionFactory . Case (
new [ ]
new [ ]
{
{
new CaseWhenClause (
new CaseWhenClause (
@ -263,8 +274,18 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal
sqlBinaryExpression . Right )
sqlBinaryExpression . Right )
} ,
} ,
sqlBinaryExpression . Left ) ) ;
sqlBinaryExpression . Left ) ) ;
return sqlBinaryExpression ; * /
SqlConstantExpression nullcons = new SqlConstantExpression ( Expression . Constant ( null ) , RelationalTypeMapping . NullMapping ) ;
SqlUnaryExpression isnullexp = new SqlUnaryExpression ( ExpressionType . Equal , sqlBinaryExpression . Left , typeof ( bool ) , null ) ;
List < CaseWhenClause > whenclause = new List < CaseWhenClause >
{
new CaseWhenClause ( isnullexp , sqlBinaryExpression . Right )
} ;
CaseExpression caseexp = new CaseExpression ( whenclause , sqlBinaryExpression . Left ) ;
Visit ( caseexp ) ;
return sqlBinaryExpression ;
return sqlBinaryExpression ;
} * /
}
return base . VisitSqlBinary ( sqlBinaryExpression ) ;
return base . VisitSqlBinary ( sqlBinaryExpression ) ;
}
}
@ -279,23 +300,37 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal
var typeMapping = convertExpression . TypeMapping ;
var typeMapping = convertExpression . TypeMapping ;
if ( typeMapping = = null )
if ( typeMapping = = null )
throw new InvalidOperationException ( RelationalStrings . UnsupportedType ( convertExpression . Type . ShortDisplayName ( ) ) ) ;
throw new InvalidOperationException (
RelationalStrings . UnsupportedType ( convertExpression . Type . ShortDisplayName ( ) ) ) ;
// We are explicitly converting to the target type (convertExpression.Type) and not the CLR type of the
// We are explicitly converting to the target type (convertExpression.Type) and not the CLR type of the
// accociated type mapping. This allows for conversions on the database side (e.g. CDBL()) but handling
// accociated type mapping. This allows for conversions on the database side (e.g. CDBL()) but handling
// of the returned value using a different (unaligned) type mapping (e.g. date/time related ones).
// of the returned value using a different (unaligned) type mapping (e.g. date/time related ones).
if ( _convertMappings . TryGetValue ( convertExpression . Type . Name , out var function ) )
if ( _convertMappings . TryGetValue ( convertExpression . Type . Name , out var function ) )
{
{
/ * Visit (
/ * Visit (
_sqlExpressionFactory . NullChecked (
_sqlExpressionFactory . NullChecked (
convertExpression . Operand ,
convertExpression . Operand ,
_sqlExpressionFactory . Function (
_sqlExpressionFactory . Function (
function ,
function ,
new [ ] { convertExpression . Operand } ,
new [ ] { convertExpression . Operand } ,
false ,
false ,
new [ ] { false } ,
new [ ] { false } ,
typeMapping . ClrType ) ) ) ;
typeMapping . ClrType ) ) ) ;
* /
* /
SqlExpression checksqlexp = convertExpression . Operand ;
SqlFunctionExpression notnullsqlexp = new SqlFunctionExpression ( function , new SqlExpression [ ] { convertExpression . Operand } ,
false , new [ ] { false } , typeMapping . ClrType , null ) ;
SqlConstantExpression nullcons = new SqlConstantExpression ( Expression . Constant ( null ) , RelationalTypeMapping . NullMapping ) ;
SqlUnaryExpression isnullexp = new SqlUnaryExpression ( ExpressionType . Equal , checksqlexp , typeof ( bool ) , null ) ;
List < CaseWhenClause > whenclause = new List < CaseWhenClause >
{
new CaseWhenClause ( isnullexp , nullcons )
} ;
CaseExpression caseexp = new CaseExpression ( whenclause , notnullsqlexp ) ;
Visit ( caseexp ) ;
return convertExpression ;
return convertExpression ;
}
}
@ -325,7 +360,7 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal
return likeExpression ;
return likeExpression ;
}
}
protected override string GetOperator ( [ NotNull] SqlBinaryExpression binaryExpression )
protected override string GetOperator ( [ JetBrains. Annotations . NotNull] SqlBinaryExpression binaryExpression )
= > binaryExpression . OperatorType switch
= > binaryExpression . OperatorType switch
{
{
ExpressionType . Add when binaryExpression . Type = = typeof ( string ) = > " & " ,
ExpressionType . Add when binaryExpression . Type = = typeof ( string ) = > " & " ,
@ -357,7 +392,8 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal
}
}
else
else
{
{
throw new InvalidOperationException ( "Jet does not support skipping rows. Switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync() if needed." ) ;
throw new InvalidOperationException (
"Jet does not support skipping rows. Switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync() if needed." ) ;
}
}
}
}
@ -441,7 +477,5 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal
protected override Expression VisitRowNumber ( RowNumberExpression rowNumberExpression )
protected override Expression VisitRowNumber ( RowNumberExpression rowNumberExpression )
= > throw new InvalidOperationException ( CoreStrings . TranslationFailed ( rowNumberExpression ) ) ;
= > throw new InvalidOperationException ( CoreStrings . TranslationFailed ( rowNumberExpression ) ) ;
}
}
}
}