@@ -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 ) ;
@@ -361,81 +366,84 @@ protected virtual SqlResult CompileInsertQuery(Query query)
361366 } ;
362367
363368 if ( ! ctx . Query . HasComponent ( "from" , EngineCode ) )
364- {
365369 throw new InvalidOperationException ( "No table set to insert" ) ;
366- }
367370
368371 var fromClause = ctx . Query . GetOneComponent < AbstractFrom > ( "from" , EngineCode ) ;
369-
370372 if ( fromClause is null )
371- {
372373 throw new InvalidOperationException ( "Invalid table expression" ) ;
373- }
374374
375375 string table = null ;
376-
377376 if ( fromClause is FromClause fromClauseCast )
378- {
379377 table = Wrap ( fromClauseCast . Table ) ;
380- }
381-
382378 if ( fromClause is RawFromClause rawFromClause )
383379 {
384380 table = WrapIdentifiers ( rawFromClause . Expression ) ;
385381 ctx . Bindings . AddRange ( rawFromClause . Bindings ) ;
386382 }
387383
388384 if ( table is null )
389- {
390385 throw new InvalidOperationException ( "Invalid table expression" ) ;
391- }
392386
393387 var inserts = ctx . Query . GetComponents < AbstractInsertClause > ( "insert" , EngineCode ) ;
388+ if ( inserts [ 0 ] is InsertQueryClause insertQueryClause )
389+ return CompileInsertQueryClause ( ctx , table , insertQueryClause ) ;
390+ else
391+ return CompileValueInsertClauses ( ctx , table , inserts . Cast < InsertClause > ( ) ) ;
392+ }
394393
395- if ( inserts [ 0 ] is InsertClause insertClause )
396- {
397- var columns = string . Join ( ", " , WrapArray ( insertClause . Columns ) ) ;
398- var values = string . Join ( ", " , Parameterize ( ctx , insertClause . Values ) ) ;
394+ protected virtual SqlResult CompileInsertQueryClause (
395+ SqlResult ctx , string table , InsertQueryClause clause )
396+ {
397+ string columns = GetInsertColumnsList ( clause . Columns ) ;
399398
400- ctx . RawSql = $ "INSERT INTO { table } ({ columns } ) VALUES ({ values } )";
399+ var subCtx = CompileSelectQuery ( clause . Query ) ;
400+ ctx . Bindings . AddRange ( subCtx . Bindings ) ;
401401
402- if ( insertClause . ReturnId && ! string . IsNullOrEmpty ( LastId ) )
403- {
404- ctx . RawSql += ";" + LastId ;
405- }
406- }
407- else
408- {
409- var clause = inserts [ 0 ] as InsertQueryClause ;
402+ ctx . RawSql = $ "{ SingleInsertStartClause } { table } { columns } { subCtx . RawSql } ";
410403
411- var columns = "" ;
404+ return ctx ;
405+ }
412406
413- if ( clause . Columns . Any ( ) )
414- {
415- columns = $ " ( { string . Join ( ", " , WrapArray ( clause . Columns ) ) } ) " ;
416- }
407+ protected virtual SqlResult CompileValueInsertClauses (
408+ SqlResult ctx , string table , IEnumerable < InsertClause > insertClauses )
409+ {
410+ bool isMultiValueInsert = insertClauses . Skip ( 1 ) . Any ( ) ;
417411
418- var subCtx = CompileSelectQuery ( clause . Query ) ;
419- ctx . Bindings . AddRange ( subCtx . Bindings ) ;
412+ var insertInto = ( isMultiValueInsert ) ? MultiInsertStartClause : SingleInsertStartClause ;
420413
421- ctx . RawSql = $ "INSERT INTO { table } { columns } { subCtx . RawSql } ";
422- }
414+ var firstInsert = insertClauses . First ( ) ;
415+ string columns = GetInsertColumnsList ( firstInsert . Columns ) ;
416+ var values = string . Join ( ", " , Parameterize ( ctx , firstInsert . Values ) ) ;
423417
424- if ( inserts . Count > 1 )
425- {
426- foreach ( var insert in inserts . GetRange ( 1 , inserts . Count - 1 ) )
427- {
428- var clause = insert as InsertClause ;
418+ ctx . RawSql = $ "{ insertInto } { table } { columns } VALUES ({ values } )";
429419
430- ctx . RawSql += ", (" + string . Join ( ", " , Parameterize ( ctx , clause . Values ) ) + ")" ;
420+ if ( isMultiValueInsert )
421+ return CompileRemainingInsertClauses ( ctx , table , insertClauses ) ;
431422
432- }
433- }
423+ if ( firstInsert . ReturnId && ! string . IsNullOrEmpty ( LastId ) )
424+ ctx . RawSql += ";" + LastId ;
434425
426+ return ctx ;
427+ }
435428
429+ protected virtual SqlResult CompileRemainingInsertClauses ( SqlResult ctx , string table , IEnumerable < InsertClause > inserts )
430+ {
431+ foreach ( var insert in inserts . Skip ( 1 ) )
432+ {
433+ string values = string . Join ( ", " , Parameterize ( ctx , insert . Values ) ) ;
434+ ctx . RawSql += $ ", ({ values } )";
435+ }
436436 return ctx ;
437437 }
438438
439+ protected string GetInsertColumnsList ( List < string > columnList )
440+ {
441+ var columns = "" ;
442+ if ( columnList . Any ( ) )
443+ columns = $ " ({ string . Join ( ", " , WrapArray ( columnList ) ) } )";
444+
445+ return columns ;
446+ }
439447
440448 protected virtual SqlResult CompileCteQuery ( SqlResult ctx , Query query )
441449 {
0 commit comments