Project

General

Profile

Bug #9396

Improve Incompatible data types in expression or assignment. (223) error handling

Added by Dănuț Filimon over 1 year ago. Updated over 1 year ago.

Status:
WIP
Priority:
Normal
Target version:
-
Start date:
Due date:
% Done:

80%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
production:
No
env_name:
topics:

History

#2 Updated by Dănuț Filimon over 1 year ago

  • Status changed from New to WIP
  • Assignee set to Dănuț Filimon

From #9377-8:

I've created unit tests for testing the behavior of temp-tables fields and literals:
Field type int char date datetime datetime-tz decimal logical recid rowid
int pass pass fail pass pass pass pass pass pass
char pass pass fail pass pass pass pass pass pass
date pass pass pass fail fail pass pass pass pass
datetime pass pass pass pass fail pass pass pass pass
datetime-tz pass pass pass fail pass pass pass pass pass
decimal pass pass fail pass pass pass pass pass pass
logical pass pass fail pass pass pass pass pass pass
recid pass pass fail pass pass pass pass pass pass
rowid pass pass fail pass pass pass pass pass fail
My findings:
There are a few problems I noticed when fixing #9377-8:
  • Let's take the following example (lok logical variable, tt9377 temporary table, l1 logical field):
    silent(() -> lok.assign(hq.unwrapQuery().prepare("for each tt9377 where l1 = 10")));
    
    this should assign false to lok, but it is true because in DynamicQueryConversion.injectVariableHelper() we always have a return value but the processing should stop right there when we get error 223. This can be fixed by throwing an error and catching it in DynamicQueryHelper.parse().
  • There's also this case (dtz1 datetime-tz field):
    silent(() -> lok.assign(hq.unwrapQuery().prepare("for each tt9377 where dtz1 = DATETIME('05-05-2002 07:15:03')")));
    
    where the injected variable is actually a CHARACTER but the conversion should fail because of the datetime function. One possible solution would be to check if the parent is a cast function and then compare it with the sibling type, determining if the types are compatible.
  • The additional error case (l1 logical field):
            lok = false.        
            DO TRANSACTION:
                hq:query-prepare("for each tt9377 where l1 = 10").
                CATCH ex AS Progress.Lang.Error :
                    Assert:Equals(1, ex:NumMessages).
                    Assert:Equals(223, ex:GetMessageNum(1)).
                    lok = true.
                END CATCH.
            END.
    
    ex:NumMessages value is 2, the error are: com.goldencode.p2j.NumberedException: ** Incompatible data types in expression or assignment. (223) and com.goldencode.p2j.NumberedException: ** null with the number -1.
    I am still thinking on how to fix this (in my opinion this is not a critial issue and removing this assertion fixes all my test cases).

Now for the second bullet point I might be mistaken. In 4gl int64(logical(int64(5))) is valid and I need to test if the first int64 function is the one that determines the data type.

#3 Updated by Dănuț Filimon over 1 year ago

The third bullet point is a regression added in trunk/15456, recordOrShowError throws a DeferredLegacyErrorException which results in the com.goldencode.p2j.NumberedException: ** null error. Added Artur as a watcher as this is related to #8912 changes (8912h branch).

#4 Updated by Dănuț Filimon over 1 year ago

Committed 9396a/15583. This commit fixes all of my testcases related to #9396-2 table (except the 3rd bullet point).

The changes include:
  • Added a new DynamicQueryException class.
  • Stop dynamic query processing when 223 error is thrown (this will make the returned query null) so code like silent(() -> lok.assign(hq.unwrapQuery().prepare("for each tt9377 where l1 = 10"))); will correctly assign lok value.
  • Support error 223 for cast functions (currently only DATETIME and DATETIME-TZ).
Next steps:
  • Expand test cases that do not rely on DATETIME and DATETIME-TZ functions and fix any issues.
  • Expand test cases to use INT64, DECIMAL, DATE, LOGICAL functions to reveal more incompatibilities and fix those as well.

#5 Updated by Dănuț Filimon over 1 year ago

This turns out to be more complicated for certain cast functions, for example you can have DATETIME(DATE(3,3,2001), 402) which will result in 4 literals to be extracted, then it is possible to have an invalid date format.

#6 Updated by Dănuț Filimon over 1 year ago

  • % Done changed from 0 to 50

Dănuț Filimon wrote:

This turns out to be more complicated for certain cast functions, for example you can have DATETIME(DATE(3,3,2001), 402) which will result in 4 literals to be extracted, then it is possible to have an invalid date format.

I've managed to fix this, find the function for any type of literal then make sure the data type resulted from the function matches the data type of the field. Improved error handling for query-prepare resulted by having a ? value as a predicate (recordOrShowDatabaseError was not used correctly) and it must also throw an error to stop any processing.

I committed 9396a/15584 and expanded my test suite.

Since most of the testing was done using dynamic queries, I must also write similar tests for static queries to make sure my solution does not turn into a regression.

#7 Updated by Dănuț Filimon over 1 year ago

Found the following test:

    @Test.
    method public void test-logical-logical-func16():
        define query q for tt9377.
        open query q for each tt9377 where l1 = logical(1).

        finally:
            close query q.
        end finally.
    end method.
where it results in the following compilation error:
    [javac] /home/ddf/gcd/dataset/src/com/goldencode/dataset/unittests/Test9377Set13.java:464: error: no suitable constructor found for logical(int)
    [javac]             (P2JQuery.Parameter) () -> new logical(1)
    [javac]                                        ^
    [javac]     constructor logical.logical(BaseDataType) is not applicable
    [javac]       (argument mismatch; int cannot be converted to BaseDataType)
    [javac]     constructor logical.logical(boolean) is not applicable
    [javac]       (argument mismatch; int cannot be converted to boolean)
    [javac]     constructor logical.logical(logical) is not applicable
    [javac]       (argument mismatch; int cannot be converted to logical)
    [javac]     constructor logical.logical(String) is not applicable
    [javac]       (argument mismatch; int cannot be converted to String)
    [javac]     constructor logical.logical(character) is not applicable
    [javac]       (argument mismatch; int cannot be converted to character)
    [javac]     constructor logical.logical(Boolean) is not applicable
    [javac]       (argument mismatch; int cannot be converted to Boolean)

The converted query looks like this:

         query16.assign(new AdaptiveQuery().initialize(tt9377, "tt9377.l1 = ?", null, "tt9377.recid asc", new Object[]
         {
            (P2JQuery.Parameter) () -> new logical(1)
         }));
while a logical(2.2) uses
 (P2JQuery.Parameter) () -> new logical(decimal.fromLiteral("2.2")) 

The solution is to either add a logical(int) constructor or make conversion changes similar to the decimal (I prefer no conversion changes).

#8 Updated by Dănuț Filimon over 1 year ago

  • Status changed from WIP to Review
  • % Done changed from 50 to 100
  • reviewer Alexandru Lungu added

Committed 9396a/15585. Added logical(int) constructor to fix #9396-7.

All written tests passed (tests cover dynamic conversion between table fields and literals, functions, variables, query-prepare handling of unknown value and static queries - note that the static queries are not targeted by the changes but did manage to reveal a compilation issue).

The changes target dynamic conversion so my test plan includes:
  • 2x Customer unit tests
  • Customer regression tests
  • ChUI regression tests
  • Harness and reports
  • ETF regression tests

Any test recommendation is welcome.

Alexandru, please review.

#9 Updated by Alexandru Lungu over 1 year ago

Review of 9396a

  • The logical constructor can be condensed: assign(value != 0). I agree that the constructor should be added.
  • I agree with the idea of a DynamicQueryException.

Before providing a green light, please better explain:

where the injected variable is actually a CHARACTER but the conversion should fail because of the datetime function. One possible solution would be to check if the parent is a cast function and then compare it with the sibling type, determining if the types are compatible.

At dynamic conversion, the literals are extracted as variables and embedded into the FQL. This way, the "convertor" will replace the variables (ex-literals) with substitution parameters. injectVariableHelper is doing this work - replacing literals with variables - but for doing so it needs to infer the data type of the variable. Instead of honoring the data type of the literal, it uses the data type of the field that is checked for equality - which in this case has a mismatch. Your attempt is to also honor the CASTs that are used when comparing that literal with the table field.

So for each tt where f1 = 1 is transformed into def var x as int. x = 1. for each tt where f1 = x. But if f1 was logical, the process would fail at injection time.

My questions:

  • Is the literal extraction happening only in f1 = 1 kind is situations? Or f1 + 1 = f2 is also a valid case in which 1 is extracted?
  • If only f1 = 1 is valid, where are the casts coming from? Or maybe f1 = LOGICAL(1) also a valid case in which the extraction is made? If so, can you point out the code in trunk that already bypasses the CASTS when considering a literal for extraction?

#10 Updated by Dănuț Filimon over 1 year ago

  • reviewer Andreea Bârzu added
  • reviewer deleted (Alexandru Lungu)

where the injected variable is actually a CHARACTER but the conversion should fail because of the datetime function. One possible solution would be to check if the parent is a cast function and then compare it with the sibling type, determining if the types are compatible.

So there are two scenarios which need to be taken into consideration:
  • If we define a static query we can't do something like
    open query q for each tt9377 where cvar = datetime('05-05-2002 07:15:03').
    , the code will not compile because of the incompatible data types.
  • For dynamic query we are allowed to use:
    hq:query-prepare("for each tt9377 where cvar = datetime('05-05-2002 07:15:03')"). 
    and it will throw an error because the types are not compatible.
As you mentioned, the literal will be extracted def var x as char. x = '05-05-2002 07:15:03'. for each tt9377 where cvar = datetime(x) but this should fail at injection type because cvar is character and this type is incompatible with datetime. In FWD, the cast type function is not considered at all when comparing the data types at injection time, it should not reach DynamicConversionHelper.injectVariable() where it starts to graft the ast for the variable and ends up calling DynamicConversionHelper.injectVariableHelper() with a STRING literalType. My point is that we:
  • allow faulty predicates to be parsed and introduce them in a cache;
  • misinterpret the data types that should be compared. Fwd should be aware of the exact data type which the extracted variable will take and determine if it's compatible before any other processing is done. DynamicConversionHelper.injectVariableHelper() only injects a literal variable and that is compared with the sibling type (the cvar), while the cast is what determines the final data type.
    Alexandru Lungu wrote:

Is the literal extraction happening only in f1 = 1 kind is situations? Or f1 + 1 = f2 is also a valid case in which 1 is extracted?

  • f1 = 1 scenario: If f1 is logical as you mentioned previously, the logical f1 and int 1 will not be compatible (error 223). If f1 is an integer, 1 will of course be extracted as a NUM_LITERAL.
  • f1 + 1 = f2 scenario: Again incompatible types if logical, 1 will be extracted as a NUM_LITERAL.
    It's better if we understand how we find out which one is a literal, this is happening in DynamicQueryHelper.extractParams() where the Ast is parsed and any node with the is-literal annotation is marked as a variable that needs to be injected eventually (there are multiple places where is-literal is added as an annotation in the rules). The short answer: yes.

If only f1 = 1 is valid, where are the casts coming from? Or maybe f1 = LOGICAL(1) also a valid case in which the extraction is made? If so, can you point out the code in trunk that already bypasses the CASTS when considering a literal for extraction?

I might have not expressed myself correctly, I am not talking about implicit casts but explicit ones (using functions like INT64, LOGICAL, DATETIME, DATE, DATETIME-TZ, DECIMAL). I did mention above the current problem which can answer these questions, we extract the literal from LOGICAL(1) which is 1 and that it's type (int) is compared with the sibling (should be logical because of the function used).

The "cast" is bypassed in DynamicConversionHelper.injectVariable(), step 2 where it checks the sibling type.

PROCESS_ANNOTATION.timer(() -> ConversionPool.runTask(ConversionProfile.ANNOTATIONS, finalPAst0));
is what finally ends up determining that it can't convert the pAst. In some cases this behaves differently (with other types), will have to look into the test cases to find some examples I've already fixed.

#11 Updated by Dănuț Filimon over 1 year ago

  • reviewer Alexandru Lungu added
  • reviewer deleted (Andreea Bârzu)

Somehow I modified this, sorry.

#12 Updated by Alexandru Lungu over 1 year ago

Is the literal extraction happening only in f1 = 1 kind is situations? Or f1 + 1 = f2 is also a valid case in which 1 is extracted?

What I meant by this is if the data type checking is done only for very specific patterns like a = b or FWD has a full implementation for any arbitrary expression (e.g. TRUNCATE(LENGTH(CONCAT("a", "b") - 5, 2) = c). Note how literals are character, but the whole left-side expression is an integer after the evaluation of functions (which are not casts). The bottom-line is if you attempt to fix this for a niche (casts) or for a full-set of problems I am not seeing.

The example will extract "a" and "b" as character variables, replacing the literals.

I might have not expressed myself correctly, I am not talking about implicit casts but explicit ones (using functions like INT64, LOGICAL, DATETIME, DATE, DATETIME-TZ, DECIMAL).

I am not sure I follow. The cast seems to be implicit in 4GL, so it is converted to an explicit one in FWD using extractParams. Therefore, casts seem to be fabricated by FWD. The bottom line of this statement is that maybe CASTS shouldn't be handled specifically for injectVariable, but rather fabricated with more care.

My primary concern I am trying to fix is that casts are not the only way in which a literal based expression can change its data-type (e.g. LENGTH("ABC") uses a CHAR literal, but returns a INTEGER):
  • If LENGTH case works because it comes from the converted code, it means that a cast should work exactly the same, without extra special handling. Thus the problem may reside in the synthetic casts from extractParams.
  • If LENGTH case doesn't work, it means this is a more general problem in which literals are incorrectly extracted. In this case, I would rather avoid extracting the literal altogether or find a unified solution to fix them all.

#13 Updated by Dănuț Filimon over 1 year ago

Alexandru, you are right. The problem also happens with other functions, the example:

silent(() -> lok.assign(hq.unwrapQuery().prepare("for each tt9377 where c1 = LENGTH('abc')")));
should not result in a query.

I'll have to work on another solution, I expect a lot of changes from this...

#14 Updated by Alexandru Lungu over 1 year ago

  • % Done changed from 100 to 80
  • Status changed from Review to WIP

Danut, lets go for to the more evident fix of not allowing the literals to be extracted in such complex scenarios. This is a good fix for now, as it will simply let the literal inlined, which is functionally OK. Lets defer the work on implementing the functions and more complex expressions for now. But first and foremost, lets do an analysis on how often such constructs appear. I don't want to rule out all functions and be victim to a large performance hit.

This means that we need to fine tune the literal detection and not consider all literals as being extract-able.

Ovidiu, can you provide an insight for this matter?

#15 Updated by Dănuț Filimon over 1 year ago

  • % Done changed from 80 to 100

Alexandru Lungu wrote:

Danut, lets go for to the more evident fix of not allowing the literals to be extracted in such complex scenarios. This is a good fix for now, as it will simply let the literal inlined, which is functionally OK. Lets defer the work on implementing the functions and more complex expressions for now. But first and foremost, lets do an analysis on how often such constructs appear. I don't want to rule out all functions and be victim to a large performance hit.

This means that we need to fine tune the literal detection and not consider all literals as being extract-able.

Got it! My idea was to remove the current literal checking changes and move the work to another branch (9396b - not created yet).

#16 Updated by Dănuț Filimon over 1 year ago

  • % Done changed from 100 to 80

I also committed the logical(int) constructor change to 9396a/15586.

Adjusted Done%.

#17 Updated by Dănuț Filimon over 1 year ago

I've run the analysis on how often we get FUNCTION(literal) constructs (the scenario involves the extended performance test of a customer, warmup + 10 runs):
Type Count Percentage from total (%)
No construct 30716 87.236 %
With construct 4490 12.752 %
No construct, but the sibling type is not taken in consideration 4 0.0113 %

The results are based on the assumption that in DynamicConversionHelper.injectVariable(), in the second step where the parent is checked that it will try to check the sibling when no construct is available. When a construct is used, then it will not check the sibling (as the parent should be an operator). The last table row is represented by cases where the sibling is checked but it is either null or the conditions are not fulfilled.

#18 Updated by Alexandru Lungu over 1 year ago

Can you check what the construct is in that case? I expect to see UPPER) kind of combination in 99% of that cases.

#19 Updated by Dănuț Filimon over 1 year ago

Alexandru Lungu wrote:

Can you check what the construct is in that case? I expect to see UPPER) kind of combination in 99% of that cases.

Retested #9396-17, the new results:
Type Count Percentage from total (%)
No construct 30597 87.352 %
With construct 4426 12.635 %
No construct, but the sibling type is not taken in consideration 4 0.0114 %
Further analysis into the "with construct", the top tokens are:
  • 528 - 4359 times (ProgressParserTokenTypes.KW_AND)
  • 152 - 62 times (ProgressParserTokenTypes.EXPRESSION)
  • 544 - 3 times (ProgressParserTokenTypes.KW_BEGINS)
  • 377 - 2 times (ProgressParserTokenTypes.FUNC_POLY)

#20 Updated by Alexandru Lungu over 1 year ago

528 - 4359 times (ProgressParserTokenTypes.KW_AND)

I wonder if this is something line tt.f1 = 1 and true kind of construct ... doesn't make much sense to extract anyway. I think it is safe to go ahead with the plan of omitting the extraction for such literals.

#21 Updated by Dănuț Filimon over 1 year ago

Alexandru Lungu wrote:

528 - 4359 times (ProgressParserTokenTypes.KW_AND)

I wonder if this is something line tt.f1 = 1 and true kind of construct ... doesn't make much sense to extract anyway. I think it is safe to go ahead with the plan of omitting the extraction for such literals.

Committed the changes to 9396a/15587, the test plan remains #9396-8.

Another commit will follow to remove unnecessary changes from previous commits that are not hit anymore.

#22 Updated by Dănuț Filimon over 1 year ago

  • Status changed from WIP to Review
  • % Done changed from 80 to 100

Committed the changes to 9396a/15588. Partially reverted changes from 15583 and 15584 revisions.

Please review.

L.E. injectVariable() is used in other FWD code, so I am not certain that the step 2 switch case can be removed.

#23 Updated by Ovidiu Maxiniuc over 1 year ago

Alexandru Lungu wrote:

Ovidiu, can you provide an insight for this matter?

First, a bit of wisdom :) from my experience working with dynamic queries: when dealing with issues in dynamic queries, run the static variant of the query firstly. It will help you see more easily how the query looks under-the-hood. (Of course, it can be done directly from DynamicQueryHelper, but debug code must be activated.)

For a long time, FWD was developed with the following paradigm: the customer MUST use valid 4GL code for conversion. This seems logical, because the source code is assumed to have already been used on a 4GL native box. Otherwise: garbage in - garbage out. As result, a lot of validations and data type checks were ignored during conversion assuming the 4GL compiler have already identified these issues and the programmers resolved them.

However, things got complicated with the introduction of dynamic support for temp-tables, find procedures and queries. We were grad when we took the static conversion and reuse it directly, but as noted above, it lacks the validations and data type checks which the 4GL compiler does in both cases (static and dynamic). The FWD runtime (for both compiled static and interpreted dynamic) is actually unchanged and the type from this PoV is undifferentiable. It assumes the code was semantically checked and executes it identically in both cases.

The problem is not only with the literals. We can add a lot of heuristic filters for them but we will not cover all the cases. There are constructs which do not involve the presence of literals. Take the following example:

DEFINE TEMP-TABLE tt003 
   FIELD l1 AS LOGICAL
   FIELD c1 AS CHARACTER
   FIELD c2 AS CHARACTER.
[...]
h:QUERY-PREPARE("for each tt003 where c1 = length(c2)") // dynamic query
[...]
FOR EACH tt003 WHERE c1 = LENGTH(c2):   // static query, non compilable in 4GL, but convertible by FWD
    [...]
END.
In both these cases, the where predicate is something like: "upper(tt003.c1) = lengthOf(upper(tt003.c2))" and, although the Java code is valid, and also intermediary processing, only H2 (in this case it's a temp-table) will be able to realize the problem.

My conclusion is that we need to add the full type checking during standard conversion with error reporting if we want to have a fully compatible runtime for dynamic queries (and not only).

#24 Updated by Alexandru Lungu over 1 year ago

Ovidiu, the work-flow of static and dynamic queries in FWD differs a bit, especially through DynamicQueryHelper. for each tt where tt.f1 = 1 has different Java outputs in static conversion vs dynamic conversion.
  • static conversion will generate tt.f1 = 1 where clause.
  • dynamic conversion will generate tt.f1 = ? where clause and a fabricated x will be used as substitution parameter.
So my POV on this matter is slightly different:
  • as DynamicQueryHelper has this literal extraction routine which already does the data type checking and little effort can be done to set this straight, lets go with such quick win.
  • for general case as you mentioned, a real type checking system is required. Unfortunately, some things can go as POLY and we can't perfectly state if the query is OK or not until the execution time. Anyway, for this case, maybe we can catch an invalid syntax from SQL and presume that the query was simply prepared in a bad way. Of course, we can LOG SEVERE and turn up all the red lights, but as a safety net, we can at least provide a minimal syntax checking through the SQL parser.
    • In a near future, we will need that type checking system.

#25 Updated by Alexandru Lungu over 1 year ago

Review of 8396a

  • While the approach should fix the evident problem, I think it is too relaxed. Mind that 1 + 1 = 2 is also a valid syntax, but the two 1 values will be considered complex, because their parent is +. This is not wrong per-se, but please mind injectVariable implmenetation:
      int var4glType = literalType;
      switch (litAst.getParent().getType())
      {
         case ProgressParserTokenTypes.KW_EQ:
         case ProgressParserTokenTypes.EQUALS:
         case ProgressParserTokenTypes.KW_NE:
         case ProgressParserTokenTypes.NOT_EQ:
         case ProgressParserTokenTypes.KW_LT:
         case ProgressParserTokenTypes.LT:
         case ProgressParserTokenTypes.KW_LTE:
         case ProgressParserTokenTypes.LTE:
         case ProgressParserTokenTypes.KW_GT:
         case ProgressParserTokenTypes.GT:
         case ProgressParserTokenTypes.KW_GTE:
         case ProgressParserTokenTypes.GTE:
            ProgressAst sibling = getSibling(litAst);
            if (sibling != null)
            {
               if (sibling.getType() > ProgressParserTokenTypes.BEGIN_FIELDTYPES &&
                   sibling.getType() < ProgressParserTokenTypes.END_FIELDTYPES)
               {
                  // only fields are taken into consideration to avoid database CASTing issues
                  var4glType = sibling.getType();
               }
               else if (sibling.getType() == ProgressParserTokenTypes.FUNC_RECID)
               {
                  // we want our operand to be bigint to match the record.id field in db
                  var4glType = ProgressParserTokenTypes.NUM_LITERAL;
               }
            }
            break;
      }
The var4glType is different from literalType only when:
  • it is recid, so the variable type will be num.
  • it is compared with a field type (aka tt.f1 kind of syntax).

In all other cases, literalType and var4glType will match. So I suggest having this switch-case from injectVariable fine tuned.

Please investigate why tt.f1 = LENGTH('abc') is hitting the switch-case, making var4glType different from literalType.

#26 Updated by Ovidiu Maxiniuc over 1 year ago

Alexandru Lungu wrote:

Ovidiu, the work-flow of static and dynamic queries in FWD differs a bit, especially through DynamicQueryHelper. for each tt where tt.f1 = 1 has different Java outputs in static conversion vs dynamic conversion.
  • static conversion will generate tt.f1 = 1 where clause.
  • dynamic conversion will generate tt.f1 = ? where clause and a fabricated x will be used as substitution parameter.
Actually, the conversion is the same. The difference you see is due to intermediary-processing (extractParams() / injectVariable()) executed on the AST tree. At any rate, this processing maintains the expression validity by keeping the same type of the literal for the new substitution variable. When the type-checking occurs in TRPL (after the injection, I admit) it should realize the incorrect match and report as an error (223). This would throw an exception which will either:
  • stop the static conversion (or at least log a serious warning) or
  • be caught by dynamic query helper and raise a runtime error condition and return false.

The _poly case, by its nature, is resolved at runtime in 4GL as well. We will do this likewise.

This is the ideal/general way to fix the problem. As a temporary short-cut we can check the compatibility of operand types in a quick pass for a set of operators. In my testcase, for = operator, since type(c1) differs from type(length(...)) error 223 should be raised, regardless of the parameters of length. In fact, this is just a fragment of the final solution, where the types of functions/methods/object methods will have to be checked based on their signature. Yet, IIRC, I think we are doing this at some point during conversion, but probably the algorithm is not covering all the cases.

#27 Updated by Greg Shah over 1 year ago

My conclusion is that we need to add the full type checking during standard conversion with error reporting if we want to have a fully compatible runtime for dynamic queries (and not only).

We will indeed be doing this, but not in this task. See #3882 which is itself dependent upon other rework like #1757.

#28 Updated by Dănuț Filimon over 1 year ago

  • % Done changed from 100 to 80
  • Status changed from Review to WIP

Resuming work for #9396-25.

#29 Updated by Dănuț Filimon over 1 year ago

Alexandru Lungu wrote:

Please investigate why tt.f1 = LENGTH('abc') is hitting the switch-case, making var4glType different from literalType.

This does not happen, the literal type remains STRING. Do you have an example where this happens?
Scenario:
  • 9396a/15582: Reaches DynamicConversionHelper.injectVariable(), in step 2 the var4glType is assigned a STRING and the switch case is not hit.
  • 9396a/15588: Reaches DynamicConversionHelper.isComplexVariableInjection(), the ast.getType() is STRING and does not change.

#30 Updated by Alexandru Lungu over 1 year ago

Danut, I am trying to drag the discussion to the point where proving that the error occurs only when var4glType and literalType are different. You stated in #9396-13 that the example with LENGTH should fail - this means that var4glType and literalType are different, right?

#31 Updated by Dănuț Filimon over 1 year ago

Alexandru Lungu wrote:

Danut, I am trying to drag the discussion to the point where proving that the error occurs only when var4glType and literalType are different. You stated in #9396-13 that the example with LENGTH should fail - this means that var4glType and literalType are different, right?

var4glType and literalType should be different indeed.

#32 Updated by Dănuț Filimon over 1 year ago

I thought about this and found that we have a map storing function definitions in SignatureHelper (map_func), this can get the return type needed to check against the other side of the operation. But a better idea is to check this in DynamicQueryHelper.extractParams() when iterating the literals by taking a look at the parent and checking if it's a function available in the map_func.

Also available in: Atom PDF