Table-valued functions in SQL Lineage
Note
This guide assumes you already know how query buckets and system routine analysis work.
What table-valued functions are, and how Blindata supports them
A table-valued function (TVF) is a database function that returns a set of rows, so SQL can use it in the FROM clause like a table:
INSERT INTO dest
SELECT sensor_id, reading
FROM analytics.readings_between(start_date, end_date);
Typical call shapes Blindata recognizes:
FROM schema.fn(...)(PostgreSQL, BigQuery, T-SQL)FROM TABLE(fn(...))(Oracle, T-SQL)FROM LATERAL fn(...),CROSS JOIN LATERAL,CROSS APPLY/OUTER APPLY- Hive
LATERAL VIEW my_tvf(...) t AS ... - Piped
CALLof a function
UNNEST, Hive explode, and similar generators are not matched to system routines. They do not have a catalogued SQL body to compose: they expand a collection that is already in the query (an array, struct, or column). Lineage therefore follows that input expression into the alias columns the generator produces.
When Blindata can match the call to a system routine, it:
- Treats the function result as a dedicated node in Full Lineage (not as a missing table).
- Composes the analyzed SQL inside that routine into the caller, so source tables used inside the function appear in the caller’s lineage and data flows.
- Wires call-site arguments to the routine Parameters (by position, or by name when every argument is named).
Tip
Cataloguing or re-analyzing the function does not rewrite callers by itself. Refresh the calling statements (or the bucket) after the routine is ready.
How to set up Blindata to analyze TVFs
Do this in order. Each step is documented on its own page — follow those guides rather than duplicating the forms here.
-
Put the function in the catalog as a system routine : crawl it or create it manually. Name and schema must match the SQL call.
-
Store an analyzable body and parameters. Routine Definition must be the SQL that produces the result (
SELECT,WITH … SELECT, and similar), not a vendorCREATE FUNCTIONwrapper. Fill Parameters (or crawlROUTINE_PARAMETERS). Crawl aliases and vendor examples: Import Metadata with SQL or JDBC . -
Analyze the routine so Blindata can persist its output columns. Use ANALYZE ALL or automatic analysis from the bucket: Analyze SQL Script or Routines .
-
Analyze the callers in a query bucket whose Systems list includes the routine’s system. Leave Disable table-valued functions off under System Routines analysis settings. Then insert or refresh the statements that call the function.
The output columns used at lookup come from that routine analysis (typically the SELECT list), not from a RETURNS TABLE (...) clause in DDL.
Expected output of the analysis
Use this as a verification checklist.
On the system routine
- Status is Analyzed (not Pending or Error).
- Parameters lists the bind arguments, for example
(start_date DATE, end_date DATE). - The SQL Lineage tab shows the extracted body statement(s).
On the calling statement
- Status is Analyzed when every table and TVF in the SQL was resolved. Partially Analyzed means at least one catalog object is still missing — including an unresolved function.
- Full Lineage is available for Analyzed and Partially Analyzed statements.
In Full Lineage
| What you see | Meaning |
|---|---|
| Purple function node | The call matched a unique analyzed routine. The body is composed into this chart. |
| Edges into the purple node | Call-site arguments bound to parameters. |
| Edges out of the purple node, plus tables from inside the function | Body lineage is inlined. Those inner tables can appear in data flow previews. |
| Blue table nodes | Catalog tables (caller or function body). |
| Orange table or function node | Not found, or the function could not be uniquely resolved. |
Right-click a purple node: header System Routine, then Name opens the routine. Orange function nodes have no such menu.
Repeated calls in one statement (FROM fn(a.x), fn(b.y)) stay as separate purple nodes so arguments do not mix.
Troubleshooting
| You see | Likely cause | What to do |
|---|---|---|
| Orange function node; statement Partially Analyzed | The call did not bind to a unique analyzed routine. Most often the crawl (or manual create) did not load what Blindata needs to resolve it. | On the system routine
, check name and schema against the SQL call, Parameters are populated, Routine Definition is the function body (not CREATE FUNCTION DDL), and status is Analyzed. If you crawl, verify the Routines Query
aliases: ROUTINE_NAME, ROUTINE_SCHEMA, ROUTINE_DEFINITION, and ROUTINE_PARAMETERS. Then refresh the caller. Overloads (same catalog/schema/name more than once in the bucket) also stay unresolved until only one match remains. |
| Routine Error / no SQL Lineage statements | Routine Definition is full CREATE FUNCTION DDL, or the body is not SQL Blindata can extract |
Store the analyzable body only. See routines . |
| Purple node, but arguments do not reach the body | Parameters missing or names/order do not match the call | Edit Parameters or crawl ROUTINE_PARAMETERS, then refresh the caller. Outputs can still compose without parameters. |
| Function never resolves | Disable table-valued functions is on | Turn it off on the bucket (Analyze SQL statements ). |
| Inner tables missing after you fixed the routine | Caller was analyzed before the routine was ready | Refresh the calling statement. Full Lineage uses the current routine graph; saved data flows still follow the usual create/refresh rules. |
| Nested TVFs stop expanding | Safety limit on how many routine statements are inlined | Expected for very deep or cyclic routine graphs; the outer call can still resolve. |
Related guides: Analyze SQL statements , Analyze SQL Script or Routines , Routines, Scripts, Stored Procedures , Import Metadata with SQL or JDBC .