All files / src/abap/5_syntax/expressions sql_compare.ts

92.13% Statements 82/89
75% Branches 30/40
100% Functions 2/2
92.13% Lines 82/89

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 891x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 75x 75x 75x 75x 75x 3x 3x 3x 72x 75x     72x 75x 65x 83x 65x 65x 65x 83x 65x 65x 65x 72x 72x 75x 7x 7x 72x 75x 75x 56x 56x 56x 56x 56x 56x 1x 56x 55x   55x 55x   55x 55x   55x 55x 55x 2x 55x 53x 53x     56x 3x 3x 56x 75x 1x 1x 56x 59x 59x 8x 8x 59x 48x 48x 1x 1x
import {AbstractToken} from "../../1_lexer/tokens/abstract_token";
import * as Expressions from "../../2_statements/expressions";
import {ExpressionNode, StatementNode} from "../../nodes";
import {CharacterType, IntegerType, NumericType, StructureType} from "../../types/basic";
import {AbstractType} from "../../types/basic/_abstract_type";
import {CurrentScope} from "../_current_scope";
import {SyntaxInput} from "../_syntax_input";
import {DatabaseTableSource} from "./database_table";
import {Dynamic} from "./dynamic";
import {Source} from "./source";
import {SQLIn} from "./sql_in";
import {SQLSource} from "./sql_source";
 
export class SQLCompare {
 
  public runSyntax(node: ExpressionNode | StatementNode, input: SyntaxInput, tables: DatabaseTableSource[]): void {
 
    let sourceType: AbstractType | undefined;
    let token: AbstractToken | undefined;
 
    if (node.getFirstChild()?.get() instanceof Expressions.Dynamic) {
      new Dynamic().runSyntax(node.getFirstChild() as ExpressionNode, input);
      return;
    }
 
    for (const s of node.findDirectExpressions(Expressions.SimpleSource3)) {
      new Source().runSyntax(s, input);
    }
 
    for (const s of node.findDirectExpressions(Expressions.SQLSource)) {
      for (const child of s.getChildren()) {
        if (child instanceof ExpressionNode) {
          token = child.getFirstToken();
          break;
        }
      }
 
      sourceType = new SQLSource().runSyntax(s, input);
    }
 
    const sqlin = node.findDirectExpression(Expressions.SQLIn);
    if (sqlin) {
      new SQLIn().runSyntax(sqlin, input);
    }
 
    const fieldName = node.findDirectExpression(Expressions.SQLFieldName)?.concatTokens();
    if (fieldName && sourceType && token) {
// check compatibility for rule sql_value_conversion
      const targetType = this.findType(fieldName, tables, input.scope);
 
      let message = "";
      if (sourceType instanceof IntegerType
          && targetType instanceof CharacterType) {
        message = "Integer to CHAR conversion";
      } else if (sourceType instanceof IntegerType
          && targetType instanceof NumericType) {
        message = "Integer to NUMC conversion";
      } else if (sourceType instanceof NumericType
          && targetType instanceof IntegerType) {
        message = "NUMC to Integer conversion";
      } else if (sourceType instanceof CharacterType
          && targetType instanceof IntegerType) {
        message = "CHAR to Integer conversion";
      } else if (sourceType instanceof CharacterType
          && targetType instanceof CharacterType
          && sourceType.getLength() > targetType.getLength()) {
        message = "Source field longer than database field, CHAR -> CHAR";
      } else if (sourceType instanceof NumericType
          && targetType instanceof NumericType
          && sourceType.getLength() > targetType.getLength()) {
        message = "Source field longer than database field, NUMC -> NUMC";
      }
      if (message !== "") {
        input.scope.addSQLConversion(fieldName, message, token);
      }
    }
  }
 
  private findType(fieldName: string, tables: DatabaseTableSource[], scope: CurrentScope): AbstractType | undefined {
    for (const t of tables) {
      const type = t?.parseType(scope.getRegistry());
      if (type instanceof StructureType) {
        return type.getComponentByName(fieldName);
      }
    }
    return undefined;
  }
 
}