diff --git a/contrib/drivers/mssql/mssql_do_filter.go b/contrib/drivers/mssql/mssql_do_filter.go index 6130b9e795e..05358bba42a 100644 --- a/contrib/drivers/mssql/mssql_do_filter.go +++ b/contrib/drivers/mssql/mssql_do_filter.go @@ -89,7 +89,7 @@ func (d *Driver) parseSql(toBeCommittedSql string) (string, error) { func (d *Driver) handleSelectSqlReplacement(toBeCommittedSql string) (newSql string, err error) { // SELECT * FROM USER WHERE ID=1 LIMIT 1 - match, err := gregex.MatchString(`^SELECT(.+?)LIMIT\s+1$`, toBeCommittedSql) + match, err := gregex.MatchString(`^SELECT([\s\S]+?)LIMIT\s+1$`, toBeCommittedSql) if err != nil { return "", err } @@ -98,7 +98,7 @@ func (d *Driver) handleSelectSqlReplacement(toBeCommittedSql string) (newSql str } // SELECT * FROM USER WHERE AGE>18 ORDER BY ID DESC LIMIT 100, 200 - pattern := `(?i)SELECT(.+?)(ORDER BY.+?)?\s*LIMIT\s*(\d+)(?:\s*,\s*(\d+))?` + pattern := `(?i)SELECT([\s\S]+?)(ORDER BY[\s\S]+?)?\s*LIMIT\s*(\d+)(?:\s*,\s*(\d+))?` if !gregex.IsMatchString(pattern, toBeCommittedSql) { return toBeCommittedSql, nil } diff --git a/contrib/drivers/mssql/mssql_do_filter_test.go b/contrib/drivers/mssql/mssql_do_filter_test.go index 24e2c80e9ed..f9ed248c0b8 100644 --- a/contrib/drivers/mssql/mssql_do_filter_test.go +++ b/contrib/drivers/mssql/mssql_do_filter_test.go @@ -58,12 +58,21 @@ func TestDriver_handleSelectSqlReplacement(t *testing.T) { d := &Driver{} // LIMIT 1 - inputSql := "SELECT * FROM User WHERE ID = 1 LIMIT 1" - expectedSql := "SELECT TOP 1 * FROM User WHERE ID = 1" + inputSql := `SELECT * FROM User WHERE ID = 1 LIMIT 1` + expectedSql := `SELECT TOP 1 * FROM User WHERE ID = 1` resultSql, err := d.handleSelectSqlReplacement(inputSql) t.AssertNil(err) t.Assert(resultSql, expectedSql) + // MultiLine LIMIT 1 + inputSql = `SELECT * +FROM User WHERE ID = 1 LIMIT 1` + expectedSql = `SELECT TOP 1 * +FROM User WHERE ID = 1` + resultSql, err = d.handleSelectSqlReplacement(inputSql) + t.AssertNil(err) + t.Assert(resultSql, expectedSql) + // LIMIT query with offset and number of rows inputSql = "SELECT * FROM User ORDER BY ID DESC LIMIT 100, 200" expectedSql = "SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY ID DESC) as ROW_NUMBER__, * FROM (SELECT * FROM User) as InnerQuery ) as TMP_ WHERE TMP_.ROW_NUMBER__ > 100 AND TMP_.ROW_NUMBER__ <= 300" @@ -100,8 +109,10 @@ func TestDriver_handleSelectSqlReplacement(t *testing.T) { t.Assert(resultSql, expectedSql) // Complex query with ORDER BY and LIMIT - inputSql = "SELECT name, age FROM User WHERE age > 18 ORDER BY age ASC LIMIT 10, 5" - expectedSql = "SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY age ASC) as ROW_NUMBER__, * FROM (SELECT name, age FROM User WHERE age > 18) as InnerQuery ) as TMP_ WHERE TMP_.ROW_NUMBER__ > 10 AND TMP_.ROW_NUMBER__ <= 15" + inputSql = `SELECT name, +age FROM User WHERE age > 18 ORDER BY age ASC LIMIT 10, 5` + expectedSql = `SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY age ASC) as ROW_NUMBER__, * FROM (SELECT name, +age FROM User WHERE age > 18) as InnerQuery ) as TMP_ WHERE TMP_.ROW_NUMBER__ > 10 AND TMP_.ROW_NUMBER__ <= 15` resultSql, err = d.handleSelectSqlReplacement(inputSql) t.AssertNil(err) t.Assert(resultSql, expectedSql) @@ -127,5 +138,19 @@ func TestDriver_handleSelectSqlReplacement(t *testing.T) { t.AssertNil(err) t.Assert(resultSql, expectedSql) + // MultiLine Queries with comment and complex ORDER BY and LIMIT + inputSql = `SELECT name, -- 名称 +age -- 年龄 +FROM User WHERE age > 18 +ORDER BY age DESC, +name ASC LIMIT 20, 10` + expectedSql = `SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY age DESC, +name ASC) as ROW_NUMBER__, * FROM (SELECT name, -- 名称 +age -- 年龄 +FROM User WHERE age > 18) as InnerQuery ) as TMP_ WHERE TMP_.ROW_NUMBER__ > 20 AND TMP_.ROW_NUMBER__ <= 30` + resultSql, err = d.handleSelectSqlReplacement(inputSql) + t.AssertNil(err) + t.Assert(resultSql, expectedSql) + }) } diff --git a/contrib/drivers/mssql/mssql_open.go b/contrib/drivers/mssql/mssql_open.go index 6e571e4e405..63e0ecb4cec 100644 --- a/contrib/drivers/mssql/mssql_open.go +++ b/contrib/drivers/mssql/mssql_open.go @@ -16,6 +16,10 @@ import ( "github.com/gogf/gf/v2/text/gstr" ) +var ( + version string +) + // Open creates and returns an underlying sql.DB object for mssql. func (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) { source, err := configNodeToSource(config) @@ -30,6 +34,13 @@ func (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) { ) return nil, err } + if err = db.QueryRow("SELECT @@VERSION").Scan(&version); err != nil { + err = gerror.WrapCodef( + gcode.CodeDbOperationError, err, + `Error querying version: SELECT @@VERSION`, + ) + return nil, err + } return } diff --git a/net/ghttp/ghttp_request.go b/net/ghttp/ghttp_request.go index 73801995b3d..445eff7e93e 100644 --- a/net/ghttp/ghttp_request.go +++ b/net/ghttp/ghttp_request.go @@ -151,8 +151,14 @@ func (r *Request) IsExited() bool { } // GetHeader retrieves and returns the header value with given `key`. -func (r *Request) GetHeader(key string) string { - return r.Header.Get(key) +func (r *Request) GetHeader(key string, def ...string) string { + header := r.Header.Get(key) + if header == "" { + if len(def) > 0 { + return def[0] + } + } + return header } // GetHost returns current request host name, which might be a domain or an IP without port.