MSSQL rows limit/offset via TOP or OFFSET ... FETCH NEXT ... ROWS
This commit is contained in:
parent
e2f32e746e
commit
cbdbe4891a
9 changed files with 54 additions and 6 deletions
bdb
boilingcore
queries
|
@ -118,6 +118,9 @@ func (m *MockDriver) PrimaryKeyInfo(schema, tableName string) (*bdb.PrimaryKey,
|
|||
// UseLastInsertID returns a database mock LastInsertID compatibility flag
|
||||
func (m *MockDriver) UseLastInsertID() bool { return false }
|
||||
|
||||
// UseTopClause returns a database mock SQL TOP clause compatibility flag
|
||||
func (m *MockDriver) UseTopClause() bool { return false }
|
||||
|
||||
// Open mimics a database open call and returns nil for no error
|
||||
func (m *MockDriver) Open() error { return nil }
|
||||
|
||||
|
|
|
@ -64,8 +64,13 @@ func (m *MSSQLDriver) Close() {
|
|||
m.dbConn.Close()
|
||||
}
|
||||
|
||||
// UseLastInsertID returns false for postgres
|
||||
// UseLastInsertID returns false for mssql
|
||||
func (m *MSSQLDriver) UseLastInsertID() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// UseTopClause returns true to indicate MS SQL supports SQL TOP clause
|
||||
func (m *MSSQLDriver) UseTopClause() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -81,6 +81,11 @@ func (m *MySQLDriver) UseLastInsertID() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// UseTopClause returns false to indicate MySQL doesnt support SQL TOP clause
|
||||
func (m *MySQLDriver) UseTopClause() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// TableNames connects to the postgres database and
|
||||
// retrieves all table names from the information_schema where the
|
||||
// table schema is public.
|
||||
|
|
|
@ -78,6 +78,11 @@ func (p *PostgresDriver) UseLastInsertID() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// UseTopClause returns false to indicate PSQL doesnt support SQL TOP clause
|
||||
func (m *PostgresDriver) UseTopClause() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// TableNames connects to the postgres database and
|
||||
// retrieves all table names from the information_schema where the
|
||||
// table schema is schema. It uses a whitelist and blacklist.
|
||||
|
|
|
@ -18,6 +18,10 @@ type Interface interface {
|
|||
// the sql.Exec result's LastInsertId
|
||||
UseLastInsertID() bool
|
||||
|
||||
// UseTopClause should return true if the Database is capable of using
|
||||
// the SQL TOP clause
|
||||
UseTopClause() bool
|
||||
|
||||
// Open the database connection
|
||||
Open() error
|
||||
// Close the database connection
|
||||
|
|
|
@ -10,6 +10,7 @@ type testMockDriver struct{}
|
|||
|
||||
func (m testMockDriver) TranslateColumnType(c Column) Column { return c }
|
||||
func (m testMockDriver) UseLastInsertID() bool { return false }
|
||||
func (m testMockDriver) UseTopClause() bool { return false }
|
||||
func (m testMockDriver) Open() error { return nil }
|
||||
func (m testMockDriver) Close() {}
|
||||
|
||||
|
|
|
@ -325,6 +325,7 @@ func (s *State) initDriver(driverName string) error {
|
|||
s.Dialect.LQ = s.Driver.LeftQuote()
|
||||
s.Dialect.RQ = s.Driver.RightQuote()
|
||||
s.Dialect.IndexPlaceholders = s.Driver.IndexPlaceholders()
|
||||
s.Dialect.UseTopClause = s.Driver.UseTopClause()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -52,6 +52,9 @@ type Dialect struct {
|
|||
// Bool flag indicating whether indexed
|
||||
// placeholders ($1) are used, or ? placeholders.
|
||||
IndexPlaceholders bool
|
||||
// Bool flag indicating whether "TOP" or "LIMIT" clause
|
||||
// must be used for rows limitation
|
||||
UseTopClause bool
|
||||
}
|
||||
|
||||
type where struct {
|
||||
|
|
|
@ -46,6 +46,12 @@ func buildSelectQuery(q *Query) (*bytes.Buffer, []interface{}) {
|
|||
|
||||
buf.WriteString("SELECT ")
|
||||
|
||||
if q.dialect.UseTopClause {
|
||||
if q.limit != 0 && q.offset == 0 {
|
||||
fmt.Fprintf(buf, " TOP (%d)", q.limit)
|
||||
}
|
||||
}
|
||||
|
||||
if q.count {
|
||||
buf.WriteString("COUNT(")
|
||||
}
|
||||
|
@ -308,11 +314,26 @@ func writeModifiers(q *Query, buf *bytes.Buffer, args *[]interface{}) {
|
|||
buf.WriteString(strings.Join(q.orderBy, ", "))
|
||||
}
|
||||
|
||||
if q.limit != 0 {
|
||||
fmt.Fprintf(buf, " LIMIT %d", q.limit)
|
||||
}
|
||||
if q.offset != 0 {
|
||||
fmt.Fprintf(buf, " OFFSET %d", q.offset)
|
||||
if !q.dialect.UseTopClause {
|
||||
if q.limit != 0 {
|
||||
fmt.Fprintf(buf, " LIMIT %d", q.limit)
|
||||
}
|
||||
|
||||
if q.offset != 0 {
|
||||
fmt.Fprintf(buf, " OFFSET %d", q.offset)
|
||||
}
|
||||
} else {
|
||||
// From MS SQL 2012 and above: https://technet.microsoft.com/en-us/library/ms188385(v=sql.110).aspx
|
||||
// ORDER BY ...
|
||||
// OFFSET N ROWS
|
||||
// FETCH NEXT M ROWS ONLY
|
||||
if q.offset != 0 {
|
||||
fmt.Fprintf(buf, " OFFSET %d", q.offset)
|
||||
|
||||
if q.limit != 0 {
|
||||
fmt.Fprintf(buf, " FETCH NEXT %d ROWS ONLY", q.limit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(q.forlock) != 0 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue