@@ -5,7 +5,6 @@ package sqlbuilder
55
66import (
77 "fmt"
8- "strconv"
98 "strings"
109)
1110
@@ -51,8 +50,6 @@ func newSelectBuilder() *SelectBuilder {
5150 Cond : Cond {
5251 Args : args ,
5352 },
54- limit : - 1 ,
55- offset : - 1 ,
5653 args : args ,
5754 injection : newInjection (),
5855 }
@@ -79,8 +76,8 @@ type SelectBuilder struct {
7976 groupByCols []string
8077 orderByCols []string
8178 order string
82- limit int
83- offset int
79+ limitVar string
80+ offsetVar string
8481 forWhat string
8582
8683 args * Args
@@ -249,14 +246,24 @@ func (sb *SelectBuilder) Desc() *SelectBuilder {
249246
250247// Limit sets the LIMIT in SELECT.
251248func (sb * SelectBuilder ) Limit (limit int ) * SelectBuilder {
252- sb .limit = limit
249+ if limit < 0 {
250+ sb .limitVar = ""
251+ return sb
252+ }
253+
254+ sb .limitVar = sb .Var (limit )
253255 sb .marker = selectMarkerAfterLimit
254256 return sb
255257}
256258
257259// Offset sets the LIMIT offset in SELECT.
258260func (sb * SelectBuilder ) Offset (offset int ) * SelectBuilder {
259- sb .offset = offset
261+ if offset < 0 {
262+ sb .offsetVar = ""
263+ return sb
264+ }
265+
266+ sb .offsetVar = sb .Var (offset )
260267 sb .marker = selectMarkerAfterLimit
261268 return sb
262269}
@@ -314,7 +321,7 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
314321 buf := newStringBuilder ()
315322 sb .injection .WriteTo (buf , selectMarkerInit )
316323
317- oraclePage := flavor == Oracle && (sb .limit >= 0 || sb .offset >= 0 )
324+ oraclePage := flavor == Oracle && (len ( sb .limitVar ) > 0 || len ( sb .offsetVar ) > 0 )
318325
319326 if sb .cteBuilderVar != "" {
320327 buf .WriteLeadingString (sb .cteBuilderVar )
@@ -349,7 +356,7 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
349356
350357 if oraclePage {
351358 if len (sb .selectCols ) > 0 {
352- buf .WriteLeadingString ("FROM ( SELECT " )
359+ buf .WriteLeadingString ("FROM (SELECT " )
353360
354361 if sb .distinct {
355362 buf .WriteString ("DISTINCT " )
@@ -368,7 +375,7 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
368375 }
369376
370377 buf .WriteStrings (selectCols , ", " )
371- buf .WriteLeadingString ("FROM ( SELECT " )
378+ buf .WriteLeadingString ("FROM (SELECT " )
372379 buf .WriteStrings (sb .selectCols , ", " )
373380 }
374381 }
@@ -436,92 +443,100 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
436443
437444 switch flavor {
438445 case MySQL , SQLite , ClickHouse :
439- if sb .limit >= 0 {
446+ if len ( sb .limitVar ) > 0 {
440447 buf .WriteLeadingString ("LIMIT " )
441- buf .WriteString (strconv . Itoa ( sb .limit ) )
448+ buf .WriteString (sb .limitVar )
442449
443- if sb .offset >= 0 {
450+ if len ( sb .offsetVar ) > 0 {
444451 buf .WriteLeadingString ("OFFSET " )
445- buf .WriteString (strconv . Itoa ( sb .offset ) )
452+ buf .WriteString (sb .offsetVar )
446453 }
447454 }
448455 case CQL :
449- if sb .limit >= 0 {
456+ if len ( sb .limitVar ) > 0 {
450457 buf .WriteLeadingString ("LIMIT " )
451- buf .WriteString (strconv . Itoa ( sb .limit ) )
458+ buf .WriteString (sb .limitVar )
452459 }
453460 case PostgreSQL , Presto :
454- if sb .limit >= 0 {
461+ if len ( sb .limitVar ) > 0 {
455462 buf .WriteLeadingString ("LIMIT " )
456- buf .WriteString (strconv . Itoa ( sb .limit ) )
463+ buf .WriteString (sb .limitVar )
457464 }
458465
459- if sb .offset >= 0 {
466+ if len ( sb .offsetVar ) > 0 {
460467 buf .WriteLeadingString ("OFFSET " )
461- buf .WriteString (strconv . Itoa ( sb .offset ) )
468+ buf .WriteString (sb .offsetVar )
462469 }
463470
464471 case SQLServer :
465472 // If ORDER BY is not set, sort column #1 by default.
466473 // It's required to make OFFSET...FETCH work.
467- if len (sb .orderByCols ) == 0 && (sb .limit >= 0 || sb .offset >= 0 ) {
474+ if len (sb .orderByCols ) == 0 && (len ( sb .limitVar ) > 0 || len ( sb .offsetVar ) > 0 ) {
468475 buf .WriteLeadingString ("ORDER BY 1" )
469476 }
470477
471- if sb .offset >= 0 {
478+ if len ( sb .offsetVar ) > 0 {
472479 buf .WriteLeadingString ("OFFSET " )
473- buf .WriteString (strconv . Itoa ( sb .offset ) )
480+ buf .WriteString (sb .offsetVar )
474481 buf .WriteString (" ROWS" )
475482 }
476483
477- if sb .limit >= 0 {
478- if sb .offset < 0 {
484+ if len ( sb .limitVar ) > 0 {
485+ if len ( sb .offsetVar ) == 0 {
479486 buf .WriteLeadingString ("OFFSET 0 ROWS" )
480487 }
481488
482489 buf .WriteLeadingString ("FETCH NEXT " )
483- buf .WriteString (strconv . Itoa ( sb .limit ) )
490+ buf .WriteString (sb .limitVar )
484491 buf .WriteString (" ROWS ONLY" )
485492 }
486493
487494 case Oracle :
488495 if oraclePage {
489- buf .WriteString (" ) " )
496+ buf .WriteString (") " )
497+
490498 if len (sb .tables ) > 0 {
491499 buf .WriteStrings (sb .tables , ", " )
492500 }
493501
494- min := sb .offset
495- if min < 0 {
496- min = 0
497- }
502+ buf .WriteString (") WHERE " )
498503
499- buf .WriteString (" ) WHERE " )
500- if sb .limit >= 0 {
504+ if len (sb .limitVar ) > 0 {
501505 buf .WriteString ("r BETWEEN " )
502- buf .WriteString (strconv .Itoa (min + 1 ))
503- buf .WriteString (" AND " )
504- buf .WriteString (strconv .Itoa (sb .limit + min ))
506+
507+ if len (sb .offsetVar ) > 0 {
508+ buf .WriteString (sb .offsetVar )
509+ buf .WriteString (" + 1 AND " )
510+ buf .WriteString (sb .limitVar )
511+ buf .WriteString (" + " )
512+ buf .WriteString (sb .offsetVar )
513+ } else {
514+ buf .WriteString ("1 AND " )
515+ buf .WriteString (sb .limitVar )
516+ buf .WriteString (" + 1" )
517+ }
505518 } else {
519+ // As oraclePage is true, sb.offsetVar must not be empty.
506520 buf .WriteString ("r >= " )
507- buf .WriteString (strconv .Itoa (min + 1 ))
521+ buf .WriteString (sb .offsetVar )
522+ buf .WriteString (" + 1" )
508523 }
509524 }
510525 case Informix :
511526 // [SKIP N] FIRST M
512527 // M must be greater than 0
513- if sb .limit > 0 {
514- if sb .offset >= 0 {
528+ if len ( sb .limitVar ) > 0 {
529+ if len ( sb .offsetVar ) > 0 {
515530 buf .WriteLeadingString ("SKIP " )
516- buf .WriteString (strconv . Itoa ( sb .offset ) )
531+ buf .WriteString (sb .offsetVar )
517532 }
518533
519534 buf .WriteLeadingString ("FIRST " )
520- buf .WriteString (strconv . Itoa ( sb .limit ) )
535+ buf .WriteString (sb .limitVar )
521536 }
522537 }
523538
524- if sb .limit >= 0 {
539+ if len ( sb .limitVar ) > 0 {
525540 sb .injection .WriteTo (buf , selectMarkerAfterLimit )
526541 }
527542
0 commit comments