Add index hint support (#2375)
Fix #1456 Reviewed-on: https://gitea.com/xorm/xorm/pulls/2375
This commit is contained in:
parent
529a264d8e
commit
b571d91858
|
@ -11,7 +11,7 @@ import (
|
|||
)
|
||||
|
||||
func TestSplitColStr(t *testing.T) {
|
||||
var kases = []struct {
|
||||
kases := []struct {
|
||||
colStr string
|
||||
fields []string
|
||||
}{
|
||||
|
@ -31,7 +31,7 @@ func TestSplitColStr(t *testing.T) {
|
|||
colStr: ` id INTEGER not null
|
||||
primary key autoincrement`,
|
||||
fields: []string{
|
||||
"id", "INTEGER", "not null", "primary", "key", "autoincrement",
|
||||
"id", "INTEGER", "not", "null", "primary", "key", "autoincrement",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1433,3 +1433,10 @@ func (engine *Engine) Transaction(f func(*Session) (interface{}, error)) (interf
|
|||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (engine *Engine) IndexHint(op, indexerOrColName string) *Session {
|
||||
session := engine.NewSession()
|
||||
session.isAutoClose = true
|
||||
session.statement.LastError = session.statement.IndexHint(op, indexerOrColName)
|
||||
return session
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2023 The Xorm Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statements
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
type ErrInvalidIndexHintOperator struct {
|
||||
Op string
|
||||
}
|
||||
|
||||
func (e ErrInvalidIndexHintOperator) Error() string {
|
||||
return "invalid index hint operator: " + e.Op
|
||||
}
|
||||
|
||||
func (statement *Statement) IndexHint(op, indexName string) error {
|
||||
op = strings.ToUpper(op)
|
||||
statement.indexHints = append(statement.indexHints, indexHint{
|
||||
op: op,
|
||||
indexName: indexName,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (statement *Statement) writeIndexHints(w *builder.BytesWriter) error {
|
||||
if len(statement.indexHints) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch statement.dialect.URI().DBType {
|
||||
case schemas.MYSQL:
|
||||
return statement.writeIndexHintsMySQL(w)
|
||||
default:
|
||||
return ErrNotImplemented
|
||||
}
|
||||
}
|
||||
|
||||
func (statement *Statement) writeIndexHintsMySQL(w *builder.BytesWriter) error {
|
||||
for _, hint := range statement.indexHints {
|
||||
if hint.op != "USE" && hint.op != "FORCE" && hint.op != "IGNORE" {
|
||||
return ErrInvalidIndexHintOperator{Op: hint.op}
|
||||
}
|
||||
if err := statement.writeStrings(" ", hint.op, " INDEX(", hint.indexName, ")")(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -254,6 +254,7 @@ func (statement *Statement) writeSelect(buf *builder.BytesWriter, columnStr stri
|
|||
return statement.writeMultiple(buf,
|
||||
statement.writeSelectColumns(columnStr),
|
||||
statement.writeFrom,
|
||||
statement.writeIndexHints,
|
||||
statement.writeWhere,
|
||||
statement.writeGroupBy,
|
||||
statement.writeHaving,
|
||||
|
|
|
@ -41,6 +41,11 @@ type join struct {
|
|||
args []interface{}
|
||||
}
|
||||
|
||||
type indexHint struct {
|
||||
op string
|
||||
indexName string
|
||||
}
|
||||
|
||||
// Statement save all the sql info for executing SQL
|
||||
type Statement struct {
|
||||
RefTable *schemas.Table
|
||||
|
@ -84,6 +89,7 @@ type Statement struct {
|
|||
BufferSize int
|
||||
Context contexts.ContextCache
|
||||
LastError error
|
||||
indexHints []indexHint
|
||||
}
|
||||
|
||||
// NewStatement creates a new statement
|
||||
|
|
|
@ -311,3 +311,8 @@ func (session *Session) Import(r io.Reader) ([]sql.Result, error) {
|
|||
|
||||
return results, lastError
|
||||
}
|
||||
|
||||
func (session *Session) IndexHint(op, indexerOrColName string) *Session {
|
||||
session.statement.IndexHint(op, indexerOrColName)
|
||||
return session
|
||||
}
|
||||
|
|
|
@ -62,3 +62,14 @@ func TestEnableSessionId(t *testing.T) {
|
|||
_, err := testEngine.Table("userinfo").MustLogSQL(true).Get(new(Userinfo))
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestIndexHint(t *testing.T) {
|
||||
assert.NoError(t, PrepareEngine())
|
||||
assertSync(t, new(Userinfo))
|
||||
if testEngine.Dialect().URI().DBType != "mysql" {
|
||||
return
|
||||
}
|
||||
|
||||
_, err := testEngine.Table("userinfo").IndexHint("USE", "UQE_userinfo_username").Get(new(Userinfo))
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue