You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.4 KiB

  1. // Copyright 2018 The Xorm Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package builder
  5. import (
  6. "fmt"
  7. "strings"
  8. )
  9. func (b *Builder) limitWriteTo(w Writer) error {
  10. if strings.TrimSpace(b.dialect) == "" {
  11. return ErrDialectNotSetUp
  12. }
  13. if b.limitation != nil {
  14. limit := b.limitation
  15. if limit.offset < 0 || limit.limitN <= 0 {
  16. return ErrInvalidLimitation
  17. }
  18. // erase limit condition
  19. b.limitation = nil
  20. ow := w.(*BytesWriter)
  21. switch strings.ToLower(strings.TrimSpace(b.dialect)) {
  22. case ORACLE:
  23. if len(b.selects) == 0 {
  24. b.selects = append(b.selects, "*")
  25. }
  26. var final *Builder
  27. selects := b.selects
  28. b.selects = append(selects, "ROWNUM RN")
  29. var wb *Builder
  30. if b.optype == unionType {
  31. wb = Dialect(b.dialect).Select("at.*", "ROWNUM RN").
  32. From(b, "at")
  33. } else {
  34. wb = b
  35. }
  36. if limit.offset == 0 {
  37. final = Dialect(b.dialect).Select(selects...).From(wb, "at").
  38. Where(Lte{"at.RN": limit.limitN})
  39. } else {
  40. sub := Dialect(b.dialect).Select("*").
  41. From(b, "at").Where(Lte{"at.RN": limit.offset + limit.limitN})
  42. final = Dialect(b.dialect).Select(selects...).From(sub, "att").
  43. Where(Gt{"att.RN": limit.offset})
  44. }
  45. return final.WriteTo(ow)
  46. case SQLITE, MYSQL, POSTGRES:
  47. // if type UNION, we need to write previous content back to current writer
  48. if b.optype == unionType {
  49. if err := b.WriteTo(ow); err != nil {
  50. return err
  51. }
  52. }
  53. if limit.offset == 0 {
  54. fmt.Fprint(ow, " LIMIT ", limit.limitN)
  55. } else {
  56. fmt.Fprintf(ow, " LIMIT %v OFFSET %v", limit.limitN, limit.offset)
  57. }
  58. case MSSQL:
  59. if len(b.selects) == 0 {
  60. b.selects = append(b.selects, "*")
  61. }
  62. var final *Builder
  63. selects := b.selects
  64. b.selects = append(append([]string{fmt.Sprintf("TOP %d %v", limit.limitN+limit.offset, b.selects[0])},
  65. b.selects[1:]...), "ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN")
  66. var wb *Builder
  67. if b.optype == unionType {
  68. wb = Dialect(b.dialect).Select("*", "ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RN").
  69. From(b, "at")
  70. } else {
  71. wb = b
  72. }
  73. if limit.offset == 0 {
  74. final = Dialect(b.dialect).Select(selects...).From(wb, "at")
  75. } else {
  76. final = Dialect(b.dialect).Select(selects...).From(wb, "at").Where(Gt{"at.RN": limit.offset})
  77. }
  78. return final.WriteTo(ow)
  79. default:
  80. return ErrNotSupportType
  81. }
  82. }
  83. return nil
  84. }