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

Support sort merge join #845

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open

Conversation

csynineyang
Copy link
Contributor

@csynineyang csynineyang commented Jul 3, 2024

What this PR does:

Which issue(s) this PR fixes:

Fixes #

Special notes for your reviewer:

Does this PR introduce a user-facing change?:


Summary by CodeRabbit

  • New Features
    • Added support for Sort Merge Join, improving efficiency for joining datasets based on specified keys.
  • Improvements
    • Enhanced error handling and result processing in join operations.

Copy link

cr-gpt bot commented Jul 3, 2024

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

Copy link

coderabbitai bot commented Jul 3, 2024

Important

Review skipped

Auto reviews are limited to specific labels.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The recent updates primarily focus on enhancing the sort-merge join operations across several packages. Key changes include importing necessary packages, revising function logic for better error handling and data processing, and introducing a new SortMergeJoin struct and associated methods to facilitate efficient join operations.

Changes

File Path Change Summary
pkg/dataset/sort_merge_join.go Added imports, modified functions for error handling, added SetColumn method, refactored join functions and data handling logic.
pkg/proto/schema.go Added ColumnName field to IndexMetadata, updated NewTableMetadata function.
pkg/runtime/optimize/dml/select.go Added logic to determine and set up a sort merge join based on table metadata indexes.
pkg/runtime/plan/dml/rename.go Modified ExecIn method to manipulate fields based on the renaming list in RenamePlan.
pkg/runtime/plan/dml/sort_merge_join.go Introduced SortMergeJoin struct with methods for executing the join and handling data retrieval.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant System
    participant Database

    User->>System: Initiate sort-merge join query
    System->>Database: Fetch Left Table Metadata
    Database-->>System: Return Left Table Metadata
    System->>Database: Fetch Right Table Metadata
    Database-->>System: Return Right Table Metadata
    System->>System: Determine join keys and conditions
    System->>Database: Execute Left Query
    Database-->>System: Return Left Dataset
    System->>Database: Execute Right Query
    Database-->>System: Return Right Dataset
    System->>System: Perform Sort-Merge Join
    System-->>User: Return joined result
Loading

Poem

In the code, where bytes align,
Joins are merging, fields refine.
Columns set with ordered grace,
Errors handled, no misplaced.
Efficient queries, swift and keen,
Data flows like a clear stream. 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Outside diff range and nitpick comments (7)
pkg/runtime/plan/dml/sort_merge_join.go (3)

1-10: Import optimization

You can combine the import blocks into a single block for better readability.

import (
	"context"

	"github.com/arana-db/arana/pkg/dataset"
	"github.com/arana-db/arana/pkg/proto"
	"github.com/arana-db/arana/pkg/resultx"
	"github.com/arana-db/arana/pkg/runtime/ast"
)

12-21: Add comment for Stmt field

Adding a comment for the Stmt field will improve code readability and maintainability.

type SortMergeJoin struct {
	// Stmt represents the SQL statement for the join operation
	Stmt *ast.SelectStatement
	LeftQuery  proto.Plan
	RightQuery proto.Plan
	JoinType   ast.JoinType
	LeftKey    string
	RightKey   string
}

Line range hint 504-558: Use strings.Builder instead of bytes.Buffer

Consider using strings.Builder instead of bytes.Buffer for better performance.

-	var b bytes.Buffer
+	var b strings.Builder
	row := rows.NewTextVirtualRow(realFields, res)
-	_, err := row.WriteTo(&b)
+	_, err := b.WriteString(row.String())
	if err != nil {
		return nil
	}
	return mysql.NewTextRow(realFields, []byte(b.String()))
pkg/proto/schema.go (1)

51-51: Add comment to explain assignment

Adding a comment to explain the assignment of indexMetadata.ColumnName to tma.Indexes will improve code readability.

for _, indexMetadata := range indexMetadataList {
	// Assign index metadata to the map using the column name as the key
	tma.Indexes[indexMetadata.ColumnName] = indexMetadata
}
pkg/runtime/plan/dml/rename.go (1)

54-63: Add comments to explain logic

Adding comments to explain the logic of updating field names based on the renaming list will improve code readability.

newFields := make([]proto.Field, 0, len(fields))
for i := 0; i < len(rp.RenameList); i++ {
	// Create a copy of the field and update its name
	f := *(fields[i].(*mysql.Field))
	f.SetName(rp.RenameList[i])
	f.SetOrgName(rp.RenameList[i])
	newFields = append(newFields, &f)
}
pkg/schema/loader.go (1)

249-251: Add comments to explain processing logic

Adding comments to explain the processing logic for the COLUMN_NAME field will improve code readability.

for {
	row, err = ds.Next()
	if errors.Is(err, io.EOF) {
		break
	}

	if err != nil {
		return nil, errors.WithStack(err)
	}

	if err = row.Scan(values); err != nil {
		return nil, errors.WithStack(err)
	}

	tableName := convertInterfaceToStrNullable(values[0])
	// Retrieve and process the column name from the query result
	columnName := convertInterfaceToStrNullable(values[1])
	indexName := convertInterfaceToStrNullable(values[2])
	result[tableName] = append(result[tableName], &proto.IndexMetadata{ColumnName: columnName, Name: indexName})
}
pkg/dataset/sort_merge_join.go (1)

Line range hint 1-36: Combine import blocks

Consider combining the import blocks for better readability.

import (
	"bytes"
	"io"
	"sync"

	"github.com/pkg/errors"
	"github.com/spf13/cast"
	"go.uber.org/atomic"

	"github.com/arana-db/arana/pkg/mysql/rows"
	"github.com/arana-db/arana/pkg/mysql"
	"github.com/arana-db/arana/pkg/proto"
	"github.com/arana-db/arana/pkg/runtime/ast"
	"github.com/arana-db/arana/pkg/util/log"
)
Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 1e525f4 and a9a5c67.

Files selected for processing (6)
  • pkg/dataset/sort_merge_join.go (11 hunks)
  • pkg/proto/schema.go (2 hunks)
  • pkg/runtime/optimize/dml/select.go (4 hunks)
  • pkg/runtime/plan/dml/rename.go (2 hunks)
  • pkg/runtime/plan/dml/sort_merge_join.go (1 hunks)
  • pkg/schema/loader.go (2 hunks)
Additional comments not posted (8)
pkg/runtime/plan/dml/sort_merge_join.go (2)

23-25: LGTM!

The Type method looks good and follows best practices.


Line range hint 254-256: LGTM!

The SetColumn method looks good and follows best practices.

pkg/proto/schema.go (1)

68-69: LGTM!

The addition of the ColumnName field in IndexMetadata looks good and follows best practices.

pkg/runtime/plan/dml/rename.go (1)

94-94: LGTM!

The convFields function call looks good and follows best practices.

pkg/schema/loader.go (1)

47-47: LGTM!

The update to the indexMetadataSQL query looks good and follows best practices.

pkg/runtime/optimize/dml/select.go (3)

614-624: LGTM! Added sort merge join plan.

The code changes introduce the sort merge join plan. Ensure thorough testing.


536-536: Verify sort merge join condition.

Ensure that the shouldSortMergeJoin function correctly identifies conditions where sort merge join is applicable.

Verification successful

Verified sort merge join condition.

The shouldSortMergeJoin function correctly identifies conditions where a sort merge join is applicable by checking for non-nil indexes on the join keys in both table metadata.

  • pkg/runtime/optimize/dml/select.go: Lines 536-536
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify the conditions for sort merge join.

# Test: Search for the function definition and usage. Expect: Correct identification of sort merge join conditions.
rg --type go 'func shouldSortMergeJoin'
rg --type go 'shouldSortMergeJoin'

Length of output: 479



Script:

#!/bin/bash
# Extract the full implementation of the shouldSortMergeJoin function
ast-grep --lang go --pattern $'func shouldSortMergeJoin($_, $_, $_, $_) bool {
  $$$
}' pkg/runtime/optimize/dml/select.go

Length of output: 123



Script:

#!/bin/bash
# Extract the full implementation of the shouldSortMergeJoin function using ripgrep
rg --no-heading -A 20 'func shouldSortMergeJoin' pkg/runtime/optimize/dml/select.go

Length of output: 667


732-734: Ensure index existence check is sufficient.

The function checks if indexes exist for the join keys. Verify that this check is sufficient for all use cases.

Verification successful

Ensure index existence check is sufficient.

The function shouldSortMergeJoin checks if indexes exist for the join keys. Based on the definition of IndexMetadata, this check is sufficient for all use cases.

  • proto.TableMetadata in pkg/proto/schema.go
  • IndexMetadata in pkg/proto/schema.go
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify the index existence check in shouldSortMergeJoin.

# Test: Search for the function definition and usage. Expect: Correct identification of index existence.
rg --type go 'func shouldSortMergeJoin'
rg --type go 'shouldSortMergeJoin'

Length of output: 479



Script:

#!/bin/bash
# Description: Gather further context around the usage of `shouldSortMergeJoin` and `proto.TableMetadata`.

# Search for the definition of `proto.TableMetadata` to understand its structure.
rg --type go 'type TableMetadata' 

# Search for the usage of `Indexes` field within `proto.TableMetadata`.
rg --type go 'Indexes' 

Length of output: 2044



Script:

#!/bin/bash
# Description: Verify the structure of `IndexMetadata` to ensure the index existence check is sufficient.

# Search for the definition of `IndexMetadata` to understand its structure.
rg --type go 'type IndexMetadata'

Length of output: 83



Script:

#!/bin/bash
# Description: Inspect the fields within `IndexMetadata` to ensure the index existence check is sufficient.

# Print the definition of `IndexMetadata` to understand its structure.
rg --type go 'type IndexMetadata struct' -A 10

Length of output: 449

Comment on lines +467 to +474
var tbLeft0 = tableLeft.Suffix()
if shardsLeft != nil {
_, tbLeft0 = shardsLeft.Smallest()
}
leftTblMeta, err := loadMetadataByTable(ctx, tbLeft0)
if err != nil {
return nil, err
}
Copy link

Choose a reason for hiding this comment

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

Add error context for better debugging.

When loading metadata for the left table, add context to the error message for easier debugging.

-    return nil, err
+    return nil, errors.Wrapf(err, "failed to load metadata for left table: %s", tbLeft0)
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var tbLeft0 = tableLeft.Suffix()
if shardsLeft != nil {
_, tbLeft0 = shardsLeft.Smallest()
}
leftTblMeta, err := loadMetadataByTable(ctx, tbLeft0)
if err != nil {
return nil, err
}
var tbLeft0 = tableLeft.Suffix()
if shardsLeft != nil {
_, tbLeft0 = shardsLeft.Smallest()
}
leftTblMeta, err = loadMetadataByTable(ctx, tbLeft0)
if err != nil {
return nil, errors.Wrapf(err, "failed to load metadata for left table: %s", tbLeft0)
}

Comment on lines +46 to +57
func fetchDs(plan proto.Plan, ctx context.Context, conn proto.VConn) proto.Dataset {
res, err := plan.ExecIn(ctx, conn)
if err != nil {
return nil
}

ds, err := res.Dataset()
if err != nil {
return nil
}

return ds
Copy link

Choose a reason for hiding this comment

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

Log error before returning nil

Consider logging the error before returning nil to improve debugging.

-	if err != nil {
-		return nil
-	}
+	if err != nil {
+		log.Errorf("Error executing plan: %v", err)
+		return nil
+	}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func fetchDs(plan proto.Plan, ctx context.Context, conn proto.VConn) proto.Dataset {
res, err := plan.ExecIn(ctx, conn)
if err != nil {
return nil
}
ds, err := res.Dataset()
if err != nil {
return nil
}
return ds
func fetchDs(plan proto.Plan, ctx context.Context, conn proto.VConn) proto.Dataset {
res, err := plan.ExecIn(ctx, conn)
if err != nil {
log.Errorf("Error executing plan: %v", err)
return nil
}
ds, err := res.Dataset()
if err != nil {
return nil
}
return ds

Comment on lines +481 to +488
var tbRight0 = tableRight.Suffix()
if shardsRight != nil {
_, tbRight0 = shardsRight.Smallest()
}
rightTblMeta, err := loadMetadataByTable(ctx, tbRight0)
if err != nil {
return nil, err
}
Copy link

Choose a reason for hiding this comment

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

Add error context for better debugging.

When loading metadata for the right table, add context to the error message for easier debugging.

-    return nil, err
+    return nil, errors.Wrapf(err, "failed to load metadata for right table: %s", tbRight0)
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var tbRight0 = tableRight.Suffix()
if shardsRight != nil {
_, tbRight0 = shardsRight.Smallest()
}
rightTblMeta, err := loadMetadataByTable(ctx, tbRight0)
if err != nil {
return nil, err
}
var tbRight0 = tableRight.Suffix()
if shardsRight != nil {
_, tbRight0 = shardsRight.Smallest()
}
rightTblMeta, err := loadMetadataByTable(ctx, tbRight0)
if err != nil {
return nil, errors.Wrapf(err, "failed to load metadata for right table: %s", tbRight0)
}

Comment on lines +27 to +44
func (h *SortMergeJoin) ExecIn(ctx context.Context, conn proto.VConn) (proto.Result, error) {
rightDs := fetchDs(h.RightQuery, ctx, conn)
leftDs := fetchDs(h.LeftQuery, ctx, conn)

joinColumn := &dataset.JoinColumn{}
joinColumn.SetColumn(h.LeftKey)
ds, err := dataset.NewSortMergeJoin(
h.JoinType,
joinColumn,
rightDs,
leftDs,
)
if err != nil {
return nil, err
}

return resultx.New(resultx.WithDataset(ds)), nil
}
Copy link

Choose a reason for hiding this comment

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

Improve error handling for fetchDs

Consider handling errors returned by fetchDs to improve robustness.

-	rightDs := fetchDs(h.RightQuery, ctx, conn)
-	leftDs := fetchDs(h.LeftQuery, ctx, conn)
+	rightDs, err := fetchDs(h.RightQuery, ctx, conn)
+	if err != nil {
+		return nil, err
+	}
+	leftDs, err := fetchDs(h.LeftQuery, ctx, conn)
+	if err != nil {
+		return nil, err
+	}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (h *SortMergeJoin) ExecIn(ctx context.Context, conn proto.VConn) (proto.Result, error) {
rightDs := fetchDs(h.RightQuery, ctx, conn)
leftDs := fetchDs(h.LeftQuery, ctx, conn)
joinColumn := &dataset.JoinColumn{}
joinColumn.SetColumn(h.LeftKey)
ds, err := dataset.NewSortMergeJoin(
h.JoinType,
joinColumn,
rightDs,
leftDs,
)
if err != nil {
return nil, err
}
return resultx.New(resultx.WithDataset(ds)), nil
}
func (h *SortMergeJoin) ExecIn(ctx context.Context, conn proto.VConn) (proto.Result, error) {
rightDs, err := fetchDs(h.RightQuery, ctx, conn)
if err != nil {
return nil, err
}
leftDs, err := fetchDs(h.LeftQuery, ctx, conn)
if err != nil {
return nil, err
}
joinColumn := &dataset.JoinColumn{}
joinColumn.SetColumn(h.LeftKey)
ds, err := dataset.NewSortMergeJoin(
h.JoinType,
joinColumn,
rightDs,
leftDs,
)
if err != nil {
return nil, err
}
return resultx.New(resultx.WithDataset(ds)), nil
}

Comment on lines +626 to +645
setPlan := func(plan *dml.HashJoinPlan, buildPlan, probePlan proto.Plan, buildKey, probeKey string) {
plan.BuildKey = buildKey
plan.ProbeKey = probeKey
plan.BuildPlan = buildPlan
plan.ProbePlan = probePlan
}

if join.Typ == ast.InnerJoin {
setPlan(hashJoinPlan, leftPlan, rightPlan, leftKey, rightKey)
hashJoinPlan.IsFilterProbeRow = true
} else {
return nil, errors.New("not support Join Type")
hashJoinPlan.IsFilterProbeRow = false
if join.Typ == ast.LeftJoin {
hashJoinPlan.IsReversedColumn = true
setPlan(hashJoinPlan, rightPlan, leftPlan, rightKey, leftKey)
} else if join.Typ == ast.RightJoin {
setPlan(hashJoinPlan, leftPlan, rightPlan, leftKey, rightKey)
} else {
return nil, errors.New("not support Join Type")
}
Copy link

Choose a reason for hiding this comment

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

Consider refactoring for readability.

The nested if-else structure for setting the hash join plan can be refactored for better readability.

-    if join.Typ == ast.InnerJoin {
-        setPlan(hashJoinPlan, leftPlan, rightPlan, leftKey, rightKey)
-        hashJoinPlan.IsFilterProbeRow = true
-    } else {
-        hashJoinPlan.IsFilterProbeRow = false
-        if join.Typ == ast.LeftJoin {
-            hashJoinPlan.IsReversedColumn = true
-            setPlan(hashJoinPlan, rightPlan, leftPlan, rightKey, leftKey)
-        } else if join.Typ == ast.RightJoin {
-            setPlan(hashJoinPlan, leftPlan, rightPlan, leftKey, rightKey)
-        } else {
-            return nil, errors.New("not support Join Type")
-        }
-    }
+    switch join.Typ {
+    case ast.InnerJoin:
+        setPlan(hashJoinPlan, leftPlan, rightPlan, leftKey, rightKey)
+        hashJoinPlan.IsFilterProbeRow = true
+    case ast.LeftJoin:
+        hashJoinPlan.IsReversedColumn = true
+        setPlan(hashJoinPlan, rightPlan, leftPlan, rightKey, leftKey)
+        hashJoinPlan.IsFilterProbeRow = false
+    case ast.RightJoin:
+        setPlan(hashJoinPlan, leftPlan, rightPlan, leftKey, rightKey)
+        hashJoinPlan.IsFilterProbeRow = false
+    default:
+        return nil, errors.New("not support Join Type")
+    }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setPlan := func(plan *dml.HashJoinPlan, buildPlan, probePlan proto.Plan, buildKey, probeKey string) {
plan.BuildKey = buildKey
plan.ProbeKey = probeKey
plan.BuildPlan = buildPlan
plan.ProbePlan = probePlan
}
if join.Typ == ast.InnerJoin {
setPlan(hashJoinPlan, leftPlan, rightPlan, leftKey, rightKey)
hashJoinPlan.IsFilterProbeRow = true
} else {
return nil, errors.New("not support Join Type")
hashJoinPlan.IsFilterProbeRow = false
if join.Typ == ast.LeftJoin {
hashJoinPlan.IsReversedColumn = true
setPlan(hashJoinPlan, rightPlan, leftPlan, rightKey, leftKey)
} else if join.Typ == ast.RightJoin {
setPlan(hashJoinPlan, leftPlan, rightPlan, leftKey, rightKey)
} else {
return nil, errors.New("not support Join Type")
}
if join.Typ == ast.InnerJoin {
setPlan(hashJoinPlan, leftPlan, rightPlan, leftKey, rightKey)
hashJoinPlan.IsFilterProbeRow = true
} else {
hashJoinPlan.IsFilterProbeRow = false
if join.Typ == ast.LeftJoin {
hashJoinPlan.IsReversedColumn = true
setPlan(hashJoinPlan, rightPlan, leftPlan, rightKey, leftKey)
} else if join.Typ == ast.RightJoin {
setPlan(hashJoinPlan, leftPlan, rightPlan, leftKey, rightKey)
} else {
return nil, errors.New("not support Join Type")
}
}
```
Updated code:
```suggestion
switch join.Typ {
case ast.InnerJoin:
setPlan(hashJoinPlan, leftPlan, rightPlan, leftKey, rightKey)
hashJoinPlan.IsFilterProbeRow = true
case ast.LeftJoin:
hashJoinPlan.IsReversedColumn = true
setPlan(hashJoinPlan, rightPlan, leftPlan, rightKey, leftKey)
hashJoinPlan.IsFilterProbeRow = false
case ast.RightJoin:
setPlan(hashJoinPlan, leftPlan, rightPlan, leftKey, rightKey)
hashJoinPlan.IsFilterProbeRow = false
default:
return nil, errors.New("not support Join Type")
}

Comment on lines +54 to +56
//if len(rp.RenameList) != len(fields) {
// panic(fmt.Sprintf("the length of field doesn't match: expect=%d, actual=%d!", len(rp.RenameList), len(fields)))
//}
Copy link

Choose a reason for hiding this comment

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

Remove commented-out code

Consider removing the commented-out code to clean up the codebase.

-	//if len(rp.RenameList) != len(fields) {
-	//	panic(fmt.Sprintf("the length of field doesn't match: expect=%d, actual=%d!", len(rp.RenameList), len(fields)))
-	//}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
//if len(rp.RenameList) != len(fields) {
// panic(fmt.Sprintf("the length of field doesn't match: expect=%d, actual=%d!", len(rp.RenameList), len(fields)))
//}

Comment on lines +66 to +93
// var renames map[int]struct{}
// for i := 0; i < len(rp.RenameList); i++ {
// rename := rp.RenameList[i]
// name := fields[i].Name()
// if rename == name {
// continue
// }
// if renames == nil {
// renames = make(map[int]struct{})
// }
// renames[i] = struct{}{}
// }

newFields := make([]proto.Field, 0, len(fields))
for i := 0; i < len(fields); i++ {
if _, ok := renames[i]; ok {
f := *(fields[i].(*mysql.Field))
f.SetName(rp.RenameList[i])
f.SetOrgName(rp.RenameList[i])
newFields = append(newFields, &f)
} else {
newFields = append(newFields, fields[i])
}
}
// if len(renames) < 1 {
// return fields
// }

// newFields := make([]proto.Field, 0, len(fields))
// for i := 0; i < len(fields); i++ {
// if _, ok := renames[i]; ok {
// f := *(fields[i].(*mysql.Field))
// f.SetName(rp.RenameList[i])
// f.SetOrgName(rp.RenameList[i])
// newFields = append(newFields, &f)
// } else {
// newFields = append(newFields, fields[i])
// }
// }
Copy link

Choose a reason for hiding this comment

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

Remove commented-out code

Consider removing the commented-out code to clean up the codebase.

-	// var renames map[int]struct{}
-	// for i := 0; i < len(rp.RenameList); i++ {
-	// 	rename := rp.RenameList[i]
-	// 	name := fields[i].Name()
-	// 	if rename == name {
-	// 		continue
-	// 	}
-	// 	if renames == nil {
-	// 		renames = make(map[int]struct{})
-	// 	}
-	// 	renames[i] = struct{}{}
-	// }
-	// if len(renames) < 1 {
-	// 	return fields
-	// }
-	// newFields := make([]proto.Field, 0, len(fields))
-	// for i := 0; i < len(fields); i++ {
-	// 	if _, ok := renames[i]; ok {
-	// 		f := *(fields[i].(*mysql.Field))
-	// 		f.SetName(rp.RenameList[i])
-	// 		f.SetOrgName(rp.RenameList[i])
-	// 		newFields = append(newFields, &f)
-	// 	} else {
-	// 		newFields = append(newFields, fields[i])
-	// 	}
-	// }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// var renames map[int]struct{}
// for i := 0; i < len(rp.RenameList); i++ {
// rename := rp.RenameList[i]
// name := fields[i].Name()
// if rename == name {
// continue
// }
// if renames == nil {
// renames = make(map[int]struct{})
// }
// renames[i] = struct{}{}
// }
newFields := make([]proto.Field, 0, len(fields))
for i := 0; i < len(fields); i++ {
if _, ok := renames[i]; ok {
f := *(fields[i].(*mysql.Field))
f.SetName(rp.RenameList[i])
f.SetOrgName(rp.RenameList[i])
newFields = append(newFields, &f)
} else {
newFields = append(newFields, fields[i])
}
}
// if len(renames) < 1 {
// return fields
// }
// newFields := make([]proto.Field, 0, len(fields))
// for i := 0; i < len(fields); i++ {
// if _, ok := renames[i]; ok {
// f := *(fields[i].(*mysql.Field))
// f.SetName(rp.RenameList[i])
// f.SetOrgName(rp.RenameList[i])
// newFields = append(newFields, &f)
// } else {
// newFields = append(newFields, fields[i])
// }
// }

Copy link

cr-gpt bot commented Jul 3, 2024

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between a9a5c67 and bbbb68b.

Files selected for processing (1)
  • pkg/runtime/plan/dml/sort_merge_join.go (1 hunks)
Additional comments not posted (6)
pkg/runtime/plan/dml/sort_merge_join.go (6)

1-16: License Header: Ensure Compliance

The license header is present and seems compliant with the Apache License, Version 2.0.


18-27: Imports: Confirm Usage

All imported packages are used in the code. No unnecessary imports found.


29-38: Struct Definition: SortMergeJoin

The SortMergeJoin struct is well-defined, and all fields are used in the methods.


40-42: Method Definition: Type()

The Type() method correctly returns the plan type as proto.PlanTypeQuery.


44-61: Improve error handling for fetchDs

Consider handling errors returned by fetchDs to improve robustness.

-	rightDs := fetchDs(h.RightQuery, ctx, conn)
-	leftDs := fetchDs(h.LeftQuery, ctx, conn)
+	rightDs, err := fetchDs(h.RightQuery, ctx, conn)
+	if err != nil {
+		return nil, err
+	}
+	leftDs, err := fetchDs(h.LeftQuery, ctx, conn)
+	if err != nil {
+		return nil, err
+	}

63-74: Log error before returning nil

Consider logging the error before returning nil to improve debugging.

-	if err != nil {
-		return nil
-	}
+	if err != nil {
+		log.Errorf("Error executing plan: %v", err)
+		return nil
+	}

Copy link

cr-gpt bot commented Jul 3, 2024

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

Copy link

cr-gpt bot commented Jul 18, 2024

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between bbbb68b and 95fd098.

Files selected for processing (2)
  • pkg/dataset/sort_merge_join.go (11 hunks)
  • pkg/runtime/plan/dml/sort_merge_join.go (1 hunks)
Additional comments not posted (15)
pkg/runtime/plan/dml/sort_merge_join.go (5)

46-63: Improve error handling for fetchDs.

Consider handling errors returned by fetchDs to improve robustness.

-	rightDs := fetchDs(h.RightQuery, ctx, conn)
-	leftDs := fetchDs(h.LeftQuery, ctx, conn)
+	rightDs, err := fetchDs(h.RightQuery, ctx, conn)
+	if err != nil {
+		return nil, err
+	}
+	leftDs, err := fetchDs(h.LeftQuery, ctx, conn)
+	if err != nil {
+		return nil, err
+	}

65-76: Log error before returning nil.

Consider logging the error before returning nil to improve debugging.

-	if err != nil {
-		return nil
-	}
+	if err != nil {
+		log.Errorf("Error executing plan: %v", err)
+		return nil
+	}

65-76: Log error before returning nil.

Consider logging the error before returning nil to improve debugging.

-	if err != nil {
-		return nil
-	}
+	if err != nil {
+		log.Errorf("Error fetching dataset: %v", err)
+		return nil
+	}

42-44: LGTM!

The method is straightforward and correctly returns the plan type.


31-40: LGTM!

The struct is well-defined and follows proper conventions.

pkg/dataset/sort_merge_join.go (10)

82-83: Improve field handling.

Consider using copy instead of append for fields.

-	fields := append(fields, innerFields...)
-	fields = append(fields, outerFields...)
+	fields := make([]proto.Field, len(innerFields)+len(outerFields))
+	copy(fields, innerFields)
+	copy(fields[len(innerFields):], outerFields)

254-256: LGTM!

The method is straightforward and correctly sets the column.


272-274: LGTM!

The method handles errors correctly and follows proper conventions.


324-324: LGTM!

The method handles errors correctly and follows proper conventions.


486-486: LGTM!

The method handles errors correctly and follows proper conventions.


486-486: LGTM!

The method calls the leftJoin method, ensuring consistency in join logic.


486-486: LGTM!

The method handles errors correctly and follows proper conventions.


486-486: LGTM!

The method handles errors correctly and follows proper conventions.


Line range hint 509-557: LGTM!

The method handles errors correctly and follows proper conventions.


607-607: LGTM!

The method handles errors correctly and follows proper conventions.

Copy link

cr-gpt bot commented Jul 18, 2024

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 95fd098 and 904ce32.

Files selected for processing (1)
  • pkg/dataset/sort_merge_join.go (11 hunks)
Files skipped from review as they are similar to previous changes (1)
  • pkg/dataset/sort_merge_join.go

@dongzl dongzl added the enhancement New feature or request label Aug 4, 2024
@dongzl dongzl added this to the 0.3.0 milestone Aug 4, 2024
@AlexStocks
Copy link
Contributor

这个 PR 先别着急合并,兔子留的一些 comment 非常好,希望继续改进下

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants