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

[Feature] [Refactoring] Create LiteralContext to hold type and value of literal and Boolean literal eval support #9389

Merged
merged 18 commits into from
Oct 6, 2022

Conversation

61yao
Copy link
Contributor

@61yao 61yao commented Sep 13, 2022

  1. Pass the literal for boolean as the correct type from thrift.
  2. Only boolean literal and some numerical types are supported.
  3. This naturally fixes the the boolean literal eval because we have query rewrite for this.

@61yao 61yao changed the title [Feature] [Refactoring] Create LiteralContext to hold type and value of literal [Feature] [Refactoring] Create LiteralContext to hold type and value of literal and Boolean literal eval support Sep 13, 2022
}

public Type getType() {
return _type;
}

public String getLiteral() {
return _value;
@Nullable
Copy link
Contributor

Choose a reason for hiding this comment

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

(minor) Not sure if we want to put @Nullable here. We usually call it after checking the type, and this annotation can potentially cause warning in IDE. If we decide to use @Nullable here, we should probably also annotate getIdentifier() and getFunction()

Copy link
Contributor

Choose a reason for hiding this comment

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

check and get seems a better idea. yes

Copy link
Contributor Author

@61yao 61yao Sep 14, 2022

Choose a reason for hiding this comment

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

Removed the annotation.
I feel the best way is to have LiteralContext, IdentifierContext and Function Context inherit from ExpressionContext, so we don't need to check and call get... it is also more clear which value field is set. but this needs a bit more refactoring.

@codecov-commenter
Copy link

codecov-commenter commented Sep 15, 2022

Codecov Report

Merging #9389 (196d90c) into master (c5d4b15) will increase coverage by 43.92%.
The diff coverage is 78.62%.

@@              Coverage Diff              @@
##             master    #9389       +/-   ##
=============================================
+ Coverage     25.97%   69.90%   +43.92%     
- Complexity       44     5213     +5169     
=============================================
  Files          1915     1928       +13     
  Lines        102376   102783      +407     
  Branches      15554    15597       +43     
=============================================
+ Hits          26592    71850    +45258     
+ Misses        73096    25848    -47248     
- Partials       2688     5085     +2397     
Flag Coverage Δ
integration1 25.97% <42.74%> (-0.01%) ⬇️
integration2 24.62% <45.80%> (?)
unittests1 67.26% <75.57%> (?)
unittests2 15.61% <0.76%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
.../pinot/core/query/reduce/GapfillFilterHandler.java 85.71% <0.00%> (+85.71%) ⬆️
.../java/org/apache/pinot/core/util/GapfillUtils.java 69.87% <0.00%> (+65.06%) ⬆️
...ot/core/operator/filter/H3IndexFilterOperator.java 82.29% <50.00%> (+82.29%) ⬆️
...ache/pinot/core/query/reduce/GapfillProcessor.java 90.86% <50.00%> (+90.86%) ⬆️
...e/pinot/common/request/context/LiteralContext.java 60.52% <60.52%> (ø)
...ot/common/request/context/RequestContextUtils.java 65.89% <66.66%> (+24.85%) ⬆️
...core/query/executor/ServerQueryExecutorV1Impl.java 83.57% <75.00%> (+4.10%) ⬆️
...r/transform/function/LiteralTransformFunction.java 69.23% <76.92%> (+32.69%) ⬆️
...inot/common/request/context/ExpressionContext.java 83.33% <86.95%> (-2.39%) ⬇️
...pache/pinot/common/utils/request/RequestUtils.java 80.55% <100.00%> (+14.53%) ⬆️
... and 1419 more

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

Comment on lines +58 to +73
private static Class<?> convertDataTypeToJavaType(FieldSpec.DataType dataType) {
switch (dataType) {
case INT:
return Integer.class;
case LONG:
return Long.class;
case BOOLEAN:
return Boolean.class;
case FLOAT:
return Float.class;
case DOUBLE:
return Double.class;
case STRING:
return String.class;
default:
throw new UnsupportedOperationException("Unsupported dataType:" + dataType);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

what's the purpose of this. we have PinotDataType for this right?

Copy link
Contributor

Choose a reason for hiding this comment

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

IMO we should focus on having Literal store DataType and Value. all conversion logics should be outside of LiteralContext

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is used to check whether the constructor for LiteralContext is valid to prevent bad usage.

Copy link
Contributor

Choose a reason for hiding this comment

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

hmm I don't think this check is needed - as there's no need to convert to a java class.

  • a simple immutable list of supported FieldTypes are sufficient.
  • even if that I don't think it is necessary since it indeed and store the date type and value without a problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hmm, what if people try to store a literal context with the wrong type, we should throw an exception right?

Comment on lines 354 to 360
private static String getStringValue(ExpressionContext expressionContext) {
if (expressionContext.getType() != ExpressionContext.Type.LITERAL) {
if(expressionContext.getType() != ExpressionContext.Type.LITERAL){
throw new BadQueryRequestException(
"Pinot does not support column or function on the right-hand side of the predicate");
}
return expressionContext.getLiteral();
return expressionContext.getLiteralString();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

add a new function

getLiteralContext(ExpressionContext expressionContext) { 
  // ...
}

and make

@Deprecated
getStringValue() {
  LiteralContext literalContext = getLiteralContext(...);
  return literalContext.getDataType().convertToString(literalContext.getValue());
}

later we make all the usage of getStringValue() go to getLiteralContext

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can do this when we deprecate getLiteralString?

Comment on lines +118 to +126
// TODO: Support null literal and other types.
switch (node.getTypeName()) {
case BOOLEAN:
literal.setBoolValue(node.booleanValue());
break;
default:
literal.setStringValue(StringUtils.replace(node.toValue(), "''", "'"));
break;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

IMO this can be added later. since @Jackie-Jiang might have some idea regarding bool <-> string casting with or w/o dictionary

Copy link
Contributor Author

@61yao 61yao Sep 22, 2022

Choose a reason for hiding this comment

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

I am not sure how this is related to casting? Can you clarify?


public LiteralContext(Literal literal) {
_type = convertThriftTypeToDataType(literal.getSetField());
_value = literal.getFieldValue();
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we also need to convert the value to match the data type

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you meant we do a conversion here? do you mean we have one member data for each type?

Copy link
Contributor

Choose a reason for hiding this comment

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

in the thrift definition file it is already a union of corresponding types right? do we need additional conversion?

Copy link
Contributor

@walterddr walterddr left a comment

Choose a reason for hiding this comment

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

looks good to me otherwise. please also fix tests

return '\'' + "" + '\'';
}
// TODO: print out the type.
if(_type == FieldSpec.DataType.STRING || _type == FieldSpec.DataType.BYTES) {
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the value for BYTES type? If it is byte[], toString() won't work

Copy link
Contributor

Choose a reason for hiding this comment

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

good question. try testing with ST_POINT(0, 0) and see what's the literal BYTES constructed.
but I think since we don't want to worry about these non-directly constructable literal types we can add a TODO and address later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, the type can never be bytes. So I removed it.

for ST_POINT(0, 0), it will be passed in as string for literal.

Copy link
Contributor

@walterddr walterddr left a comment

Choose a reason for hiding this comment

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

lgtm

@walterddr
Copy link
Contributor

the failure looks real in compatibility regression test

java.io.IOException: org.apache.pinot.common.exception.HttpErrorStatusException: Got error status code: 500 (Internal Server Error) with reason: "Failed to get a reason, exception: com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
 at [Source: (String)""; line: 1, column: 0]" while sending request: http://localhost:8099/query/sql
	at org.apache.pinot.controller.helix.ControllerTest.sendPostRequest(ControllerTest.java:751) ~[pinot-controller-0.12.0-SNAPSHOT-tests.jar:0.12.0-SNAPSHOT-e3a3f1f21448c67f2588a26fc48bcc74031189c5]
	at org.apache.pinot.controller.helix.ControllerTest.sendPostRequest(ControllerTest.java:741) ~[pinot-controller-0.12.0-SNAPSHOT-tests.jar:0.12.0-SNAPSHOT-e3a3f1f21448c67f2588a26fc48bcc74031189c5]
	at org.apache.pinot.compat.Utils.postSqlQuery(Utils.java:60) ~[pinot-compatibility-verifier-0.12.0-SNAPSHOT.jar:0.12.0-SNAPSHOT-e3a3f1f21448c67f2588a26fc48bcc74031189c5]
	at org.apache.pinot.compat.QueryOp.verifyQueries(QueryOp.java:127) [pinot-compatibility-verifier-0.12.0-SNAPSHOT.jar:0.12.0-SNAPSHOT-e3a3f1f21448c67f2588a26fc48bcc74031189c5]
	at org.apache.pinot.compat.QueryOp.runOp(QueryOp.java:80) [pinot-compatibility-verifier-0.12.0-SNAPSHOT.jar:0.12.0-SNAPSHOT-e3a3f1f21448c67f2588a26fc48bcc74031189c5]
	at org.apache.pinot.compat.BaseOp.run(BaseOp.java:78) [pinot-compatibility-verifier-0.12.0-SNAPSHOT.jar:0.12.0-SNAPSHOT-e3a3f1f21448c67f2588a26fc48bcc74031189c5]
	at org.apache.pinot.compat.CompatibilityOpsRunner.runOps(CompatibilityOpsRunner.java:56) [pinot-compatibility-verifier-0.12.0-SNAPSHOT.jar:0.12.0-SNAPSHOT-e3a3f1f21448c67f2588a26fc48bcc74031189c5]
	at org.apache.pinot.compat.CompatibilityOpsRunner.main(CompatibilityOpsRunner.java:77) [pinot-compatibility-verifier-0.12.0-SNAPSHOT.jar:0.12.0-SNAPSHOT-e3a3f1f21448c67f2588a26fc48bcc7[403](https://github.com/apache/pinot/actions/runs/3183296104/jobs/5190340281#step:5:404)1189c5]
Caused by: org.apache.pinot.common.exception.HttpErrorStatusException: Got error status code: 500 (Internal Server Error) with reason: "Failed to get a reason, exception: com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
 at [Source: (String)""; line: 1, column: 0]" while sending request: http://localhost:8099/query/sql
	at org.apache.pinot.common.utils.http.HttpClient.wrapAndThrowHttpException(HttpClient.java:442) ~[pinot-common-0.12.0-SNAPSHOT.jar:0.12.0-SNAPSHOT-e3a3f1f21448c67f2588a26fc48bcc74031189c5]
	at org.apache.pinot.controller.helix.ControllerTest.sendPostRequest(ControllerTest.java:747) ~[pinot-controller-0.12.0-SNAPSHOT-tests.jar:0.12.0-SNAPSHOT-e3a3f1f21448c67f2588a26fc48bcc74031189c5]
	... 7 more

plz kindly take a look

@61yao
Copy link
Contributor Author

61yao commented Oct 6, 2022

@walterddr I fixed the test and it should work now, but somehow the tests don't run anymore

@61yao 61yao requested a review from walterddr October 6, 2022 04:21
@siddharthteotia
Copy link
Contributor

@walterddr I fixed the test and it should work now, but somehow the tests don't run anymore

I trigered the run

Copy link
Contributor

@walterddr walterddr left a comment

Choose a reason for hiding this comment

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

looks good. I will add the comment in the commit message to handle the quote/unquote issue for the literal toString

@walterddr walterddr merged commit f342684 into apache:master Oct 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants