@@ -17,6 +17,11 @@ public partial class Compiler
1717 protected virtual string LastId { get ; set ; } = "" ;
1818 protected virtual string EscapeCharacter { get ; set ; } = "\\ " ;
1919
20+
21+ protected virtual string SingleInsertStartClause { get ; set ; } = "INSERT INTO" ;
22+ protected virtual string MultiInsertStartClause { get ; set ; } = "INSERT INTO" ;
23+
24+
2025 protected Compiler ( )
2126 {
2227 _compileConditionMethodsProvider = new ConditionsCompilerProvider ( this ) ;
@@ -391,81 +396,84 @@ protected virtual SqlResult CompileInsertQuery(Query query)
391396 } ;
392397
393398 if ( ! ctx . Query . HasComponent ( "from" , EngineCode ) )
394- {
395399 throw new InvalidOperationException ( "No table set to insert" ) ;
396- }
397400
398401 var fromClause = ctx . Query . GetOneComponent < AbstractFrom > ( "from" , EngineCode ) ;
399-
400402 if ( fromClause is null )
401- {
402403 throw new InvalidOperationException ( "Invalid table expression" ) ;
403- }
404404
405405 string table = null ;
406-
407406 if ( fromClause is FromClause fromClauseCast )
408- {
409407 table = Wrap ( fromClauseCast . Table ) ;
410- }
411-
412408 if ( fromClause is RawFromClause rawFromClause )
413409 {
414410 table = WrapIdentifiers ( rawFromClause . Expression ) ;
415411 ctx . Bindings . AddRange ( rawFromClause . Bindings ) ;
416412 }
417413
418414 if ( table is null )
419- {
420415 throw new InvalidOperationException ( "Invalid table expression" ) ;
421- }
422416
423417 var inserts = ctx . Query . GetComponents < AbstractInsertClause > ( "insert" , EngineCode ) ;
418+ if ( inserts [ 0 ] is InsertQueryClause insertQueryClause )
419+ return CompileInsertQueryClause ( ctx , table , insertQueryClause ) ;
420+ else
421+ return CompileValueInsertClauses ( ctx , table , inserts . Cast < InsertClause > ( ) ) ;
422+ }
424423
425- if ( inserts [ 0 ] is InsertClause insertClause )
426- {
427- var columns = string . Join ( ", " , WrapArray ( insertClause . Columns ) ) ;
428- var values = string . Join ( ", " , Parameterize ( ctx , insertClause . Values ) ) ;
424+ protected virtual SqlResult CompileInsertQueryClause (
425+ SqlResult ctx , string table , InsertQueryClause clause )
426+ {
427+ string columns = GetInsertColumnsList ( clause . Columns ) ;
429428
430- ctx . RawSql = $ "INSERT INTO { table } ({ columns } ) VALUES ({ values } )";
429+ var subCtx = CompileSelectQuery ( clause . Query ) ;
430+ ctx . Bindings . AddRange ( subCtx . Bindings ) ;
431431
432- if ( insertClause . ReturnId && ! string . IsNullOrEmpty ( LastId ) )
433- {
434- ctx . RawSql += ";" + LastId ;
435- }
436- }
437- else
438- {
439- var clause = inserts [ 0 ] as InsertQueryClause ;
432+ ctx . RawSql = $ "{ SingleInsertStartClause } { table } { columns } { subCtx . RawSql } ";
440433
441- var columns = "" ;
434+ return ctx ;
435+ }
442436
443- if ( clause . Columns . Any ( ) )
444- {
445- columns = $ " ( { string . Join ( ", " , WrapArray ( clause . Columns ) ) } ) " ;
446- }
437+ protected virtual SqlResult CompileValueInsertClauses (
438+ SqlResult ctx , string table , IEnumerable < InsertClause > insertClauses )
439+ {
440+ bool isMultiValueInsert = insertClauses . Skip ( 1 ) . Any ( ) ;
447441
448- var subCtx = CompileSelectQuery ( clause . Query ) ;
449- ctx . Bindings . AddRange ( subCtx . Bindings ) ;
442+ var insertInto = ( isMultiValueInsert ) ? MultiInsertStartClause : SingleInsertStartClause ;
450443
451- ctx . RawSql = $ "INSERT INTO { table } { columns } { subCtx . RawSql } ";
452- }
444+ var firstInsert = insertClauses . First ( ) ;
445+ string columns = GetInsertColumnsList ( firstInsert . Columns ) ;
446+ var values = string . Join ( ", " , Parameterize ( ctx , firstInsert . Values ) ) ;
453447
454- if ( inserts . Count > 1 )
455- {
456- foreach ( var insert in inserts . GetRange ( 1 , inserts . Count - 1 ) )
457- {
458- var clause = insert as InsertClause ;
448+ ctx . RawSql = $ "{ insertInto } { table } { columns } VALUES ({ values } )";
459449
460- ctx . RawSql += ", (" + string . Join ( ", " , Parameterize ( ctx , clause . Values ) ) + ")" ;
450+ if ( isMultiValueInsert )
451+ return CompileRemainingInsertClauses ( ctx , table , insertClauses ) ;
461452
462- }
463- }
453+ if ( firstInsert . ReturnId && ! string . IsNullOrEmpty ( LastId ) )
454+ ctx . RawSql += ";" + LastId ;
464455
456+ return ctx ;
457+ }
465458
459+ protected virtual SqlResult CompileRemainingInsertClauses ( SqlResult ctx , string table , IEnumerable < InsertClause > inserts )
460+ {
461+ foreach ( var insert in inserts . Skip ( 1 ) )
462+ {
463+ string values = string . Join ( ", " , Parameterize ( ctx , insert . Values ) ) ;
464+ ctx . RawSql += $ ", ({ values } )";
465+ }
466466 return ctx ;
467467 }
468468
469+ protected string GetInsertColumnsList ( List < string > columnList )
470+ {
471+ var columns = "" ;
472+ if ( columnList . Any ( ) )
473+ columns = $ " ({ string . Join ( ", " , WrapArray ( columnList ) ) } )";
474+
475+ return columns ;
476+ }
469477
470478 protected virtual SqlResult CompileCteQuery ( SqlResult ctx , Query query )
471479 {
0 commit comments