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
| -- Scalar functions
UPPER('hello')
SUBSTRING('text', 1, 2)
COALESCE(col1, col2, 'default')
-- Aggregate functions
COUNT(*)
SUM(amount)
AVG(price)
|
Analytical Functions
| -- 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
| -- 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
| -- 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
| -- 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
| -- 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
| -- 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
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