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

93.25% Statements 83/89
78.04% Branches 32/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 110x 110x 110x 110x 110x 3x 3x 3x 107x 110x     107x 110x 99x 122x 99x 99x 99x 122x 99x 99x 99x 107x 107x 110x 8x 8x 107x 110x 110x 86x 86x 86x 86x 86x 86x 1x 86x 85x   85x 85x   85x 85x 1x 85x 84x 84x 2x 84x 82x 82x     86x 4x 4x 86x 110x 1x 1x 86x 89x 89x 10x 10x 89x 76x 76x 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;
  }
 
}