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

executor: fix bug of point get when meet null values #11219

Merged
merged 6 commits into from
Jul 12, 2019

Conversation

alivxxx
Copy link
Contributor

@alivxxx alivxxx commented Jul 11, 2019

What problem does this PR solve?

For point get queries like select b, b from t where a = 1, if b is null, tidb will panic now.

What is changed and how it works?

The reason is that len(decodedVals[decodedPos]) will be 0 for null values, then it will not make reference for the second columns in the chunk, so it will panic when tidb tries to produce the result. This PR makes reference in the chunk for it.

Check List

Tests

  • Unit test

Code changes

  • Has exported function/method change

Side effects

  • None

Related changes

  • Need to cherry-pick to the release branch

@alivxxx alivxxx added type/bugfix This PR fixes a bug. sig/execution SIG execution labels Jul 11, 2019
@codecov
Copy link

codecov bot commented Jul 11, 2019

Codecov Report

Merging #11219 into master will decrease coverage by 0.0157%.
The diff coverage is 84.6153%.

@@              Coverage Diff               @@
##             master   #11219        +/-   ##
==============================================
- Coverage   81.2958%   81.28%   -0.0159%     
==============================================
  Files           423      423                
  Lines         90071    90011        -60     
==============================================
- Hits          73224    73161        -63     
- Misses        11551    11553         +2     
- Partials       5296     5297         +1

@coocood
Copy link
Member

coocood commented Jul 11, 2019

This function looks complex, can we remove decodedPos2SchemaPos and range over e.schema.Columns to decode to chunk?

@winoros
Copy link
Member

winoros commented Jul 11, 2019

@coocood If we remove it, we still need to implement the same logic like this map since the column value can only be decoded once but it can be referenced multiple times?

@coocood
Copy link
Member

coocood commented Jul 11, 2019

@winoros
We can use col.ID to find the position in colID2DecodedPos, then get the value from the decoded row.

@alivxxx
Copy link
Contributor Author

alivxxx commented Jul 12, 2019

@coocood I think the main point of @winoros is if we need to decode one column several times, if not, then the code will not be cleaner. By the way, even if we can decode it several times, it does not make it cleaner because most of the codes are dealing with the different situation of columns.

@coocood
Copy link
Member

coocood commented Jul 12, 2019

@lamxTyler
Just decode as needed is straight forward, we don't need to optimize this case, it's a very rare case.

@coocood
Copy link
Member

coocood commented Jul 12, 2019

I think this is much simpler

func (e *PointGetExecutor) decodeRowValToChunk(rowVal []byte, chk *chunk.Chunk) error {
	//  One column could be filled for multi-times in the schema. e.g. select b, b, c, c from t where a = 1.
	// We need to set the positions in the schema for the same column.
	colID2CutPos := make(map[int64]int, e.schema.Len())
	for _, col := range e.schema.Columns {
		if _, ok := colID2CutPos[col.ID]; !ok {
			colID2CutPos[col.ID] = len(colID2CutPos)
		}
	}
	cutVals, err := tablecodec.CutRowNew(rowVal, colID2CutPos)
	if err != nil {
		return err
	}
	if cutVals == nil {
		cutVals = make([][]byte, len(colID2CutPos))
	}
	decoder := codec.NewDecoder(chk, e.ctx.GetSessionVars().Location())
	for colIdx, col := range e.schema.Columns {
		if e.tblInfo.PKIsHandle && mysql.HasPriKeyFlag(col.RetType.Flag) {
			chk.AppendInt64(colIdx, e.handle)
			continue
		}
		// ExtraHandleID is added when building plan, we can make sure that there's only one column's ID is this.
		if col.ID == model.ExtraHandleID {
			chk.AppendInt64(colIdx, e.handle)
			continue
		}
		cutVal := cutVals[colID2CutPos[col.ID]]
		if cutVal == nil {
			colInfo := getColInfoByID(e.tblInfo, col.ID)
			d, err1 := table.GetColOriginDefaultValue(e.ctx, colInfo)
			if err1 != nil {
				return err1
			}
			chk.AppendDatum(colIdx, &d)
			continue
		}
		_, err = decoder.DecodeOne(cutVal, colIdx, col.RetType)
		if err != nil {
			return err
		}
	}
	return nil
}

executor/point_get.go Outdated Show resolved Hide resolved
executor/point_get.go Outdated Show resolved Hide resolved
@coocood
Copy link
Member

coocood commented Jul 12, 2019

LGTM

@coocood coocood added the status/LGT1 Indicates that a PR has LGTM 1. label Jul 12, 2019
Copy link
Member

@winoros winoros left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@alivxxx
Copy link
Contributor Author

alivxxx commented Jul 12, 2019

/run-all-tests

@alivxxx alivxxx added status/LGT2 Indicates that a PR has LGTM 2. status/all tests passed and removed status/LGT1 Indicates that a PR has LGTM 1. labels Jul 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
sig/execution SIG execution status/LGT2 Indicates that a PR has LGTM 2. type/bugfix This PR fixes a bug.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants