Skip to content

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

1
SELECT * FROM users;

AST Structure:

1
2
3
TFromClause
└── relations: ArrayList<TTable>
    └── TTable (users)

Multiple tables (comma-separated)

1
SELECT * FROM users, orders, products;

AST Structure:

1
2
3
4
5
TFromClause
└── relations: ArrayList<TTable>
    ├── TTable (users)
    ├── TTable (orders)
    └── TTable (products)

FROM with JOINs

1
2
3
4
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:

1
2
3
4
5
TFromClause
└── relations: ArrayList<TTable>
    ├── TTable (users u)
    ├── TTable (orders o) [via JOIN]
    └── TTable (addresses a) [via JOIN]

FROM with subquery

1
2
3
4
5
SELECT * FROM (
    SELECT customer_id, SUM(amount) as total
    FROM orders 
    GROUP BY customer_id
) AS customer_totals;

AST Structure:

1
2
3
4
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;
        }
    }
}

Extracting All Table Names

 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

1
2
3
FROM users
FROM schema.table_name
FROM database.schema.table_name

Derived Tables (Subqueries)

1
FROM (SELECT * FROM users WHERE active = 1) AS active_users

Table Functions

1
2
3
4
5
-- SQL Server
FROM OPENROWSET('SQLNCLI', 'connection_string', 'query')

-- PostgreSQL
FROM unnest(ARRAY[1,2,3]) AS t(id)

Common Table Expressions (CTEs)

1
2
3
4
5
6
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

1
2
3
4
5
6
7
-- 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

1
2
3
4
5
6
-- 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

1
2
3
4
5
6
7
-- 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

1
2
3
4
-- Index hints
FROM users USE INDEX (idx_name)
FROM users FORCE INDEX (idx_name)
FROM users IGNORE INDEX (idx_name)

Performance Considerations

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