%YAML 1.2
---
scalar_functions:
  -
    name: "add"
    description: "Add two decimal values."
    impls:
      - args:
          - name: x
            value: decimal<P1,S1>
          - name: y
            value: decimal<P2,S2>
        options:
          overflow:
            values: [ SILENT, SATURATE, ERROR ]
        return: |-
          init_scale = max(S1,S2)
          init_prec = init_scale + max(P1 - S1, P2 - S2) + 1
          min_scale = min(init_scale, 6)
          delta = init_prec - 38
          prec = min(init_prec, 38)
          scale_after_borrow = max(init_scale - delta, min_scale)
          scale = init_prec > 38 ? scale_after_borrow : init_scale
          DECIMAL<prec, scale>
  -
    name: "subtract"
    impls:
      - args:
          - name: x
            value: decimal<P1,S1>
          - name: y
            value: decimal<P2,S2>
        options:
          overflow:
            values: [ SILENT, SATURATE, ERROR ]
        return: |-
          init_scale = max(S1,S2)
          init_prec = init_scale + max(P1 - S1, P2 - S2) + 1
          min_scale = min(init_scale, 6)
          delta = init_prec - 38
          prec = min(init_prec, 38)
          scale_after_borrow = max(init_scale - delta, min_scale)
          scale = init_prec > 38 ? scale_after_borrow : init_scale
          DECIMAL<prec, scale>
  -
    name: "multiply"
    impls:
      - args:
          - name: x
            value: decimal<P1,S1>
          - name: y
            value: decimal<P2,S2>
        options:
          overflow:
            values: [ SILENT, SATURATE, ERROR ]
        return: |-
          init_scale = S1 + S2
          init_prec = P1 + P2 + 1
          min_scale = min(init_scale, 6)
          delta = init_prec - 38
          prec = min(init_prec, 38)
          scale_after_borrow = max(init_scale - delta, min_scale)
          scale = init_prec > 38 ? scale_after_borrow : init_scale
          DECIMAL<prec, scale>
  -
    name: "divide"
    impls:
      - args:
          - name: x
            value: decimal<P1,S1>
          - name: y
            value: decimal<P2,S2>
        options:
          overflow:
            values: [ SILENT, SATURATE, ERROR ]
        return: |-
          init_scale = max(6, S1 + P2 + 1)
          init_prec = P1 - S1 + P2 + init_scale
          min_scale = min(init_scale, 6)
          delta = init_prec - 38
          prec = min(init_prec, 38)
          scale_after_borrow = max(init_scale - delta, min_scale)
          scale = init_prec > 38 ? scale_after_borrow : init_scale
          DECIMAL<prec, scale>
  -
    name: "modulus"
    impls:
      - args:
          - name: x
            value: decimal<P1,S1>
          - name: y
            value: decimal<P2,S2>
        options:
          overflow:
            values: [ SILENT, SATURATE, ERROR ]
        return: |-
          init_scale = max(S1,S2)
          init_prec = min(P1 - S1, P2 - S2) + init_scale
          min_scale = min(init_scale, 6)
          delta = init_prec - 38
          prec = min(init_prec, 38)
          scale_after_borrow = max(init_scale - delta, min_scale)
          scale = init_prec > 38 ? scale_after_borrow : init_scale
          DECIMAL<prec, scale>
  -
    name: "abs"
    description: Calculate the absolute value of the argument.
    impls:
      - args:
          - name: x
            value: decimal<P,S>
        return: decimal<P,S>
  - name: "bitwise_and"
    description: >
      Return the bitwise AND result for two decimal inputs.
      In inputs scale must be 0 (i.e. only integer types are allowed)
    impls:
      - args:
          - name: x
            value: "DECIMAL<P1,0>"
          - name: y
            value: "DECIMAL<P2,0>"
        return: |-
          max_precision = max(P1, P2)
          DECIMAL<max_precision, 0>
  - name: "bitwise_or"
    description: >
      Return the bitwise OR result for two given decimal inputs.
      In inputs scale must be 0 (i.e. only integer types are allowed)
    impls:
      - args:
          - name: x
            value: "DECIMAL<P1,0>"
          - name: y
            value: "DECIMAL<P2,0>"
        return: |-
          max_precision = max(P1, P2)
          DECIMAL<max_precision, 0>
  - name: "bitwise_xor"
    description: >
      Return the bitwise XOR result for two given decimal inputs.
      In inputs scale must be 0 (i.e. only integer types are allowed)
    impls:
      - args:
          - name: x
            value: "DECIMAL<P1,0>"
          - name: y
            value: "DECIMAL<P2,0>"
        return: |-
          max_precision = max(P1, P2)
          DECIMAL<max_precision, 0>
  - name: "sqrt"
    description: Square root of the value. Sqrt of 0 is 0 and sqrt of negative values will raise an error.
    impls:
      - args:
          - name: x
            value: "DECIMAL<P,S>"
        return: fp64
  - name: "factorial"
    description: >
      Return the factorial of a given decimal input. Scale should be 0 for factorial decimal input.
      The factorial of 0! is 1 by convention. Negative inputs will raise an error.
      Input which cause overflow of result will raise an error.
    impls:
      - args:
          - name: "n"
            value: "DECIMAL<P,0>"
        return: "DECIMAL<38,0>"
  -
    name: "power"
    description: "Take the power with x as the base and y as exponent.
    Behavior for complex number result is indicated by option complex_number_result"
    impls:
      - args:
          - name: x
            value: "DECIMAL<P1,S1>"
          - name: y
            value: "DECIMAL<P2,S2>"
        options:
          overflow:
            values: [ SILENT, SATURATE, ERROR ]
          complex_number_result:
            values: [ NAN, ERROR ]
        return: fp64

aggregate_functions:
  - name: "sum"
    description: Sum a set of values.
    impls:
      - args:
          - name: x
            value: "DECIMAL<P, S>"
        options:
          overflow:
            values: [ SILENT, SATURATE, ERROR ]
        nullability: DECLARED_OUTPUT
        decomposable: MANY
        intermediate: "DECIMAL?<38,S>"
        return: "DECIMAL?<38,S>"
  - name: "avg"
    description: Average a set of values.
    impls:
      - args:
          - name: x
            value: "DECIMAL<P,S>"
        options:
          overflow:
            values: [ SILENT, SATURATE, ERROR ]
        nullability: DECLARED_OUTPUT
        decomposable: MANY
        intermediate: "STRUCT<DECIMAL<38,S>,i64>"
        return: "DECIMAL<38,S>"
  - name: "min"
    description: Min a set of values.
    impls:
      - args:
          - name: x
            value: "DECIMAL<P, S>"
        nullability: DECLARED_OUTPUT
        decomposable: MANY
        intermediate: "DECIMAL?<P, S>"
        return: "DECIMAL?<P, S>"
  - name: "max"
    description: Max a set of values.
    impls:
      - args:
          - name: x
            value: "DECIMAL<P,S>"
        nullability: DECLARED_OUTPUT
        decomposable: MANY
        intermediate: "DECIMAL?<P, S>"
        return: "DECIMAL?<P, S>"
  - name: "sum0"
    description: >
      Sum a set of values. The sum of zero elements yields zero.

      Null values are ignored.
    impls:
      - args:
          - name: x
            value: "DECIMAL<P, S>"
        options:
          overflow:
            values: [ SILENT, SATURATE, ERROR ]
        nullability: DECLARED_OUTPUT
        decomposable: MANY
        intermediate: "DECIMAL<38,S>"
        return: "DECIMAL<38,S>"
