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
|
// UseLastInsertID returns a database mock LastInsertID compatibility flag
|
||||||
func (m *MockDriver) UseLastInsertID() bool { return false }
|
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
|
// Open mimics a database open call and returns nil for no error
|
||||||
func (m *MockDriver) Open() error { return nil }
|
func (m *MockDriver) Open() error { return nil }
|
||||||
|
|
||||||
|
|
|
@ -64,8 +64,13 @@ func (m *MSSQLDriver) Close() {
|
||||||
m.dbConn.Close()
|
m.dbConn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// UseLastInsertID returns false for postgres
|
// UseLastInsertID returns false for mssql
|
||||||
func (m *MSSQLDriver) UseLastInsertID() bool {
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,11 @@ func (m *MySQLDriver) UseLastInsertID() bool {
|
||||||
return true
|
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
|
// TableNames connects to the postgres database and
|
||||||
// retrieves all table names from the information_schema where the
|
// retrieves all table names from the information_schema where the
|
||||||
// table schema is public.
|
// table schema is public.
|
||||||
|
|
|
@ -78,6 +78,11 @@ func (p *PostgresDriver) UseLastInsertID() bool {
|
||||||
return false
|
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
|
// TableNames connects to the postgres database and
|
||||||
// retrieves all table names from the information_schema where the
|
// retrieves all table names from the information_schema where the
|
||||||
// table schema is schema. It uses a whitelist and blacklist.
|
// table schema is schema. It uses a whitelist and blacklist.
|
||||||
|
|
|
@ -18,6 +18,10 @@ type Interface interface {
|
||||||
// the sql.Exec result's LastInsertId
|
// the sql.Exec result's LastInsertId
|
||||||
UseLastInsertID() bool
|
UseLastInsertID() bool
|
||||||
|
|
||||||
|
// UseTopClause should return true if the Database is capable of using
|
||||||
|
// the SQL TOP clause
|
||||||
|
UseTopClause() bool
|
||||||
|
|
||||||
// Open the database connection
|
// Open the database connection
|
||||||
Open() error
|
Open() error
|
||||||
// Close the database connection
|
// Close the database connection
|
||||||
|
|
|
@ -10,6 +10,7 @@ type testMockDriver struct{}
|
||||||
|
|
||||||
func (m testMockDriver) TranslateColumnType(c Column) Column { return c }
|
func (m testMockDriver) TranslateColumnType(c Column) Column { return c }
|
||||||
func (m testMockDriver) UseLastInsertID() bool { return false }
|
func (m testMockDriver) UseLastInsertID() bool { return false }
|
||||||
|
func (m testMockDriver) UseTopClause() bool { return false }
|
||||||
func (m testMockDriver) Open() error { return nil }
|
func (m testMockDriver) Open() error { return nil }
|
||||||
func (m testMockDriver) Close() {}
|
func (m testMockDriver) Close() {}
|
||||||
|
|
||||||
|
|
|
@ -325,6 +325,7 @@ func (s *State) initDriver(driverName string) error {
|
||||||
s.Dialect.LQ = s.Driver.LeftQuote()
|
s.Dialect.LQ = s.Driver.LeftQuote()
|
||||||
s.Dialect.RQ = s.Driver.RightQuote()
|
s.Dialect.RQ = s.Driver.RightQuote()
|
||||||
s.Dialect.IndexPlaceholders = s.Driver.IndexPlaceholders()
|
s.Dialect.IndexPlaceholders = s.Driver.IndexPlaceholders()
|
||||||
|
s.Dialect.UseTopClause = s.Driver.UseTopClause()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,9 @@ type Dialect struct {
|
||||||
// Bool flag indicating whether indexed
|
// Bool flag indicating whether indexed
|
||||||
// placeholders ($1) are used, or ? placeholders.
|
// placeholders ($1) are used, or ? placeholders.
|
||||||
IndexPlaceholders bool
|
IndexPlaceholders bool
|
||||||
|
// Bool flag indicating whether "TOP" or "LIMIT" clause
|
||||||
|
// must be used for rows limitation
|
||||||
|
UseTopClause bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type where struct {
|
type where struct {
|
||||||
|
|
|
@ -46,6 +46,12 @@ func buildSelectQuery(q *Query) (*bytes.Buffer, []interface{}) {
|
||||||
|
|
||||||
buf.WriteString("SELECT ")
|
buf.WriteString("SELECT ")
|
||||||
|
|
||||||
|
if q.dialect.UseTopClause {
|
||||||
|
if q.limit != 0 && q.offset == 0 {
|
||||||
|
fmt.Fprintf(buf, " TOP (%d)", q.limit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if q.count {
|
if q.count {
|
||||||
buf.WriteString("COUNT(")
|
buf.WriteString("COUNT(")
|
||||||
}
|
}
|
||||||
|
@ -308,11 +314,26 @@ func writeModifiers(q *Query, buf *bytes.Buffer, args *[]interface{}) {
|
||||||
buf.WriteString(strings.Join(q.orderBy, ", "))
|
buf.WriteString(strings.Join(q.orderBy, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
if q.limit != 0 {
|
if !q.dialect.UseTopClause {
|
||||||
fmt.Fprintf(buf, " LIMIT %d", q.limit)
|
if q.limit != 0 {
|
||||||
}
|
fmt.Fprintf(buf, " LIMIT %d", q.limit)
|
||||||
if q.offset != 0 {
|
}
|
||||||
fmt.Fprintf(buf, " OFFSET %d", q.offset)
|
|
||||||
|
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 {
|
if len(q.forlock) != 0 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue