Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge main into hacking-demo #79

Merged
merged 19 commits into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a25885c
Readme: Updated readme and modified the version of TiDB cluster deplo…
pupillord Aug 26, 2021
fc737c0
Go Mod, Makefile: Dependency update (#51)
AmoebaProtozoa Aug 26, 2021
1b93def
Explaintest, Server: Changed Explaintest's driver (#52)
AmoebaProtozoa Aug 27, 2021
8ddec3c
Executor: Added support for setting isolation level in begin (#57)
AmoebaProtozoa Sep 2, 2021
5b86a8c
readme: update url for build status (#56)
pupillord Sep 2, 2021
5406f54
executor: uncommented some previously skipped test (#54)
AmoebaProtozoa Sep 2, 2021
2a306ab
variable,session: add search_path system variable. (#58)
Orion7r Sep 6, 2021
b9b01bd
formatting: fixed formatting issues (#59)
AmoebaProtozoa Sep 8, 2021
8687857
fixed a bug that params description will be sent when no params in ha…
pupillord Sep 8, 2021
4597116
infoschema , util, autoid: Compatible with some tables in pg_catalog …
Orion7r Sep 9, 2021
1719d28
expression:PostgreSQL system function support (#64)
Orion7r Sep 13, 2021
662a612
fixed built in function unit tests (#66)
AmoebaProtozoa Sep 14, 2021
dab1c50
core, executor: add the implemet of setparamtype at show, showddl, da…
pupillord Sep 15, 2021
b4a2c60
Executor: Sort param (#72)
AmoebaProtozoa Sep 18, 2021
08c0517
Conn: Improved extended query handling (#73)
AmoebaProtozoa Sep 18, 2021
3bc9cb5
Server: Improved Extended Query Protocol (#74)
AmoebaProtozoa Sep 23, 2021
e66b884
Bind binary (#75)
AmoebaProtozoa Sep 24, 2021
d74b2a0
Server: Restructure Parse OID handling (#77)
AmoebaProtozoa Sep 28, 2021
744e489
Merge remote-tracking branch 'upstream/hacking-demo' into HackingCamp…
AmoebaProtozoa Sep 28, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 45 additions & 36 deletions executor/prepared.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
"github.com/pingcap/tidb/util/hint"
"github.com/pingcap/tidb/util/sqlexec"
"math"
"sort"
"strings"
"time"
)
Expand Down Expand Up @@ -173,7 +174,10 @@ func (e *PrepareExec) Next(ctx context.Context, req *chunk.Chunk) error {

//Pgsql extend query has its own order
//sort according to its own order
ParamMakerSortor(extractor.markers)
err = ParamMakerSorter(extractor.markers)
if err != nil {
return err
}

err = plannercore.Preprocess(e.ctx, stmt, e.is, plannercore.InPrepare)

Expand Down Expand Up @@ -250,44 +254,47 @@ func (e *PrepareExec) Next(ctx context.Context, req *chunk.Chunk) error {
return vars.AddPreparedStmt(e.ID, preparedObj)
}

// ParamMakerSortor sort by order.
// in the query, most situations are in order.so bubble sort and insert sort are Preferred
// we choose insert sort here.
// todo: According to different parameters situations, choose the most suitable sorting method
func ParamMakerSortor(markers []ast.ParamMarkerExpr) {
if len(markers) <= 1 {
return
}

var val ast.ParamMarkerExpr
var index int
for i := 1; i < len(markers); i++ {
val, index = markers[i], i-1
for {
if val.(*driver.ParamMarkerExpr).Order < markers[index].(*driver.ParamMarkerExpr).Order ||
(val.(*driver.ParamMarkerExpr).Order == markers[index].(*driver.ParamMarkerExpr).Order &&
val.(*driver.ParamMarkerExpr).Offset < markers[index].(*driver.ParamMarkerExpr).Offset) {
markers[index+1] = markers[index]
} else {
break
}
index--
if index < 0 {
break
}
}
markers[index+1] = val
// ParamMakerSorter sort by order.
func ParamMakerSorter(markers []ast.ParamMarkerExpr) error {
// nothing to sort
if len(markers) == 0 {
return nil
}
// first we sort the given markers by their original order
sort.Slice(markers, func(i, j int) bool {
return markers[i].(*driver.ParamMarkerExpr).Order < markers[j].(*driver.ParamMarkerExpr).Order
})

//todo Eliminate compatibility with "?"
// if the smallest order is 0, then we are in mySQL compatible mode
mySQLCompatibleMode := markers[0].(*driver.ParamMarkerExpr).Order == 0

// If more than two ParamMarkerExpr.Order are zero, it means that the placeholder is "?".
// So we need reassign order.
if markers[1].(*driver.ParamMarkerExpr).Order == 0 {
for i := 0; i < len(markers); i++ {
markers[i].SetOrder(i)
// then we check for any error that might exist
// this checks that there's no mix use of mySQL and postgres' param notation
// if the first element has order 0, then the last element's order should be 0
if mySQLCompatibleMode && markers[len(markers)-1].(*driver.ParamMarkerExpr).Order != 0 {
return errors.Errorf("Mix Use of $ notation and ? notation, or use $0")
}

// while checking for repeated use, we change the slice to be 1 indexed (Compatibility with mysql's ?):
if mySQLCompatibleMode {
sort.Slice(markers, func(i, j int) bool {
return markers[i].(*driver.ParamMarkerExpr).Offset < markers[j].(*driver.ParamMarkerExpr).Offset
})

for markerIndex, marker := range markers {
marker.SetOrder(markerIndex) // note that this is 0 indexed
}
} else {
for markerIndex, marker := range markers {
// TODO: Add support for reusing same paramMarker and remove this check
if marker.(*driver.ParamMarkerExpr).Order != markerIndex+1 {
return errors.Errorf("Repeated use of same parameter expression not currently supported")
}
marker.SetOrder(marker.(*driver.ParamMarkerExpr).Order - 1) // make it 0 indexed
}
}

return nil
}

//SetInsertParamType when the plan is insert, set the type of parameter expression
Expand Down Expand Up @@ -325,9 +332,11 @@ func SetInsertParamType(insertPlan *plannercore.Insert, paramExprs *[]ast.ParamM
exprOffset := exprConst.Offset // the offset of the value expression
// the if the query doesn't specify order, aka 'insert into test values ...', we simply set according to insert order
if queryColumns == nil {
setParam(paramExprs, exprOrder, schemaColumns[queryOrder])
if exprOffset != 0 { // a non-zero offset indicates a value expression
setParam(paramExprs, exprOrder, schemaColumns[queryOrder])
}
} else {
if exprOffset != 0 { // a non-zero offset indicates a value expression, aka ?
if exprOffset != 0 { // a non-zero offset indicates a value expression
constShortName := queryColumns[queryOrder].Name.O
setParamByColName(schemaColumns, constShortName, paramExprs, exprOrder)
}
Expand Down
126 changes: 125 additions & 1 deletion executor/prepared_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ import (
"strings"
"sync/atomic"

"github.com/DigitalChinaOpenSource/DCParser/ast"
"github.com/DigitalChinaOpenSource/DCParser/auth"
"github.com/DigitalChinaOpenSource/DCParser/model"
"github.com/DigitalChinaOpenSource/DCParser/mysql"
. "github.com/pingcap/check"
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/executor"
plannercore "github.com/pingcap/tidb/planner/core"
"github.com/pingcap/tidb/session"
driver "github.com/pingcap/tidb/types/parser_driver"
"github.com/pingcap/tidb/util"
"github.com/pingcap/tidb/util/testkit"
"github.com/pingcap/tidb/util/testleak"
Expand Down Expand Up @@ -349,6 +352,127 @@ func (s *testPrepareSuite) TestPlanCacheWithDifferentVariableTypes(c *C) {
}
}

type sorterTestCase struct {
query string // the sql responsible for creating this test case
input []ast.ParamMarkerExpr
expected []ast.ParamMarkerExpr
shouldErr bool // true if this should raise an error
}

// newMockParamExpr returns a mock ParamMarkerExpr with only Order and Offset set
func newMockParamExpr(order, offset int) ast.ParamMarkerExpr {
// casting magic
return &driver.ParamMarkerExpr{
Order: order,
Offset: offset,
}
}

func (s *testPrepareSuite) TestParamMakerSorter(c *C) {
testCases := []sorterTestCase{
{
query: "INSERT INTO param_test VALUES (?)",
input: []ast.ParamMarkerExpr{newMockParamExpr(0, 31)},
expected: []ast.ParamMarkerExpr{newMockParamExpr(0, 31)},
shouldErr: false,
},
{
query: "INSERT INTO param_test VALUES ($1)",
input: []ast.ParamMarkerExpr{newMockParamExpr(1, 32)},
expected: []ast.ParamMarkerExpr{newMockParamExpr(0, 32)},
shouldErr: false,
},
{
query: "INSERT INTO param_test VALUES (?), (?)",
input: []ast.ParamMarkerExpr{
newMockParamExpr(0, 36),
newMockParamExpr(0, 31),
},
expected: []ast.ParamMarkerExpr{
newMockParamExpr(0, 31),
newMockParamExpr(1, 36),
},
shouldErr: false,
},
{
query: "INSERT INTO param_test VALUES ($1), ($2)",
input: []ast.ParamMarkerExpr{
newMockParamExpr(1, 31),
newMockParamExpr(2, 36),
},
expected: []ast.ParamMarkerExpr{
newMockParamExpr(0, 31),
newMockParamExpr(1, 36),
},
shouldErr: false,
},
{
query: "INSERT INTO param_test VALUES ($2), ($1)",
input: []ast.ParamMarkerExpr{
newMockParamExpr(2, 32),
newMockParamExpr(1, 38),
},
expected: []ast.ParamMarkerExpr{
newMockParamExpr(0, 38),
newMockParamExpr(1, 32),
},
shouldErr: false,
},
{
query: "INSERT INTO param_test VALUES ($1), ($1)",
input: []ast.ParamMarkerExpr{
newMockParamExpr(1, 32),
newMockParamExpr(1, 38),
},
expected: nil,
shouldErr: true,
},
{
query: "INSERT INTO param_test VALUES ($1), (?)",
input: []ast.ParamMarkerExpr{
newMockParamExpr(1, 32),
newMockParamExpr(0, 37),
},
expected: nil,
shouldErr: true,
}, {
query: "INSERT INTO param_test VALUES ($0), ($1)",
input: []ast.ParamMarkerExpr{
newMockParamExpr(0, 32),
newMockParamExpr(1, 38),
},
expected: nil,
shouldErr: true,
},
}

runSorterTest(c, testCases)
}

func runSorterTest(c *C, testCases []sorterTestCase) {
for _, testCase := range testCases {
err := executor.ParamMakerSorter(testCase.input)
if testCase.shouldErr {
// For test case that should return error
c.Assert(err, NotNil)
} else {
equalOrderOffset(c, testCase.input, testCase.expected)
}
}
}

// equalOrderOffset checks that every pair of ParamMarkerExpr from source and target has the same Offset and Order
func equalOrderOffset(c *C, source, target []ast.ParamMarkerExpr) {
// source and target must have same length
c.Assert(len(source), Equals, len(target))

// loop through source input and compare Order and Offset for each case
for index, sourceCase := range source {
c.Assert(sourceCase.(*driver.ParamMarkerExpr).Order, Equals, target[index].(*driver.ParamMarkerExpr).Order)
c.Assert(sourceCase.(*driver.ParamMarkerExpr).Offset, Equals, target[index].(*driver.ParamMarkerExpr).Offset)
}
}

type testParamType struct {
sql string
expectType []byte
Expand Down Expand Up @@ -403,7 +527,7 @@ func (s *testPrepareSuite) TestGetPrepareParamType(c *C) {

if cachedStmt, ok := tk.Se.GetSessionVars().PreparedStmts[stmtID].(*plannercore.CachedPrepareStmt); ok {
cachedParams := cachedStmt.PreparedAst.Params
for i, _ := range cachedParams {
for i := range cachedParams {
paramType := cachedParams[i].GetType().Tp
c.Assert(paramType, Equals, v1.expectType[i])
}
Expand Down
Loading