-
Notifications
You must be signed in to change notification settings - Fork 11
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
FETCH .. WITH TIES issue detection #2111
Changes from 12 commits
fd998d5
e4e0408
d3f4cdf
1fdc3da
ec88f04
dd87f93
920622d
f999e0b
5d2df92
87637ee
8336ad3
6981662
0037cea
2d8eec2
4156499
0d8b01f
0274a38
5df9e18
83ebcb2
42c09f9
d293c2d
69c7a4c
65c787e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,8 +16,12 @@ limitations under the License. | |
package queryissue | ||
|
||
import ( | ||
"fmt" | ||
|
||
mapset "github.com/deckarep/golang-set/v2" | ||
pg_query "github.com/pganalyze/pg_query_go/v6" | ||
log "github.com/sirupsen/logrus" | ||
"google.golang.org/protobuf/proto" | ||
"google.golang.org/protobuf/reflect/protoreflect" | ||
|
||
"github.com/yugabyte/yb-voyager/yb-voyager/src/query/queryparser" | ||
|
@@ -195,3 +199,46 @@ func (d *RangeTableFuncDetector) GetIssues() []QueryIssue { | |
} | ||
return issues | ||
} | ||
|
||
type SelectStmtDetector struct { | ||
query string | ||
limitOptionWithTiesDetected bool | ||
} | ||
|
||
func NewSelectStmtDetector(query string) *SelectStmtDetector { | ||
return &SelectStmtDetector{ | ||
query: query, | ||
} | ||
} | ||
|
||
func (d *SelectStmtDetector) getSelectStmtFromProto(msg protoreflect.Message) (*pg_query.SelectStmt, error) { | ||
protoMsg := msg.Interface().(proto.Message) | ||
selectStmtNode, ok := protoMsg.(*pg_query.SelectStmt) | ||
if !ok { | ||
return nil, fmt.Errorf("failed to cast %s to %s", queryparser.PG_QUERY_SELECTSTMT_NODE, queryparser.PG_QUERY_SELECTSTMT_NODE) | ||
} | ||
return selectStmtNode, nil | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lets add this function in |
||
|
||
func (d *SelectStmtDetector) Detect(msg protoreflect.Message) error { | ||
if queryparser.GetMsgFullName(msg) == queryparser.PG_QUERY_SELECTSTMT_NODE { | ||
selectStmtNode, err := d.getSelectStmtFromProto(msg) | ||
if err != nil { | ||
return err | ||
} | ||
// checks if a SelectStmt node uses a FETCH clause with TIES | ||
// https://www.postgresql.org/docs/13/sql-select.html#SQL-LIMIT | ||
if selectStmtNode.LimitOption == pg_query.LimitOption_LIMIT_OPTION_WITH_TIES { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. define this limit option const There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it. Don't think we can completely avoid this because the return type would be a pg_query.SelectStmt. But we probably don't need to have an explicit dependency. But broadly speaking, agree with not preferring to use pg_query directly here. (as much as possilble). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, as much as possible we should avoid using it directly in the queryissue. |
||
d.limitOptionWithTiesDetected = true | ||
} | ||
} | ||
return nil | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am thinking can we stick to one of the approaches (protomsg) as a primary approach, and use other one where its significantly making things easy, other code might become a bit messy. Here in this case i guess something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see your point about consistency. But why, in general, do you prefer accessing fields of a message via protoreflect.Message rather than structs directly?
I doubt there is significant overhead. It's just type assertion. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Merged this for now, since it's been pending for a while and I had to resolve a lot of conflicts! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
@makalaaneesh Consistency here is another reason. |
||
|
||
func (d *SelectStmtDetector) GetIssues() []QueryIssue { | ||
var issues []QueryIssue | ||
if d.limitOptionWithTiesDetected { | ||
issues = append(issues, NewFetchWithTiesIssue(DML_QUERY_OBJECT_TYPE, "", d.query)) | ||
} | ||
return issues | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: maybe "FETCH .. WITH TIES Clause"?