Skip to content

TFunctionCall

Overview

The TFunctionCall node represents all types of function calls in SQL, from simple built-in functions to complex analytical functions with window specifications. It handles various function syntaxes and database-specific extensions.

Function Categories

Standard Functions

1
2
3
4
5
6
7
8
9
-- Scalar functions
UPPER('hello')
SUBSTRING('text', 1, 2)
COALESCE(col1, col2, 'default')

-- Aggregate functions
COUNT(*)
SUM(amount)
AVG(price)

Analytical Functions

1
2
3
4
-- Window functions
ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary)
RANK() OVER (ORDER BY score DESC)
LAG(price, 1) OVER (ORDER BY date)

Special Syntax Functions

1
2
3
4
5
6
7
8
-- CAST function
CAST(column AS VARCHAR(50))

-- EXTRACT function
EXTRACT(YEAR FROM date_column)

-- TRIM function
TRIM(BOTH ' ' FROM text_column)

Key Properties

Property Type Description Access Method
functionName TObjectName Function name getFunctionName()
args TExpressionList Function arguments getArgs()
functionType EFunctionType Type of function getFunctionType()
windowDef TWindowDef Window specification getWindowDef()
aggregateType EAggregateType Aggregate type getAggregateType()

Function Types

The EFunctionType enum categorizes different function syntaxes:

Type Description Example
udf_t User-defined or standard function UPPER(name)
cast_t CAST function CAST(id AS VARCHAR)
extract_t EXTRACT function EXTRACT(YEAR FROM date)
trim_t TRIM function TRIM(' ' FROM text)
convert_t CONVERT function CONVERT(VARCHAR, id)
contains_t SQL Server CONTAINS CONTAINS(text, 'search')
substring_t SUBSTRING function SUBSTRING(text, 1, 5)

Common Usage Patterns

Basic Function Analysis

 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
public void analyzeFunctionCall(TFunctionCall func) {
    System.out.println("Function: " + func.getFunctionName().toString());
    System.out.println("Type: " + func.getFunctionType());

    // Check if it's an aggregate function
    if (func.getAggregateType() != EAggregateType.none) {
        System.out.println("Aggregate type: " + func.getAggregateType());
    }

    // Analyze arguments
    TExpressionList args = func.getArgs();
    if (args != null) {
        System.out.println("Arguments (" + args.size() + "):");
        for (int i = 0; i < args.size(); i++) {
            TExpression arg = args.getExpression(i);
            System.out.println("  Arg " + (i + 1) + ": " + arg.toString());
        }
    }

    // Check for window specification
    if (func.getWindowDef() != null) {
        System.out.println("Window function detected");
        analyzeWindowSpecification(func.getWindowDef());
    }
}

Window Function Analysis

 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
public void analyzeWindowFunction(TFunctionCall func) {
    if (func.getWindowDef() == null) {
        System.out.println("Not a window function");
        return;
    }

    TWindowDef windowDef = func.getWindowDef();
    System.out.println("Window function: " + func.getFunctionName());

    // Analyze PARTITION BY
    if (windowDef.getPartitionClause() != null) {
        TExpressionList partitions = windowDef.getPartitionClause().getExpressionList();
        System.out.println("PARTITION BY:");
        for (int i = 0; i < partitions.size(); i++) {
            System.out.println("  " + partitions.getExpression(i).toString());
        }
    }

    // Analyze ORDER BY
    if (windowDef.getOrderByClause() != null) {
        TOrderByItemList orderItems = windowDef.getOrderByClause().getItems();
        System.out.println("ORDER BY:");
        for (int i = 0; i < orderItems.size(); i++) {
            TOrderByItem item = orderItems.getOrderByItem(i);
            System.out.println("  " + item.getSortKey().toString() + 
                " " + item.getSortType());
        }
    }

    // Analyze window frame
    if (windowDef.getWindowFrame() != null) {
        TWindowFrame frame = windowDef.getWindowFrame();
        System.out.println("Frame: " + frame.getFrameType() + 
            " BETWEEN " + frame.getStartBoundary() + 
            " AND " + frame.getEndBoundary());
    }
}

Special Function Handling

 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
public void analyzeSpecialFunctions(TFunctionCall func) {
    switch (func.getFunctionType()) {
        case cast_t:
            System.out.println("CAST function:");
            System.out.println("  Expression: " + func.getExpr1().toString());
            System.out.println("  Target type: " + func.getTypename().toString());
            break;

        case extract_t:
            System.out.println("EXTRACT function:");
            System.out.println("  Time part: " + func.getExtract_time_token().toString());
            System.out.println("  From expression: " + func.getExpr1().toString());
            break;

        case trim_t:
            System.out.println("TRIM function:");
            TTrimArgument trimArg = func.getTrimArgument();
            if (trimArg != null) {
                System.out.println("  Trim type: " + trimArg.getTrimType());
                System.out.println("  Trim character: " + trimArg.getTrimCharacter());
                System.out.println("  Source: " + trimArg.getStringExpression());
            }
            break;

        case substring_t:
            System.out.println("SUBSTRING function:");
            System.out.println("  Source: " + func.getSourceExpression());
            System.out.println("  Start: " + func.getStartExpression());
            if (func.getLengthExpression() != null) {
                System.out.println("  Length: " + func.getLengthExpression());
            }
            break;
    }
}

Function Dependency Analysis

 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
public Set<String> getFunctionDependencies(TFunctionCall func) {
    Set<String> dependencies = new HashSet<>();

    // Add function name as dependency
    dependencies.add(func.getFunctionName().toString());

    // Analyze arguments for column references
    TExpressionList args = func.getArgs();
    if (args != null) {
        for (int i = 0; i < args.size(); i++) {
            TExpression arg = args.getExpression(i);
            dependencies.addAll(extractColumnReferences(arg));
        }
    }

    // Handle special function expressions
    if (func.getExpr1() != null) {
        dependencies.addAll(extractColumnReferences(func.getExpr1()));
    }
    if (func.getExpr2() != null) {
        dependencies.addAll(extractColumnReferences(func.getExpr2()));
    }

    // Window function dependencies
    if (func.getWindowDef() != null) {
        dependencies.addAll(getWindowDependencies(func.getWindowDef()));
    }

    return dependencies;
}

Database-Specific Functions

SQL Server

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
-- Full-text search
CONTAINS(description, 'search terms')
FREETEXT(content, 'free text search')

-- Conversion functions
CONVERT(VARCHAR(10), date_col, 101)
TRY_CAST(string_col AS INT)

-- String functions
STRING_AGG(name, ', ') WITHIN GROUP (ORDER BY name)

Access via: - getColumnNameOrListExpression() - CONTAINS/FREETEXT column - getSearchCondition() - Search condition - getTypename() - CONVERT target type - getStyle() - CONVERT style parameter

Oracle

1
2
3
4
5
6
7
-- XML functions
EXTRACT(xml_col, '/root/element')
XMLQUERY('//element' PASSING xml_col RETURNING CONTENT)

-- Analytical functions
LISTAGG(name, ', ') WITHIN GROUP (ORDER BY name)
RANK() OVER (ORDER BY salary DESC)

Access via: - getXMLType_Instance() - XML instance - getXPath_String() - XPath expression - getWithinGroup() - WITHIN GROUP clause

PostgreSQL

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
-- Array functions
ARRAY_AGG(column ORDER BY column)
UNNEST(array_column)

-- JSON functions
JSON_EXTRACT_PATH(json_col, 'key')
JSONB_PATH_QUERY(jsonb_col, '$.path')

-- Window functions with filter
COUNT(*) FILTER (WHERE condition) OVER (...)

Access via: - getFilterClause() - FILTER clause - getOrderByList() - ORDER BY in aggregates

MySQL

1
2
3
4
5
6
7
-- String functions
GROUP_CONCAT(name ORDER BY name SEPARATOR ', ')
MATCH(title, content) AGAINST ('search terms')

-- Date functions
DATE_ADD(date_col, INTERVAL 1 DAY)
TIMESTAMPDIFF(DAY, start_date, end_date)

Access via: - getGroupConcatParam() - GROUP_CONCAT parameters - getMatchColumns() - MATCH columns - getAgainstExpr() - AGAINST expression

Performance Considerations

Function Classification

 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
public void classifyFunctionPerformance(TFunctionCall func) {
    String funcName = func.getFunctionName().toString().toUpperCase();

    // Deterministic vs non-deterministic
    if (isDeterministic(funcName)) {
        System.out.println("Deterministic function - can be optimized");
    } else {
        System.out.println("Non-deterministic function - limited optimization");
    }

    // Scalar vs aggregate
    if (func.getAggregateType() != EAggregateType.none) {
        System.out.println("Aggregate function - requires grouping");
    }

    // Window function performance
    if (func.getWindowDef() != null) {
        analyzeWindowPerformance(func.getWindowDef());
    }
}

private boolean isDeterministic(String funcName) {
    Set<String> nonDeterministic = Set.of(
        "RAND", "RANDOM", "NOW", "GETDATE", "CURRENT_TIMESTAMP",
        "NEWID", "UUID", "SYSDATE"
    );
    return !nonDeterministic.contains(funcName);
}

Window Function Optimization

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public void analyzeWindowPerformance(TWindowDef windowDef) {
    // Check for expensive operations
    if (windowDef.getPartitionClause() != null) {
        int partitionCount = windowDef.getPartitionClause().getExpressionList().size();
        if (partitionCount > 3) {
            System.out.println("WARNING: Many partition columns may impact performance");
        }
    }

    // Frame analysis
    if (windowDef.getWindowFrame() != null) {
        TWindowFrame frame = windowDef.getWindowFrame();
        if (frame.getFrameType() == EFrameType.RANGE) {
            System.out.println("RANGE frame - may be slower than ROWS frame");
        }
    }
}

Built-in Function Detection

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public boolean isBuiltInFunction(TFunctionCall func, EDbVendor dbVendor) {
    // Use built-in detection
    return func.isBuiltIn(dbVendor);
}

public void categorizeFunction(TFunctionCall func, EDbVendor dbVendor) {
    if (func.isBuiltIn(dbVendor)) {
        System.out.println("Built-in function");
    } else {
        System.out.println("User-defined function");

        // Check if it's a table function
        if (isTableFunction(func, dbVendor)) {
            System.out.println("Table-valued function");
        }
    }
}

See Also