TFromClause
Overview
The TFromClause
node represents FROM clauses in SQL statements. It contains the collection of table references and data sources that provide the input data for queries.
SQL to AST Mapping
Simple FROM clause
AST Structure:
| TFromClause
└── relations: ArrayList<TTable>
└── TTable (users)
|
Multiple tables (comma-separated)
| SELECT * FROM users, orders, products;
|
AST Structure:
| TFromClause
└── relations: ArrayList<TTable>
├── TTable (users)
├── TTable (orders)
└── TTable (products)
|
FROM with JOINs
| SELECT u.name, o.total
FROM users u
INNER JOIN orders o ON u.id = o.user_id
LEFT JOIN addresses a ON u.id = a.user_id;
|
AST Structure:
| TFromClause
└── relations: ArrayList<TTable>
├── TTable (users u)
├── TTable (orders o) [via JOIN]
└── TTable (addresses a) [via JOIN]
|
FROM with subquery
| SELECT * FROM (
SELECT customer_id, SUM(amount) as total
FROM orders
GROUP BY customer_id
) AS customer_totals;
|
AST Structure:
| TFromClause
└── relations: ArrayList<TTable>
└── TTable (derived table)
└── subQuery: TSelectSqlStatement
|
Key Properties
Property |
Type |
Description |
Access Method |
relations |
ArrayList<TTable> |
List of table references |
getRelations() |
Common Usage Patterns
Iterating Through Tables
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 analyzeFromClause(TFromClause fromClause) {
if (fromClause == null) {
System.out.println("No FROM clause");
return;
}
ArrayList<TTable> relations = fromClause.getRelations();
System.out.println("Tables in FROM clause:");
for (TTable table : relations) {
System.out.println(" Table: " + table.getFullName());
// Check for alias
if (table.getAliasClause() != null) {
System.out.println(" Alias: " + table.getAliasName());
}
// Check table type
switch (table.getTableType()) {
case objectname:
System.out.println(" Type: Regular table");
break;
case subquery:
System.out.println(" Type: Derived table (subquery)");
break;
case function:
System.out.println(" Type: Table function");
break;
case join:
System.out.println(" Type: Join expression");
break;
}
}
}
|
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 | public Set<String> getAllTableNames(TFromClause fromClause) {
Set<String> tableNames = new HashSet<>();
if (fromClause != null) {
for (TTable table : fromClause.getRelations()) {
// Get base table name
if (table.getTableName() != null) {
tableNames.add(table.getFullName());
}
// Handle derived tables (subqueries)
if (table.getTableType() == ETableSource.subquery &&
table.getSubquery() != null) {
// Recursively extract tables from subquery
extractTablesFromSubquery(table.getSubquery(), tableNames);
}
// Handle table functions
if (table.getTableType() == ETableSource.function &&
table.getFuncCall() != null) {
tableNames.add(table.getFuncCall().getFunctionName().toString());
}
}
}
return tableNames;
}
|
Building Table Lineage
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 Map<String, TableInfo> buildTableLineage(TFromClause fromClause) {
Map<String, TableInfo> lineage = new HashMap<>();
if (fromClause != null) {
for (TTable table : fromClause.getRelations()) {
TableInfo info = new TableInfo();
info.tableName = table.getFullName();
info.alias = table.getAliasName();
info.tableType = table.getTableType();
// For derived tables, capture the source query
if (table.getTableType() == ETableSource.subquery) {
info.sourceQuery = table.getSubquery();
info.sourceTables = extractTablesFromSubquery(table.getSubquery());
}
lineage.put(info.getEffectiveName(), info);
}
}
return lineage;
}
class TableInfo {
String tableName;
String alias;
ETableSource tableType;
TSelectSqlStatement sourceQuery;
Set<String> sourceTables;
String getEffectiveName() {
return alias != null ? alias : tableName;
}
}
|
Analyzing Join Relationships
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 | public void analyzeJoinRelationships(TFromClause fromClause) {
if (fromClause == null) return;
ArrayList<TTable> relations = fromClause.getRelations();
for (TTable table : relations) {
if (table.getTableType() == ETableSource.join &&
table.getJoinExpr() != null) {
TJoinExpr joinExpr = table.getJoinExpr();
System.out.println("Join detected:");
System.out.println(" Type: " + joinExpr.getJoinType());
// Analyze join conditions
if (joinExpr.getJoinItems() != null) {
for (int i = 0; i < joinExpr.getJoinItems().size(); i++) {
TJoinItem joinItem = joinExpr.getJoinItems().getJoinItem(i);
if (joinItem.getOnCondition() != null) {
System.out.println(" ON condition: " +
joinItem.getOnCondition().toString());
}
if (joinItem.getUsingColumns() != null) {
System.out.println(" USING columns: " +
joinItem.getUsingColumns().toString());
}
}
}
}
}
}
|
Table Types in FROM Clause
Regular Tables
| FROM users
FROM schema.table_name
FROM database.schema.table_name
|
Derived Tables (Subqueries)
| FROM (SELECT * FROM users WHERE active = 1) AS active_users
|
Table Functions
| -- SQL Server
FROM OPENROWSET('SQLNCLI', 'connection_string', 'query')
-- PostgreSQL
FROM unnest(ARRAY[1,2,3]) AS t(id)
|
Common Table Expressions (CTEs)
| WITH user_stats AS (
SELECT user_id, COUNT(*) as order_count
FROM orders
GROUP BY user_id
)
SELECT * FROM user_stats;
|
Database-Specific Features
SQL Server
| -- Table hints
FROM users WITH (NOLOCK)
FROM users WITH (INDEX=ix_users_name)
-- APPLY operators
FROM users u
CROSS APPLY (SELECT TOP 3 * FROM orders WHERE user_id = u.id) o
|
PostgreSQL
| -- LATERAL joins
FROM users u,
LATERAL (SELECT * FROM orders WHERE user_id = u.id) o
-- Table functions
FROM generate_series(1, 10) AS t(id)
|
Oracle
| -- Flashback queries
FROM users AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '1' HOUR)
-- Hierarchical queries
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id
|
MySQL
| -- Index hints
FROM users USE INDEX (idx_name)
FROM users FORCE INDEX (idx_name)
FROM users IGNORE INDEX (idx_name)
|
Join Order Analysis
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | public void analyzeJoinOrder(TFromClause fromClause) {
if (fromClause == null) return;
ArrayList<TTable> relations = fromClause.getRelations();
// Analyze table order for join optimization
for (int i = 0; i < relations.size(); i++) {
TTable table = relations.get(i);
// Estimate table size (would need statistics)
long estimatedRows = estimateTableSize(table);
if (i == 0 && estimatedRows > 1000000) {
System.out.println("WARNING: Large table (" + table.getFullName() +
") as driving table may impact performance");
}
}
}
|
Cartesian Product Detection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | public boolean hasCartesianProduct(TFromClause fromClause) {
if (fromClause == null) return false;
ArrayList<TTable> relations = fromClause.getRelations();
// If multiple tables without explicit joins, check for join conditions
if (relations.size() > 1) {
boolean hasJoinConditions = false;
for (TTable table : relations) {
if (table.getTableType() == ETableSource.join) {
hasJoinConditions = true;
break;
}
}
return !hasJoinConditions;
}
return false;
}
|
Attribute Collection
The TFromClause
implements IRelation
interface and provides attribute collection:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | // Collect all available attributes from tables in FROM clause
public void analyzeAvailableAttributes(TFromClause fromClause) {
if (fromClause == null) return;
// Trigger attribute collection
fromClause.collectAttributes();
// Get all attributes
ArrayList<TAttributeNode> attributes = fromClause.getAttributes();
System.out.println("Available attributes:");
for (TAttributeNode attr : attributes) {
System.out.println(" " + attr.getName() +
" (from " + attr.getSourceTable() + ")");
}
}
|
See Also