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

93.25% Statements 83/89
80.48% Branches 33/41
100% Functions 2/2
93.25% Lines 83/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 185x 185x 185x 185x 185x 13x 13x 13x 172x 185x     172x 185x 150x 196x 150x 150x 150x 196x 150x 150x 150x 172x 172x 185x 21x 21x 172x 185x 185x 126x 126x 126x 126x 126x 126x 1x 126x 125x   125x 125x   125x 125x 1x 125x 124x 124x 2x 124x 122x 122x     126x 4x 4x 126x 185x 1x 1x 126x 129x 129x 13x 13x 129x 113x 113x 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 static runSyntax(node: ExpressionNode | StatementNode, input: SyntaxInput, tables: DatabaseTableSource[]): void {
 
    let sourceType: AbstractType | undefined;
    let token: AbstractToken | undefined;
 
    if (node.getFirstChild()?.get() instanceof Expressions.Dynamic) {
      Dynamic.runSyntax(node.getFirstChild() as ExpressionNode, input);
      return;
    }
 
    for (const s of node.findDirectExpressions(Expressions.SimpleSource3)) {
      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 = SQLSource.runSyntax(s, input);
    }
 
    const sqlin = node.findDirectExpression(Expressions.SQLIn);
    if (sqlin) {
      SQLIn.runSyntax(sqlin, input);
    }
 
    const fieldName = node.findDirectExpression(Expressions.SQLFieldName)?.concatTokens().toUpperCase();
    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 = `${fieldName}: Integer to CHAR conversion`;
      } else if (sourceType instanceof IntegerType
          && targetType instanceof NumericType) {
        message = `${fieldName}: Integer to NUMC conversion`;
      } else if (sourceType instanceof NumericType
          && targetType instanceof IntegerType) {
        message = `${fieldName}: NUMC to Integer conversion`;
      } else if (sourceType instanceof CharacterType
          && targetType instanceof IntegerType) {
        message = `${fieldName}: CHAR to Integer conversion`;
      } else if (sourceType instanceof CharacterType
          && targetType instanceof CharacterType
          && sourceType.getLength() > targetType.getLength()) {
        message = `${fieldName}: Source field longer than database field, CHAR -> CHAR`;
      } else if (sourceType instanceof NumericType
          && targetType instanceof NumericType
          && sourceType.getLength() > targetType.getLength()) {
        message = `${fieldName}: Source field longer than database field, NUMC -> NUMC`;
      }
      if (message !== "") {
        input.scope.addSQLConversion(fieldName, message, token);
      }
    }
  }
 
  private static 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;
  }
 
}