Release Notes¶
GSP Java v3.x to v4 Migration Guide
Version history of general sql parser¶
GSP Java version 4.2.16(2026-10-12)¶
- 2026-10-11 Oracle, PostgreSQL and MySQL names follow the rules of the real servers (checked on Oracle 23.26, PostgreSQL 16.15 and MySQL 8.4.10). Oracle keeps
ßwhen it upper-cases an unquoted name:CREATE TABLE straßecreatesSTRAßE, soSELECT x FROM STRASSEreads another table, as Oracle's ORA-00942 shows. WithCREATE TABLE straße(x int); CREATE TABLE t(x int); INSERT INTO t SELECT x FROM STRASSE, lineage readstraße.xand now readsSTRASSE.x, a table the script does not create. PostgreSQL lower-cases onlyAtoZin an unquoted name and cuts names to 63 bytes: afterCREATE TABLE "Äbc"(x int),INSERT INTO t SELECT x FROM ÄBCnow reads"Äbc".x, where it read a separate tableÄBC, and Greek or Georgian capitals stay as written. MySQL compares table names by the simple lower-case mapping, column and index names the same way, and function, procedure and parameter names by the simple upper-case mapping: withlower_case_table_names=1,`İ`andiare one table,ςandσare two columns, andİandiare one column; index and parameter names ignore case whateverlower_case_table_namesis.IdentifierRules.CaseFoldhas three new values,UPPER_SIMPLE,LOWER_SIMPLEandLOWER_ASCII, andIdentifierRulestwo new fields,collapse(IdentifierRules.CaseCollapse) andmaxUtf8Bytes, set by a new six-argument constructor; the rules areIdentifierRules.forOracleNative(),forPostgreSQLNative(),forMySQLNative(int),forMySQLNativeColumn()andforMySQLNativeRoutine(). Greenplum, GaussDB, EDB, OceanBase, Doris, StarRocks, Dameng and the other dialects derived from these three keep their earlier rules. - 2026-10-11 SQL Server accent-insensitive collations make
caféandcafeone name. GSP compares with a table of accent equivalences measured on SQL Server 2022 forLatin1_General_CI_AI,Latin1_General_CS_AI,SQL_Latin1_General_CP1_CI_AI,Latin1_General_100_CI_AIandLatin1_General_100_CS_AI, with their_SCand_SC_UTF8variants; it treated_CS_AIas exact and did not equateøwitho,łwithl,đwithdorıwithiunder_CI_AI. Other_AIcollations are compared as before.IdentifierService.isCaseSensitive(ESQLDataObjectType)is new, and it,NameService.isCaseSensitiveandVendorNameMatcher.isCaseSensitivenow returntruefor_CS,_BINand_BIN2collations. - 2026-10-11 TSQLResolver2 looks names up with the
IdentifierProfilegiven toTGSqlParser.setIdentifierProfile, where some lookups used the vendor's default rules. WithLatin1_General_CI_AI,SELECT d.cafe FROM (SELECT 1 AS [café]) dresolves to[café](it wasNOT_FOUND); with MySQLlower_case_table_names=0,WITH c AS (SELECT 1 AS y), C AS (SELECT 2 AS y) SELECT y FROM CreadsC. - 2026-10-11
IdentifierService.keyForMapreturns keys that are equal exactly whenareEqualis true, for every vendor. The key is not a name: for SQL Server it is an encoded collation key, and a MySQL column key is lower case. Before, one SQL Server or MySQL column name could give two different keys. - 2026-10-11
IdentifierService.persistentKeyV1gives new policy IDs for Oracle, PostgreSQL and MySQL, because their rules changed (Oracle tablespk1-ry85qY4x...becamepk1-Yo5P1xXR...). A key saved by an earlier release for these three databases does not match a key of this release; make the keys again from the names. Keys of the other databases are unchanged. - 2026-10-10 SQL Server dynamic SQL whose table names come from a configuration table in the procedure gives lineage (Mantis 4962). A
#temptable or table variable that the procedure fills with literalINSERT ... VALUESrows is queried as SQL Server would query it:SELECT @target = raw_table FROM #registry WHERE pipeline_type = @pipeline_typereads the matching rows, with=,<>,<,>,<=,>=,IN,LIKE,IS [NOT] NULL,AND,OR,NOT,TOPandORDER BY. AfterINSERT INTO #registry VALUES ('Pipeline_TypeX', 'dbo.BIZ_RAW_X'), ('Pipeline_TypeY', 'dbo.BIZ_RAW_Y'), a procedure that runsSET @sql = 'BULK INSERT ' + @target + ' FROM ''' + @file + ''''andEXEC sp_executesql @sql, called asEXEC dbo.ingest 'E:\in\orders_x.csv', 'Pipeline_TypeX', now givesdbo.BIZ_RAW_X.* <- 'E:\in\orders_x.csv'and nothing fordbo.BIZ_RAW_Y; its dynamic SQL site was UNRESOLVED ("argument is a runtime variable") and gave no lineage. When every call of the procedure in the analysis is bound, only the bound statements are published; otherwise the statements for every row are published as well. Parameter values come, in this order, fromDataFlowAnalyzer.resolveDynamicSqlLineage(...), presets inTSQLEnv, a literalEXECin the same script and a literalEXECin another file of the analysis; a caller's variable or parameter, and calls nested up to four deep, are followed. Dynamic SQL insideBEGIN TRY ... END CATCHis evaluated, where the whole body was skipped andresolveDynamicSqlLineagereturned no sites;DynamicSqlSite.isExecutionCertain()is false for a statement in a CATCH block or behind a condition or loop the analysis cannot decide. A query the evaluator does not model (a JOIN, an aggregate, a subquery, an unknown function), more than 8 values for one variable (DynamicLineageOptions.maxValueSetSize) or more than 1024 rows (maxConstRelationRows, which was 64) leaves the site UNRESOLVED with the reason instead of guessing. String comparisons ignore case and trailing blanks, as SQL Server's default collation does;Option.setDynamicSqlCaseSensitiveCompare(true)makes them case-sensitive. The query evaluator is public ingudusoft.gsqlparser.compiler:TLiteralRelationQuery.evaluate(...)runs a SELECT over the rows of anISqlRowSource, with values asTSqlValue. Not there yet: in a procedure without callers, a BULK INSERT built withSET @sql = ...gives no path node, while theSELECT @sql = ...form gives one. - 2026-10-10 SQL Server
BULK INSERTgives lineage from its file to its table (Mantis 4962):BULK INSERT dbo.BIZ_RAW_X FROM 'E:\in\orders_x.csv' WITH (FIRSTROW = 2)gives the path node'E:\in\orders_x.csv'anddbo.BIZ_RAW_X.* <- 'E:\in\orders_x.csv', as RedshiftCOPYdoes, where it gave nothing. The edge goes to the whole table, never to columns by position. A file name that comes from a procedure parameter with no known value gives a template path node,'@file', whosetable.getEndpointKind()isDYNAMIC_TEMPLATE. ForWITH (DATA_SOURCE = 'src')the XML output gives the path node adataSourceName, and itsuristarts with the LOCATION of aCREATE EXTERNAL DATA SOURCE srcin the script. The parser keeps the WITH options:TMssqlBulkInsert.getOptions(),getOption(String)andgetOptionValue(String)return them asTMssqlBulkInsertOptionnodes, withgetName()andgetValue(). - 2026-10-10 A procedure's parameters can be preset for dynamic SQL lineage (Mantis 4962).
TSQLEnv.setProcedureParameterValue("dbo.ingest", "@pipeline_type", "Pipeline_TypeX"), orprocedures[].parameterBindingsin a metadata JSON file (for each entry a parameter name and a string, a number or null), gives a procedure analyzed without its callers the values its dynamic SQL is built from;getProcedureParameterValue(procedure, parameter)andgetProcedureParameterPresets(procedure)read them back asTSQLRoutine.PresetValue. A procedure name without a database or schema is in the default catalog and schema, so preset a procedure defined underUSE XwithXin its name. An explicit binding ofresolveDynamicSqlLineagereplaces the presets, and the presets come before the calls found in the analysis. - 2026-10-10 The evaluation of SQL Server dynamic SQL strings follows T-SQL in three more places (Mantis 4962).
SET @sql += ' WHERE x = 1'appends to@sql; it was read asSET @sql = ' WHERE x = 1', so the statement lost its start. ASELECT @v = col FROM t WHERE ...that finds no row leaves@vunchanged, andSET @v = (SELECT col FROM t WHERE ...)sets it to NULL, so a site whose value comes only from a query that finds no row is UNRESOLVED and its reason says the query returned zero rows, where every row of a table variable was published because WHERE was ignored. A value read into a variable is converted to the variable's declared type.
GSP Java version 4.2.15(2026-10-10)¶
- 2026-10-09 Teradata parses eleven forms that Vantage accepts and that returned 2 from
parse()with a syntax error (Mantis 4945-4947, 4952-4958, 4961): LEAD, LAG, SCRIPT and COLUMNS as names (LEFT JOIN (SELECT k FROM t2) LEAD ON t1.k = LEAD.k,SUM(lag) OVER (...),FROM Script SCR,SELECT Columns AS col_b), whileLEAD(x) OVER (...),LAG(x) OVER (...)and the SCRIPT table operator keep their meaning;trunc(date); the type attribute100.0(DOUBLE PRECISION); a column namedperiodfollowed by(NAMED a, CHAR(17)); more than one name after an array index in a JSON path,col."result"[0]."x"."y"; a derived table's column list,(SELECT DISTINCT k FROM t2) c (k); an alias that starts with$after AS,AS $col_b(every other$nameis still read as a placeholder variable, as before); and a CREATE TABLE AS column list that mixes attributed and bare names,(col_a CASESPECIFIC, col_b NOT NULL, col_c, col_d) - 2026-10-09 SQL Server parses the two-argument
LTRIM(string, characters)andRTRIM(string, characters)(Mantis 4948), whose two argumentsTFunctionCall.getArgs()returns; a statement that ends in a--comment starting with a digit and has no newline after it,... ON a.k = b.k--1 note(Mantis 4951), which gave no statement and an empty error message (a line that holds only blanks and--followed by a digit is now always a comment, as SQL Server reads it, whatever the length of the lines before it); andrenameas a table or derived-table alias,FROM (SELECT col_a FROM tab1) rename(Mantis 4959). RENAME stays a keyword before OBJECT, DATABASE, COLUMN and CONSTRAINT, soRENAME OBJECT t TO t2parses as before - 2026-10-09 Oracle parses
WITH FUNCTIONin front of the query of a CREATE VIEW (Mantis 4949), which failed with "Error when tokenize" at the first;of the function, and a function declaration section with variables and constants; an expression as the third argument ofTRANSLATE,TRANSLATE(col_a, 'x', (SELECT max(c1) FROM tab2) || ' ')(Mantis 4950), whose columns are now lineage sources and whose literal is no longer listed as a column (the third argument is now an ordinary expression, so a literal there issimple_constant_t, where it wassimple_source_token_t); and an expression as the XQuery string ofXMLTABLE,xmltable(('"' || replace(str, '//', '","') || '"'))(Mantis 4960).TXmlTableParameter.getXQueryExpression()returns the string in every form;getXQueryString()still returns the literal or bind variable and returns null for any other expression - 2026-10-08 Teradata parses the forms it writes into stored view text (Mantis 4899-4905, 4907-4909); each returned 2 from
parse()with a syntax error: a temporal qualifier after a table name,FROM t CURRENT TRANSACTIONTIMEandFROM t TRANSACTIONTIME AS OF (SELECT ...) s(and the VALIDTIME forms), kept asTTable.getFlashback();TD_SYSFNLIB.XMLAGG,TD_SYSFNLIB.XMLSERIALIZEandTD_SYSFNLIB.XMLTABLE;XMLTABLE(... PASSING BY VALUE ...);LAG(x RESPECT NULLS, 1, NULL)andLEAD(x IGNORE NULLS, 1, NULL); the interval qualifierSECOND(4,6); a table operator without USING,SYSLIB.GetColumns ( ON DBC.COLUMNSV ) AS G; the RETURNS clause of a function call,(f(x) RETURNS INTEGER),(f(x) RETURNS STYLE t.c)andTRYCAST(x) RETURNS INTEGER, whose typeTFunctionCall.getTypename()returns; and a method call on a parenthesized value,(NEW JSON(x, LATIN)).JSONEXTRACTVALUE('$.a'). A function call followed by RETURNS without the enclosing parentheses is still a syntax error, as Teradata requires them. Not there yet: the source columns of an interval-qualified expression and ofNEW JSON(...), the table read in an AS OF subquery, and the aggregate edge ofTD_SYSFNLIB.XMLAGG(Mantis 4918-4921). - 2026-10-08 Teradata parses
PERIOD(a, b)right after an opening bracket,SELECT (PERIOD(T.B, T.E)) AS PandSELECT (PERIOD(DATE(T.B), DATE(T.E))) AS P(Mantis 4906); the bracket was read as the start of a cast shorthand such asx (PERIOD(DATE)), which still works, and lineage givesP <- T.B, T.E. - 2026-10-08
TCreateTableSqlStatement.isIfNotExists()returns true forCREATE TABLE IF NOT EXISTSin every dialect whose grammar accepts it. It was true only in Hive, Impala, Oracle and Dameng, and false in BigQuery, Spark SQL, Databricks, Athena, Presto, Trino, MySQL, PostgreSQL, Snowflake, Redshift and the other dialects that parse the clause. Lineage reads the flag, so in these dialects too aCREATE TABLE IF NOT EXISTSof a table declared earlier in the script declares no fields of its own.toScript()and the formatter output are unchanged. - 2026-10-08 Databricks reads every column alias of a LATERAL VIEW, as Spark SQL and Hive do. In
LATERAL VIEW posexplode(items) lv AS pos, item,TLateralView.getColumnAliasList()returned[pos]anditembecame a second table of the FROM clause, soCREATE VIEW v AS SELECT pos, item.name AS name FROM events LATERAL VIEW posexplode(items) lv AS pos, itemstopped with a NullPointerException; the aliases are now[pos, item], and the view giveslv.item <- events.itemsandv.name <- lv.item.lv AS x, other_table o, which parsed as a comma join, is now a syntax error, as in Spark SQL and Hive. - 2026-10-08 A field of a constructed STRUCT that reads a field under another name gets its edge in the simple output. Trino
CAST(ROW(payload.address.city, payload.phone) AS ROW(town VARCHAR, tel VARCHAR)) AS contactgave no edge for its fields; it now givesv.contact.town <- events.payload.address.cityandv.contact.tel <- events.payload.phone, and a renamed field of a Hive, Spark SQL or Databricksnamed_structgets its edge in the same way. The simple output keeps every source that anfddpath of the full output reaches and no longer drops a STRUCT source whose last name part differs from the target's;DataflowRemoveHelperandRemoveDataflowFunctionfold the same way. - 2026-10-08 A STRUCT select item behind a star of a table without DDL counts as one item, whatever its number of fields. With
CREATE TABLE contacts (order_id INT64, note STRING, contact STRUCT<name STRING, city STRING>), BigQueryINSERT INTO contacts (order_id, note, contact) SELECT o.*, STRUCT(c.name AS name, c.city AS city) FROM recent_orders o, customers cgavecontacts.note <- customers.nameandcontacts.contact <- customers.city; it now givescontacts.note <- recent_orders.*,contacts.contact.name <- customers.nameandcontacts.contact.city <- customers.city, and so do the column list of a view, a CREATE TABLE and a CTE, and an INSERT without a column list. A CTE column list over one star with an item after it,CREATE VIEW v AS WITH c (x, y, z) AS (SELECT s.*, t.p FROM src s, other t) SELECT x, y, z FROM c, stopped the analysis with an IndexOutOfBoundsException; it now givesv.x <- src.*,v.y <- src.*andv.z <- other.p. - 2026-10-07
TABLE t, the SQL-standard shorthand forSELECT * FROM t, is analyzed asSELECT * FROM tin PostgreSQL, DuckDB, GaussDB, EDB, Greenplum, SQLite, MySQL, OceanBase, Spark SQL, Databricks, Athena, Presto, Trino and Snowflake. The parser built an empty select for it, so the table was missing fromgetTables(), TSQLResolver2 and lineage:CREATE TABLE t2 AS TABLE t1gave no lineage in PostgreSQL and Snowflake and stopped the analysis of the statement with a NullPointerException in Athena, Presto and Trino; it now givest2.a <- t1.aandt2.b <- t1.b, asCREATE TABLE t2 AS SELECT * FROM t1does. The same holds forINSERT INTO t2 TABLE t1, a UNION, EXCEPT or IN branchTABLE t3,WITH c AS (TABLE t1)and a statementTABLE t1 [ORDER BY ...] [LIMIT ...], which Athena, Presto, Trino, Databricks, Snowflake, Greenplum and SQLite now accept.toString()still printsTABLE t, andtoScript()writes it back asTABLE [ONLY] t; a relation writtenONLY tnow keepsONLYintoScript()(SELECT * FROM ONLY srcgaveselect * from src). API changes: forCREATE TABLE dst AS TABLE src,getTables()of the CREATE TABLE statement is[dst]andsrcis a table ofgetSubQuery(), as for theAS SELECTform, andgetAsTable()returns that table (null before on Athena, Presto, Databricks, Snowflake, MySQL, OceanBase and Spark SQL);TPostgresqlTableStmtkeeps its statement typesstPostgresqlTableand now extendsTSelectSqlStatement;TFromTable.isOnlyKeyword()andTTable.isOnlyKeyword()are true forONLY tin the PostgreSQL family and Databricks. - 2026-10-07 Databricks parses a CREATE TABLE AS SELECT written without
ASorUSING(Mantis 4894):CREATE TABLE my_schema.t2 SELECT * FROM my_schema.t1andCREATE OR REPLACE TABLE ...returned 2 fromparse()with a syntax error at SELECT and gave no lineage; they now parse as theASform does,TCreateTableSqlStatement.getSubQuery()returns the query, and lineage gives the same edges,my_schema.t2.* <- my_schema.t1.*.CREATE TABLE t2 (values INT)and other first columns named like a keyword stay column definitions. - 2026-10-07 Databricks parses
DESCRIBE TABLE [EXTENDED] t AS JSON(Mantis 4895), which dbt-databricks issues; it returned 2 fromparse()with a syntax error at AS. The statement is aTDescribeStmtandTDescribeStmt.isAsJson()returns true. - 2026-10-07 Databricks splits
DECLARE [OR REPLACE] [VARIABLE] name [type] [DEFAULT expr]into a statement of its own, typedESqlStatementType.sstmysqldeclare, as Spark SQL does (Mantis 4896).DECLARE VARIABLE my_var STRING DEFAULT 'x'; SELECT my_var;returned 1 fromparse()with a tokenizer error, and the lineage of every other statement of such a script was lost:DECLARE ...; INSERT INTO s.t2 SELECT a FROM s.t1;now givess.t2.a <- s.t1.a. - 2026-10-07 SQL Server parses an XML method called on the result of another,
T.c.query('.').value('.', 'varchar(10)')(Mantis 4897), in SELECT, INSERT, SELECT INTO, UPDATE, DELETE, MERGE, WHERE and function arguments; it returned 1 fromparse()with a syntax error at the second dot.INSERT INTO dbo.target (v) SELECT T.c.query('.').value('.', 'varchar(10)') FROM dbo.src s CROSS APPLY s.xml_col.nodes('/Root/item') T(c)now givesdbo.target.v <- dbo.src.xml_col, the edge the single methodT.c.value(...)gives, and TSQLResolver2 sees the column under the chain. - 2026-10-07 MySQL parses a CREATE TABLE whose query is in parentheses right after the table name (Mantis 4898):
CREATE TABLE t2 ( SELECT * FROM t1 ORDER BY c ASC )returned 2 fromparse()with a syntax error at*; it now parses asCREATE TABLE t2 AS SELECT ...does, with the ORDER BY kept ingetSubQuery(), and gives the same lineage.IF NOT EXISTS,TEMPORARY, a parenthesized UNION,WITH,VALUESandTABLE t1queries parse too; column lists, constraints and columns named like a keyword are unchanged. - 2026-10-07 Spark SQL parses a field of an array element,
items[0].name, and a subscript that is any expression,items[i].nameoritems[i + 1].name, as Hive and Databricks do (Mantis 4885).SELECT items[0].name AS n FROM eventsreturned 2 fromparse()with a syntax error at the dot; it now parses, the expression is a field access (EExpressionType.field_access_t) over the subscript, and lineage givesRS-1.n <- events.items[*].name, the edges Hive gives for the same SQL. - 2026-10-07 A STRUCT that a select item builds keeps its fields wherever the item goes (Mantis 4878, 4891, 4892, 4893). With
CREATE TABLE out (payload STRUCT<a STRING, b STRING>, z STRING), BigQueryINSERT INTO out (payload, z) SELECT STRUCT(s.x AS a, s.y AS b) AS payload, s.w FROM src sgaveout.payload <- src.xandout.z <- src.y, the fields counted as two positions; it now givesout.payload.a <- src.x,out.payload.b <- src.yandout.z <- src.w, and so do a view's column list (TrinoCREATE VIEW w (contact, z) AS SELECT CAST(ROW(s.x, s.y) AS ROW(a VARCHAR, b VARCHAR)), s.w ...), a CREATE TABLE column list and a CTE column list; an item without an alias feeds the fields too, beside its whole column. HiveCREATE TABLE out AS WITH q AS (SELECT named_struct('a', s.x, 'b', s.y) AS payload FROM src s) SELECT payload FROM qgaveout.payload <- src.x, src.y; it now givesout.payload.a <- src.xandout.payload.b <- src.y, through a CTE, a derived table (Spark SQLFROM (SELECT named_struct(...) AS payload FROM src s) q) or a UNION branch, while a branch that builds no STRUCT feeds the whole column. A field read through a derived table,q.payload.a, reads only its field. A STRUCT inside a STRUCT publishes its leaves,named_struct('a', named_struct('b', s.x))givesout.payload.a.b <- src.x, and a typed BigQuerySTRUCT<a STRING>(s.x)names its fielda, by its type, where it took the name of the value columnx. Behind a star of a table without DDL,INSERT INTO out (x, y, payload) SELECT s.*, STRUCT(s.z AS a) FROM src sgivesout.payload.a <- src.z: the last item fills the last column whatever the width of the star. Hivestruct(s.x, s.y) AS stnames its fieldscol1andcol2; Spark SQL and Databricks name a field that reads a column after it,st.xandst.y. A BigQuery view ofSTRUCT(customer.name AS name, order_id AS id) AS buyernow lists the columnbuyerabovebuyer.nameandbuyer.id, as Trino does. The elements of an array constructor feed the column: PostgreSQLSELECT ARRAY[t.a, t.b] AS arr FROM tgivesRS-1.arr <- t.a, t.b, where it gave nothing. A declared STRUCT column projected whole,SELECT customer AS c FROM orders_raw, stays one edge. - 2026-10-07 A Hive, Spark SQL or Databricks LATERAL VIEW is one relation of its SELECT (Mantis 4887, 4888, 4889, 4890). The WHERE clause of a query with a LATERAL VIEW now gives its row lineage,
RS-1.RelationRows <- lv.item, and a CASE over a field of the element reads that field,v.n <- events.items[*].name. The function's argument is read from the relation TSQLResolver2 resolves among those to the view's left: inFROM src, host LATERAL VIEW explode(src.items) lv AS itemit readssrc.itemsand neverhost.items, an input of a CTE or derived table to the left is read, and one that names a relation to the right reads nothing. A LATERAL VIEW over a field of an earlier one,explode(item.subs), readsevents.items[*].subs. A view without a table alias (Spark SQL, Databricks) and a view after a JOIN resolve their column aliases, every INSERT of a Hive multi-insert reads the view of the shared FROM clause, and the relation of a view never publishes the name of a table: one aliased like a table of the script is numbered,tmp1-1. - 2026-10-07 The fields of a nested column follow the CREATE TABLE in force at each statement (Mantis 4861, 4862, 4884). After an Athena
DROP TABLE eventsand a secondCREATE EXTERNAL TABLE events (payload STRUCT<new_field:STRING>) LOCATION 's3://b/new/', a read ofpayload.new_fieldgivesRS-1.new_value <- events.payload.new_field, and a field only the dropped table declared is no field any more; aCREATE TABLE IF NOT EXISTSof an existing table declares nothing. An Athena array's element node is fed by its LOCATION:events.tags[*] <- 's3://b/e/'.tags[*]. Impala builds the same tree as Hive,table events: items, items[*], items[*].name, where it published the fields as columns. A subscript reads the array's element in every dialect that models nested columns: BigQuerytags[OFFSET(0)], Hive, Spark SQL, Databricks, Athena, Presto and Trinotags[1]givev.t <- events.tags[*], where several gavev.t <- events.tags; a subscript of a declared MAP reads its value node, and one of a declared STRUCT or JSON column reads the column. - 2026-10-07
DlineageUtil.modelsStructTree(EDbVendor),DlineageUtil.modelsStructTree(),NameResolver.isTrinoFamily(EDbVendor)andNameResolver.readsFieldChains(EDbVendor)are deprecated. They keep returning what they returned; the vendor rules for nested columns now live in one public class,gudusoft.gsqlparser.nodes.structured.NestedAccessProfile, andNestedAccessProfile.forVendor(vendor)withbuildsDeclaredTree(),isTrinoFamily()andreadsFieldChains()replaces them. - 2026-10-06 dlineage reports the positions of what it analyzes inside SQL Server dynamic SQL (
EXEC (@sql),EXEC ('...'),sp_executesql) in the procedure, not in the string (Mantis 4851). For a procedure whose line 4 isSET @SQL1 = 'and whose lines 5-7 continue the string withINSERT INTO dbo.tgt (a) SELECT COALESCE(s.x, s.y) FROM dbo.src s, the source columns.xhad the coordinate[3,17], line 3 of the string, and now has[6,17]; so did tables, columns and the statement itself. A string built in severalSETs keeps the literal each part was read from,''counts as two characters of the source, and a part that comes from a variable takes the place where it is spliced in, after the closing quote of the literal before it. A string assembled out of source order, and dynamic SQL inside dynamic SQL, take the position of their EXEC. EXECUTE IMMEDIATE and theEXECUTEof other dialects keep the positions of the string, and so do the syntax errors reported inside a dynamic string. - 2026-10-05 Hive, Spark SQL and Databricks
named_struct('a', x, 'b', y) AS payloadgives each field its own lineage, as BigQuerySTRUCT(x AS a, y AS b)does (Mantis 4847).CREATE TABLE out AS SELECT named_struct('a', s.x, 'b', s.y) AS payload FROM src sgaveout.payload <- src.x, src.y, and a laterSELECT payload.a FROM outread a field node that nothing fed; it now givesout.payload.a <- src.xandout.payload.b <- src.y, and the read givesv.a <- out.payload.a; a view gets the same fields. A CREATE TABLE AS SELECT of a Trino, Athena or PrestoCAST(ROW(s.x, s.y) AS ROW(a VARCHAR, b VARCHAR)) AS contactmade the columnsaandbof the table; it now makes the field nodesout.contact.aandout.contact.b, as a view does (Mantis 4834). Anamed_structwith a name that is not a non-empty string literal, qualified by a database, inside another function or in a filter is analyzed as before; one without an alias, or paired by position with a column list (INSERT INTO t (a, b) SELECT ...,CREATE VIEW v (a, b) AS ...), is covered by the 2026-10-07 entry on STRUCT select items. - 2026-10-05 A field of the element that a Hive, Spark SQL or Databricks LATERAL VIEW explodes is read from the array's element (Mantis 4845). After
CREATE TABLE events (id INT, items ARRAY<STRUCT<name:STRING>>),CREATE VIEW v AS SELECT lv.item.name AS n FROM events LATERAL VIEW explode(items) lv AS itemgavev.n <- lv.item, the whole element, and TSQLResolver2 reportedlv.item.nameasNOT_FOUND; it now givesv.n <- events.items[*].name, with and without DDL, andlv.item.nameresolves withTObjectName.getFieldPathRead()item.name. TSQLResolver2 keeps a relation for a LATERAL VIEW, whose columns are its aliases, so an unqualifieditemresolves to it (TObjectName.getSourceTable()is the view's table, of typeETableSource.lateralView) instead of to the first table of the FROM clause, which gave lineage columns such asods_adp.lofta_tinstitutionantimoneyinfo.contract_splitthat the table does not have; a name that another table also has is ambiguous. An unqualifieditem.nameover a declared table, or a LATERAL VIEW without column aliases, no longer stops the analysis of the view with a NullPointerException, and forposexplodeand other LATERAL VIEWs a field read reads the whole column,lv.item. The LATERAL VIEWs of two queries that share an alias were one table, so the lineage of each query reached the column the other exploded; a later view now gets a table of its own, numberedtmp1-1,tmp1-2, and a script without a repeated alias gives the same output as before. - 2026-10-05
DynamicLineageEdgenames each call of a function as a node of its own (Mantis 4848).DynamicSqlLineageResolvernamed an intermediate node by its display name only, so the threeCOALESCE(...)calls ofINSERT INTO dbo.tgt (k1, k2, d) SELECT COALESCE(A.k1, B.k1), COALESCE(A.k2, B.k2), COALESCE(A.d, B.d) ...run throughEXEC (@sql)were one nodeCOALESCE.COALESCE, and a consumer that followedgetSourceColumn()togetTargetColumn()through it linked every input to every output, 18 base edges where 6 are real. A display name that several nodes share is now numbered,COALESCE#1.COALESCE,COALESCE#2.COALESCEandCOALESCE#3.COALESCE, across all the dynamic statements and value variants of oneDynamicSqlLineageResolver.resolvecall, whosegetProjectedEdges()is one list, so theRS-1of a secondEXECisRS-1#2; a number that a table's name already has is skipped, and the first node with a name no other node has keeps it, such as a function called once,RS-16orINSERT-SELECT-1. - 2026-10-05 A column that
ALTER TABLE ... ADD COLUMN(ADD COLUMNS,ADD COLUMN IF NOT EXISTS) adds to a table declared earlier in the script is a column of that table, with its type, for the statements after the ALTER, in lineage and in TSQLResolver2 (Mantis 4846). The catalog kept the table asCREATE TABLEdeclared it, andDataFlowAnalyzeranalyzed every view before every ALTER: afterCREATE TABLE events (id BIGINT); ALTER TABLE events ADD COLUMNS (payload STRUCT<name:STRING>);, Hive, Spark SQL and DatabricksCREATE VIEW v AS SELECT payload.name AS n FROM eventshad no lineage andpayload.namewasNOT_FOUND; it now givesv.n <- events.payload.name, andTObjectName.getFieldPathRead()returnspayload.name. In every dialectCREATE VIEW v AS SELECT * FROM eventsafterALTER TABLE events ADD COLUMN c INTnow also givesv.c <- events.c. A statement before the ALTER still sees the table without the column: therecinSELECT c FROM events, otheris stillother.c, andSELECT * FROM eventsreads noc. The ALTER gives theTSQLEnva new version of the table,TSQLTable.newVersion(), asCREATE OR REPLACE TABLEreplaces one, and a statement before it keeps the version it found; an ALTER inside a routine, which runs when the routine is called, and a sealed table are left alone.eventsandpublic.eventsare one table here too. A stored procedure after the ALTER, and a view that such a procedure reads, still read the table as declared (Mantis 4883), and so does TSQLResolver2 for a SQL Server#temptable (Mantis 4886). - 2026-10-05 Hive
items[0].namereads the fieldnameof an element of the array columnitems(Mantis 4844). The grammar builds a field access over the subscript, and nothing below it was parsed or visited, soCREATE VIEW va AS SELECT items[0].name AS n FROM eventshad no lineage and TSQLResolver2 had no reference toitems; it now givesva.n <- events.items[*].name, with and without DDL, also fore.items[0][1].name(events.items[*][*].name),items[0].a[1].b(events.items[*].a[*].b) and(items[0]).name, andTObjectName.getFieldPathRead()returnsitems[*].name. The column records the subscripts and the field after them inTObjectName.getIndirection(), as BigQuery's grammar does (Mantis 4833). Impala, whose grammar builds the same expression, now resolves the column inside it too:items[0].namegivesva.n <- events.items[*].namewhere it gave nothing (the element node since the 2026-10-07 entry on nested fields). - 2026-10-05 An input that ends inside a double-quoted identifier is a syntax error at the opening quote, in every dialect (Mantis 4842). The lexer reached the end inside the identifier and returned no token for it, so the quote and everything after it were dropped:
SELECT 1 id";returned 0 fromparse()with no error in Athena, PostgreSQL, Oracle and almost every other dialect,SELECT 1 id"; SELECT 2;lost its second statement, and Oracle acceptedSELECT 1 AS "id;.parse()now fails, andgetSyntaxErrors()gives the position of the quote, line 1 column 12 forSELECT 1 id";. In MySQL, where double quotes delimit a string, the same holds for that string. Closed identifiers parse as before; an input ending inside a single-quoted string or a block comment is unchanged (Mantis 4882). - 2026-10-05 The columns of a VALUES table without a column list take the vendor's names, in lineage and in TSQLResolver2 (Mantis 4823): PostgreSQL, Greenplum, Redshift and Snowflake call them
column1,column2, ..., Spark SQL and Databrickscol1,col2, ....SELECT r.column1 FROM (VALUES ((SELECT x FROM t), 2)) AS rin PostgreSQL gave no lineage andr.column1wasNOT_FOUND; nowRS-1.column1 <- result_of_r-1.column1 <- t.xandr.column1resolves.TValueClause.defaultColumnName(vendor, position)is the rule. - 2026-10-05 A function in a VALUES row gives the column its value in lineage, as in a SELECT list (Mantis 4824): in
SELECT r.a FROM (VALUES (COALESCE((SELECT x FROM t), 0))) AS r(a),r.anow hast.xupstream throughCOALESCE; the same forABS,CASEand a column inside a function, such asCROSS APPLY (VALUES (UPPER(t.name))) AS r(a)in SQL Server. - 2026-10-05 A derived table's alias column list renames the columns a
SELECT *expands to, by position, in TSQLResolver2 (Mantis 4843). Overt3(c1, c2, c3), inSELECT d.a, d.b, d.c1, d.c3 FROM (SELECT * FROM t3) d(a, b),d.aandd.bwereNOT_FOUNDandd.c1resolved; nowd.aresolves tot3.c1andd.btot3.c2(ColumnSource.getFinalColumnName()returnsc1andc2),d.c1andd.c2areNOT_FOUND, andd.c3still resolves. A column after the star takes the position after the star's columns. The star's columns are known from DDL, or from a catalog table that lists every one of them; otherwise (no metadata, a catalog table without columns or with an unexpanded star,* EXCEPT,* EXCLUDEor* REPLACE, aUSING,NATURAL, semi or anti join)d.ais a column ofdwith no column oft3behind it (ColumnSource.getFinalTable()returns null andgetAllFinalTables()is empty), instead of an inventedt3.a, and a name renamed away stays visible when another column of the star may pass it on. In lineage every name past such a star reads the star:INSERT INTO o (x, y) SELECT d.a, d.b FROM (SELECT * FROM t) d(a, b)giveso.x <- t.*ando.y <- t.*, where it gaveo.x <- t.aand nothing foro.y. A derived table over a set operation,(SELECT * FROM t UNION ALL SELECT * FROM u) d(a), is Mantis 4870. - 2026-10-05 A PostgreSQL
SELECT ... INTO namestatement creates the tablename, in lineage and in the parse (Mantis 4857), as PostgreSQL documents and asINTO TEMP name, Greenplum and Redshift already did. AfterCREATE TABLE TABLE_1 (COL_1 int, COL_2 int); select COL_1, COL_2 into TMP2 from TABLE_1; insert into TABLE_2 (COL_1, COL_2_RENAMED) select * from TMP2;the target was a record variable, so the simple output dropped it and gave onlyTABLE_2.COL_1 <- TABLE_1.COL_1; it now gives the tableTMP2withTMP2.COL_1 <- TABLE_1.COL_1,TMP2.COL_2 <- TABLE_1.COL_2,TABLE_2.COL_1 <- TMP2.COL_1andTABLE_2.COL_2_RENAMED <- TMP2.COL_2. The target'sTObjectName.getDbObjectType()isEDbObjectType.tableand the SELECT lists it among its tables withETableEffectType.tetSelectInto, as for the other forms. The body of aLANGUAGE SQLfunction holds SQL and creates the table too, while in a PL/pgSQL body, of a function, a procedure or a DO block, INTO still assigns variables, and aSELECT ... INTOrun throughEXECUTE, which PL/pgSQL rejects, creates none. - 2026-10-05 OceanBase in a MySQL tenant ends a stored routine written without a DELIMITER command at the
END;that closes its outermostBEGIN, as MySQL does (Mantis 4841).CREATE PROCEDURE p() BEGIN SELECT 1; END;followed bySELECT 2;gave one statement and a syntax error atSELECT 2, so every statement after a routine was lost;TGSqlParser(EDbVendor.dbvoceanbase)now splits such a script into the statementsEDbVendor.dbvmysqlgives, also for routines in a row, a nestedBEGIN ... END;orBEGIN ... END label;, and inside a bodyEND IF;,END WHILE;,CASE ... END CASE;and aCASE ... ENDexpression, which do not end the routine. A name ending in$, such ascol$, ends a routine only after a DELIMITER command set$. - 2026-10-05 Doris INSERT, INSERT OVERWRITE, UPDATE, DELETE and CREATE VIEW are parsed into their statement classes and have lineage (Mantis 4855). They returned 0 from
parse()asTUnknownSqlStatements with no AST, soDataFlowAnalyzerfound no relationship in them and nothing reported it:INSERT INTO t2 SELECT a FROM t1now givest2.a <- t1.a, as in MySQL. The Doris forms parse too:INSERT ... WITH LABEL name,INSERT OVERWRITE TABLE t PARTITION(*),DELETE FROM t PARTITION p1andPARTITIONS (p1, p2),UPDATE t1 SET ... FROM t2 JOIN t3 ON ..., whose FROM tables are read, theCOMMENTof a view and of its columns, andCREATE VIEW IF NOT EXISTS.CREATE MATERIALIZED VIEWis now its own type,ESqlStatementType.sstcreatematerializedview, and like MERGE it stays a statement without an AST. - 2026-10-05 In the simple output with
fdredges shown, a source that reaches a column through a value path is anfddsource of that column even when it also reaches it through a filter, whatever relationship ids the statements before it used (Mantis 4867). The fold walked each intermediate node once, meeting a node's relationships in the string order of their ids (10before7), so the first path to a shared node decided the type:INSERT INTO tgt (v) SELECT SUM(e.k) FROM (SELECT d.k FROM (SELECT k FROM s) d WHERE ABS(d.k) > 0) egavefdr s.k -> tgt.vwith clause typewherewhen analyzed alone, andfdd s.k -> tgt.vafter two other statements. A node is now walked again when a better path reaches it, so a value path always wins, and the source shown, with its clause type and transforms, comes from a path of the type it gets: withOption.setTransform(true)thefddedge intotgt.vlistsSUM(e.k), no longer the filter'sABS(d.k). Only such paths can mark the folded relationship as an assumed external-script passthrough.Option.setIgnoreRecordSet(true)folds the same way. The default simple output, which showsfddedges only, is unchanged. - 2026-10-05 In the simple output, a source read in a WHERE, ON or HAVING filter through a function, aggregate, CASE, derived table, CTE or variable carries the filter's clause (Mantis 4866). The simple output (
Option.setSimpleOutput(true), withfdredges shown throughOption.setSimpleShowRelationTypes("fdd", "fdr")) folds such intermediate nodes away, and the folded source kept the clause of the edge that reads the table, which has none:UPDATE t1 SET v = 1 WHERE ABS(t1.x) > 5 AND t1.y = 2gavet1.ythe clause typewhereandt1.xnone, and so didHAVING SUM(o.amount) > 100000,ON UPPER(c.code) = o.code, a CASE, and... FROM (SELECT id, x FROM s) d WHERE d.x > 5fors.x.sourceColumn.getClauseType()of such a foldedfdrsource now returnswhere,joinConditionorhaving, the clause the full output gives the filter's own operand, in the XML and the JSON model alike; a folded source that has a clause of its own keeps it, and one that also reaches the target as a value stays anfddsource without a clause. A GROUP BY key that an aggregate in HAVING reads getshavingtoo: withGROUP BY o.customer_id HAVING SUM(o.amount) > 100000, bothOrders.amountandOrders.customer_idfeed the result'sRelationRowswithhaving. The same holds withOption.setIgnoreRecordSet(true)and inParallelDataFlowAnalyzer. Only the attribute moves: no edge is added or removed, the default simple output, which showsfddedges only, is unchanged, and a source that reaches the filter only through a condition analyzed without a clause, such as a MERGEWHEN ... ANDcondition, still gets none. - 2026-10-04 A function, aggregate or CASE operand of a WHERE, ON or HAVING filter carries the filter's clause on its lineage source (Mantis 4865). Such an operand is its own node: for
HAVING SUM(o.amount) > 100000the source of thefdredge into the result'sRelationRowsisSUM.SUM, andsourceColumn.getClauseType()returnedunknownfor it, or nothing for a CASE, where a column operand returnswhere,joinConditionorhaving. A consumer that tells filters apart by the source's clause type, as the dlineage guide says to, missedHAVING SUM(...),WHERE ABS(...)andON UPPER(c.code) = o.code. In the full output (Option.setSimpleOutput(false)) the source now carrieshaving,whereorjoinCondition, in the XML and the JSON model alike; the relationship's ownclausewas already right, and no edge is added or removed. The same holds for a constant function such as BigQueryCURRENT_TIMESTAMP(), read from the constants table. A condition analyzed without a clause, such as an IF condition, a MERGEWHEN ... ANDcondition or a windowPARTITION BY, is unchanged.
GSP Java version 4.2.14.1(2026-10-07)¶
- 2026-10-07 [Formatter] Multi-row INSERT VALUES keeps a stable indentation for sibling tuples. Stacked rows previously inherited the preceding row's final column, and normalizing every row repeatedly padded the first tuple; large batches could allocate quadratic amounts of whitespace and exhaust the Java heap. Each tuple is now normalized once and stacked rows share the first tuple's indentation. SQL tokens and comments are preserved.
GSP Java version 4.2.14(2026-10-04)¶
- 2026-10-04 A table reference that names its database finds the table that a
CREATE TABLEor the metadata declares without one (Mantis 4751). After SybaseCREATE TABLE DW_RE0.BusinessOwners (CustomerName varchar(300), ...),create view dw_dina.DW_RE0.aa_BusinessOwners as select * from dw_dina.DW_RE0.BusinessOwnersgave onlydw_dina.DW_RE0.aa_BusinessOwners.* <- dw_dina.DW_RE0.BusinessOwners.*; it now gives one edge per declared column, such asdw_dina.DW_RE0.aa_BusinessOwners.customername <- dw_dina.DW_RE0.BusinessOwners.customername, andTTable.getResolvedTable()andTTable.getExpandedStarColumns()return the declared table and its columns. A column the declaration does not have is no longer guessed to belong to the reference: withCREATE TABLE DW_RE0.T1 (a int),cinSELECT c FROM dw_dina.DW_RE0.T1, DW_RE0.T2is an orphan column instead ofdw_dina.DW_RE0.T1.c, as it already was when the DDL nameddw_dina.DW_RE0.T1. A declaration without a database is in the session's current database, so the match is made only while that database is unknown: afterUSE other_dbthe table is inother_db, and afterTSQLEnv.setDefaultCatalogName("prod")it is inprod, so a reference todw_dinastill finds nothing. Only the database may be missing:CREATE TABLE T1is notdw_dina.DW_RE0.T1. A table or synonym that the named database holds still wins, and a reference through a linked server (serverB.dw_dina.DW_RE0.T1) or a database link is never matched. The match is a best guess, not a proof: two references naming different databases,dw_dina.DW_RE0.T1andother_db.DW_RE0.T1, both read the one declaration, and each keeps its own name in the lineage (in BigQuery too, wheredb1.s1.t1anddb2.s1.t1stay two tables beside the declareds1.t1). This holds in every dialect with a database above the schema. - 2026-10-04 [Formatter] Formatting on several threads at once no longer throws a
NullPointerException.GFmtOptFactory.newInstance(), whichSQLUtil.formatSqlalso uses, tookSystem.nanoTime()as the option'ssessionId, so two threads could get the same id, and the firstFormatterFactory.ppcall to finish removed the formatters the other call was still using. Each option now gets an id of its own. - 2026-10-04 The files of an external table's LOCATION now feed each STRUCT field the table declares, including the elements and fields of an ARRAY of STRUCTs, not only its columns (Mantis 4858), in Athena, Spark SQL, Databricks, Hive, Presto and Trino. After
CREATE EXTERNAL TABLE events (payload STRUCT<address:STRUCT<city:STRING>>) STORED AS PARQUET LOCATION 's3://b/e/',SELECT payload.address.city AS c FROM eventsgaveRS-1.c <- events.payload.address.city, a field node with no upstream, soccould not be traced to the files; the field now hasevents.payload.address.city <- 's3://b/e/'.payload.address.city, next to the unchangedevents.payload <- 's3://b/e/'.payload. Each field is fed from its own field of the files, so a sibling such aspayload.address.zipis never a source ofc. - 2026-10-04 An INSERT fed by
SELECT *from a permanent table made bySELECT ... INTOpairs the columns by position in SQL Server, Azure SQL, SAP ASE, SAP IQ, SQL Anywhere, Redshift and Greenplum (Mantis 4856). Afterselect COL_1, COL_2 into TMP2 from TABLE_1,insert into TABLE_2 (COL_2_RENAMED, COL_1) select * from TMP2gave only the wrongTABLE_2.COL_1 <- TMP2.COL_1; it now givesTABLE_2.COL_2_RENAMED <- TMP2.COL_1andTABLE_2.COL_1 <- TMP2.COL_2, as does an INSERT without the column list into aTABLE_2declared as(COL_2_RENAMED int, COL_1 int). An ALTER TABLE of the table, or a secondSELECT ... INTOmaking it, leaves its*unexpanded. When the*reads a table whose column order is not known (no DDL, its columns known only from other statements), an INSERT column-list target now reads that table's*instead of the column named like it:insert into TABLE_2 (COL_2_RENAMED, COL_1) select * from T9; select COL_1, COL_2 from T9;givesTABLE_2.COL_1 <- T9.*(was<- T9.COL_1). - 2026-10-03 An INSERT column list fed by
SELECT *from a temporary table made bySELECT ... INTOpairs the columns by position in SAP ASE, SAP IQ, SQL Anywhere and Redshift, and for SQL Server'sdbo.#tand[#t](Mantis 4753). Afterselect COL_1, COL_2 into #TMP from TABLE_1,insert into TABLE_2 (COL_1, COL_2_RENAMED) select * from #TMPlinked only the same-namedTABLE_2.COL_1 <- #TMP.COL_1, and the reordered list(COL_2_RENAMED, COL_1)gave the wrongTABLE_2.COL_1 <- #TMP.COL_1. They now giveTABLE_2.COL_2_RENAMED <- #TMP.COL_2, andTABLE_2.COL_2_RENAMED <- #TMP.COL_1withTABLE_2.COL_1 <- #TMP.COL_2, as SQL Server did for an unqualified#TMP; Redshift'sselect ... into temp table ttoo. A read of a column theSELECT ... INTOdid not create,binselect a into #T2 from S1; insert into X (xa, xb) select a, b from #T2, no longer gets an edge. A temporary table that twoSELECT ... INTOstatements make, as in the two branches of an IF, takes its columns from the branch that ran, so its*is not paired by position. - 2026-10-03 HAVING clause lineage. Each column and aggregate a HAVING clause reads now influences the result's rows, as WHERE does:
SELECT o.customer_id FROM sales.dbo.Orders o GROUP BY o.customer_id HAVING SUM(o.amount) > 100000givesfdr SUM -> RelationRowswithclause="having"(JoinRelationship.JoinClauseType.having), andfdd Orders.amount -> SUM. An aggregate in HAVING reads its GROUP BY keys and its rows as the same aggregate in the select list does, soHAVING count(1) > 1is traced back to its table (Mantis 4854). In MySQL (and OceanBase in a MySQL tenant), BigQuery, Hive, Spark SQL, Databricks, Impala and Doris a SELECT-list alias named in HAVING (SELECT o.amount AS amt ... HAVING amt > 1) is now read as the alias, in both resolvers and in lineage, instead of an invented columnorders.amt. A column of that name that the FROM clause provably has still wins, except in MySQL, where it wins only when GROUP BY names it, as MySQL documents. - 2026-10-03 Hive, Spark SQL and Databricks model a STRUCT column as a tree, as BigQuery and the Trino family do (Mantis 4821, 4837).
CREATE TABLE events (payload STRUCT<name:STRING>)kept only a columnname, so the declared column disappeared and every read ofpayload.namewas dropped; without DDL a field read invented a column named after the field. TSQLResolver2 now readspayload.nameandcustomer.address.cityas the column with a field path when the first part names no relation in scope (a LATERAL VIEW alias is a relation), and lineage givesv.city <- orders_raw.customer.address.citywith and without DDL. A HivelistType_tor DatabricksARRAY<STRUCT<...>>column gets its element nodes,items[*].name. - 2026-10-03 A STRUCT field read through a CTE or derived table reads the field, not the whole column (Mantis 4836):
WITH c AS (SELECT customer FROM orders_raw) SELECT customer.address.city AS city FROM cgivesv.city <- orders_raw.customer.address.city(wasorders_raw.customer). When the CTE's column passes the table column on unchanged, each result column on the way gets a field nodecustomer.address.city; a set operation, a function, a STRUCT the query builds or a wildcard keep reading the whole column. - 2026-10-02 A UNION derived table's column in a JOIN or WHERE condition influences the rows (Mantis 4819). In
LEFT JOIN (SELECT 0 AS rank, 'G' AS type UNION ALL SELECT 1, 'I') AS r ON r.type = c.cos_typethefdron the result's rows listed onlycalls.cos_type;result_of_r.typeis there now, as it is for theVALUESform. - 2026-10-03 BigQuery
items[OFFSET(0)].item_namereads the field of the array element,orders_raw.items[*].item_name, not the whole array (Mantis 4833), with and without DDL, qualified or not (o.items[OFFSET(0)].item_name), and forSAFE_OFFSET,ORDINAL,SAFE_ORDINALand a plain index;items[OFFSET(0)]with no field after it still reads the array columnitems. The same item without an alias no longer stops the analysis with a NullPointerException; its column is named after the field,item_name. The grammar now records the subscript and the field after it on the array column (TObjectName.getIndirection()), whichTObjectName.getFieldPathRead()reads. - 2026-10-03 A
ROW(...)constructor has lineage (Mantis 4834). Its values were never sources; nowROW(a, b) AS contactgivescontact <- a, b, and a Trino, Athena or PrestoCAST(ROW(payload.address.city, payload.phone) AS ROW(city VARCHAR, phone VARCHAR)) AS contactgives one column per field,v.contact.city <- events.payload.address.cityandv.contact.phone <- events.payload.phone, as BigQuerySTRUCT(... AS city) AS contactdoes. In a view these are field nodes below the view's columncontact, so a laterSELECT v.contact.city FROM vreadsv.contact.city. A row compared in a predicate,ROW(a, b) = ROW(1, 2), now makesaandbfilter sources. - 2026-10-03 BigQuery
PIVOT(COUNT(customer.name) FOR order_id IN (1))reads the counted field,v.1 <- orders_raw.customer.name, andcustomeris no longer published as a grouping column (Mantis 4829). Through a CTE the read is of the CTE's columncustomer. - 2026-10-03 A STRUCT field read through a CTE or derived table reads the column it starts at (Mantis 4830, 4831, 4818). BigQuery
WITH c AS (SELECT * FROM orders_raw) SELECT customer.address.city AS city FROM cgavev.city <- orders_raw.addressand invented the columnaddress, andSELECT x.customer.address.city FROM (SELECT customer FROM orders_raw) xinventedorders_raw.city; both now givev.city <- orders_raw.customer. In Athena, Presto and BigQuerySELECT payload.name AS n FROM (SELECT payload FROM events) subnow has the edge from the derived columnpayloadton. The read is of the whole column; field paths through result sets are Mantis 4836. - 2026-10-03 BigQuery and Athena
CREATE VIEW v AS SELECT customer.* FROM orders_rawwithout DDL gives the view one column*read fromorders_raw.customer(Mantis 4827), not the columns*andCUSTOMERwith no edge. With DDL the declared fields expand as before. - 2026-10-03 An attribute read two levels deep after a table alias,
o.customer.address.city, reads the columncustomer(Mantis 4839, 4840). Redshift SUPER reads were NOT_FOUND because the four-part name put the alias in the database slot; they now resolve toorders_rawwith the field pathaddress.city, and lineage givesv.city <- orders_raw.customerwith and without DDL instead of nothing or the invented columnscityando.customer.name. Oracle object-type attributes were resolved but lost in lineage; they now give the same edge. - 2026-10-02 BigQuery
UNNESTof a CTE or derived-table column has lineage (Mantis 4835):WITH c AS (SELECT items FROM orders_raw) SELECT i.item_name AS item FROM c, UNNEST(c.items) AS igivesv.item <- orders_raw.items. The unnest elementicomes from a result set, which carries no field nodes (Mantis 4836), so a field read through the element's name reads the whole element; a derived table analyzed later in the FROM clause is analyzed first. - 2026-10-02 BigQuery
SELECT item_name FROM orders_raw, UNNEST(items)without DDL no longer bindsitem_nametoorders_raw(Mantis 4828). An unaliased UNNEST is a value table that exposes its element's fields under their own names, so without the element type nothing proves whetheritem_nameis a column of the table or a field of the element:ResolutionResult.getStatus()is now AMBIGUOUS with both as candidates, and lineage lists the column as an orphan instead of inventingorders_raw.item_name. With DDL the field is read as before,orders_raw.items[*].item_name; an aliased UNNEST and the UNNEST argument itself are not affected. Presto, Trino and Athena, which expand an unaliasedUNNESTof anARRAY(ROW)into one column per field, get the same reading; with several unaliased UNNESTs every value table is a candidate, and an UNNEST argument considers only the value tables to its left. - 2026-10-02 Trino and Athena UNNEST output columns are linked to the unnested array, as Presto's were (Mantis 4826):
CREATE VIEW v AS SELECT t.x AS n FROM events CROSS JOIN UNNEST(arr) AS t(x)givesv.n <- events.arr[*]. An alias reads the argument at its position when the counts agree, every alias reads the one argument's element when there is a single argument (Trino expands anARRAY(ROW)into one alias per field), and theWITH ORDINALITYalias, whichTUnnestClause.isWithOrdinality()now records, reads every array whole; with several arguments and a different number of aliases no edge is published, because the mapping needs the element types. For Trino and Athena the link is made through the resolver's binding of each argument, so joins, filters, other tables, several UNNESTs and an argument from a CTE or derived table keep their lineage; Presto's derived-table argument is now matched by name, not by its position in the UNNEST, and a CTE before an UNNEST is no longer modelled as a table. - 2026-10-02 Lineage reads the columns inside an array subscript, as in Athena, Presto and Trino
SELECT arr[n] AS part FROM logsandSELECT split(principal_id, ':')[n] AS part FROM logs(Mantis 4817). The index column selects the element, sologs.nis now a source ofpart(and of thesplitfunction's result), as it already was forelement_at(split(principal_id, ':'), n); TSQLResolver2 resolvesntologs.TObjectName.getSubscriptExpressions(),TFunctionCall.getSubscriptExpressions()andTIndices.getSubscriptExpressions()expose the expressions inside[...], andTIndices.acceptChildrenvisits them. - 2026-10-02
COUNT(*)over a table function has a row-filter source, as it has over a table (Mantis 4815): SQL ServerSELECT COUNT(*) AS n FROM DB..FN(@D)addsfdr COUNT.COUNT <- DB..FN.RelationRows. WithOption.setShowJoin(true)a join on a table function's column,ON t.id = f.c, records the function's output column as the join side. - 2026-10-02 resolver2 reads a derived table's alias column list, as in
FROM (SELECT z FROM t3) d(y)(Mantis 4814, 4832, 4819). The columns were named after the SELECT list, soywas NOT_FOUND againstd; inSELECT (SELECT max(y) FROM (SELECT z FROM t3) d(y)) AS m FROM othe enclosing table captured it andy.getSourceTable()waso. It isdnow, withResolutionResult.getStatus()EXACT_MATCH, in the default resolver, resolver2 and parse-time linking alike (the deprecated legacyEResolverType.RESOLVERis unchanged). The list renames the columns by position, also for a set operation(... UNION ALL ...) AS r(rank, type), and names the cells of a VALUES derived table(VALUES (0, 'G'), (1, 'I')) AS r(rank, type), whoser.rankandr.typewere NOT_FOUND. TrinoSELECT x.p.address.city FROM (SELECT payload FROM events) AS x(p)resolves toxwith the field pathp.address.city, and its lineagev.city <- events.payloadis back. - 2026-10-02 Spark SQL parses a nested type whose closers are written together, as in
CREATE TABLE orders_raw (order_id BIGINT, customer STRUCT<name: STRING, address: STRUCT<city: STRING>>),ARRAY<ARRAY<ARRAY<INT>>>andCAST(x AS STRUCT<a: ARRAY<INT>>)(Mantis 4838). The lexer read>>as one operator token that no grammar rule accepted; it now gives a run of>or<one character at a time, as the Hive and Databricks lexers do. The same token made the shift operators unparseable:SELECT a << 2, a >> 2, a >>> 2 FROM tnow parses, withEExpressionType.left_shift_tandright_shift_t(>>>isright_shift_ttoo, its three tokens tell it apart), and the shifts bind below+and-as in Spark's operator table. Because the lexer gives one bracket at a time, a spaceda > > bis read as a shift as well, as Hive, Databricks and BigQuery already read it. - 2026-10-02 Athena keeps the argument of an aliased UNNEST, as in
FROM events CROSS JOIN UNNEST(arr) AS t(x)(Mantis 4825).TUnnestClause.getColumns()(orgetArrayExpr()forUNNEST(split(csv, ','))) was null for the aliased forms and set only for the unaliased ones, soarrwas neither resolved toeventsnor available to lineage. - 2026-10-02 OceanBase in a MySQL or system tenant reads a routine's DECLAREd variable as that variable, as MySQL does (Mantis 4813). In
CREATE PROCEDURE p() BEGIN DECLARE c INT; SELECT c FROM t1; END;withCREATE TABLE t1 (c INT, d INT),cin the SELECT hadgetDbObjectType()column andgetSourceTable()t1 fordbvoceanbase; it is nowvariable, anddstays the column of t1. The routine body also keeps every statement MySQL keeps: DECLARE, OPEN, FETCH, CLOSE, IF, CASE, SET, RETURN and the ITERATE stub were dropped for OceanBase, SET inside a routine became a DB2 statement, and a LOOP threw a NullPointerException out ofparse(). The Oracle tenant is unchanged. - 2026-10-02
IScope.getVisibleNamespaces()of resolver2 terminates when called on a SELECT, UPDATE, DELETE or MERGE scope or on its FROM scope (Mantis 4820). The SELECT scope asked its FROM scope for the visible namespaces and the FROM scope asked its parent, the same SELECT scope, so the call overflowed the stack; the owner now reads the FROM scope's own relations, and every namespace is listed once. - 2026-10-02 The lineage of SQL in several files,
new DataFlowAnalyzer(File[], Option), is the lineage of the same SQL in one file. The metadata that the analyzer reads from the CREATE statements of the files kept the columns of a table without their types when the table came from a later file, and it took the files in the order their threads finished. A STRUCT column keeps its fields in its type, so withCREATE TABLE orders_raw (..., items ARRAY<STRUCT<item_name STRING, qty INT64>>)in one file andCREATE VIEW v AS SELECT item_name FROM orders_raw, UNNEST(items)in another, the edge fromorders_raw.items[*].item_nametov.item_namewas missing in about one run out of three. The files are now merged in their order, and a column keeps its type; a column that an earlier file gives without a type, as aCREATE TABLE ... AS SELECTdoes, takes the type of a later definition. - 2026-10-02 Athena, Spark SQL, Databricks, Presto and Trino lineage shows the files of a table, as it already did for Hive, Impala and Redshift:
CREATE EXTERNAL TABLE events (city STRING) STORED AS PARQUET LOCATION 's3://b/e/'gives the path's3://b/e/'indataflow.getPaths()and an edge from's3://b/e/'.citytoevents.city, so that a table can be traced back to its files.TCreateTableSqlStatement.getTableLocation()returns the location given by theLOCATIONclause of Athena, Spark SQL and Databricks, and by the table propertyexternal_locationof Presto, Trino and Athena, orlocationof the Iceberg and Delta Lake connectors, inWITH (...); it was null for all of them. A table without a column list, as inCREATE TABLE events USING DELTA LOCATION 's3://b/e/', gets an edge from's3://b/e/'.*toevents.*. In Hive,CREATE EXTERNAL TABLE events LIKE src LOCATION 's3://b/e/'gets the same edge; it gave a path with no column and no edge. ACREATE TABLE ... AS SELECTwrites its result to the location, so it gives the location but no path, as in Hive. The Spark SQL and DatabricksLOCATIONoption is the newECreateTableOption.etoLocation, with its path inTCreateTableOption.getTableLocation(); in Databricks it wasetoUnknown. - 2026-10-02 BigQuery, Athena, Presto and Trino keep the lineage of a STRUCT field read through a CTE or a subquery, as in
WITH c AS (SELECT customer FROM orders_raw) SELECT customer.address.city FROM c: the read comes from the CTE columncustomer, so fromorders_raw.customer, because a CTE has no field nodes of its own. In 4.2.13 it came from every leaf field ofcustomerwhen the script declaredorders_raw, and it had no lineage without DDL, through an aliased subquery (x.customer.name) or a CTE column list, or in Athena, Presto and Trino. The same read in a WHERE or ON condition, a GROUP BY or a BigQuerySELECT * REPLACE (customer.name AS customer)comes from the CTE column too; a WHERE condition added a CTE column named after the field (address), and TSQLResolver2 now resolves the columns of a REPLACE expression. The read has no edge when the DDL of the column that the CTE passes on has no such field, or when its first part also names the table it is read from (c.name FROM q AS c). A BigQuerycustomer.address.citywith an alias on the table that declarescustomer, as inFROM orders_raw o, z, comes fromorders_raw.customer.address.city; it came from a columnz.customer.address.city, or had no lineage when the script declaredz. The new page STRUCT columns in lineage, explained shows the lineage of STRUCT columns with examples. - 2026-10-02 BigQuery, Athena, Presto and Trino lineage models a STRUCT or ROW column as a tree: the declared column, and below it a node for every field, intermediate fields included, with
[*]for the element of an array (orders_raw.customer.address.city,orders_raw.items[*].item_name). A read of the whole column comes from the declared column, and a read of a field from exactly that field, with and without DDL in the script. Before, BigQuery with DDL had only the leaf fields, soSELECT customercame from every leaf ofcustomerandSELECT customer.addressalso from its siblingcustomer.phone, and Athena, Presto and Trino read every field from the whole column (events.payload). The tables in the output list the field nodes after their column, and a field that the DDL does not declare gets no node, as a column the table does not declare gets no column. - 2026-10-02 The STRUCT tree covers the forms around a field read.
UNNEST(items) AS ireads the array elementorders_raw.items[*], and BigQueryi.item_namethe fieldorders_raw.items[*].item_name, also for a nested array as inUNNEST(customer.orders);WITH OFFSET AS offstays a column of the UNNEST. A PrestoUNNEST(payload.items) AS t(item)readsevents.payload.items[*]instead of a columnevents.itemsthe table does not have.SELECT customer.*reads the fields ofcustomer: one result column per field when the DDL declares them, otherwise one column fromcustomer; Athena, Presto and Trino readpayload.*that way too instead of as every column ofevents. BigQueryUPDATE ... SET customer.name = ...andMERGE ... UPDATE SET customer.name = ...writeorders_raw.customer.name, where the write went to a columnorders_raw.namewithout DDL and was dropped with DDL.INSERT INTO t SELECT STRUCT(...) ...writes the declared fields of a STRUCT column by position, andARRAY[customer.customer_id]reads the field. When two tables in scope could own the column, as inSELECT customer.address.city FROM orders, items, the read is an orphan instead of a column of an invented tablecustomer.address; when only one of them declarescustomer, the read comes from that one. - 2026-10-02 Presto, Trino and Athena keep the fields of a
ROW(...)type and the element type ofARRAY(...)in the parse tree:TTypeName.getColumnDefList()andgetTypeOfList()were empty for them, soCREATE TABLE events (payload ROW(address ROW(city VARCHAR)))declared no fields. BigQuery resolves the columns inside anINTERVALexpression, as inDATE_ADD(d, INTERVAL SAFE_CAST(n AS INT64) DAY), which TSQLResolver2 never visited. In Athena, Presto and Trino a column declared by DDL wins over a table of the same name for the first part of a dotted name, sopayload.events.id FROM source, eventsreads the fieldevents.idofsource.payload. - 2026-10-02 Athena, Presto and Trino keep the lineage of a read two or more fields deep into a STRUCT or ROW column, as in
SELECT payload.address.city FROM events(Mantis 4822). The read comes from the fieldevents.payload.address.city: withCREATE EXTERNAL TABLE events (payload STRUCT<address:STRUCT<city:STRING>>)in the script it was dropped without an error, and without DDL it invented a columnevents.city. The same holds behind a table alias (e.payload.address.city) or a schema-qualified table (sch.events.payload.address), with more fields or a subscript (payload.address.city[1]), in WHERE, GROUP BY, DELETE and correlated subqueries, and for aROW(...)column; Trino now also reads the one-field forms of Mantis 4811. A dotted name is read the way Trino reads it, longest qualifier first, sosch.events.idis the column of the tablesch.eventsin scope even when an enclosing query aliases another tablesch. A column that receives such a read is named after its last field (INSERT INTO t SELECT payload.address.city ...writest.city;SELECT payload.addresswrotet.payload.addressand now writest.address). When no DDL decides which of two joined tables ownspayload, lineage reports an orphan column instead of inventing a tablepayload.address. - 2026-10-01
DataFlowGraphGenerator.genDataflowGraph(Dataflow, boolean)andgenDlineageGraph(EDbVendor, boolean, dataflow, boolean)can keep the tables and resultsets that take part in no relationship (Mantis 4812). Withtrue, a script that only declares a table, orSELECT 1 AS n, gives a graph with that node and no edge, and a table nothing reads joins the graph next to the connected ones; the methods without the option still drop them, as before. - 2026-10-01 Athena and Presto keep the lineage of a read of a STRUCT or ARRAY field, as in
SELECT payload.items[1].name FROM events(Mantis 4811). WithCREATE EXTERNAL TABLE events (payload STRUCT<...>)in the script the read was dropped without an error, because the table's lineage columns were the struct's field names (items,name); they are now the declared columns with a node for every field, and the read comes from the fieldevents.payload.items[*].name, also through a table alias. Without DDL the read no longer invents a columnevents.items: a qualifier that names no table in scope is read as a column with a field path, as Trino does. - 2026-10-01 Lineage of a join with a
VALUESderived table, as inLEFT JOIN (VALUES (0, 'G'), (1, 'I')) AS r(rank, type) ON r.type = c.cos_type, no longer fails withNullPointerException: ... "joinResultSet" is nullin PostgreSQL, Athena and Databricks (Mantis 4802). The statement is analyzed to its end, so the join condition reportsr.typeandc.cos_typeas row influence, the lineage SQL Server and Snowflake give for the same SQL, and no literal becomes a column of a table. A scalar subquery that is itself aVALUEScell now feeds its column, in every dialect. - 2026-10-01 Athena parses
GROUPSwindow frames, inline and in aWINDOWclause, such asfirst_value(value) OVER (ORDER BY ts GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)(Mantis 4803). The frame keeps its unit,TWindowFrame.getLimitRowType()returnsELimitRowType.Groups, and both bounds; it is not read asROWS. A window namedgroupsis still a window name, as inOVER (groups). - 2026-10-01 Athena accepts a
VALUESquery as the body of a CTE, as inWITH v(id, label) AS (VALUES (1, 'a'), (2, 'b')) SELECT id, label FROM v(Mantis 4804). The CTE columns take the rows by position, and lineage reports no physical source for the literals. - 2026-10-01 Athena accepts a lambda whose single parameter is in parentheses, as in
filter(ARRAY['a', ''], (x) -> COALESCE(x, '') <> '')(Mantis 4805). Lineage no longer reports a lambda parameter as an orphan column ofpseudo_table_include_orphan_columnwhen the query has aFROMclause, in every dialect with lambdas:SELECT transform(arr, x -> x + t.off) FROM treads onlyt.arrandt.off. TSQLResolver2 marks lambda parameters withTObjectName.ttobjLambdaParameter, and matches them by the dialect's identifier rules on a name's first segment: in Snowflake the quoted"X"in"x" -> "X"stays a column of the table, andx[1]orx.nameread the parameterx, where they were reported as a columnxor an orphan. - 2026-10-01 Athena accepts a field or a subscript directly after a call, as in
element_at(queues, 1).queue_nameandsplit(principal_id, ':')[2](Mantis 4806, 4807). The postfix is inTFunctionCall.getIndirection(), and lineage reads the call's arguments. The subscript ofMAP(...)[key], which was parsed and then dropped, is kept the same way. - 2026-10-01 Athena accepts an aggregate
FILTER (WHERE ...), as inCOUNT(*) FILTER (WHERE "date"(creation_date) <> partition_date), also withDISTINCTandOVER(Mantis 4808). The predicate is inTFunctionCall.getFilterClause(), and lineage matches PostgreSQL's.filteris still an identifier everywhere else: thefilter(array, lambda)function and a column or alias namedfilterparse as before. - 2026-10-01 Athena accepts
MAPas a table alias, a qualifier or a column name in a query, as inSELECT map.field0 FROM events map(Mantis 4809).MAP(...)and theMAP<k, v>type keep their meaning. - 2026-10-01 Athena accepts
DATE(expression), the alias ofCAST(expression AS DATE), as inSELECT DATE(c.year || '-' || c.month || '-' || c.day) FROM dates c(Mantis 4810). It is a call shaped like"date"(expression), so lineage linksyear,monthanddayas it does for the cast;DATE('2020-01-01')stays the typed literal it was. - 2026-10-01 Lineage reads a table function's column in a WHERE, ON or CASE condition and in GROUP BY or HAVING through the function, as it already did in the select list (Mantis 4797). In
SELECT ... FROM [dbo].[fn_StrToTable](@strId, ',') tbl_Id JOIN dim_LagerSapClassifier LSC ON (tbl_Id.id = LSC.classifierId)the join condition had no source from the function, and the derived table(SELECT DATARIFERIMENTO FROM HERMIONE_AX443_FILIALI_ESTERE_ULT(@D_RIF) WHERE DATARIFERIMENTO = @D_RIF)filtered on nothing of its own; both now read the function's output. A table function the catalog does not know is no longer taken to have none of the columns read from it (TFunctionCall.isColumnInThisTableFunctionanswers not sure instead of no): its columns were reported as orphans inpseudo_table_include_orphan_column, or bound to a table next to it, and now flow from the function. - 2026-10-01 The statements of a script see the tables its
CREATE TABLEstatements declare before them while they are parsed, whatever the resolver (Mantis 4797). Column linking at parse time (TCustomSqlStatement.linkColumnToTable) reads the parser's catalog, which got the script'sCREATE TABLEonly from the resolver run after the parse, and withEResolverType.NONEnever: inCREATE TABLE t1 (a int); CREATE TABLE t2 (b int); SELECT a, b FROM t1, t2,parser.getSqlEnv().searchTable("..t1")returned null andaandbhad nogetSourceTable(), and in the SAP IQ query of Mantis 4752,RESOLVERandNONEread the subquery nameKas a column ofCollateralsinstead of the enclosing alias. Each declaration is now taken when it is parsed, as resolver2 places it: in the database and schema of theUSEstatements before it, also inside a block, and a procedure's temporary table only inside that procedure. ACREATE TABLE ... AS SELECThas the columns of its query (aSELECT *leaves them open), a#tis the same table in every database, soSELECT a FROM #tafterUSE db2andSELECT a FROM tempdb..#tread it, and aSELECT ... INTO #tinside a procedure is read by the procedure's later statements in every resolver type. The resolvers still register the declarations themselves, at their positions; withNONEthe parser's catalog gets what resolver2 would put in it when the parse succeeds, sogetSqlEnv()holds them in every resolver type, and a procedure'sSELECT ... INTO #tno longer reaches it, where another procedure's#twas read as that table. - 2026-10-01 Knowing the script's tables while it is parsed exposed four rules of column linking, which now follow SQL (Mantis 4797). An unqualified name that two tables of a statement both have is ambiguous: with
t1andt2both declaringa,SELECT a FROM t1, t2andSELECT a FROM t1 x, t1 yno longer readaas a column of the first table, with the caller's catalog too, unlessUSING (a)or aNATURALjoin merges the column; and a guess between several tables never takes one the catalog proves has no such column. An unqualified name in a derived table belongs to that derived table while one of its tables may have the column, as a derived table sees neither the tables next to it nor the enclosing query: inSELECT x.a FROM t, (SELECT a FROM u WHERE a > 0) xthe innerawas taken for a column oftwhenever the catalog knewt, and lineage reported a derived table over a table function, such as(SELECT PORTFOLIO_ID FROM TABLE(pkg.fn(...))) PF, as reading a table next to it; ClickHouse still prefers an enclosingWITH ... ASalias to a column. A subquery in an expression reads a name from its own tables while they may have it, and reads the enclosing query's column only when the name is compared with a column of the subquery's own tables, its own tables do not prove it and the enclosing query does, by one rule at parse time and in resolver2 alike: inSELECT (SELECT max(v) FROM customfieldvalues WHERE resourceid = resumeid) FROM (SELECT id AS resumeid FROM resumes) r,resumeidisr's, where resolver2 took it for a column ofcustomfieldvalues, while in(select Jahr from m_version_table2 where Jahr234 = year(now()))both names staym_version_table2's though a derived table around the subquery names them too. In MySQL, and OceanBase in a MySQL or system tenant, a name declared as a local variable or a parameter of the routine is that variable, also when a table of the statement has a column of that name, as MySQL documents: afterDECLARE BirthDate DATE,SELECT BirthDate INTO BirthDate FROM Employeesreads the variable, and lineage no longer reportsEmployees.BirthDateflowing into it, whileVALUES(c)andDEFAULT(c)inON DUPLICATE KEY UPDATEread the columnc. Oracle reads the column there, as Oracle documents, and now does so with a script's own declarations too. - 2026-10-01
CountSqlreads each file by its byte order mark and writes its CSV andsql_statements.jsonas UTF-8 (Mantis 4801). It read every file in the platform charset, so a UTF-16 file came out as one statement full of U+0000, and a UTF-8 file with a byte order mark gave no statements at all: in the test corpus, a 552-statement Oracle script counted 0. A file without a mark is still read in the platform charset, which-Dfile.encodingsets. On a windows-1252 JVMsql_statements.jsonno longer holds windows-1252 bytes, and the CSV no longer writes a file name it cannot encode as?. The vendor taken from a directory name no longer depends on the default locale: under a Turkish locale the directoryINFORMIXgavedbvgeneric. - 2026-10-01 The JSON that
CountSqlwrites tosql_statements.jsonand the analyzer v2 export (AnalysisResult.exportJson()) stay valid when a value holds a control character (Mantis 4800). Their escapers passed U+0000-U+001F through raw, apart from the few each one named, so a statement, or a quoted routine or table name, holding one made the JSON invalid: run over the stored-procedure test corpus, 275 of the 2624 lines thatCountSqlwrote held a raw U+0000. Such characters are now written as\u00XX, and the analyzer export also escapes\band\f. - 2026-10-01
JSON.toJSONStringwrites every value inside a JSON array by its type (Mantis 4799). A number, a boolean or a nested array inside a list or array went through the bean writer and came out as{}or as its getters, so re-serializing parsed metadata JSON, as the analysis of a SQLFlow or Grabit export,FileSplitterandLargeFileDetectordo, turned[1,true,[2],2.5]into[{},{},{"empty":false,"first":2,"last":2},{"infinite":false,"naN":false}]. A top-level list of strings came out as each string's getters, a bean whose list held a null threwJSONException, andNaNorInfinitywas written as is, which is not JSON; it is now written asnull, asJSON.stringifydoes. The lineage and graph JSON that GSP builds itself hold no such values and are unchanged byte for byte. - 2026-10-01 The lineage graph JSON stays valid when a node label contains a double quote, a backslash or a control character (Mantis 4798).
DataFlowGraphGenerator.genDataflowGraph,genDlineageGraphandgenERGraphkey theirtooltipmap by the node label, shortened when it is longer than 25 characters, andJSON.toJSONStringescaped values but wrote map keys verbatim, soSELECT o.amount AS "customer_lifetime_value_usd" FROM orders oproduced"tooltip":{""customer_...e_value_usd"":...}, which no JSON reader accepts (the output first reported in Mantis 4385). A backslash, as in the label'C:\temp\new_folder' || o.name, kept the JSON valid but made the key read back as a different string, so a viewer that looks a tooltip up by its label found nothing.JSON.toJSONString, with or without aWriter, now escapes every map key like a value, writes a control character as\u00XXinstead of raw, no longer cuts a string short at a U+FFFF character, and no longer leaves a trailing comma after a null at the end of a list or array.
GSP Java version 4.2.13(2026-10-01)¶
- 2026-09-30 [Sybase, Sybase IQ, SQL Anywhere] A SELECT-list alias used again in its SELECT block is the alias (Mantis 4752). In
select COL_1 as ALIAS_1, ALIAS_1 as ALIAS_2 into TABLE_2 from TABLE_1,ALIAS_1was read as a column ofTABLE_1, soTABLE_2.ALIAS_2had no lineage, and with no catalog lineage reported a columnTABLE_1.ALIAS_1that does not exist. As SAP IQ and SQL Anywhere document, an unqualified name that matches an alias defined earlier in the same SELECT block now means that alias, in the select list, WHERE, GROUP BY and HAVING, for the older resolver and for resolver2:TObjectName.getSourceColumn()is the alias'sTResultColumnandgetSourceTable()is null. Lineage reportsTABLE_2.ALIAS_2 <- TABLE_1.COL_1. The alias wins over a column of the same name, as SQL Anywhere documents, and a table-qualified name still reaches the column. This applies todbvsybase,dbvsybaseiqanddbvsqlanywhere; Sybase ASE (dbvsybasease) is unchanged. A name in a subquery stands for an alias of the SELECT block around it too, as SQL Anywhere allows: inSELECT a AS x, (SELECT x) AS y FROM outer_t,yreadsa, no longer the columnouter_t.x. That holds when the subquery provably has no such column: it reads no table, or the catalog knows all the columns of each table it reads, as bound in that statement's own database, and none has that name. A table with no metadata, or one whose columns are not all known (as afterSELECT * INTO #t), may have it, so there the name stays a column of that table. Lineage follows the alias wherever the resolvers bound one, also over a column of the same name: inSELECT DepartmentID AS DepartmentName FROM Departments WHERE DepartmentName = 'Marketing'the filter readsDepartmentID, notDepartments.DepartmentName. - 2026-09-30 [Sybase, Sybase IQ, SQL Anywhere] An
ORDER BYin the argument list ofLISTparses (Mantis 4721).LIST([ALL | DISTINCT] expr [, 'delimiter'] ORDER BY expr [ASC | DESC], ...), as SAP IQ and SQL Anywhere document it, was a syntax error atORDER, so the statement, or the whole procedure, got no lineage. It now parses indbvsybase,dbvsybaseiqanddbvsqlanywhere, and the clause is theTFunctionCall.getSortClause()of the call; Sybase ASE, which has noLIST, still rejects it. Wherever the parser keeps such anORDER BYas theTFunctionCall.getSortClause()of the call (PostgreSQLstring_aggandarray_agg, Oracle and TeradataXMLAGG, among others), its keys now resolve to their tables like the arguments, in resolver2 and in the older resolver, and lineage reports each key as an indirect (fdr) source of the function, as it already did for OracleXMLAGG: in PostgreSQLstring_agg(s.a, ',' ORDER BY u.b),TObjectName.getSourceTable()ofu.breturned null and lineage had no edge fromusr.b. AnXMLAGGkey named like the alias of the call, ascinXMLAGG(... ORDER BY c) AS c, is now the column instead of an unlinked alias. A key of BigQueryARRAY_AGGstays a direct source, now of the table it names: inARRAY_AGG(s.a ORDER BY u.b)overds.src s JOIN ds.usr u, lineage gaveu.bto the first table of the FROM clause and reportedds.src.b; it now reportsds.usr.b. TheORDER BYof BigQuerySTRING_AGGis still not kept in the syntax tree. - 2026-09-30 [Oracle, Snowflake] The WHEN conditions of a conditional multi-table insert (
INSERT ALL,INSERT FIRST) are row filters (fdr) of exactly the INTO clauses they route rows to. An INTO clause without a column list or VALUES, such asWHEN ottl > 290000 THEN INTO special_orders, got no filter at all; a qualified condition such asWHEN X.K > 0, or a name inside a function, reached no column; and every condition was applied to every target, so inINSERT ALL WHEN K > 0 THEN INTO S.Y (C1) VALUES (V) WHEN W > 0 THEN INTO S.Z (D1) VALUES (V) SELECT ...Wwas reported as a filter ofS.Y.C1. AnINSERT ALLclause is now filtered by its own condition, anINSERT FIRSTclause by its own and every earlier one, and an ELSE clause by all of them, and each condition name is bound to the select item it reads (TObjectName.getSourceColumn()), including the names in the conditions of a CASE inside a WHEN. A name read through a wildcard (SELECT X.* FROM S.X X) reaches its column when the table is declared or the wildcard reads a CTE; over an undeclared table it gets no filter, because inside a routine it may be a parameter rather than a column. - 2026-09-29 [Oracle, Snowflake] A multi-table insert (
INSERT ALL,INSERT FIRST) has lineage for every INTO clause, by that clause's own column list and VALUES. The INTO clauses were mapped by the subquery's column order, soINSERT ALL INTO S.Y (C2, C1) VALUES (V, W) SELECT X.V, X.W FROM S.X XsentX.VintoC1when the script declaredS.Y, and had no lineage at all when it did not. A second INTO clause into the same table replaced the first, the ELSE branch had no lineage, a VALUES expression such asV + Wor a select-list alias was not followed, and a VALUES name ofINSERT FIRSTwas bound to the insert target, soTTable.getLinkedColumns()of the target listed the value names as its columns. Each VALUES item now reads the select item its names are bound to (TObjectName.getSourceColumn()), every branch of a UNION subquery reaches the target, and a name that reads no select item, such as a PL/SQL variable, is not credited to a column of the subquery's tables. - 2026-09-29 A DML target column whose name starts with its table's alias no longer reports the alias as a schema (Mantis 4747). In Oracle
MERGE INTO S.T TGT USING (...) SRC ON (...) WHEN MATCHED THEN UPDATE SET TGT.OBJCOL.ATTR = SRC.V, S.T.W = SRC.V, the targetTGT.OBJCOL.ATTR, an attribute of the object columnOBJCOL, reportedTObjectName.getSchemaString()TGT,getTableString()OBJCOLandgetColumnNameOnly()ATTR, the same shape as the schema-qualifiedS.T.W, whilegetSourceTable()wasS.T; lineage then wrote a columnS.T.ATTRthat the table does not have. The same name in a WHERE clause or a SELECT list was already read as the aliasTGT, the columnOBJCOLand the attributeATTR(getPropertyToken()). A target is now read the same way, under everyEResolverType, in theSETofUPDATEandMERGEand in the column lists ofINSERT,MERGE ... INSERTand OracleINSERT ALL, for every vendor: BigQueryUPDATE ds.t tgt SET tgt.info.name = 'x'now names the fieldnameof the STRUCT columninfo. Lineage writesS.T.OBJCOL.ATTR, or the declared columnS.T.OBJCOLwhen the script declares the table, the column a read of the attribute lands in; an UPDATE or MERGE into such a declared table no longer loses the edge, and an INSERT column list no longer writes the attribute into the declared column at its list position. Two attributes of one object column set by one statement keep their own values. A schema-qualified target such asS.T.W, MySQLtest.t1.cor SQL Serverdbo.t.cis unchanged. - 2026-09-29 [Sybase, Sybase IQ, SQL Anywhere] The Watcom CASE statement of a procedure body parses (Mantis 4717).
CASE [expr] WHEN ... THEN statements ... [ELSE statements] END [CASE]insideCREATE PROCEDURE ... BEGIN ... ENDwas a syntax error from its firstWHEN, so the procedure lost its lineage, while the same logic written withIF ... THEN ... END IFworked. It now parses to aTCaseStmt, whosegetCaseExpr()holds the WHEN branches and the ELSE statements, withEND CASEand with a bareEND, fordbvsybase,dbvsybaseiqanddbvsqlanywhere, and lineage reports the statements of every branch. The statement splitter also no longer takes theCASEofEND CASEfor the start of another CASE, which merged every statement after such a procedure into it. Sybase ASE has no CASE statement and still rejects it. - 2026-09-29 [SQL Server, Sybase] An
EXECof a procedure that a later unit defines binds its arguments (Mantis 4730). Each query of a SQLFlow ingester export, and each file of a multi-file analysis, is analyzed in turn, so when an export listedOD_CustomTransferOfficersbeforeCopyOrganizationProd,EXEC PARAMETER_CONTEXT_TEST.CopyOrganizationProd @SrcOrgID, @AnalystIDbound no argument: lineage had neither@OrgID <- @SrcOrgIDnor@SenderID <- @AnalystID, which it reported when the export listed the two procedures the other way round. Such a call's arguments,OUTPUTones included, are now bound in either order, and the procedure the call names is described by its definition: indataflow.getProcedures()and the JSONdbobjs,CopyOrganizationProdhas the name and position of its ownCREATE PROCEDURE, where it had those of theEXEC. The column lineage of anINSERT ... EXEC, and calls of functions, into a routine that a later unit defines still depend on the order. - 2026-09-29 [Redshift, Sybase] The date part of a date function is no longer taken for a column (Mantis 4760). After
DELETE FROM hist WHERE d < DATEADD(YEAR, -1, CURRENT_DATE),INSERT INTO tgt SELECT * FROM histwas reported with a columnYEARofhistfeedingtgt.YEAR, andTObjectName.getSourceTable()ofYEARreturnedhist. The first argument of Redshift'sDATEADD,DATEDIFF,DATE_PARTandPGDATE_PART, ofDATEADD,DATEDIFF,DATENAMEandDATEPARTin SAP ASE, SAP IQ and SQL Anywhere, and of SAP IQ'sDATEFLOOR,DATECEILINGandDATEROUNDis now a date part for the parser, both resolvers and lineage, as it already was for SQL Server, Snowflake and Vertica. A column in another argument, such asyearinDATEADD(day, year, d), is still a column, and so is the first argument of a function namedDATENAMEorDATEPARTin Redshift, which has no such built-in: the parser no longer marks it as a date part. - 2026-09-29 A procedure's temporary table is its own: lineage no longer merges the temporary tables that unrelated procedures create under one name (Mantis 4715). Next to a procedure that runs
create table #T(COL_2 varchar(10)), the table increate procedure P1() begin select COL_1 into #T from S.TABLE_1; insert into S.TABLE_2(COL_1) select T.COL_1 from #T as T endtook the other declaration's columns, so#T.COL_1 -> S.TABLE_2.COL_1was lost andS.TABLE_2had no source; afterCREATE TEMP TABLE,CREATE TEMPORARY TABLEorCREATE VOLATILE TABLEin another procedure, anINSERTwithout a column list was mapped onto that procedure's columns and reported a column feeding a table it never reaches. A temporary table is now shared where the SQL proves it: a procedure sees the tables of the procedures that call it, and a session table (PostgreSQL, Greenplum, Redshift, MySQL, Snowflake, BigQuery, TeradataVOLATILE, SAP HANA local, SAP IQ and SQL Anywhere#tables, OraclePRIVATE TEMPORARY) created by a procedure is also seen by its caller after the call, while a SQL Server or SAP ASE#table ends with the procedure that creates it. A reference before the declaration, or in a procedure that neither declares the table nor is called with it, no longer reads it, and a temporary table named like a permanent table hides it only inside its procedure. Global temporary tables (Oracle, Db2, Teradata, SAP HANA and VerticaGLOBAL TEMPORARY, SQL Server##) stay one table for every procedure; PostgreSQL's and Snowflake'sGLOBAL TEMPORARYare session tables, as those databases define them. Scripts without procedures are analyzed as before. - 2026-09-29 [SQL Server] A procedure, function or trigger whose body holds a statement GSP cannot parse can keep the rest of its body:
TGSqlParser.setRecoverRoutineBodyErrors(true), orOption.setRecoverRoutineBodyErrors(true)for dlineage, where it applies to the analyzed SQL and not to SQL parsed on the way (dynamic SQL); off by default. Without it such a routine fails as a whole and keeps no body statement, so one statement GSP cannot parse loses the lineage of every other statement in the routine. With it the statement holding each syntax error is skipped -- the innermost statement, in the innermostBEGIN ... ENDblock around the error, that the raw statement splitter finds -- and the routine is parsed again over the same tokens, so every position stays the original one and temporary tables and variables keep their context across the skipped statement. The skipped statements' errors are reported bygetRecoveredSyntaxErrors()(dlineage adds them as syntax errors noted "statement at lines a-b skipped, rest of the routine analyzed") and do not count ingetErrorCount(). A statement that holds aBEGIN ... ENDblock (an IF or WHILE whose condition is broken), or that runs on past a semicolon into the next, is not skipped: it would take statements that parse with it. A routine it cannot recover -- an error in the header, one no statement holds, blocks that do not balance, such a statement -- fails exactly as without the option: every parse of the routine starts from its tokens' state before the first, since a parse changes the tokens it reads. - 2026-09-29 [SQL Server]
ALTER TABLE ... SWITCHhas lineage. The parser readALTER TABLE source SWITCH [PARTITION p] TO target [PARTITION q], but dlineage built no relation for it, so a load that switches a staging table into a partition of a fact table, or a partition out to an archive table, had no lineage at all. The rows move one way (effectType="switch_partition", a newEffectTypeconstant). With every column of both tables known (aCREATE TABLE, or aSELECT ... INTOthat names them all, in the script, or metadata) each column flows into its namesake under the identifier rules, a real column named*([*]) included, and a column only one of the tables has gets no relation; with one table's columns known the other takes them, as SWITCH requires the same columns on both; with neither, one relation joins the source's*to the target's*.EXCHANGE PARTITIONswaps, so it keeps a relation in each direction. The table-level relation'spartitionis the source partition when one is written (SWITCH PARTITION 1 TO archive), which is whatexchange_partitionrecords too: the partition of the altered table. The SLPC adapter lists the new effect with the other storage operations it does not map yet. - 2026-09-29 A CTE exposes only the columns its SELECT list projects, and the body of a CTE or of a derived table no longer sees the FROM clause that contains it. A CTE without a star claimed any other name when its body read a table, so in
WITH s AS (SELECT id FROM t1) SELECT t2.id FROM t2 WHERE EXISTS (SELECT 1 FROM s WHERE s.id = t2.id AND region = 'EU')the correlatedregionbound tos, and lineage published a columnsdoes not have instead oft2.region; a column of another joined table without metadata became ambiguous and lost its lineage. A name a body's own FROM clause lacks bound to a sibling table or to the CTE or derived table itself, which in Snowflake replaced a select-list alias referenced in WHERE. LATERAL and APPLY bodies, and every Teradata or DuckDB derived table, still see the tables to their left, and a wildcard over a CTE still binds to it. - 2026-09-28 A MERGE's row-level lineage reaches its target whatever the USING source is. With a table,
#temp, VALUES or CTE source, or a subquery without a filter of its own, the ON and WHEN conditions stopped at the source's result set (RESULT_OF_<alias>), and a source table filled under a filter or a join (SELECT ... INTO #t ... WHERE) passed none of that on, so those columns reached no table. The rows the conditions pick, and such a source table's rows, now reach the target'sRelationRows(effectType="merge") and the rows of the MERGE's UPDATE and INSERT actions, as a filtered subquery source's rows already did. Oracle'sUPDATE ... WHERE,DELETE WHEREandINSERT ... WHEREin a MERGE are analyzed as conditions too. - 2026-09-28 [ClickHouse] A column, table or database named
formatin anINSERTis no longer taken for itsFORMATclause. The parser took the firstformatword for the clause and the text after it for data rows, soINSERT INTO t (format, b) VALUES (1, 2),INSERT INTO t (a, format) VALUES (1, 'csv'),INSERT INTO format (a) SELECT x FROM sandINSERT INTO db.format FORMAT CSV ...failed to parse. The clause is now theFORMATafter the table, outside parentheses, that is followed by a format name, so a setting namedformat(SETTINGS format = 1) is passed over too. - 2026-09-28 [Formatter] Each
FormatterFactory.ppcall prints in the output format its own option asks for.ppkept the output config of the firstGFmtOpt.outputFmt = GOutputFmt.ofhtmlcall in a static field and printed every later call in the JVM with it, so after one HTML callppandSqlFormatter.formatreturned HTML for default options, andremoveCommentparsed its own HTML as SQL and returned a second layer of HTML (17,715 characters for a 36-character query). A config set withFormatterFactory.setOutputConfigstill applies to every call until it is set back tonull, and the comment-removal pass now always reads SQL back, also under such a config. Threads can share such a config: the calls that first printed with it at the same time could throw aNullPointerException, becauseHtmlOutputConfigmarked itself ready before it had filled its renders. - 2026-09-28 [ClickHouse, Formatter] The rows after
INSERT ... FORMAT <name>keep their text. They were read as SQL tokens, soFormatterFactory.ppand pp2 printedINSERT INTO t FORMAT CSV\n1,a\n2,b;as the single row1,a 2,b, turned the tabs ofFORMAT TSVrows into spaces, merged runs of spaces and re-cased values such asselectandnull, and pp2 reportedOK. The rows are now one token holding the text as written, from where ClickHouse starts reading them: after the format name, the spaces and tabs after it, and one line break. pp2 compares that token byte for byte, so output that changes a row is no longer reportedOK. Rows a SQL reader would take for something else are data too: a first row readingselect(the statement failed to parse), and rows holding only a comment or a blank line (removed byremoveCommentand the empty-line options). The HTML output escapes the rows and shows their line breaks. - 2026-09-28 [Informix] An
EXECUTEorEXECof a prepared statement starts at its keyword. The splitter began the statement afterEXECUTEwithout adding it, sogetStartToken()was the space after the keyword,toString()returnedstatement_1 USING :order_date;, and the formatter printed the keyword outside the statement (EXECUTE s1;EXECUTEon one line). Parse results and corpus coverage are unchanged - 2026-09-28 [ClickHouse] Any
--starts a line comment, as in ClickHouse, where the space after it may be omitted. GSP kept MySQL's rule, where--followed by anything but a space is two minus signs, soSELECT a --original value FROM swas read asa - -original AS value: lineage reported a source columnoriginaland a target columnvalueinstead ofa, and--commentlines stopped a script from parsing.SELECT 1--1is now1followed by a comment, as ClickHouse reads it, and an operator stops before a--(a !=--noteis!=and a comment). In the rows ofINSERT ... FORMAT, which are data, a;after--or#still ends the rows:1,--none--;or1,-- x;followed by another statement no longer takes that statement into the rows - 2026-09-28 [ClickHouse]
stmt1 PARALLEL WITH stmt2keeps its words. The parser rewrote their text to;to split the two statements, soFormatterFactory.ppand pp2 printedDROP TABLE a PARALLEL WITH DROP TABLE b;asDROP TABLE a ; ;and reportedOK: the combinator was silently lost, and pp2's content check could not see it. The words now keep their text, stay keywords (socaseKeywordsapplies to them) and belong to neither statement, so the first statement'stoString()isDROP TABLE a(it wasDROP TABLE a ;) and each statement's text still parses on its own; the parse and the lineage of both statements are unchanged.FormatterFactory.ppgives the keyword case to any keyword between two statements, which no statement's case step reached before: Informixexecutein front of anEXECUTEstatement now takes it too - 2026-09-28 [Formatter, SQL Server, Sybase] pp2 keeps every
GObatch separator. A script that took pp2's per-statement path, because a statement did not parse orPp2FormatOptions.wholeDocumentFastPathwas off, came back without itsGOlines and with statusOK: each statement was formatted without itsGO, and nothing put it back. AfterCREATE PROCEDURE p AS SELECT 1the lostGOput the next batch in the procedure's body.GO 5keeps its count on its line, and a directPp2Engine.formatcall for Azure SQL splits batches atGOtoo. If the output of the per-statement path changes the input's tokens, pp2 now returns the input unchanged with statusFAILEDinstead - 2026-09-28 [Formatter] The delimited-name case (
caseQuotedIdentifier) no longer changes a double-quoted text that the script or the dialect makes a string, inFormatterFactory.ppor pp2. AfterSET QUOTED_IDENTIFIER OFF,SET ANSI_NULLS, QUOTED_IDENTIFIER OFForSET ANSI_DEFAULTS OFF(SQL Server, Azure SQL, SQL Anywhere), after SQL Anywhere'sSET TEMPORARY OPTION quoted_identifier = 'Off'and Firebird'sSET SQL DIALECT 1, and anywhere in Access, MDX, MySQL and the other dialects whose double quotes can delimit strings,SELECT "abc"keeps"abc", where 4.2.12 upper-cased it and pp2 reported the whole document as formatted. A laterSET QUOTED_IDENTIFIER ONis not followed, so a double-quoted name after it keeps its case. Without such a statement SQL Server, Azure SQL, SQL Anywhere and Firebird double quotes are names, as GSP's parser reads them: a script for a connection that has the option off must turn it off itself - 2026-09-28 [Formatter] The name cases of 4.2.12 (
caseTableName,caseColumnName,caseTableAlias,caseColumnAlias) no longer change a name in backticks where the dialect delimits names with them, as ClickHouse, Databricks and Spark do:SELECT `Id` FROM `Orders`keeps both names - 2026-09-28 [Formatter] Under those name cases a name written alike comes out spelled alike. Where a column alias and its use (
SELECT a AS Foo FROM t ORDER BY Foo), or a column and a declaration name resolution does not report (WITH c(Foo) AS (SELECT 1) SELECT c.Foo FROM c, ClickHouseALTER TABLE t MODIFY COLUMN Foo Int32), would come out spelled two ways, the four settings are off for the whole input andPp2FormatResult.isNameCaseApplied()is false; 4.2.12 wroteAS FOO ... ORDER BY foo - 2026-09-27 [Snowflake] A statement in the block of
CREATE TASK ... AS BEGIN ... ENDhas lineage. Looking up the procedure such a statement belongs to went back and forth between the task and the unnamed block until the stack overflowed, so the analysis reported only an error; the task's statements now belong to no procedure - 2026-09-27 With
SELECT *over a join, a column that the join'sUSINGlist names is published once, matched by the vendor's identifier rules. A quoted name such as"a(b"made the statement lose its lineage,USING (a, b)publishedA1andB1,USING ("A")did not merge, and aUSINGin a comment or in a subquery, or one that does not join the table, merged the column anyway - 2026-09-27 [Formatter] Formatting no longer slows down on long scripts. With logging off, the formatter still built a log message for every token edit, each walking a stack trace, and it stripped the blanks before a line break with a regex that went quadratic on a long run of blanks: a customer script that took 1.7 s now formats in 25 ms, with the same output
- 2026-09-27 [Formatter] Removing the tokens before a join's table (
SourceTokenOperator.removeAllBeforeTokenVT) no longer loops forever when one of them was already deleted or token operations are off - 2026-09-27 [OceanBase] Splitting a script no longer slows down on an unclosed comment or quoted text. The regexes that hid comments and strings before looking for system-tenant DDL retried from every position, so a 130 KB script took 6.9 s; it now takes 3.5 ms
- 2026-09-27 Lineage's procedure exclusion patterns (
*,?) and the folding ofLTRIMandRTRIMin dynamic SQL match in one pass, where regexes could retry every split of a long name or text; the results are unchanged - 2026-09-27 The parallel analyzer's merges join a call of a routine, analyzed by one worker, to the routine another worker defined by the vendor's identifier rules, taken from the names as written. In PostgreSQL
SELECT * FROM "MyFn"()now reaches the lineage of the routine"MyFn", which it missed, andmyfn()or"MyFn"()no longer reach the lineage of a different routine ("MyFn",myfn), also with normalized output (Option.setNormalizeOutput(true)), which renames both before the merge - 2026-09-27 [Oracle] In a PIVOT query a bare select-list name no longer resolves to a quoted pivot column of another name. In
SELECT Store FROM orders PIVOT (SUM(order_total) FOR order_mode IN ('direct' AS "Store")),Storeis Oracle'sSTORE, a column oforders, where lineage reported the pivot column"Store" - 2026-09-27 [BigQuery] A column of
UNNEST((SELECT ...))is published under its name as written (MixedCol), like the columns around it, where its folded name (MIXEDCOL) was - 2026-09-26
DlineageUtil.getIdentifierNormalColumnName,normalizeColumnName,getIdentifierNormalTableName,getIdentifierNormalFunctionName,getIdentifierNormalNameandgetColumnNameare deprecated. Lineage no longer calls them; they keep forwarding for callers outside the library, and each deprecation names its replacement for identity and for display - 2026-09-26 A relationship endpoint carries the name of the column its ids point to. When lineage makes one column of several references to it, such as a column reached both through
SELECT *and by name, the endpoints that named it by another spelling now carry the column's published name, in the full and the simple output, the JSON model, the CSV exports and after the parallel analyzer's merges. InCREATE TABLE tgt AS (SELECT p.*, a AS b FROM src p)both edges intotgt.bare labelledb, where one saidB. In a PostgreSQL function that reads aRECORDinIF EXISTS (...)beforeINSERT INTO rolepermissions (role_psk, permission_psk) VALUES (query_record.r_psk, query_record.p_psk),permission_pskis fed byquery_record.P_PSK, where the label saidR_PSK. A label can therefore change case or delimiters with the name its column is published under (EMPLOYEES_DUMP.employee_idis nowEMPLOYEES_DUMP.EMPLOYEE_ID). A relationship that then repeats another in every attribute is reported once. The public merges of published output,DataflowUtility.mergeDataflowsandDataflowUtility.iterativeMergeDataflowsFromFiles, keep apart two relationships one merged dataflow reported apart: the same edge reached from two places in the SQL keeps both coordinates, where a merge kept only the first when their labels agreed. The parallel analyzer withignoreCoordinateno longer drops an edge from one of two stars of one select list: inselect s1.*, s2.* into tgt from s1 join s2 on s1.id = s2.id,tgt.*is fed from both stars, where its merge kept only the edge froms1.* - 2026-09-26 Columns that lineage reaches through
SELECT *are told apart by the vendor's identifier rules instead of by their folded names. With metadata that lists a PostgreSQL or Oracle tabletwith the columns"Amount"andamount,CREATE VIEW v AS SELECT * FROM treports two columns oftand ofv,"Amount"andAMOUNT, each fed by its own column, where one column (AMOUNTin PostgreSQL,Amountin Oracle) fed by both was reported. [Snowflake] A string used as a column alias, as inCREATE TABLE t2 AS (SELECT p.*, a COMMENT 'Remark' FROM t p), is no longer also reported as a column'REMARK'of the select list and oft2. The parallel analyzer's spilled merge no longer reports a column twice when one worker reached it through a star and another named it (SQL ServerCAPARTENZAbesideCAPartenza); it publishes the columns its in-memory merge publishes. The in-memory merge no longer merges a column that one worker only inferred without an identity, such as a name taken from a routine parameter inINSERT INTO tbl VALUES (a), into a same-named column another worker published with one; the spilled merge already kept them apart. The system propertygsp.dlineage.starLinks=legacyrestores the grouping by folded name - 2026-09-26 [Oracle] A record declared as a row of the table it is inserted into (
m g%ROWTYPE, thenINSERT INTO g VALUES m) fills each column ofgfrom the field of the column's name, also for a field writtenm.lidbySELECT ... INTO m.lid. AfterUPDATE g SET v = NULL WHERE lid = m.lid; SELECT s.NEXTVAL INTO m.lid FROM dual; INSERT INTO g VALUES m;the insert reaches the columng.lidthat theUPDATEreads, where a second columnlidofgwas reported;m."Lid"fillsg."Lid"andm.Lidfillsg.LIDthe same way - 2026-09-26 The parallel lineage analyzer (
ParallelDataFlowAnalyzer) keeps column identity where it lost it. Each worker's copy of the catalog keeps every object's name as it was created: PostgreSQL"Amount"no longer becomes a secondamount, a Netezza view created asS."$v_q"is found by the worker that reads it instead of being reported as a new table"$v_q", and functions, synonyms and Oracle packages keep their return columns, priority and members. Merging the workers' results keeps one column per identity: a result set keeps its own columns (a.idandb.idare no longer merged into one), a column named*is not merged into the star, a merged column keeps every attribute a worker stated for it, and SQL ServerNameandNAMEare one column also when results are spilled to disk - 2026-09-25 Two columns of one result set are qualified by their tables (
qualifiedTable) when they are one name under the vendor's rules, not when their folded texts match: HANAsp.Position, sp.POSITIONare still qualified, and so area.NAME RSK, b.NAME RSK(one alias twice, shown asRSKandRSK(1)) and BigQuery struct leavesa.left.Name, b.right.name; a literal'Name'beside the columnNameno longer is. A table function'sRETURN TABLEcolumns are matched to its query's columns by identity - 2026-09-25 [SQL Server, BigQuery] Lineage output tells a column named
*from a star. Such a column is published withstar="false"(column.standsForStar()reads the marker), soDataflowUtility.mergeDataflowsno longer adds anexpand_staredge from it to the table's other columns, the ER graph keeps it, and a whole-row pseudo star of a table that also has such a column is reported under its own endpoint instead of the column's id. A star written into the catalog for a table whose width is not known, byCREATE VIEW ... SELECT *or by lineage writing back a star it could not expand, is recorded as such (TSQLTable.addUnresolvedStar(),TSQLColumn.isUnresolvedStar()) and is not a column of the table; a catalog column named*is a column, so a synonym over it keeps itssynonymrelationship - 2026-09-25 [SQL Server, BigQuery] A column named
*([*]in SQL Server,`*`in BigQuery) is a column, not a star, although it is shown as*.INSERT INTO t2 (x, y) SELECT [*], a FROM treportst.* -> INSERT-SELECT-1.* -> t2.x; previouslyt2.xhad no source, and a columnAthattdoes not have was reported - 2026-09-25 A select-list expression that contains
*, such asa * borCOUNT(*), is no longer taken for a star. ACREATE TABLE ... AS SELECTwhose list has one is defined by its select list, so a laterINSERT INTOthat table without a column list maps by position to its columns instead of adding columns named after the inserted ones, and a script variable such as$listinNOT IN ($list)is no longer reported as a column of the table - 2026-09-25 [Oracle] A synonym in the metadata catalog is matched to the analyzed SQL by identity under Oracle's rules.
FROM ZY."address_synonym" areads the stored lower-case synonymaddress_synonymand reaches its base table; the unquotedZY.address_synonym, which Oracle reads asADDRESS_SYNONYM, no longer does. A profile's own rules for synonyms (IdentifierProfile.builder(vendor).withObjectRules(ESQLDataObjectType.dotSynonyms, ...)) apply to them. A synonym relationship stated both by the metadata and by the catalog is reported once, and a base table named only by the catalog reports no source position - 2026-09-25 [Snowflake, ClickHouse, BigQuery, Oracle] The SQLDep and sqlflow metadata readers key names by the vendor's rules instead of a folded name: Snowflake
ordersand"orders", ClickHouseOrdersandorders, and BigQueryp.d.Ordersandp.d.ordersare two tables, and Oracle proceduresload_pandLOAD_Pin SQLDep metadata are one. Procedures, functions, triggers and synonyms are keyed by their own object rules, and a metadata server of another vendor than the analysis keeps that vendor's rules for its tables and columns - 2026-09-25 [Oracle] A pipelined table function's cursor may name a schema-qualified table by its bare name: in
FOR item IN (SELECT src_table.id FROM hr.src_table)the function's column traces tohr.src_table.id, no longer to a tablesrc_tablethe query does not read. Object and collection types are found by their names as written, so"demo_row"andDEMO_ROWare two types. TheModelBindingManagerpipelined registry methods that take text keys (indexObjectType,getObjectTypeFields,indexCollectionType,getElementTypeName,findPipelinedSignature,findPipelinedSignatureAny,getPipelinedSignatures) and thePendingPipelinedCallSiteconstructor are deprecated in favour ofindexObjectTypeFields,getObjectTypeFieldsByKey,indexCollectionElementType,getCollectionElementType,findPipelinedSignatureByKeys,findPipelinedSignatureAnyByKeys,getPipelinedSignaturesByKeyandPendingPipelinedCallSite.forFunctionKeys - 2026-09-25 [Oracle] Lineage reads a package body's variables, constants and cursors from every member of the package.
v_count := 0inreset_countandINSERT INTO log_t(n) VALUES (v_count)inlog_itnow read one package variablev_count; previously each member got its own unrelated copy, and only a member named like its package saw the package's.FOR r IN c LOOPandFETCH c INTO ...over a package-level cursorcin a member now follow that cursor, sosrc.a -> dst.athrough it is reported - 2026-09-25 [Oracle] A routine declared inside another routine or inside a trigger reads the enclosing routine's variables: in
PROCEDURE outer_p AS v NUMBER; PROCEDURE inner_p IS BEGIN INSERT INTO dst(a) VALUES (v); END; BEGIN SELECT a INTO v FROM src; inner_p; END;thevininner_pisouter_p's, sosrc.a -> dst.ais reported. AFETCH ... INTOthose variables binds each cursor column to its own target instead of fanning every column onto every target. A declaration in the nested routine still shadows the outer one: a nestedCURSOR cis its own cursor - 2026-09-25 [Oracle]
%ROWTYPEand%TYPEanchors name the cursor, record or type declared in scope before a table of the same name, as PL/SQL does: with a tablecand a localCURSOR c,r c%ROWTYPEtakes its fields from the cursor, and nothing flows out of the tablec. A record-field anchor such ass_col g_gof.sColumn%TYPEis a type, no longer a data flow from a local variable that happens to be calledsColumn - 2026-09-25 [SQL Server, Sybase, MySQL] After
USE db, a reference inside a routine to one of its parameters is that parameter. A second, differently scoped copy is no longer created:CREATE PROCEDURE find_jobs @nm VARCHAR(50) AS ... WHERE JobTitle = @nmreports one@nm. An argument passed to a routine binds to the callee's parameter, not to a same-named local of the caller - 2026-09-25 [SQL Server] Inside a routine body, the routine's own parameter wins over a same-named variable of a later batch. In
CREATE PROCEDURE copy_it (@OrgID INT, @SenderID INT, @AnalystId INT = NULL) AS EXEC push_it @OrgID, @SenderID, @AnalystId, followed afterGObyDECLARE @AnalystID INT ... EXEC copy_it @SrcOrgID, @AnalystID, the@AnalystIdpassed topush_itiscopy_it's parameter. The batch's@AnalystIDfills@SenderID(the second positional argument) and no longer appears to reach the column fed by@AnalystId - 2026-09-25 [Oracle] A trigger's correlation names (
:NEW,:OLD,REFERENCINGaliases) and its local variables are separate names: withREFERENCING NEW AS nandDECLARE n NUMBER,:n.a := nwrites the localninto the new row's columna. Two triggers that declare the same variable name keep two variables - 2026-09-25 Variables, cursors, declared types, trigger correlation names and table variables in the lineage model are keyed by the scope that declares them and their names as written, under the analysis's identifier rules.
ModelBindingManager.getTableByName(String)finds one by its name as written, such as@x; a name composed with a routine's scope, such asPROC.@X, no longer finds a variable, andModelBindingManager.getModel(Object)no longer returns variables or cursors for such composed strings. NewModelFactory.createReferencedVariable(...)resolves a reference to the declaration visible from it;ModelFactory.createVariable(...)keeps declaring in the current scope.ModelBindingManager.pushIdentityScope(String),ModelBindingManager.peekIdentityScope()andModelFactory.pushIdentityScope(String)are deprecated - 2026-09-25 [Oracle] A call to a package member written with its package, such as
emp_admin.hire_employee(...), binds to that member, so its arguments flow into the member's parameters instead of into an opaque function result. A call never binds to a trigger of the same name - 2026-09-25 [SQL Server]
EXEC schema.[innerSp]binds to a procedure defined as[schema].[innerSp], and a call writtensync2_CanUpdatebinds tosync2_canUpdate: calls match definitions by the vendor's identifier rules, not by raw text - 2026-09-25 [DB2, Oracle, SQL Server] A delimited routine name is matched by the vendor's rules. DB2
F_GetRFECustomerName(...), which DB2 reads asF_GETRFECUSTOMERNAME, no longer links toCREATE FUNCTION "F_GetRFECustomerName", a different routine; an Oracle call"mixedCase"(...)now links toCREATE FUNCTION "mixedCase". A delimited name that contains a parenthesis, such as SQL Server[P(], is read as one name - 2026-09-24 [Teradata] Parsing Teradata on several threads at once no longer loses data type names. Two threads could fill the type maps together on their first lookup and lose entries for the rest of the JVM, so
x(DATE)parsed as a function call; the maps are now filled once, before any thread reads them - 2026-09-24 A call is published as made from the routine it is written in, not from the first routine of that name: in PostgreSQL, a call of
h()inside the overloadp(a int, b int)was published as made fromp(a int) - 2026-09-24 Lineage tells tables apart by the vendor's identifier rules also when the analysis configures no identifier profile. Under the vendor defaults it keyed a table by a folded name, so it merged tables the rules keep apart, such as Snowflake
ordersand"Orders", and split tables the rules call one; a table found in the SQL, in the catalog or in a metadata file now carries the identity of its name as written
GSP Java version 4.2.12(2026-09-28)¶
- 2026-09-27 [Formatter] New
GFmtOptsettings give table names, column names, table aliases and column aliases a case of their own:caseTableName,caseColumnName,caseTableAliasandcaseColumnAlias. Unset, they followcaseIdentifier, so existing output does not change. Which name is which comes from name resolution (TSQLResolver2), so they apply only to SQL that parses. They never change delimited names ("x",[x],`x`), and where resolution does not report every use of a table name or alias (for example SQL Server'sUPDATE o ... FROM orders o) and one name would get two cases, they are off for the whole input - 2026-09-27 [Formatter]
Pp2FormatResult.isWholeDocument()tells whether pp2 returnedpp's output for the whole input, andisNameCaseApplied()whether the per-kind name cases above applied.FormatterFactory.ppclears its per-session objects even when formatting throws - 2026-09-27 [Formatter] Requested transformations are accepted in their exact expected form:
Pp2FormatOptions.transformPolicy(TransformPolicy) letsTokenEquivalenceand pp2's guards accept variable case, delimited-name case, compact mode's rewrite of--comments as/* -- ... */, and comment removal, each only as asked, or unchanged. Optimizer hints and MySQL/*! ... */comments never change, and name case applies only to real names in each dialect (not to double-quoted strings in MySQL and related dialects, never to{...}ODBC escapes). With the policy, pp2 keeps compact or comment-removing output instead of falling back to recovery layout - 2026-09-27 [Formatter]
GFmtOptFactory.newRegisteredCopyregisters a full copy of aGFmtOptunder a fresh session id, andGFmtOptFactory.removereleases a registration - 2026-09-27 GSP format worker service (
gsp_format_worker): the Instant SQL Formatter's compact mode is applied, with its line width in compact mode; table, column, alias and other identifier case each apply to their own names; column aliases keep their spelling; the list style no longer stacks function arguments (a call such asCOALESCE(a, b, 'none')stays on one line, as in the classic formatter);/checkaccepts apolicyfor requested transformations; and each candidate reports the options its run did not apply (options_not_applied)
GSP Java version 4.2.11(2026-09-25)¶
- 2026-09-25 No change to the parser library: 4.2.11 is 4.2.10 plus three endpoints in the GSP format worker service (
gsp_format_worker):/checkreports whether formatted SQL kept every token and comment of the input,/parse-probereports which of several dialects parse a script, within a time budget, and/highlightcolors SQL by the GSP lexer without changing its text
GSP Java version 4.2.10(2026-09-24)¶
- 2026-09-24 [Doris, StarRocks] More column definitions parse in
CREATE TABLE: the aggregate typesHLL_UNION,BITMAP_UNION,REPLACE_IF_NOT_NULL,PERCENTILE_UNION(StarRocks) andQUANTILE_UNION(Doris);ARRAY<...>,MAP<...>andSTRUCT<...>column types, nested ones such asARRAY<ARRAY<INT>>included;CREATE EXTERNAL TABLE; StarRocks generated columns written without parentheses (newcol DOUBLE AS array_avg(arr));DECIMALV3(p, s)and inverted indexes withPROPERTIES (...)on Doris;VARBINARYwithout a length on StarRocks. Doris readsPROPERTIESvalues written in double quotes, and the>>operator parses on both - 2026-09-24 [Doris, StarRocks] More
CREATE TABLE ... AS SELECTforms parse with their query: a list of column names, as inCREATE TABLE t (a, b, c) AS SELECT k1, k2, k3 FROM src, which names the columns of the query by position; aPROPERTIES (...)table option, also before the query (on DorisPROPERTIESstays usable as a column name); and table clauses the grammar does not read, such asDISTRIBUTED BYorPRIMARY KEYon StarRocks orPROPERTIESwith double-quoted strings, which are skipped while the table name, the column list and the query are kept. A syntax error inside the query is reported instead of the query being cut short - 2026-09-24 [Sybase] After
SET QUOTED_IDENTIFIER OFF, a double-quoted text such as"psychology"is read as a character string, as ASE reads it, instead of a column, so lineage no longer reports a column the script never named.SET QUOTED_IDENTIFIER ONrestores the identifier reading. A script that never sets the option keeps reading double-quoted text as an identifier - 2026-09-24 Lineage keeps two different names apart when the legacy name fold gives them one string. Examples: PostgreSQL and Snowflake
"Amount"andamount, ClickHouseuserIdanduserid, Oracle and Dameng"Amount"andamount, and SQL ServerAmountandAMOUNTunder a case-sensitive collation. Without metadata, a reference throughSELECT *used to report both columns as its source; it now reports its own. FlinkCREATE TABLE OrdersandCREATE TABLE ordersare now two tables. A column list overSELECT *(CTAS, view, CTE) still gets the column in its position. Analyses without such a pair produce the same output as before - 2026-09-23 [ANSI, Generic, ODBC] Regular identifiers fold to upper case and delimited ones stay exact, as the SQL standard specifies:
"ORDERS"now matchesorders, and"orders"no longer does. Metadata stored in upper case is found by a bare reference - 2026-09-23 [Access, DAX, MDX, Power Query] Identifier rules follow each product. Access, DAX and MDX compare delimited names case-insensitively and keep their case, and Power Query M compares names case-sensitively. Access reads
[Orders]as a delimited name. InSQL_RENDERlistings a DAX column keeps its brackets, and a simple DAX table name is shown without quotes (Orders, while'Sales Territory'keeps them) - 2026-09-23 [Sybase, SQL Anywhere] A quoted name matches its other spellings case-insensitively (
"Orders"andordersare one table on ASE, IQ and SQL Anywhere), so metadata registered under a quoted name is found andSELECT *expands to its columns - 2026-09-23 [DuckDB, SQLite, Firebird] DuckDB and SQLite compare quoted names case-insensitively and keep their case; Firebird folds unquoted names to upper case like Oracle. Metadata stored as
"Orders"("ORDERS"on Firebird) is found byorders, andSELECT *expands to its columns - 2026-09-23 [Flink] Identifiers keep their case and match case-sensitively, quoted or not, as Flink specifies: a backticked
`userId`is the columnuserId, andsrcno longer resolves to a tableSrc - 2026-09-23 [Teradata] Quoted names compare case-insensitively, as Teradata specifies, and keep their stored case, so metadata that quotes every name (as the SQLFlow exporter writes it) matches unquoted references
- 2026-09-23 [Hive, Spark SQL, Impala, Databricks] Backticked names compare case-insensitively, as each product documents, and keep their stored case:
`Orders`resolves to metadata stored asorders, andSELECT *through it expands to the real columns. Backticked column names are shown without backticks in lineage output - 2026-09-23 [Redshift] Delimited identifiers fold to lower case and compare case-insensitively, as AWS documents when
enable_case_sensitive_identifieris off:"Orders"andordersare one table. Delimited column names are shown without delimiters in lineage output - 2026-09-23 Lineage follows a configured
IdentifierProfile. Under a stricter configuration (for example SQL Server with a case-sensitive collation), tables such asdbo.Ordersanddbo.ORDERS, and columns such asAmountandAMOUNT, stay two objects in the lineage model, the output merges and resolver2'sSELECT *push-down. A configured profile with neither metadata nor DDL no longer produces an empty analysis. Output under the default rules is unchanged - 2026-09-23 The catalog's schema index is keyed by the name service for every vendor, so
TSQLEnv.searchTablegives the same answer whether it is passed aTObjectNameor a qualifiedString. Previously the two could disagree under a configured rule for all but Snowflake and BigQuery - 2026-09-22
IdentifierProfilerules can be configured per object category withIdentifierProfile.builder(vendor).withObjectRules(ESQLDataObjectType, IdentifierRules), for example case-insensitive table names alongside case-sensitive column names.TSQLEnv(vendor, profile),TGSqlParser.setIdentifierProfile,Option.setIdentifierProfile(lineage) andTSQLResolverConfig.setIdentifierProfileapply one configuration to the catalog, the parser, resolver2 and lineage of an analysis, and a conflicting configuration throws - 2026-09-22 [Spark SQL, DuckDB, ClickHouse] Columns removed by a star exclusion (
* EXCEPT (...),* EXCLUDE (...)) are no longer projected into lineage. A ClickHouseEXCEPT (x) REPLACE (...)keeps itsEXCEPT, and an exclusion by regular expression keeps the full expansion, since its excluded set cannot be computed. Two stars of unknown width in one select list are no longer split between the targets by position - 2026-09-22 [BigQuery] Tables whose names differ only in case stay two tables in the schema index and in lineage
- 2026-09-21 Lineage keeps a column's spelling and catalog identity through lookup, star expansion, model copies and merging. [Oracle] A
%TYPEanchor keeps its written name, and an ordinary qualified type name no longer creates a dependency - 2026-09-21 [Formatter] PrettyScore penalizes a script formatted into one over-wide line: the new TOKEN_WALL, INDENT_NOT_SHOWN and WIDTH_DOMINANT findings fire only when most of the script sits on one line, so such output no longer outranks a real wrap
- 2026-09-20 [Snowflake] Quoted names that differ only in case (
"Orders",ORDERS) stay separate catalog objects, and environment merges keep stored names - 2026-09-20 Lineage looks up a delimited table by its spelling as written, so a table missing from the catalog is not retried as a different, unquoted object
- 2026-09-20 The catalog provider is now the only index in
TSQLEnv. Oracle"Orders"andORDERSno longer share an entry, soSELECT * FROM "Orders"no longer expands to the columns ofORDERS. SQL Server[my.db].dbo.t2is filed under the catalogmy.db, and a name with a dot inside it is no longer found by its last part - 2026-09-20
TTable.getCatalogStatus()(ETableCatalogStatus:NOT_CHECKED,FOUND,NOT_FOUND) reports whether a base table was found in the catalog, separately from how its columns resolved. Oracle"Orders"andORDERSno longer collide in the catalog store - 2026-09-20 Metadata files declare how their names are written:
"nameForm": "SQL_LEXICAL"or"CATALOG_STORED". A name read back from a database catalog (Oracle stores a column created as"Amount"underAmount) is now matched as that stored name. The sqlflow servers format (plain and sharded) defaults toSQL_LEXICALand the JSON manifest toCATALOG_STORED. Eager and lazy catalog loading and the model validator all honour the declaration, and a misspellednameFormfails loudly - 2026-09-20 [MySQL, Doris, OceanBase, StarRocks] A catalog column, function, procedure or trigger is normalized by its own object type rather than the table rule, so a column registered as
AmountreportsgetName()=Amount - 2026-09-19 Keyword tables were audited against each vendor's official reserved words. 108 missing reserved words were added across 11 dialects, among them Snowflake
WINDOW, MySQLQUALIFYandTABLESAMPLE, and HiveMERGEandEXCEPT. The SAP IQ and HANA lists were extended, SAP IQ no longer shares ASE's table, and thirteen dialects get a table of their own. Generated SQL names delimit these words - 2026-09-19
SQL_RENDERlistings print one deterministic spelling per object instead of echoing each spelling the script used, sodbo.SalesOrderand[dbo].[SalesOrder]are one table.SqlNameGenerator.QuotePolicy(WHEN_NEEDEDby default, orALWAYS) controls the delimiters - 2026-09-19 The Tables/Fields listings (
TGetTableColumn,TSQLResolver2ResultFormatter) de-duplicate by object identity rather than by rendered text: BigQuerySalesandSALESare listed as two tables, and OracleSales,SALESand"SALES"as one - 2026-09-19 New
SqlNameGeneratorgenerates a SQL name from stored name segments with correct delimiting and escaping. For example, a SQL Server stored name[db name], whose brackets are part of the name, becomes[[db name]]]. A name it cannot prove correct fails with a reason instead of returning a plausible-looking spelling - 2026-09-19 Display names come from the name service.
DisplayNameMode.CANONICAL, which used to behave likeDISPLAY, now folds unquoted names as the vendor does (upper case on Oracle and Snowflake, lower case on PostgreSQL), while quoted names keep their case - 2026-09-18 Opt-in SQL comment object bindings: with
Option.setCollectCommentBindings(true)lineage collects each comment together with the AST object it belongs to, keeps the bindings through merging, filtering and parallel analysis, and reports coverage and degradation diagnostics. Off by default - 2026-09-18 [Oracle] Bare and qualified PL/SQL calls (
proc_name;,pkg.member()) bind to the declared package members, including forward calls, and keep their argument lineage, call-site comments and anonymous callers; a fullwidth comma (U+FF0C) is accepted as a separator without rewriting the SQL - 2026-09-17 [SQL Server] Temporary-table metadata stays local to each routine, while proven caller and session visibility is kept. Function-name output is compatible again, and expanding declared columns keeps their source coordinates
- 2026-09-17 DDL metadata in a script is resolved at each statement's position, and catalog names are kept distinct from their SQL spellings
- 2026-09-17 [Doris, StarRocks]
CREATE TABLEis built as aTCreateTableSqlStatementby the statement splitter and parsed by the grammar, where it used to pass through unparsed - 2026-09-17 [Oracle] A bind variable is accepted as the
XMLTABLEquery string, andPASSINGexpressions are traversed so the resolver and lineage see their SQL inputs (MantisBT #4740) - 2026-09-16 [Oracle] A script's own comments reach the output: the xml procedure model gains
commentanddisplayName(GSP never fillsdisplayName),oraclePackagegainscomment, andgetCommentAfterNode()returns the comment after a node instead of the leading one (it used to throw on a node without one); the newgetCommentBeforeNode(boolean)returns the comment block that belongs to a node - 2026-09-16 [Databricks] Liquid clustering (
CLUSTER BY) in CREATE TABLE and CTAS is parsed and its columns are registered against the target for the resolver and lineage (MantisBT #4732) - 2026-09-16 [Databricks] Parenthesized table sources in FROM are parsed, keeping the underlying table name for resolution and column lineage (MantisBT #4733)
- 2026-09-16 [Teradata] Generic table operators accept
ASinput aliases,PARTITION BYandORDER BY; the input clauses are exposed apart from the output alias and resolve against the ON source only (MantisBT #4734) - 2026-09-16 [Snowflake]
COPY INTOwith an explicit target column list and a stage source binds the destination columns to the COPY target and keeps the selected subset in stage/file lineage (MantisBT #4735) - 2026-09-16 [Snowflake] Function names with an omitted schema (
db..func()) are parsed and resolved, applying Snowflake's PUBLIC schema rule independently of the session's current schema (MantisBT #4736) - 2026-09-16 [Oracle] The physical table inside a Data Pump
RELATIONAL(...)wrapper is parsed with its flashback clause and alias, so resolver and lineage keep the actual source table (MantisBT #4737) - 2026-09-16 [Oracle] Support
SHARINGbefore table definitions and CTAS - 2026-09-16 [Oracle] Support
AS OF SNAPSHOTflashback expressions - 2026-09-16 [Oracle] Preserve bind parameters in character type lengths
- 2026-09-16 [Oracle] Recognize
U-prefixed Unicode string literals - 2026-09-16 [Oracle] Support asterisk precision for
DECIMALandDEC - 2026-09-16 [Oracle] Support index maintenance clauses after a partition exchange
- 2026-09-16 [Oracle] Support parenthesized value tuples in row comparisons
- 2026-09-15 The Tables/Fields listing drops a
t.*line once every column oftis printed on its own line (listStarColumn=falsestill hides it outright), and resolver2 seesCREATE TABLEstatements earlier in the same batch - 2026-09-14 [BigQuery, Snowflake] A struct field whose base column more than one relation in
FROMcould provide is left unresolved, instead of being bound silently to the first relation. resolver2 now modelsJOIN ... USINGmerged columns, soSELECT c FROM a JOIN b USING (c)resolvescinstead of reporting it as ambiguous - 2026-09-11 [SQL Server] A signed literal in an
EXECargument (EXEC p @NumberRecords = -1) keeps its digits and is typed as unary minus (MantisBT #4724) - 2026-09-11 [Snowflake] A
CREATE FUNCTIONbody delimited by single quotes is returned bygetBlockBody(), stamped as a Snowflake block node, like the$$form; lineage was not affected (MantisBT #4723)
GSP Java version 4.2.9(2026-09-09)¶
- 2026-09-05 [Snowflake]
IDENTIFIER(...)table names are recognised from the SQL tokens, so whitespace or a comment before the opening parenthesis no longer leaks into the source table name; qualified-name parts and quoted spelling are preserved (MantisBT #4714) - 2026-09-05 [Formatter] PrettyScore no longer rewards an alias split off its expression under the ALIAS_COLUMN_VAR rule
- 2026-09-04 [SQL Server] MERGE and UPDATE targets that are writable CTEs are analyzed: the modified projections map to the one physical base table behind the CTE. An ambiguous or non-updatable CTE stays a result set and raises a syntax hint instead of inventing a base table
- 2026-09-04 Projected DML targets in lineage are hardened against the same shape
- 2026-09-04 [Formatter] Statements inside PL/SQL
IFbranches are laid out on their own lines, and a standalone comment is aligned with the code it precedes - 2026-09-04 Fix the source offsets reported for the end-of-file token
- 2026-09-02 [Snowflake] Parse dynamic table refresh DML
- 2026-09-01 [Snowflake] Parse the dynamic table
EXECUTE ASuser and column nullability - 2026-08-31 [Oracle] A trigger's
SELECT INTOkeeps each pseudo-record target by ordinal, so a multi-columnSELECT INTOno longer collapses every column onto the final field. CustomREFERENCINGbindings and positional handling through set operations are preserved (MantisBT #4707) - 2026-08-31 [SQL Server] Optional support for
:name,:1and:@namebind variables, off by default and scoped to the parser instance (Option.setEnableMssqlColonBindVariables, also honoured byDataFlowAnalyzer);ITokenListHandlecallbacks are restored for delegated parsers (MantisBT #4706) - 2026-08-30 [SQL Server]
SEND ON CONVERSATIONkeeps its parsedconversation_handlewhen the optional clauses are absent, instead of failing a token-to-object-name cast (MantisBT #4690) - 2026-09-03 [SQL Server]
DynamicSqlSite.getUnresolvedFragments()names the holes of a dynamic-SQL site: for everyEXEC/sp_executesqlsite the abstract evaluator saw, oneUnresolvedFragmentper value it could not fold, with the variable or parameter (@Where,@entity), the hole kind (SqlFragment.HoleOrigin, now alsoQUERY_ASSIGNED_VARIABLEandFLOW_DEPENDENT_VARIABLE), the reason, the data source the value would come from (dbo.SSF_Entity.Entity), and the 1-based origin span to highlight (the assignment, the parameter declaration, or the reference).getMaterializedText()is the materialized argument when it reduced.INSERT INTO t EXEC(@sql)(the string form, no module name) is now analyzed like its top-level twin: it records a site and its inner statement's lineage.getUnresolvedHoleCount()now equals the list size whenever the fragments are known: a variable assigned from a query, appended to a literal, reported0exact; a query-assigned statement executed throughINSERT INTO #t EXEC sp_executesql @sqlreported-1(the evaluator did not descend intoINSERT ... EXEC). A site whose argument is nothing but one unknown value is reported asargument is a runtime variableinstead of a parse failure of text that was never SQL. In LEGACY trust mode a RESOLVED site whose argument carries a real hole no longer lists proven relationship ids. The evaluator now treats a variable written by anOUTPUTargument or return status of a static procedure call, or byFETCH ... INTO, as an unknown value: previously it was believed NULL, soCONCAT(...)/ISNULL(...)erased it and a fabricated literal string could be analyzed as resolved lineage; those sites are now UNRESOLVED with the variable listed. Lineage output is otherwise unchanged - 2026-09-02 [Formatter]
TokenEquivalenceexposes its two halves,solidTokensEquivalentandcommentsPreserved, and the format worker (gsp_format_worker) now applies them instead of a second token policy of its own: a candidate GSP core accepts is usable in the worker too (the Oracle SQL*Plus-vs-keyword case), a pp candidate core rejects is reported asINVARIANT_FAILEDwhile the token-safe pp2 result stays usable (the DB2=?files), and the comment check compares text and order rather than counts - 2026-09-02 [Formatter] Fixes for the ISF prettyscore corpus handoff:
FormatterFactory.ppno longer throws NullPointerException on a BigQuery subquery expression without its own parenthesis tokens;TokenEquivalenceaccepts the Oracle lexer's SQL*Plus-command classification of a word at column 0 (exit) against the same word as a keyword once indented; andFormatterFactory.pp2gains a whole-document fast path (Pp2FormatOptions.wholeDocumentFastPath, default on): when the input parses as a whole and pp formats it without changing a token, pp2 returns that text asOK, giving byte parity with pp on parseable input and fixing the SnowflakeEND$$end-of-input token loss; the regional pipeline still handles everything else - 2026-09-02 [Formatter] Compound statements without a dedicated formatter (T-SQL
BEGIN TRY ... END CATCH, PL/pgSQL and DB2 loops, MySQL and DB2IF/WHILE,REPEAT) had their bodies printed as one glued line byFormatterFactory.pp. Their body statements now get their own lines one indent deeper, the opening (ELSE,BEGIN CATCH) and closing (END ...,EXCEPTION,ELSEIF) keywords start their own line at the statement column, and the body statements are formatted recursively. A SQL Server procedure whose body starts after comment lines is laid out too (the search forASskipped no comments and left the whole body on one line) - 2026-09-02 [Snowflake, BigQuery, Teradata, Databricks]
FormatterFactory.ppputs aQUALIFYclause on its own line, aligned with the other clause keywords, and breaks its predicate at AND / OR like WHERE;GROUP BY ALLgets its own line although it has no items - 2026-09-02 [Formatter]
CREATE MATERIALIZED VIEW ... AS <query>is laid out likeCREATE VIEW(AS on its own line, the query one block indent deeper) instead of hanging off the column after AS. PrettyScore no longer treats BigQuery'sSELECT * EXCEPT (...)/* REPLACE (...)as a set operator that must start a line - 2026-09-02 [Formatter] A function argument that fits on its line keeps its
AND,ORand||inline inFormatterFactory.pp(If(a = 1 OR b = 'X', x, NULL)used to break beforeORlike a WHERE clause); a packed select list (longer thanmaxSelectListColumn) is filled by line width only, without the extra break every 20 items - 2026-09-02 [Formatter] PrettyScore consistency rule: a width-filled list (several items per line up to the line width, pp's layout for lists longer than
maxSelectListColumn) no longer counts as LIST_STYLE_MIXED when every line break is forced by the width or by a multi-line item, and the select list of a parenthesized subquery is judged once instead of again as a paren list - 2026-09-02 [Formatter] Inside a routine body the clause keywords of DELETE, UPDATE, INSERT and MERGE (SET, WHERE, VALUES) landed at column 0 while the statement was indented; they now follow the statement column like SELECT's clauses. Alias alignment no longer follows one over-long select item past the line width (the outlier keeps a single blank). A wrapped argument list (
functionCallParametersStyle=AsWrapped, the default) breaks atlineWidthinstead of staying on one line. After( -- commentthe next token starts right after the parenthesis - 2026-09-02 [Formatter] PrettyScore spine rule: a JOIN under the first table of FROM and an INSERT ... SELECT whose query sits one unit under INSERT are pp's own layouts and no longer count as CLAUSE_COLUMN_DRIFT
- 2026-09-02 [Formatter] Lay out
CREATE TABLE ... AS <query>likeCREATE VIEWinFormatterFactory.pp:ASon its own line at the statement column and the query one block indent deeper. The query used to hang off the column afterAS, so a long table name pushed every line of the query to the right. SQL Serveralias = exprselect items are no longer padded by alias alignment - 2026-09-02 [Formatter] Break the line before a statement that starts on the line of the previous statement's terminator (
SELECT x FROM t; SELECT y ...) inFormatterFactory.pp; every column of the second statement was measured from the terminator, so its select items landed at column 24 and its FROM at column 10 - 2026-09-02 [Formatter] PrettyScore indent rule:
SELECT *before FROM no longer demotes FROM from a clause head (a*is not a multiplication there), select-list modifiers (DISTINCT, TOP n, DISTINCT ON) no longer count as the first item, and inside CASE an AND hanging under the WHEN predicate or a||one unit past the THEN expression is accepted. These were scorer false positives that made INDENT_JUMP the top backlog rule - 2026-09-02 [Formatter] Keep packed select lists readable in
FormatterFactory.pp. A select list longer thanmaxSelectListColumn(default 20) is packed several items per line; a packed line now respectslineWidth, ends at a comment (the item after the comment used to be re-indented to the column it would have had on the unbroken line, up to hundreds of blanks), gives a CASE expression or subquery item a line of its own, and is no longer padded by alias alignment (MantisBT #4299). The re-indent after a line comment elsewhere is capped at half the line width and otherwise falls back to the indent of the preceding code, so successive comment lines no longer push statements further right - 2026-09-02 [Formatter] Stop emitting blanks before a line break in
FormatterFactory.ppoutput. A blank left behind a--comment became part of the comment when the output was lexed again, and most formatted lines ended in trailing whitespace; no-format zones stay verbatim and the blank after a MySQL$delimiter is kept. Existing golden outputs were regenerated (whitespace only) - 2026-09-02 [BigQuery] Keep the user's spelling of a backtick-quoted path such as
`project.dataset.table`in formatted output (pp and pp2). The BigQuery tokenizer splits it into parts for the grammar; the parts now carryTSourceToken.splitFromand the formatter prints the original token once - 2026-09-02 [Formatter] Fix NullPointerException in pp when a comment sits between
WITHand the first CTE, between a CTE'sASand its query, or between an INSERT column list's(and its first column (SourceTokenSearcher.backforwardSearchSolidskips trivia), and when a function-call argument list has no source token - 2026-09-02 [Formatter] Add PrettyScore (
gudusoft.gsqlparser.pp.score.PrettyScore), a readability scorer for formatted SQL: given a formatted text and its dialect (plus optionally the original text and the formatter options used) it returns a 0-100 score, the attainable score with unfixable deductions added back, per-dimension scores (spine, indent, width, density, alignment, consistency, grouping, comments), every finding with a position-independent fingerprint, and a ranked improvement list mapped toGFmtOpt/ pp2 renderer targets. Three style profiles ship (isf-default,river,compact); syntax-broken input is scored through the pp2 lexical facts. JSON contract versionprettyscore/0.1, calibrationheuristic-v0(relative comparison within one profile and corpus only). CLIgudusoft.gsqlparser.demos.prettyscore.PrettyScoreMainadds gold anchoring, corpus baselines with regression checks, a per-rule backlog, finding-level run diffs and blind acceptance samples
GSP Java version 4.2.8(2026-08-31)¶
- 2026-08-31 Refactor the build process for the SQLFlow integration
GSP Java version 4.2.7(2026-08-30)¶
- 2026-08-31 [SQL Server] Accept statements the grammar models as a bare dummy node —
DROP PARTITION FUNCTION,DROP PARTITION SCHEME,DROP SYNONYM,CREATE MASTER KEY,CREATE CREDENTIAL,CREATE DATABASE SCOPED CREDENTIAL,CREATE DATABASE ENCRYPTION KEY,CREATE EVENT SESSION,CREATE EXTERNAL DATA SOURCE,CREATE EXTERNAL LANGUAGE,CREATE SELECTIVE XML INDEXandALTER SECURITY POLICY— as the body of anIF/WHILE. They parsed standalone but produced no statement object when embedded - 2026-08-30 [Teradata] Reject empty INSERT column lists instead of failing later
- 2026-08-30 [Snowflake] Reject malformed SET statement roots
- 2026-08-30 [SQL Server] Reject an
IF/WHILEwith no statement body - 2026-08-30 [SQL Server] Guard prefixed literal decoding against malformed input
- 2026-08-30 [SQL Server, Teradata] Guard against cycles in CTE resolution
- 2026-08-30 [SQL Server, Oracle] Narrow the SELECT recovery guards so valid statements are not affected
- 2026-08-30 [SQL Server, Greenplum] Build constraint attributes on recovered statements
- 2026-08-29 [SQL Server] Prevent data lineage model crashes on recovered ASTs
- 2026-08-29 [Databricks] Support
$varnotebook variable substitution - 2026-08-28 [SQL Server, Sybase] Fix NullPointerException on a malformed select-list alias form
- 2026-08-28 [MySQL, ClickHouse] Fix NullPointerException on
RENAMEwithout theCOLUMNkeyword - 2026-08-27 [Semantic IR] Publish Join Analysis Consumption Profile v1. New integrations should use
SqlSemanticAnalyzerand consume immutable join facts, structured diagnostics, andCatalogDTO input; low-level builder and binding APIs remain advanced/preview, while validation and parity packages remain internal - 2026-08-27 [Semantic IR] Make
AnalysisResult.getSchemaVersion()match the payload-sensitive version written to its JSON (3for join-analysis facts);SqlSemanticAnalyzer.schemaVersion()remains the historical baseline version1 - 2026-08-26 [SQL Server] Fix statement splitting in CTE-bodied views
- 2026-08-25 Report the ON/WHERE operand's own coordinate on data lineage join and filter sources: a
clauseType="joinCondition"/"where"source now points at the operand reference in the clause instead of the definition site of a shared#temp/CTE/derived-table column, and star-expandedSELECT * INTO #tcolumns carry the*token's span instead of a degenerate[1,1]coordinate - 2026-08-25 [Snowflake] Drop the stale session schema after USE <database>
- 2026-08-24 [Snowflake] Resolve a bare
USE <name>asUSE DATABASE - 2026-08-24 Keep dynamic-SQL lineage when an enrichment walk fails instead of dropping the dynamic site
- 2026-08-24 Guard null children in acceptChildren to prevent NullPointerException on recovered ASTs
- 2026-08-20 [Sybase, Sybase IQ, SQL Anywhere, SQL Server] Support
DROP ... IF EXISTS - 2026-08-20 [SQL Server] Resolve finite dynamic SQL values
- 2026-08-19 [Oracle] Classify pseudocolumns instead of binding them, and fix the edge cases found in review
GSP Java version 4.2.6(2026-08-18)¶
- 2026-08-18 [MySQL] Reach 100% measured syntax coverage: 135 of 135 documented constructs, 242 of 242 statements
- 2026-08-18 [MySQL] Recognize the admin DDL statement families in the statement splitter: ALTER USER, ALTER INSTANCE, CREATE/ALTER/DROP SERVER, TABLESPACE (including UNDO TABLESPACE), LOGFILE GROUP, CREATE/DROP ROLE, GET DIAGNOSTICS, and IMPORT TABLE FROM
- 2026-08-18 [MySQL] End a BEGIN-bodied stored routine at a nesting-balanced END; when no DELIMITER command was issued, instead of merging every following statement into the routine; a routine terminator fused with the delimiter character (END$) works again
- 2026-08-18 [MySQL] Parse the ODBC escape sequence { OJ ... } as a table reference
GSP Java version 4.2.5(2026-08-18)¶
- 2026-08-18 [Oracle] Reach 100% measured syntax coverage: 182 of 182 documented constructs, 319 of 319 statements
- 2026-08-18 [Oracle] Recognize the admin DDL statement families in the statement splitter: ANALYTIC VIEW, ATTRIBUTE DIMENSION, AUDIT POLICY, HIERARCHY, INMEMORY JOIN GROUP, LOCKDOWN PROFILE, MATERIALIZED ZONEMAP, PLUGGABLE DATABASE, PMEM FILESTORE, FLASHBACK ARCHIVE, DATABASE LINK and SYNONYM alter forms, EDITION, ADMINISTER KEY MANAGEMENT, and private/or-replace OUTLINE variants; fix a typo that broke CREATE RESTORE POINT
- 2026-08-18 [Oracle] Keep multi-line SET CONSTRAINT[S]/ROLE/TRANSACTION as SQL statements instead of truncating them as line-terminated SQL*Plus SET commands, and keep semicolons inside a CREATE JAVA SOURCE class body from ending the statement
- 2026-08-18 [Oracle] Parse TRUNCATE CLUSTER, ALTER MATERIALIZED VIEW option heads (CONSIDER FRESH, ENABLE/DISABLE QUERY REWRITE, COMPILE), DROP MATERIALIZED VIEW LOG ON, and CREATE DATABASE with its full clause list
GSP Java version 4.2.4(2026-08-18)¶
- 2026-08-18 [SQL Server] Reach 100% measured syntax coverage: 290 of 290 documented constructs, 1082 of 1082 statements
- 2026-08-18 [SQL Server] Recognize 48 admin DDL statement kinds in the statement splitter (DROP/ALTER/CREATE for broker priorities, encryption keys, external objects, resource pools, audits, availability groups and more) and stop mid-statement splits at SET, IF EXISTS and MERGE
- 2026-08-18 [SQL Server] Parse GRANT/DENY/REVOKE securable classes (ENDPOINT::, AVAILABILITY GROUP::, SYMMETRIC KEY::, XML SCHEMA COLLECTION:: and more), CASCADE tails, REVOKE GRANT OPTION FOR, and CREATE ENDPOINT as a grantable permission
- 2026-08-18 [SQL Server] Parse CREATE EXTERNAL TABLE without WITH, selective XML index ALTERs, SEND ON CONVERSATION handle lists, DROP DEFAULT IF EXISTS, and GET CONVERSATION GROUP
GSP Java version 4.2.3(2026-08-18)¶
- 2026-08-18 [Snowflake] Reach 100% measured syntax coverage: 455 of 455 documented constructs, 757 of 757 statements
- 2026-08-18 [Snowflake] Recognize integration, managed account, stream, procedure, DESC, EXPLAIN USING and SHOW statement families in the statement splitter
- 2026-08-18 [Snowflake] Fix a mid-statement split that turned ALTER ... SET into two statements, and stop re-parsing CREATE EXTERNAL FUNCTION request URLs as SQL bodies
- 2026-08-18 [Snowflake] Parse ALTER DATABASE/SCHEMA/PIPE/TASK/EXTERNAL TABLE variants, CREATE DATABASE AS REPLICA, REVOKE ... FROM SHARE, open-ended privilege names, SHOW STREAMS/TASKS filters, and Windows file paths in PUT
GSP Java version 4.2.2(2026-08-18)¶
- 2026-08-18 [ClickHouse] Reach 100% measured syntax coverage: 156 of 156 documented constructs, 717 of 717 statements
- 2026-08-18 [ClickHouse] Recognize access-entity and admin DDL in the statement splitter: CREATE/ALTER USER, ROLE, ROW POLICY, QUOTA, SETTINGS PROFILE, MASKING POLICY, NAMED COLLECTION, DICTIONARY, plus CHECK, EXISTS, EXECUTE AS, MOVE, EXCHANGE TABLES, UNDROP, REPLACE TABLE and the SHOW family
- 2026-08-18 [ClickHouse] Parse dollar-quoted strings ($tag$...$tag$), query parameters {name: Type}, TRUNCATE/USE/SET/DESCRIBE variants, CREATE DATABASE engine clauses, more ALTER TABLE forms, ASSUME constraints, compound and unit-less INTERVAL, and AT TIME ZONE
- 2026-08-18 [ClickHouse] Fix a tokenizer crash that silently produced zero tokens for query-parameter syntax followed by whitespace
GSP Java version 4.2.1(2026-08-18)¶
- 2026-08-18 [ClickHouse] Raise measured syntax coverage from 78/156 to 100/156 constructs (504 to 548 of 706 statements)
- 2026-08-18 [ClickHouse] Parse Map literals, two-argument CAST, dotted nested column names and tuple element access (a.2)
- 2026-08-18 [ClickHouse] Fix statement mistyping after token-level rewrites: a statement following a :: typecast could be reported as invalid
- 2026-08-18 [ClickHouse] Parse ALTER TABLE UPDATE/DELETE IN PARTITION, column names from/to, INSERT ... FORMAT with inline data, and PARALLEL WITH
- 2026-08-18 [ClickHouse] Parse named Tuple fields in type and expression positions, ILIKE column matchers, COLUMNS arithmetic
- 2026-08-17 [ClickHouse] Parse == comparison, ASC/DESC COLLATE, INTERSECT DISTINCT, OFFSET/FETCH, GROUPING SETS, ASOF/ANY join order, WITH FILL STALENESS/INTERPOLATE, VALUES table literals, trailing commas
GSP Java version 4.2.0(2026-08-17)¶
- 2026-08-17 [Sybase ASE, SAP SQL Anywhere, Sybase IQ] Add three per-product vendors, each with its own grammar, splitter and syntax coverage page;
sybaseremains the permissive union of the family and is unchanged - 2026-08-17 [Sybase ASE] Reject Watcom-SQL procedure syntax that belongs to SQL Anywhere: leading parameter modes, DEFAULT parameter defaults, RESULT clauses, ON EXCEPTION RESUME, a body without AS, and parameter names without @
- 2026-08-17 [Sybase ASE, SAP SQL Anywhere] Reject Sybase IQ specialized index types and IQ-only DDL
- 2026-08-17 [Sybase IQ, SAP SQL Anywhere] Reject ASE-only statements such as DUMP TRANSACTION, READTEXT, UPDATE INDEX STATISTICS and DELETE STATISTICS, with a message naming the statement that belongs to a different product
- 2026-08-17 Report the full capability matrix for all 42 dialects
- 2026-08-16 [Sybase] Keep the trailing parameter mode OUTPUT/OUT
- 2026-08-15 [Sybase] Support DEFAULT in procedure parameters
- 2026-08-14 [Snowflake, Vertica] Bind WHERE clause references to a SELECT list alias
- 2026-08-14 [Snowflake] Pin COPY INTO option order
- 2026-08-14 [Snowflake] Keep quotes in PIVOT IN-list column names, and fix Oracle PIVOT quote naming
- 2026-08-13 [Snowflake] Resolve FLATTEN implicit output columns
- 2026-08-13 [SQL Server] Decode quoted SELECT aliases in data lineage output
- 2026-08-02 Fix a multi-threading defect where repeated analysis of the same input returned different results
- 2026-08-02 Add a column lookup cache to speed up data lineage analysis
- 2026-08-01 Detect large SQL files automatically and split them for parallel analysis
- 2026-08-01 Merge and deduplicate data lineage incrementally, and speed up relation deduplication by replacing MD5 with a 64-bit hash
- 2026-08-01 Fix null pointer and concurrency defects in data lineage analysis, and improve sorting and temporary file cleanup
- 2026-08-01 Scan the whole SQL environment before dataflow and procedure dataflow analysis
- 2026-07-31 Avoid out-of-memory and an infinite loop when dataflow analysis falls back to procedure dataflow analysis
- 2026-07-30 Fix missing database and schema when source code is read from JSONL without a group
GSP Java version 4.1.11(2026-08-10)¶
- 2026-08-10 [ClickHouse] Model remote()/remoteSecure() table functions as lineage sources, with ClickHouse-exact string-literal decoding
- 2026-08-10 [ClickHouse] Parse ALTER TABLE sub-clause families: DETACH/ATTACH/MOVE PART, FREEZE WITH NAME, MATERIALIZE/CLEAR/APPLY, projections, expression indexes, MODIFY/RESET SETTING, TTL and COMMENT
- 2026-08-09 [ClickHouse] Resolve expression-CTE aliases (WITH expr AS name) as scalar symbols in the resolver and data lineage
- 2026-08-09 [ClickHouse] Parse expression CTEs, materialized CTEs and lambda-bodied CREATE FUNCTION
- 2026-08-09 [ClickHouse] Parse the VIEW family: ON CLUSTER, refreshable materialized views, MODIFY QUERY
- 2026-08-09 [ClickHouse] Parse OPTIMIZE TABLE tails and table functions in FROM
- 2026-08-09 [ClickHouse] Add a documented syntax coverage corpus; measured coverage rises from 51/156 to 78/156 constructs (504/704 statements)
- 2026-08-09 Document fault-tolerant SQL formatting and all SQL formatter options
- 2026-07-29 [PostgreSQL] Map && to overlaps_t and parse unknown operators
- 2026-07-29 [Snowflake] Support alias after parenthesized PIVOT table
- 2026-07-29 Render aliased nodes from the token chain, not list index
GSP Java version 4.1.10(2026-08-08)¶
- 2026-08-08 Stop duplicating star-traced columns in linkedColumns
- 2026-08-08 Reorganize documentation by user goal
- 2026-08-07 Keep undefined MERGE VALUES names unresolved
- 2026-08-07 [SQL Server] Fix CLR routines with AS EXTERNAL NAME
- 2026-08-07 [BigQuery] Fix CTE with parenthesized main query
- 2026-08-07 Add AST rewriting how-to and demo guide
- 2026-08-07 Add offline SQL syntax validation guide
- 2026-08-06 [Vertica] Raise syntax coverage from 77% to 100% of corpus
- 2026-08-06 [OpenEdge] Raise corpus parse rate from 52% to 100%
- 2026-08-06 [Teradata] Raise corpus parse rate from 83% to 98%
- 2026-08-06 [HANA] Raise syntax coverage from 77% to 98% of corpus
- 2026-08-06 [Informix] Raise corpus parse rate from 86% to 94%
- 2026-08-06 [Greenplum] Raise corpus parse rate from 75% to 96%
- 2026-08-05 [DB2] Reach 100% corpus parse coverage
- 2026-08-05 [Impala] Raise corpus parse rate from 70% to 99%
- 2026-08-05 [Exasol] Raise syntax coverage from 42% to 98% of corpus
- 2026-08-05 [Flink] Raise corpus parse rate from 67% to 98%
- 2026-08-05 [Sybase] Raise IQ syntax coverage to 88% of corpus
- 2026-08-05 [SQL Server] Fix token shift from Exasol token placement
- 2026-08-05 [Teradata] Fix whitespace-sensitive cast shorthand
- 2026-08-04 [Databricks] Fix Mantis 4638-4646 syntax gaps
- 2026-08-04 Add trusted playground lineage
- 2026-08-03 Harden stored procedure lineage trust
- 2026-08-03 Add doris, starrocks, flink, soql and odbc to the sqlcoverage corpus
- 2026-08-01 Add SELECT/DML/proc parse rates to coverage docs
- 2026-07-31 [Databricks] Pin ODBC date escape shapes from Mantis 4575
- 2026-07-31 [Docs] Fix quick-start Java sample and trial-limit claims
- 2026-07-31 Unify public dialect metadata
- 2026-07-31 Publish an SBOM and smoke-test the install daily
- 2026-07-30 [MySQL] Only treat line-leading DELIMITER as a directive
- 2026-07-30 [SQL Server] Allow empty OVER() in WITHIN GROUP
- 2026-07-29 [Teradata] Support table operators and CTAS COMPRESS
- 2026-07-29 [Presto] Add MERGE, view security, UNNEST and ident fixes
- 2026-07-29 [Oracle] Support OFFSET expr and per-INTO LOG ERRORS
- 2026-07-29 Add generator for docs-site parse-coverage tables
- 2026-07-28 [Oracle] Restore record-fill lineage with exact bindings
GSP Java version 4.1.9(2026-07-28)¶
- 2026-07-28 Apply the trial size cap once, where SQL is read
- 2026-07-26 Fixed stackover flow bug.
- 2026-07-26 Fix several CREATE FUNCTION bugs
- 2026-07-26 Fix getLastSelectStmt returning the wrong SELECT statement
- 2026-07-26 fix(dlineage): Fix intermediate result retention in stored procedure/function scenarios
- 2026-07-26 fix(dataflow): Fix parallel analysis losing stored procedure/function lineage
- 2026-07-26 fix(DataflowUtility): Fix loss of stored procedure short-name mappings
- 2026-07-26 feat(dataflow): Add procedure variable association and target table marking
- 2026-07-26 refactor(dataflow): Refactor stored procedure/function name retrieval and improve result set handling
- 2026-07-25 feat: Add stored procedure ID association logic and improve data flow analysis
- 2026-07-25 Stop column-level CSV export dropping all lineage on NPE
- 2026-07-22 Fix schema-topology sqlflow-sharded lineage loading
- 2026-07-21 [SQL Server] Add TEXTPTR statement lineage
- 2026-07-21 [SQL Server] Add TEXTPTR statement AST support
- 2026-07-21 [MSSQL] Enable external-script passthrough by default
- 2026-07-21 [MSSQL] Add opt-in external-script passthrough lineage
- 2026-07-21 [MSSQL] Recover external-script input lineage
- 2026-07-21 [MSSQL] Harden sharded version parse, baseDir, block source (round 3)
- 2026-07-21 [MSSQL] Close remaining sharded consumer gaps (round 2)
- 2026-07-21 [MSSQL] Skip sourceUnavailable records instead of parsing their text
- 2026-07-20 [MSSQL] Let the LR automaton report what the prefix committed to
- 2026-07-20 [MSSQL] Prove span ownership by token identity, not by text
- 2026-07-20 [MSSQL] Scan tokens, direct the roles, bind the parse to the site
- 2026-07-20 [MSSQL] Do not let delimited names trip the structural scan
- 2026-07-20 [MSSQL] Require structural containment and edge-owned bindings
- 2026-07-20 [MSSQL] Fix caller-trusted evidence and uncommitted binder regions
- 2026-07-20 [MSSQL] Close direct-binding trace gaps before gating
- 2026-07-20 [MSSQL] Require the alias wrapper in binding-trace completeness
- 2026-07-20 [MSSQL] Add binding-trace capture to resolver2
- 2026-07-19 [MSSQL] Count CREATE TABLE reparse only when it actually runs
- 2026-07-19 [MSSQL] Fix CASE re-evaluation blowup and typing gaps in fragment IR
- 2026-07-19 [MSSQL] Close provenance-laundering paths in fragment IR
- 2026-07-19 [MSSQL] Add fragment provenance to dynamic-SQL evaluator
- 2026-07-19 [Oracle] Guard null trigger body in acceptChildren
- 2026-07-18 [Oracle, MSSQL] Add routine identity + catalog B0
- 2026-07-18 Guard recovered argument bindings against wildcards
- 2026-07-18 [MSSQL] Bind nested EXEC arguments under USE context
- 2026-07-18 [Oracle] Bind PL/SQL package-member call arguments
- 2026-07-18 [Oracle] Resolve DBMS_SQL.PARSE dynamic SQL
- 2026-07-18 [MSSQL, Oracle] Index cross-file routines in a shared catalog
- 2026-07-18 [Oracle] Bind EXECUTE IMMEDIATE via call-site literals
- 2026-07-18 [MSSQL] Resolve dynamic SQL via cross-file call bindings
- 2026-07-18 [MSSQL] Resolve dynamic SQL via literal call-site bindings
- 2026-07-17 [MSSQL] Discover dynamic-SQL sites inside WHILE loops
- 2026-07-17 [MSSQL] Evaluate template-built dynamic SQL in default lineage path
- 2026-07-17 [Oracle] Bind trigger correlation names for column lineage
- 2026-07-17 [Snowflake] Restore extractSnowflakeSQL script callback
- 2026-07-17 [Snowflake] Skip non-SQL procedure bodies in lineage
- 2026-07-17 [Redshift, PostgreSQL] Accept ANALYSE spelling of ANALYZE
- 2026-07-17 [Redshift] Allow PRIOR as a table alias in expressions
- 2026-07-16 [DuckDB, EDB] Eliminate parser conflicts
- 2026-07-16 Eliminate parser conflicts in 10 more dialects
- 2026-07-16 [Oracle, MSSQL, MySQL, PostgreSQL] Eliminate conflicts
- 2026-07-16 [MSSQL, MySQL, PostgreSQL] Fix parser conflicts
- 2026-07-16 [BigQuery] Fix all 5 reduce/reduce grammar conflicts
- 2026-07-15 [Redshift] Support INTERVAL field-qualified types
- 2026-07-15 [Redshift] Support order-independent COPY QUOTE option
- 2026-07-15 [Redshift] Support schema-qualified PERCENTILE_DISC/CONT
- 2026-07-14 [Build] Fix Maven trial artifact metadata (QS-001/002/009)
- 2026-07-13 [Teradata] Split same-line statement after SET QUERY_BAND
- 2026-07-13 [Databricks] Support standalone REPLACE TABLE
- 2026-07-13 [Databricks] Support CTE with the AS keyword omitted
- 2026-07-13 [Databricks] Support {d } and {t } ODBC date/time escapes
- 2026-07-13 [Databricks] Support SEMI JOIN and ANTI JOIN
- 2026-07-13 [Databricks] Support POSITION(substr IN expr) form
- 2026-07-12 Add identifier normalization guide and guard
- 2026-07-12 Skip no-op segment parse on identifier hot path
- 2026-07-12 Reconcile NameService onto the canonical engine
- 2026-07-12 Refine dlineage identifier comparison scope (P0d.3c2)
- 2026-07-12 Vendor-aware PL/SQL scope name matching (P0d.3d)
- 2026-07-12 Canonicalize dlineage wrapper compares (P0d.3c)
- 2026-07-12 Canonicalize TObjectName table matching (P0d.3b)
- 2026-07-12 Drop hand-rolled strippers in resolver2 (P0d.3a)
- 2026-07-12 Unify all identifier equality on the canon (P0d.2)
- 2026-07-12 Make areEqual canonical-key equality (P0d.1)
- 2026-07-12 Fold identifiers with Locale.ROOT (P0d.0)
- 2026-07-12 Convert AST node identifier compares (P0b w4)
- 2026-07-12 Convert dlineage identifier compares (P0b w3)
- 2026-07-12 Convert resolver2 qualified-name compares (P0b w2)
- 2026-07-12 Route safe identifier compares to sameName (P0b w1)
- 2026-07-12 Add sameName identifier equality facade (P0a)
- 2026-07-11 Index column-name matching in analyzeDataFlowRelation
- 2026-07-11 Memoize CTENamespace final-table tracing
- 2026-07-11 Speed up column lineage with provable memoization
- 2026-07-10 [Databricks] Support named bind variable markers (:param)
- 2026-07-05 perf(cloneTable): Optimize table cloning performance and add a parallel-clone threshold
- 2026-07-04 refactor(sqlutil): Optimize parseNames performance and caching logic
- 2026-07-02 Fix an array index out-of-bounds bug
- 2026-06-28 feat(FileSplitter): add structured logging and improve error handling
- 2026-06-12 Apply GF-029 ruling: set-op row influence is FILTER
GSP Java version 4.1.5.14(2026-07-08)¶
- 2026-07-08 [Redshift] Support LIKE/ILIKE ... ESCAPE clause
- 2026-07-08 [Redshift] Support SUPER object UNPIVOT in FROM clause
- 2026-07-08 [Redshift] Support BETWEEN in the SELECT list
- 2026-07-08 [Redshift] Support $$-quoted SQL UDF body with semicolons
- 2026-07-08 [Redshift] Support IS [NOT] DISTINCT FROM operator
- 2026-07-08 [Redshift] Support named inline column constraints
- 2026-07-08 [Redshift] Support UNLOAD EXTENSION AS clause
- 2026-07-08 [Redshift] Support array unnesting with AT index alias
- 2026-07-06 Fix constructor escape and routine metadata races
- 2026-07-06 Fix shared-SQLEnv DDL registration races and NPE
GSP Java version 4.1.5.13(2026-07-06)¶
- 2026-07-06 [Sybase] Support empty statements and ON COMMIT ROWS
- 2026-07-02 [Snowflake] Support GRANT OWNERSHIP COPY CURRENT GRANTS
- 2026-06-30 [SQL Server] Don't fail unit on partial-fold dynamic-SQL re-parse
GSP Java version 4.1.5.12(2026-06-30)¶
- 2026-06-30 [SQL Server] Degrade undecidable-gated dynamic-SQL sites to CONDITIONAL
- 2026-06-29 [Sybase] Guard create-procedure cast against stale rootNode
- 2026-06-29 [SQL Server] Fold CAST/CONVERT, degrade unfoldable dynamic SQL to PARTIAL
- 2026-06-28 [SQL Server] Resolve dynamic-SQL lineage with parameter bindings
- 2026-06-28 [SQL Server] Expose endpoint classification on dlineage model
- 2026-06-28 Add sqlflow-sharded JSON file splitting (FileSplitter)
- 2026-06-28 Add sqlflow-sharded metadata parsing and SQL environment support
- 2026-06-27 Add owner-name fields to catalog model objects
- 2026-06-27 Add catalog metadata helpers for sharded scenarios
GSP Java version 4.1.5.10(2026-06-27)¶
- 2026-06-26 Expose candidate set for unqualified tables ambiguous across schemas
- 2026-06-26 [Hive] Resolve unqualified column ambiguous across derived tables
- 2026-06-26 Honor Option default database over attached TSQLEnv
GSP Java version 4.1.5.9(2026-06-25)¶
- 2026-06-25 Resolve ambiguous columns to physical base tables in candidateTables (UNION/EXCEPT/INTERSECT/CTE aware)
- 2026-06-24 [SQL Server] Fold literal EXEC('
') so it yields lineage - 2026-06-24 [SQL Server] Emit per-site dynamic-SQL diagnostics and produced-lineage signal
- 2026-06-23 [Oracle] Improve synonym and dblink data lineage analysis
- 2026-06-23 Improve synonym support; fix synonym resolution and lineage propagation
- 2026-06-22 Add catalog metadata fields to dlineage model
- 2026-06-21 Fix NPE in dataflow Table model
GSP Java version 4.1.5.8(2026-06-21)¶
- 2026-06-21 [SQL Server] Add synonym base target, resolution, and export
GSP Java version 4.1.5.7(2026-06-19)¶
- 2026-06-19 [Oracle] Add MantisBT 4516 regression for ${} regex literal
- 2026-06-19 [SQL Server] Accept NULL/NOT NULL on scalar DECLARE
- 2026-06-19 [SQL Server] Set itSpatial index type on CREATE SPATIAL INDEX
- 2026-06-18 [Snowflake] Wire scoped temporary into temp-kind consumers
- 2026-06-18 [Snowflake] Support SCOPED TEMPORARY table
- 2026-06-18 [Snowflake] Allow colon path access on constants
- 2026-06-18 [Snowflake] Support CASE cast in SQL UDF body
- 2026-06-18 [Oracle] Fix CTE alias resolution for repeated references
- 2026-06-18 [dlineage] Add /csv-simple option to DataFlowAnalyzer
- 2026-06-18 [Teradata] Parse MEETS/PRECEDES/SUCCEEDS period predicates
- 2026-06-18 [Snowflake] Add regression tests for TIMESTAMP-typed proc params
- 2026-06-18 [Snowflake] Flag temporary view in dlineage output
- 2026-06-18 [Core] Add null checks to several methods to avoid NPE
- 2026-06-17 [Snowflake] Allow TIMESTAMP as procedure parameter name
- 2026-06-17 [Teradata] Allow trailing loop label on END WHILE / END REPEAT
- 2026-06-17 [Snowflake] Add regression test for 4540 PIVOT aliased IN values
- 2026-06-17 [SQL Server] Add regression test for 4530 ALTER DATABASE in block
- 2026-06-17 [SQL Server] Add regression test for 4531 GRANT ON TYPE::
- 2026-06-17 [SQL Server] Allow chained methods on parenthesized expr
- 2026-06-17 [Snowflake] Gate procedure exclusion on statement type
- 2026-06-17 [Snowflake] Apply procedure exclusion to SQL procedures
GSP Java version 4.1.5.6(2026-06-15)¶
- 2026-06-15 [Dameng] Support CREATE [OR REPLACE] PROCEDURE
- 2026-06-13 [SQL Server] Add single-quote regression tests for 4496
- 2026-06-13 [Oracle] Add regression tests for ${} in string literals
- 2026-06-12 [PostgreSQL] Fix NOT DEFERRABLE token corruption
- 2026-06-12 [PostgreSQL] Support EXCLUDE WHERE and constraint attributes
- 2026-06-12 [PostgreSQL] Extend Mantis 4512 regression coverage
- 2026-06-12 [PostgreSQL] Fix constraint toString truncating clauses
- 2026-06-12 [PostgreSQL] Fix formatter NPE on ADD CONSTRAINT CHECK
GSP Java version 4.1.5.5(2026-06-11)¶
- 2026-06-11 [Snowflake] Allow commas in ALTER DYNAMIC TABLE SET
- 2026-06-11 [Snowflake] Add dynamic table SCHEDULER attribute
- 2026-06-11 [OceanBase] Add Q-quote regression test for Oracle mode
- 2026-06-11 [Dameng] Fix Q-quote lexing and stale keyword values
- 2026-06-11 [Oracle, OceanBase] Fix Q' inside Q-quote literals
- 2026-06-11 [Oracle] Add regression test for MantisBT 4508
- 2026-06-11 [Oracle] Match quoted parameter names in resolution
- 2026-06-11 [Oracle] Don't report errors for partial dynamic SQL
- 2026-06-11 [Oracle] Skip unknowable dynamic SQL in lineage
- 2026-06-10 Link UPDATE target alias to FROM clause table
- 2026-06-10 Fix lineage crash on expression with quoted dot
- 2026-06-10 [Snowflake] Support ODBC fn escape syntax
- 2026-06-10 [Redshift] Add TRIM comma-form regression test
- 2026-06-10 [Redshift] Allow ANSI TRIM position keyword without char
- 2026-06-09 [PostgreSQL, Greenplum, Redshift] '/' on a line is division
- 2026-06-09 [Redshift] Treat '/' alone on a line as division
GSP Java version 4.1.5.4(2026-06-08)¶
- 2026-06-08 Mark LATERAL joins lateral in the join graph
- 2026-06-07 Degrade non-exact ON-predicate binding over join
- 2026-06-07 Degrade star expansion over nested join
- 2026-06-07 [Oracle] Fix synonym filtering and complete star-column bridge relations
- 2026-06-07 Degrade catalog-less star expansion over join
- 2026-06-06 Recurse into parenthesized joined-table operand
- 2026-06-06 Degrade non-exact column binding over join graph
- 2026-06-06 [Oracle, PostgreSQL] Degrade USING-join unqualified column miss
- 2026-06-06 [Oracle] Support (+) outer-join syntax in implicit joins
- 2026-06-06 [Oracle] Promote implicit comma-join predicates to INNER joins
- 2026-06-06 [Oracle, PostgreSQL] Resolve unqualified NATURAL JOIN merged key
- 2026-06-06 [Formatter] pp2: break statements onto separate lines
- 2026-06-05 [SQL Server] Fix MERGE USING CTE dropping lineage
- 2026-06-05 [Teradata] Support PIVOT DEFAULT ON NULL clause
- 2026-06-05 [BigQuery] Fix bitwise shift vs AND precedence
- 2026-06-03 [Semantic IR] Expose semi-joins and fix USING clause span
- 2026-06-03 [Semantic IR] Degrade catalog-less NATURAL JOIN to a warning
- 2026-06-02 [Impala] Parse PRIMARY KEY / FOREIGN KEY in CREATE TABLE
- 2026-06-02 [Vertica] Parse AUTO_INCREMENT column attribute
- 2026-06-02 [DB2] Surface stored-procedure CALL in dlineage call graph
- 2026-06-02 [Couchbase] Parse ANSI JOIN ... ON
- 2026-06-02 [SparkSQL] Parse PRIMARY KEY / FOREIGN KEY in CREATE TABLE
- 2026-06-02 [Informix] Carry column list on table-level PRIMARY KEY
- 2026-06-02 [DB2] Populate FETCH FIRST n count on TFetchFirstClause
- 2026-06-02 [Impala] Attach ON condition to LEFT [OUTER] JOIN
- 2026-06-02 Surface inline column PRIMARY KEY / FOREIGN KEY in dlineage
- 2026-06-02 [SQL Server] Support CROSS/OUTER APPLY in semantic IR
- 2026-06-02 [MySQL] Degrade STRAIGHT_JOIN to INNER in semantic IR
GSP Java version 4.1.5.3(2026-06-02)¶
- 2026-06-02 [Oracle] Filter invalid coordinates in coordinate handling
- 2026-06-02 [Oracle] Fix uninitialized coordinateItems update; add synonym + dataflow merge tests
- 2026-06-01 [Oracle] Support synonym statement parsing and analysis
- 2026-06-01 Refactor dataflow merge logic and ID handling
- 2026-05-30 [Semantic IR] Admit PIVOT row-shaping clauses
- 2026-05-29 [SQL Server] Lock in permanent SELECT INTO target tableKind=etkBase
- 2026-05-29 [Sybase] Support Watcom IF ... THEN ... END IF in procedure bodies
- 2026-05-29 [Hive, SparkSQL] Structured-dataflow lineage for explode(from_json(...))
- 2026-05-29 [Hive] Harden CTE chain walkers
- 2026-05-29 [Hive] Stop calculated/aliased CTE columns leaking into base linkedColumns
- 2026-05-28 [Hive] Treat comments as trivia in ALL.col lookahead
- 2026-05-28 [Hive] Allow ALL as table alias in qualified name
- 2026-05-28 Admit nested PIVOT/UNPIVOT in a predicate-subquery body
- 2026-05-28 Admit nested PIVOT/UNPIVOT in a set-op branch
- 2026-05-28 Admit nested PIVOT/UNPIVOT as a CTE body
- 2026-05-27 Admit nested PIVOT/UNPIVOT in FROM-subquery body
- 2026-05-27 Expand bare SELECT * over subquery-source PIVOT/UNPIVOT
- 2026-05-27 Admit PIVOT/UNPIVOT over a FROM-subquery source
- 2026-05-27 Expand multi-value UNPIVOT SELECT * via catalog
- 2026-05-27 Expand bare SELECT * over UNPIVOT via catalog
- 2026-05-27 Expand bare SELECT * over PIVOT via catalog
- 2026-05-27 Add multi-value-column UNPIVOT lineage
- 2026-05-27 Add UNPIVOT output-column lineage
- 2026-05-27 Add PIVOT output-column lineage
- 2026-05-27 Bind PIVOT source + capture consumed refs
- 2026-05-27 Add structured GROUP BY element model
- 2026-05-27 Capture GROUP BY ROLLUP/CUBE/GROUPING SETS refs
- 2026-05-27 Validate QUALIFY inline window-fn names
- 2026-05-26 Lift QUALIFY, emit qualifyColumnRefs
- 2026-05-26 Unify MERGE OUTPUT USING-source lineage
- 2026-05-26 Unify RETURNING/OUTPUT subquery lineage
- 2026-05-26 [PG, MSSQL] MERGE USING-subquery sees outer CTE
- 2026-05-26 [PG, MSSQL, Snowflake, Oracle] Admit scalar-body WHERE predicate subqueries
GSP Java version 4.1.5.2(2026-05-26)¶
- 2026-05-26 [BigQuery] Harden star-column lineage guard
- 2026-05-25 [BigQuery] Fix UNNEST CTE star lineage crash
- 2026-05-25 [Teradata] Allow optional alias in MERGE USING VALUES
- 2026-05-25 [Teradata] Support NUMBER(*) unbounded precision
- 2026-05-25 [Snowflake] Harden COPY INTO lineage
- 2026-05-25 [Snowflake] Support COPY INTO inside procedure block
- 2026-05-25 [Snowflake] Model USING TEMPLATE distinct from CTAS
- 2026-05-25 [Snowflake] Support CREATE TABLE USING TEMPLATE
- 2026-05-25 [Hana] Support WITH RANGE_RESTRICTION clause
- 2026-05-25 [Oracle] Resolve PL/SQL params in dynamic SQL, not orphan columns
- 2026-05-25 Centralize re-parse coordinate shifting
- 2026-05-24 Harden EXECUTE IMMEDIATE coordinate shift for nested statements
- 2026-05-24 Fix wrong line numbers for function/procedure body coordinates
- 2026-05-24 [Oracle] Fix wrong line numbers for dynamic SQL coordinates
- 2026-05-24 [PG, MSSQL, Snowflake] Admit FROM-subquery body WHERE predicate subqueries
- 2026-05-24 [PG, MSSQL, Snowflake, Oracle] Admit UPDATE SET-RHS mixed-expression scalar subqueries
- 2026-05-23 [PG, Oracle] Admit MERGE per-WHEN action WHERE correlated predicate subqueries
- 2026-05-23 [PG, MSSQL, Snowflake, Oracle, MySQL] Admit UPDATE SET-RHS correlated scalar subqueries
- 2026-05-23 Handle null DataFlow gracefully in parallel analysis
- 2026-05-23 Thread-safe CatalogStore
- 2026-05-23 [PG, Oracle] Admit uncorrelated MERGE per-WHEN action WHERE predicate subqueries
- 2026-05-23 [PG, MSSQL, Snowflake, Oracle, MySQL] Admit uncorrelated UPDATE SET-RHS scalar subqueries
- 2026-05-23 [PG, MSSQL, Snowflake] Admit uncorrelated WHERE-side predicate subqueries on CTE bodies
- 2026-05-22 [PG, MSSQL, Snowflake] Admit uncorrelated WHERE-side predicate subqueries on set-op branches
- 2026-05-22 [PG, MSSQL, Snowflake] Admit uncorrelated WHERE-side predicate subqueries on SELECT
- 2026-05-22 [PG, MSSQL, Snowflake] Admit uncorrelated WHERE-side predicate subqueries on DELETE
- 2026-05-22 [PG, MSSQL, Snowflake] Admit uncorrelated WHERE-side predicate subqueries on UPDATE
- 2026-05-22 [Hive] Admit outer-WITH on Hive multi-insert
- 2026-05-22 [PG, Oracle, Snowflake] Admit mixed outer+inner WITH on INSERT (shadowing case)
- 2026-05-22 [PG, Oracle, Snowflake] Admit mixed outer+inner WITH on INSERT (disjoint names)
- 2026-05-21 [SQL Server] Split plain BEGIN block from preceding statement
- 2026-05-19 [Snowflake] Preserve closing quote after even backslash run
- 2026-05-19 [Snowflake] Fix MantisBT 4435 sequential backslash-escaped quotes
- 2026-05-19 [Teradata, Snowflake] Pin MantisBT 4440 join-with-comments behavior
- 2026-05-19 [Sybase] Hook EXCEPTION clause into TBlockSqlNode + TMssqlBlock
- 2026-05-19 [Sybase] Support Watcom EXCEPTION handler + SIGNAL/RESIGNAL
- 2026-05-18 [Snowflake] Support LAG=DOWNSTREAM in CREATE DYNAMIC TABLE
GSP Java version 4.1.5.1(2026-05-18)¶
- 2026-05-18 [PG, MSSQL, Snowflake, Redshift] Admit outer WITH on DELETE
- 2026-05-18 [PG, MSSQL, Snowflake, Redshift] Admit outer WITH on UPDATE
- 2026-05-18 [PG, MSSQL, Oracle, Snowflake, Redshift, Hive] Admit outer WITH on INSERT
- 2026-05-18 [Catalog] Stabilize concurrentSnapshotReadsDoNotThrow test
- 2026-05-18 [SqlGuard] Add bin/probe.sh inner-loop wrapper for the worker
- 2026-05-17 [PG, MSSQL] Admit WITH cte(a,b) SELECT rename
- 2026-05-17 [PG, MSSQL] Admit WITH cte(a,b) MERGE rename
- 2026-05-17 [PG, MSSQL] Admit WITH-clause / CTE on MERGE
- 2026-05-17 [MSSQL] OUTPUT pseudo-table star expansion (MERGE and non-MERGE)
- 2026-05-17 [MSSQL] MERGE OUTPUT projection
- 2026-05-17 [MSSQL, BigQuery] MERGE WHEN NOT MATCHED BY SOURCE
- 2026-05-17 [PostgreSQL, DuckDB] MERGE WHEN MATCHED THEN DO NOTHING (PG 15+)
- 2026-05-17 MERGE per-WHEN action WHERE predicates
- 2026-05-17 [Teradata] Allow STORAGE FORMAT after JSON INLINE LENGTH (MantisBT 4438)
- 2026-05-17 [SqlGuard] Worker startup + smoke scripts; default port 18083
- 2026-05-16 MERGE skeleton + Semantic IR semantics for MERGE
- 2026-05-16 [Teradata] Support INLINE LENGTH on JSON(n) datatypes (MantisBT 4438)
- 2026-05-16 [Hive] Fix CROSS JOIN + other JOIN associativity (MantisBT 4436)
- 2026-05-16 [Teradata] Add ALTER TABLE ... ALTER (column action[, ...]) support
- 2026-05-16 [MySQL] Self-reference DELETE admission
- 2026-05-16 [Hive] Fix LATERAL VIEW with 3+ column aliases (MantisBT 4455)
- 2026-05-16 [Oracle] MODIFY SUBPARTITION exposes partition name (MantisBT 4459)
- 2026-05-16 [Snowflake] DELETE USING full-contract tests
- 2026-05-16 RETURNING /t. catalog-backed expansion
- 2026-05-16 [Oracle] Fix MODIFY col DECRYPT/VISIBLE/INVISIBLE wrongly sets datatype
- 2026-05-15 Fix alias incorrectly filtered bug (Gitee IJNQ17)
- 2026-05-15 [BigQuery] Fix NPE in DataFlowAnalyzer for EXCEPT/REPLACE with aggregates
- 2026-05-14 [Oracle] Admit RETURNING INTO; Resolver2 sees RETURNING refs
- 2026-05-14 Case-insensitive alias lookup in lineage emitter
- 2026-05-14 [MySQL] USING/NATURAL joined UPDATE
- 2026-05-14 RETURNING / OUTPUT projections
- 2026-05-14 [MySQL] Joined DELETE
- 2026-05-13 UPDATE FROM subquery (Semantic IR)
- 2026-05-13 Joined UPDATE / single-target DELETE / UPDATE shapes (Semantic IR)
- 2026-05-13 CTAS / CREATE VIEW Semantic IR skeleton
- 2026-05-13 INSERT INTO target SELECT (Semantic IR)
- 2026-05-13 Catalog-miss WARN + corpus parity; minimal catalog DTO; SqlSemanticAnalyzer API
- 2026-05-13 Anonymous FROM-subquery admit (Semantic IR)
- 2026-05-13 [PostgreSQL] DISTINCT ON column refs (Semantic IR)
- 2026-05-13 Set-op outer row-limit + vendor row-limit metadata
- 2026-05-12 [Sybase] Allow SQL SECURITY in CREATE FUNCTION
- 2026-05-12 Single-SELECT LIMIT / FETCH FIRST (Semantic IR)
- 2026-05-12 Single-SELECT ORDER BY projection alias / ordinal (Semantic IR)
- 2026-05-12 Structured diagnostics in Semantic IR
- 2026-05-12 NATURAL JOIN / JOIN USING / CROSS JOIN (Semantic IR)
- 2026-05-11 Constant-only projection lift; CTE/FROM-subquery star
- 2026-05-10 GSP binding name resolution rewrite (case-insensitive, catalog-verified)
- 2026-05-10 [BigQuery] Regen dataflow fixtures for case-insensitive resolution
- 2026-05-08 [Vertica] Support AND filter and WHERE in MERGE clauses
GSP Java version 4.1.1.0(2026-05-08)¶
- 2026-05-07 Fix DataFlowAnalyzer ClassCastException (TObjectName cannot be cast to TResultColumn)
- 2026-05-06 Add dlineage tests for Oracle PL/SQL procedures (Gitee IJLBB7, IJLB9E)
- 2026-05-02 Add procedure include/exclude filter for data flow analysis (Gitee IJJX1M)
- 2026-05-02 [BigQuery] Strengthen tests for func(args).* STRUCT star expansion (Mantis #4426)
- 2026-05-01 [BigQuery] Support func(args).* star expansion on STRUCT return
- 2026-05-01 [Teradata] Fix NPE on USING ... ABORT BTEQ statements
GSP Java version 4.1.0.15(2026-05-01)¶
- 2026-05-01 [BigQuery] Fix CTE self-reference resolution in ScopeBuilder (Mantis #4412)
- 2026-05-01 [Snowflake] Populate stageLocation for quoted COPY INTO source
- 2026-05-01 [Redshift] Support UNION DISTINCT syntax
- 2026-05-01 [Redshift] Support bare postfix NOTNULL operator
- 2026-04-28 Harden MERGE formatter (codex review follow-ups)
- 2026-04-27 Fix MERGE formatter: USING indent and WHEN action layout
- 2026-04-21 [Hive] Add regression tests for ALTER TABLE CHANGE ... ENABLE
- 2026-04-21 [Teradata] Fix SET with subquery RHS spanning multiple lines
- 2026-04-21 Fix TFunctionCall isBuiltIn array index out of bounds
- 2026-04-20 [DAX, PowerQuery] Fix DAX label and promote PowerQuery tier
- 2026-04-20 [PowerQuery] Wire lineage into DataFlowAnalyzer
- 2026-04-20 [PowerQuery] Infer vendor from inline connector calls
- 2026-04-20 [Snowflake] Support GROUP BY ALL syntax and lineage
- 2026-04-19 [PowerQuery] Add parser, AST and lineage analyzer
- 2026-04-19 [BigQuery] Add column-level lineage for array_agg(table_alias)
- 2026-04-18 [Oracle] Add XML column-level data lineage for XML functions and XMLTABLE
- 2026-04-18 [MSSQL] Support WRITETEXT inside stored procedures
- 2026-04-18 [Oracle] Support ARRAY as synonym for VARRAY in CREATE TYPE
- 2026-04-18 [Teradata] Support IF/WHILE/LOOP inside CASE stmt
- 2026-04-18 [PostgreSQL] Correct toScript() for LIMIT/OFFSET clauses
- 2026-04-18 [DB2] Support IMPLICITLY HIDDEN column attribute
- 2026-04-18 [Oracle] Support PARALLEL/NOPARALLEL in CTAS
- 2026-04-18 [Oracle] Trace pipelined function lineage through CTEs
- 2026-04-18 [Teradata] Support USING source-table MERGE prefix
- 2026-04-18 [Teradata] Support parenthesized type in USING var defs
- 2026-04-18 [Teradata] Support temporal qualifier DML
- 2026-04-18 [MSSQL] Support 3/4-part column names in INSERT column list
GSP Java version 4.1.0.12(2026-04-17)¶
- 2026-04-16 [Databricks] Accept bare time units in TIMESTAMPDIFF
- 2026-04-14 [OceanBase] Support SWITCH REPLICA LEADER SERVER/TENANT options
- 2026-04-14 [OceanBase] Support ALTER SYSTEM ADD ZONE IDC/ZONE_TYPE options
- 2026-04-14 [OceanBase] Add XA transaction support in MySQL mode
- 2026-04-14 [OceanBase] Add CREATE/DROP RESTORE POINT support
- 2026-04-14 [OceanBase] Add CREATE/DROP DBLINK support
- 2026-04-14 [OceanBase] Add CREATE TABLEGROUP PARTITION BY KEY N and LIST COLUMNS N
- 2026-04-14 [OceanBase] Add ALTER TABLEGROUP partition operations
- 2026-04-14 [OceanBase] Add ALTER SYSTEM CANCEL BACKUP operations
- 2026-04-14 [OceanBase] Add ALTER RESOURCE POOL SPLIT and MERGE operations
- 2026-04-14 [Dameng] Support CREATE [OR REPLACE] PACKAGE BODY
- 2026-04-14 [Dameng] Support CREATE [OR REPLACE] PACKAGE specification
- 2026-04-14 [Dameng] Add TIMER (scheduled) triggers on DATABASE
- 2026-04-14 [Dameng] Add system-event and DDL-event triggers ON DATABASE
- 2026-04-14 [Dameng] Add INSTEAD OF trigger on view
- 2026-04-14 [Dameng] Add combined-event triggers with IF/ELSIF/ELSE and EXCEPTION decl
- 2026-04-14 [Dameng] Add basic DML CREATE TRIGGER support
- 2026-04-13 [OceanBase] Fix statement splitter for RELEASE SAVEPOINT, PURGE INDEX/TENANT, CREATE/DROP TABLESPACE
- 2026-04-13 [OceanBase] Fix statement splitter for ALTER USER, CREATE/DROP ROLE in MySQL mode
- 2026-04-13 [OceanBase] Fix CREATE OR REPLACE OUTLINE splitter in both MySQL and Oracle modes
- 2026-04-13 [OceanBase] Add Oracle mode TABLEGROUP PARTITION, ALTER TABLEGROUP ADD TABLE, ALTER TABLE SET TABLEGROUP
- 2026-04-13 [OceanBase] Add MySQL mode TABLEGROUP RANGE COLUMNS N and SUBPARTITION support
- 2026-04-13 [OceanBase] Add FLASHBACK TENANT and FLASHBACK RENAME TO support
- 2026-04-13 [OceanBase] Add CREATE/ALTER RESOURCE UNIT space-separated parameter syntax
- 2026-04-13 [OceanBase] Add CREATE INDEX IF NOT EXISTS support in MySQL mode
- 2026-04-13 [OceanBase] Add ALTER TENANT extended options in system tenant mode
- 2026-04-13 [OceanBase] Add ALTER TABLE SET OceanBase-specific options in MySQL mode
- 2026-04-13 [OceanBase] Add ALTER SYSTEM server/zone management ZONE= and REGION= clauses
- 2026-04-13 [OceanBase] Add ALTER SYSTEM advanced operations (SWITCH REPLICA, BOOTSTRAP, RECOVERY, RESTORE)
- 2026-04-13 [OceanBase] Add ALTER SYSTEM SET COMMENT clause and FLUSH PLAN CACHE extensions
- 2026-04-13 [Dameng] Support PRINT statement in PL/SQL blocks
- 2026-04-13 [Dameng] Support PL/SQL variable assignment (:=) in block body
- 2026-04-13 [Dameng] Support DROP TYPE and DROP TYPE BODY with IF EXISTS
- 2026-04-13 [Dameng] Support DECLARE anonymous PL/SQL blocks
- 2026-04-13 [Dameng] Support CREATE/ALTER/DROP CLASS (Dameng proprietary)
- 2026-04-13 [Dameng] Support CREATE TYPE BODY with method implementations
- 2026-04-13 [Dameng] Support CREATE Type AS VARRAY and TABLE OF (collection types)
- 2026-04-13 [Dameng] Support CREATE TYPE AS OBJECT with member functions
- 2026-04-13 [Dameng] Support CREATE FUNCTION with PL/SQL body (BEGIN/END)
- 2026-04-13 [Dameng] Support CREATE FUNCTION ... AGGREGATE USING
- 2026-04-13 [Dameng] Support // single-line comments in Dameng lexer
- 2026-04-12 [OceanBase] Add SHOW extensions (TENANTS, RECYCLEBIN, TABLEGROUPS, PARAMETERS, TENANT STATUS)
- 2026-04-12 [OceanBase] Add SHOW TENANT / SHOW RESOURCE POOL / SHOW CREATE TENANT
- 2026-04-12 [OceanBase] Add SELECT FOR UPDATE WAIT N support
- 2026-04-12 [OceanBase] Add MERGE INTO statement support
- 2026-04-12 [OceanBase] Add FLASHBACK and PURGE statement support
- 2026-04-12 [OceanBase] Add EXPLAIN statement support
- 2026-04-12 [OceanBase] Add ALTER TABLEGROUP ADD TABLE and ALTER TABLE SET TABLEGROUP
- 2026-04-12 [OceanBase] Add ALTER SYSTEM subcommands (FLUSH, MINOR FREEZE, FREEZE TENANT)
- 2026-04-12 [OceanBase] Add ALTER SYSTEM low-priority subcommands
- 2026-04-12 [OceanBase] Add ALTER SYSTEM SET extended clauses (SCOPE, TENANT, COMMENT)
- 2026-04-12 [OceanBase] Add ALTER SEQUENCE support
- 2026-04-12 [OceanBase] Add checksyntax OceanBase tenant-mode vendor aliases
- 2026-04-12 [OceanBase] CREATE TENANT with space-separated SET clause
- 2026-04-12 [OceanBase] CREATE TABLEGROUP with trailing partition_clause
- 2026-04-12 [Dameng] Support flashback query clause + trailing alias
- 2026-04-12 [Dameng] Support bare parameterless package call (PKG.PROC;)
- 2026-04-12 [Dameng] Support WHEN TIMESTAMP flashback query clause
- 2026-04-12 [Dameng] Support DROP TABLE ... CASCADE (PostgreSQL-style)
- 2026-04-12 [Dameng] Support CREATE HUGE TABLE syntax
- 2026-04-12 [Dameng] Support AS OF LSN and VERSIONS BETWEEN LSN flashback
- 2026-04-12 [Dameng] Support ALTER TABLE WITH/WITHOUT ADVANCED LOG
- 2026-04-12 [Dameng] Support ALTER TABLE TRUNCATE ADVANCED LOG
- 2026-04-11 [Dameng] Support zero-argument pseudo-function calls
- 2026-04-11 [Dameng] Support uppercase hex literals (0xFFFEE)
- 2026-04-11 [Dameng] Support multi-row VALUES clause in INSERT
- 2026-04-11 [Dameng] Support TIME and DATETIME typed datetime literals
- 2026-04-11 [Dameng] Support SQL-standard SUBSTRING and OVERLAY
- 2026-04-11 [Dameng] Support REFRESH MATERIALIZED VIEW statement
- 2026-04-11 [Dameng] Support IDENTITY + CLUSTER PRIMARY KEY and STORAGE clause
- 2026-04-11 [Dameng] Support DROP VIEW with RESTRICT/CASCADE
- 2026-04-11 [Dameng] Support DROP SCHEMA CASCADE
- 2026-04-11 [Dameng] Support DROP MATERIALIZED VIEW [IF EXISTS]
- 2026-04-11 [Dameng] Support DROP MATERIALIZED VIEW LOG [IF EXISTS] ON
- 2026-04-11 [Dameng] Support DATE() as a conversion function
- 2026-04-11 [Dameng] Support CREATE VIEW WITH LOCAL/CASCADED CHECK OPTION
- 2026-04-11 [Dameng] Support CREATE MV LOG PURGE options
- 2026-04-11 [Dameng] Support CREATE MV FOR ON PREBUILT TABLE
- 2026-04-11 [Dameng] Support CONNECT BY LEVEL without FROM in SELECT
- 2026-04-11 [Dameng] Support ALTER MV ENABLE/DISABLE QUERY REWRITE and COMPILE
- 2026-04-11 [Dameng] Parse CREATE LIBRARY libname AS 'path'
- 2026-04-11 [Dameng] Parse CREATE FUNCTION IF NOT EXISTS external bodies
- 2026-04-11 [Dameng] Parse CREATE FUNCTION ... EXTERNAL body
- 2026-04-11 [Dameng] Parse AS LANGUAGE C|CS LIBRARY function body
- 2026-04-11 [Dameng] Parse two-argument XMLQUERY form
- 2026-04-11 [Dameng] Parse bare top-level function-call statement
- 2026-04-11 [Dameng] Parse SELECT ... FOR XML PATH clause
- 2026-04-11 [Dameng] Add Dameng database dialect support
- 2026-04-09 [Teradata] Fix SHOW TABLE statement recognition
- 2026-04-09 [Teradata] Store first argument of QUANTILE function
- 2026-04-09 [Teradata] Recognize BEGIN REQUEST / END REQUEST block
- 2026-04-09 [PostgreSQL] Fix COMMENT ON PROCEDURE with empty parens
- 2026-04-09 [MSSQL] Fix ALTER DATABASE inside procedure body
- 2026-04-09 [BigQuery] Support FORMAT('literal') in CAST clause
- 2026-04-09 [Oracle] Add pipelined table function lineage stitching
- 2026-03-12 [PostgreSQL] Fix ClassCastException in TSequenceOption
- 2026-03-12 [Oracle] Fix OOM in TSqlplusCmdStatement.extractCommandText
- 2026-03-12 [MySQL] Fix tokenize error for backslash delimiter
- 2026-03-10 [Snowflake] Fix escaped quotes unescaping in proc body
- 2026-03-10 [Oracle] Fix &variable. substitution with trailing dot
- 2026-03-10 [MySQL] Fix NPE when FK REFERENCES has no column list
- 2026-03-10 [MSSQL] Fix SELECT not split from CREATE VIEW body
- 2026-03-10 [MSSQL] Fix NPE in EXECUTE sp_executesql without args
- 2026-03-09 [PostgreSQL] Fix ClassCastException for SEQUENCE NAME option
- 2026-03-08 [Snowflake] Fix procedure with $$ body blocking subsequent statements
- 2026-03-08 [Snowflake] Fix GRANT/REVOKE after procedure body not splitting
- 2026-03-08 [MSSQL] Fix splitter incorrectly splitting proc on END; CREATE TABLE
- 2026-03-07 [MySQL] Fix trailing tokens after conditional comments
- 2026-03-07 [MySQL] Fix tokenizer error on multi-dash comments
- 2026-03-07 [MySQL] Fix tokenizer error on dash-separator comments
- 2026-03-07 [Hive] Fix statement splitter for SET after semicolon-less statements
- 2026-03-07 [Hive] Fix statement splitter for SELECT after semicolon-less SELECT
GSP Java version 4.1.0.11(2026-04-08)¶
- 2026-04-08 [Snowflake] Support LIKE ANY/ALL/SOME with pattern list or expr
- 2026-04-08 [Hive] Accept backtick alias with dot after subquery
- 2026-04-08 [DB2] Support CREATE PROCEDURE with single inline DML body
- 2026-04-07 [PostgreSQL, Snowflake] Fix regressions from #3672 and #3491
- 2026-04-07 [BigQuery] Allow digit-leading identifiers in qualified names
- 2026-04-07 [Snowflake] Support * REPLACE, # comments and nameless masking policy
- 2026-04-07 [Redshift] Allow LIKE/ILIKE/SIMILAR TO in SELECT list
- 2026-04-07 [PostgreSQL] Support TRIM(LEADING|TRAILING|BOTH FROM expr, expr)
- 2026-04-07 [PostgreSQL] Fix toScript emitting MySQL LIMIT for non-MySQL dialects
- 2026-04-07 [Oracle] Allow CREATE TYPE AS (attrs) without OBJECT keyword
- 2026-04-07 [Snowflake] Support DESC SCHEMA, SHOW TERSE ROLES, SHOW DATABASES IN ACCOUNT
- 2026-04-07 [Teradata] Allow DIAGNOSTIC ... ON FOR SESSION inside macro body
- 2026-04-07 [Oracle] Do not inherit implicit schema for db_link tables
- 2026-04-07 [MSSQL] Populate cursorName for OPEN/CLOSE cursor stmts
- 2026-04-07 [Teradata] Support RESPECT NULLS on window functions
- 2026-04-07 [Teradata] Allow alias on multi-column PIVOT IN tuple
- 2026-04-07 Set dbObjectType on cloneSourceTable to populate parts
- 2026-04-07 [Oracle] Allow SUBPARTITIONS n in composite partition clause
- 2026-04-07 [Teradata] Allow LAST_VALUE/FIRST_VALUE as column names
- 2026-04-07 [Oracle] Add composite LIST+subpartition rule
- 2026-04-07 [Snowflake] Treat \'
as escape + close quote in string literals - 2026-04-07 [MSSQL] Add DROP PARTITION FUNCTION, ALTER SEQUENCE, fix ALTER INDEX SET splitter
- 2026-04-07 [Oracle] Dispatch CREATE CLUSTER to TOracleCreateClusterStmt
- 2026-04-07 [PostgreSQL] Map uuid type to EDataType.uuid_t
- 2026-04-07 [MSSQL] UPDATE alias resolution + trigger splitter follow-up
- 2026-04-07 [MSSQL] Distinguish WHILE from IF in sqlstatementtype
- 2026-04-07 [MSSQL] Add TRY_CONVERT with typename exposed via getTypename()
- 2026-04-07 [MSSQL] Preserve ALTER statement type for procedure/function/trigger
- 2026-04-06 [Redshift] Register ELSIF keyword in lexer for PL/pgSQL
- 2026-04-06 [GaussDB] Support EXECUTE DIRECT ON statement
- 2026-04-06 [GaussDB] Support SET LOCAL TRANSACTION and CREATE DIRECTORY
- 2026-04-06 [MSSQL] Expose CHECK/NOCHECK CONSTRAINT in AST
- 2026-04-06 [Teradata] Support angle-bracket identifiers in BTEQ
- 2026-04-05 [Snowflake] Expose new stage name in ALTER STAGE RENAME TO
- 2026-04-05 [Snowflake] Expose stage properties in ALTER STAGE
- 2026-04-05 [Teradata] Support CREATE OR REPLACE syntax
- 2026-04-05 [Teradata] Support @Parameter in macro body
- 2026-04-05 [Vertica] Parse AS SELECT subquery in CREATE PROJECTION
- 2026-04-05 [BigQuery] Fix incorrect target column name for ARRAY[scalar_function()]
- 2026-04-05 [Teradata] Support qualified column names in COLLECT STATISTICS COLUMN()
- 2026-04-05 Fix thread-safety issues in multi-threaded parsing
- 2026-04-05 [MDX] Add data lineage support for MDX queries
- 2026-04-04 [Teradata] Fix formatter for REPLACE VIEW with LOCKING
- 2026-04-04 [Redshift] Wire EXCLUDE clause to TExceptReplaceClause
- 2026-04-04 Add getTableKind() to TIntoClause for SELECT INTO
GSP Java version 4.1.0.10(2026-04-04)¶
- 2026-04-03 [Databricks] Add ODBC escape syntax support
- 2026-04-02 [Oracle] Fix CASE WHEN direct/indirect dataflow handling in DataFlowAnalyzer
- 2026-04-01 [Teradata] Fix dataflow analysis for complex queries
- 2026-03-31 [Teradata, Hive] Set schemaToken in parseTablename
- 2026-03-31 [DuckDB] Comprehensive DuckDB dialect support: PIVOT/UNPIVOT, MACRO, SECRET, lambda expressions, list comprehension, struct/map/union types, QUALIFY, EXCLUDE/REPLACE on star, POSITIONAL/ASOF JOIN, FROM-first syntax, USING SAMPLE, and 60+ additional syntax features
GSP Java version 4.1.0.9(2026-03-23)¶
- 2026-03-23 [MSSQL] Fix $action column order in MERGE OUTPUT clause
- 2026-03-23 [MSSQL] Resolve MERGE OUTPUT inserted/deleted to MERGE target
- 2026-03-22 [EDB] Comprehensive EDB Postgres SPL support (triggers, types, collections, cursors, exceptions, loops, bulk operations)
- 2026-03-20 [BigQuery] Fix star column dedup in resolver
- 2026-03-20 [MSSQL] Preserve star column relationships with ignoreCoordinate
- 2026-03-19 [Teradata] Unify GRANT privilege types
- 2026-03-19 [Redshift] Add interval unit keywords and AT TIME ZONE support
- 2026-03-19 [Redshift] Add GROUPING SETS, ROLLUP, CUBE support
- 2026-03-18 [Snowflake] Add TEMP/TEMPORARY FUNCTION with $$ body
- 2026-03-17 [MSSQL, Snowflake] Respect vendor flags in identifier rules
- 2026-03-17 [Oracle, Snowflake, BigQuery] Prevent AIOOB in statement splitter
- 2026-03-17 Add builder pattern for custom IdentifierRules injection
- 2026-03-16 Optimize core parse path performance
- 2026-03-15 [Netezza] Fix AexprConst precedence and trim whitespace
- 2026-03-15 Eliminate parser S/R and R/R conflicts across all vendors
- 2026-03-14 Allow unreserved keywords as column names for all vendors
- 2026-03-14 [Redshift] Allow AWS-unreserved keywords as column names
GSP Java version 4.1.0.8(2026-03-13)¶
- 2026-03-14 [Redshift] Allow LISTAGG, CONVERT, APPROXIMATE, CONNECT_BY_ROOT, CHARACTER, DOUBLE as unquoted column names
- 2026-03-13 [MySQL] Fix tokenize error for backslash delimiter
- 2026-03-13 [Hive] Add CREATE PROCEDURE support
- 2026-03-13 [Greenplum, Snowflake] Fix syntax parsing issues
- 2026-03-13 [Oracle] Fix OOM in TSqlplusCmdStatement.extractCommandText
GSP Java version 4.1.0.7(2026-03-12)¶
- 2026-03-12 [BigQuery, PostgreSQL, MSSQL, MySQL, Greenplum] Fix syntax issues across 5 SQL dialects
- 2026-03-12 [BigQuery] Support PIVOT/UNPIVOT in JOIN context
- 2026-03-11 [PostgreSQL] Support RETURN as top-level statement
- 2026-03-11 [PostgreSQL] Fix ClassCastException in TSequenceOption
- 2026-03-11 [Snowflake] Support {var} template variables in identifiers
- 2026-03-11 [Oracle] Split multi-statement files with CTE after SELECT
- 2026-03-11 [Oracle] Support $P{} and $X{} template variables
- 2026-03-11 [Oracle] Support MATCH_RECOGNIZE after aliased table
- 2026-03-11 [MSSQL] Fix NPE in EXECUTE sp_executesql without args
- 2026-03-11 [MySQL] Fix NPE when FK REFERENCES has no column list
- 2026-03-10 [Snowflake] Support {{ variable }} template syntax
- 2026-03-10 [Oracle] Fix &variable. substitution with trailing dot
- 2026-03-10 [Redshift] Support CREATE PROCEDURE without args
- 2026-03-10 [MSSQL] Fix SELECT not split from CREATE VIEW body
- 2026-03-10 [DB2] Support {{ variable }} template syntax
- 2026-03-10 [Oracle] Support ${variable} template syntax
- 2026-03-10 [MySQL] Accept -- comments without trailing space
- 2026-03-10 [BigQuery] Support ${variable} template syntax
- 2026-03-10 [Snowflake] Handle \' escaped quotes in SQL input
- 2026-03-10 [Snowflake] Fix \'' in direct expression context
- 2026-03-10 [Snowflake] Fix \'' unescaping in single-quoted proc body
- 2026-03-10 [MSSQL] Split CTE without semicolon after DML
- 2026-03-09 [MySQL] Support ON as value in SET variable assignment
- 2026-03-09 [PostgreSQL] Support PL/pgSQL PERFORM FROM, ELSEIF, RETURN NEXT
- 2026-03-09 [PostgreSQL] Fix ClassCastException for SEQUENCE NAME option
- 2026-03-09 [Snowflake] Support ${variable} and backtick-quoted identifiers
- 2026-03-09 [Redshift] Split DDL statements without semicolons
- 2026-03-09 [Oracle] Handle forward slash delimiter on same line as semicolon
- 2026-03-09 [Snowflake] Split SET statements without semicolons
- 2026-03-09 [MySQL] Support DEFAULT before both CHARSET and COLLATE
- 2026-03-09 [PostgreSQL] Support TYPE as name in column alias lists
- 2026-03-09 [Snowflake] Split DDL statements without semicolons
GSP Java version 4.1.0.6(2026-03-09)¶
- 2026-03-09 [MySQL] Support CREATE/DROP SEQUENCE statements
- 2026-03-08 [Hive] Support ${variable} template substitution syntax
- 2026-03-08 [PostgreSQL] Support COMMENT ON FUNCTION/PROCEDURE without args
- 2026-03-08 [MSSQL] Fix splitter incorrectly splitting proc on END; CREATE TABLE
- 2026-03-08 [MSSQL] Support bracket-quoted XML method names
- 2026-03-08 [MSSQL] Support WITH XMLNAMESPACES combined with CTEs for all DML
- 2026-03-07 [Snowflake] Fix GRANT/REVOKE after procedure body not splitting
- 2026-03-07 [MySQL] Support function calls in CHECK constraints
- 2026-03-07 [Snowflake] Fix procedure with $$ body blocking subsequent statements
- 2026-03-07 [Snowflake] Add CREATE OR ALTER DYNAMIC TABLE to splitter
- 2026-03-07 [Snowflake] Support standalone scripting statements
- 2026-03-07 [Snowflake] Handle standalone scripting blocks (WHILE/FOR/LOOP/IF)
- 2026-03-07 [PostgreSQL] Handle psql meta-commands and RETURNS TABLE LANGUAGE
- 2026-03-07 [PostgreSQL] Add CASCADE and VERSION options to CREATE EXTENSION
- 2026-03-07 [Hive] Fix statement splitter for SELECT after semicolon-less SELECT
- 2026-03-07 [Hive] Fix statement splitter for SET after semicolon-less statements
- 2026-03-07 [MySQL] Fix tokenizer error on dash-separator comments
- 2026-03-07 [PostgreSQL] Allow CREATE TYPE inside DO blocks
- 2026-03-06 [MySQL] Fix tokenizer error on multi-dash comments
- 2026-03-06 [Snowflake] Support CREATE SEARCH OPTIMIZATION statement
- 2026-03-06 [MySQL] Fix trailing tokens after conditional comments
- 2026-03-06 Support TAlterViewStatement
- 2026-03-06 [Teradata] Support GRANT LOGON syntax
GSP Java version 4.1.0.5(2026-03-06)¶
- 2026-03-06 [Teradata] Support abbreviated GRANT privileges
- 2026-03-06 [Vertica] Support CREATE FLEX TABLE syntax
- 2026-03-06 [Teradata] Support USER, DATABASE, CREATE USER as GRANT privileges
- 2026-03-06 [Teradata] Support TABLE, VIEW, MACRO as GRANT privileges
- 2026-03-06 [Snowflake] Populate stage location from COPY INTO subquery
- 2026-03-06 [Redshift] Support IGNORE/RESPECT NULLS in both positions
- 2026-03-06 Add comprehensive TAttributeNode deprecated API inventory
- 2026-03-06 Support SQL query statistics
- 2026-03-06 Add large SQL file splitter tool
- 2026-03-06 Fixed NPE in logger error handling
- 2026-03-05 [Oracle] Improve call graph for parameterless calls and trigger tables
- 2026-03-05 [Oracle] Fix forward declaration causing AMBIGUOUS resolution
- 2026-03-05 [Oracle] Model package body initializer as synthetic routine
- 2026-03-05 [Oracle] Classify built-in functions as external deps
- 2026-03-05 [Oracle] Detect calls from enclosing routine to nested functions
- 2026-03-05 [Oracle] Detect function calls in TABLE(func) without arguments
- 2026-03-05 [Oracle] Detect parameterless function calls in all contexts
- 2026-03-05 [Oracle] Detect calls inside EXCEPTION handler blocks
- 2026-03-05 [Oracle] Detect constructor calls inside PIPE ROW statements
- 2026-03-05 [Oracle] Filter boolean literals from call graph edges
- 2026-03-05 [Oracle] Detect function calls in PL/SQL declarative sections
- 2026-03-05 [Oracle] Traverse compound trigger timing section bodies
- 2026-03-05 [Oracle] Detect double-parenthesized function calls
- 2026-03-05 [Oracle] Detect standalone dotted procedure calls
- 2026-03-05 [Oracle] Detect procedure calls in CASE statement branches
- 2026-03-05 [Oracle] Filter collection parameter access from call graph
- 2026-03-05 [Oracle] Filter SYSDATE and pseudo-columns from call graph
- 2026-03-05 [Oracle] Filter out collection variable/method calls from call graph
- 2026-03-05 [Oracle] Merge forward declaration and implementation
- 2026-03-05 [Oracle] Resolve calls to procs with default parameters
- 2026-03-05 [Oracle] Detect built-in SQL function calls in PL/SQL expressions
- 2026-03-05 [Oracle] Deduplicate cursor table accesses on OPEN CURSOR
- 2026-03-05 [Oracle] Fix trigger ON table access kind classification
- 2026-03-05 [MSSQL] Add T-SQL call graph support (Phase A IR)
- 2026-03-05 [MSSQL] Filter XML methods and .WRITE() from call graph
- 2026-03-05 [MSSQL] Classify JSON built-in functions as external deps
- 2026-03-05 [MSSQL] Detect function calls in SET assignments
- 2026-03-04 [Vertica] Support PLvSQL truncating assignment (<-)
- 2026-03-03 [PostgreSQL] Fix parser errors on various SELECT commands
- 2026-03-03 [PostgreSQL] Expose ON CONFLICT clause in GSP API
- 2026-03-03 [PostgreSQL] INCLUDE clause in constraints
- 2026-03-03 [PostgreSQL] Add PGvector distance operators
- 2026-03-03 [PostgreSQL] Process operands for binary operator expressions
- 2026-03-03 [PostgreSQL] Fix NPE in TElsifStmt.acceptChildren
- 2026-03-03 Fix null guards in TStarColumnPushDownResolver
- 2026-03-03 [SparkSQL] Support FOR loop statement
- 2026-03-03 [SparkSQL] Support LOOP/END LOOP statement
- 2026-03-03 [SparkSQL] Support labeled WHILE and REPEAT loops
- 2026-03-03 [SparkSQL] Support LEAVE and ITERATE without labels
- 2026-03-02 [Redshift] Database@Catalog cross-database notation
- 2026-03-02 [Redshift] VACUUM TO PERCENT BOOST and ANALYZE ALL COLUMNS
- 2026-03-02 [Redshift] Transaction isolation level extensions
- 2026-03-02 [Redshift] SHOW TEMPLATES LIKE/LIMIT and SHOW DATABASES extensions
- 2026-03-02 [Redshift] SHOW COLUMN GRANTS/CONSTRAINTS and FOR ROLE
- 2026-03-02 [Redshift] SHOW GRANTS extended types and FOR/LIMIT clauses
- 2026-03-02 [Redshift] COPY SIMPLIFY AUTO clause for Shapefile format
- 2026-03-02 [Redshift] CREATE/ALTER USER EXTERNALID double-quoted value
- 2026-03-02 [Redshift] ALTER USER CONNECTION LIMIT, VALID UNTIL, SET SEARCH_PATH
- 2026-03-02 [Redshift] ALTER TABLE MASKING and RLS FOR DATASHARES
- 2026-03-02 [Redshift] CREATE DATABASE extensions
- 2026-03-02 [Redshift] ALTER DATABASE CONNECTION LIMIT and SET INTEGRATION REFRESH
- 2026-03-02 [Redshift] Allow POSITION keyword as column name
GSP Java version 4.1.0.3(2026-03-02)¶
- 2026-03-02 [SparkSQL] Support standalone TABLE expression
- 2026-03-02 [SparkSQL] Support MSCK REPAIR TABLE with ADD/DROP/SYNC PARTITIONS
- 2026-03-02 [SparkSQL] Support FROM-first query syntax
- 2026-03-02 [SparkSQL] Support ILIKE operator for case-insensitive pattern matching
- 2026-03-02 [SparkSQL] Support VALUES with table alias and column definitions
- 2026-03-02 [SparkSQL] Support default keyword as schema/database identifier
- 2026-03-02 [SparkSQL] Support compound statement (BEGIN...END)
- 2026-03-02 [SparkSQL] Support Pipe Syntax operators
- 2026-03-02 [SparkSQL] Support TRANSFORM clause, UNPIVOT, CREATE SQL FUNCTION
- 2026-03-02 [SparkSQL] Support ALTER DATABASE, ALTER TABLE extended operations
- 2026-03-02 [SparkSQL] Support WITHIN GROUP, GROUP BY WITH ROLLUP/CUBE
- 2026-03-02 [SparkSQL] Support IGNORE/RESPECT NULLS, EXCEPT ALL, MINUS ALL
- 2026-03-02 [SparkSQL] Support OFFSET, SET VAR, DROP TEMPORARY VARIABLE
- 2026-03-02 [SparkSQL] Support EXECUTE IMMEDIATE, DECLARE VARIABLE
- 2026-03-02 [SparkSQL] Support star EXCEPT with struct field references
- 2026-03-02 [SparkSQL] Support WINDOW clause, INSERT BY NAME, REPLACE WHERE
- 2026-03-02 [SparkSQL] Support ADD/LIST resource management, CREATE TABLE/VIEW AS VALUES
- 2026-03-02 [SparkSQL] Support CREATE/ALTER VIEW WITH SCHEMA EVOLUTION
- 2026-03-02 [SparkSQL] Support SHOW SCHEMAS, SHOW SYSTEM FUNCTIONS, ANALYZE TABLES
- 2026-03-02 [Redshift] Support SHOW TEMPLATE command
- 2026-03-02 [Redshift] Support NONATOMIC stored procedures
- 2026-03-02 [Redshift] Support CREATE EXTERNAL MODEL with MODEL_TYPE BEDROCK
- 2026-03-02 [Redshift] Support EXTERNALID and namespaced usernames
- 2026-03-02 [Redshift] Support CREATE EXTERNAL SCHEMA FROM MSK with AUTHENTICATION
- 2026-03-02 [Redshift] Support nested complex types in CREATE EXTERNAL TABLE
- 2026-03-02 [Redshift] Support BZIP2 and SERIALIZETOJSON in COPY command
- 2026-03-02 [Redshift] Support DISTSTYLE AUTO and SORTKEY AUTO
- 2026-03-02 [Redshift] Support VACUUM BOOST, LATERAL, ARRAY()
- 2026-03-02 [Redshift] Support CREATE VIEW WITH NO SCHEMA BINDING
- 2026-03-02 [Redshift] Support GENERATED ALWAYS AS IDENTITY
- 2026-03-02 [Redshift] Support UNPIVOT INCLUDE/EXCLUDE NULLS
- 2026-03-02 [Redshift] Support CREATE/ALTER/DROP RLS POLICY and MASKING POLICY
- 2026-03-02 [Redshift] Support CONNECT BY hierarchical queries
- 2026-03-02 [Redshift] Support COPY/UNLOAD extensions (ORC, SHAPEFILE, KMS_KEY_ID)
- 2026-03-02 [Redshift] Support CREATE/ALTER DATABASE extensions
- 2026-03-02 [Redshift] Support CREATE/ALTER USER extensions
- 2026-03-02 [Redshift] Support SHOW extensions (COLUMNS, TABLES, SCHEMAS, GRANTS, DATASHARES)
- 2026-03-02 [Redshift] Support CREATE/ALTER/DROP TEMPLATE, ROLE, DATASHARE
- 2026-03-02 [Redshift] Support CREATE EXTERNAL FUNCTION for Lambda UDFs
- 2026-03-02 [Redshift] Support GRANT/REVOKE extensions (column-level, scoped, ROLE)
- 2026-03-02 [Redshift] Support SELECT * EXCLUDE (columns) syntax
- 2026-03-02 [Redshift] Support USE statement
- 2026-03-02 [Snowflake] Add CHANGES clause for time travel queries
- 2026-03-02 [Snowflake] Support object wildcard {} and {table.} in SELECT
- 2026-03-02 [Snowflake] Support @%table and @~ stage references in SELECT
- 2026-03-02 [Snowflake] Support parenthesized COPY in CREATE PIPE
- 2026-03-02 [Snowflake] Support FILE_FORMAT shorthand and quoted MATCH_BY_COLUMN_NAME
- 2026-03-02 [Snowflake] Support unquoted S3 URLs in COPY INTO FROM
- 2026-03-02 [Snowflake] Support PARTITION BY with external locations in COPY INTO
- 2026-03-02 [Snowflake] Support standalone HEADER keyword in COPY INTO
- 2026-03-02 [Snowflake] Support @stage/ trailing slash in COPY INTO
- 2026-03-02 [Snowflake] Allow varchar2 as unquoted identifier
- 2026-03-02 [Snowflake] Support ALTER TABLE extensions (search optimization, policies, tags, metrics)
- 2026-03-02 [Snowflake] Support multi-column ALTER/MODIFY, constraint management
- 2026-03-02 [BigQuery] Support CREATE MODEL ARIMA custom holidays, INPUT/OUTPUT clauses
- 2026-03-02 [BigQuery] Support Apache Spark procedures and WITH CONNECTION for Python UDFs
- 2026-03-02 [BigQuery] Support OPTIONS clause after function body
- 2026-03-02 [BigQuery] Support hyphenated identifiers in DROP CAPACITY/RESERVATION/ASSIGNMENT
- 2026-03-02 [BigQuery] Support RANGE
type in column definitions - 2026-03-02 fix: getFinalTable() traces through column aliases to physical tables
- 2026-03-02 feat: Add getTracedFinalTable() for alias-aware lineage
- 2026-03-02 fix: [Oracle] ALTER INDEX RENAME TO sets newIndexName, not tableName
GSP Java version 4.1.0.2(2026-02-25)¶
- 2026-02-25 Fixed NPE
- 2026-02-25 [BigQuery] Regenerate yacc table to fix parser regression
- 2026-02-25 [BigQuery] Fix NPE crash on malformed input
- 2026-02-25 [BigQuery] Support CREATE FUNCTION OPTIONS after RETURNS
- 2026-02-25 [BigQuery] Support labeled loop and block statements
- 2026-02-25 [BigQuery] Support bare RAISE statement in exception handlers
- 2026-02-25 [BigQuery] Support ELSEIF in IF statements
- 2026-02-25 [BigQuery] Add tests for REPEAT...UNTIL loop syntax
- 2026-02-25 [BigQuery] Support WHILE...DO loop syntax
- 2026-02-25 [Snowflake] Support CREATE PROCEDURE without LANGUAGE clause
- 2026-02-25 [Snowflake] Support EXECUTE IMMEDIATE FROM with DRY_RUN option
- 2026-02-25 [Snowflake] Support EXECUTE IMMEDIATE FROM with USING clause
- 2026-02-25 [Snowflake] Support EXECUTE IMMEDIATE FROM syntax
- 2026-02-25 [Netezza] Regenerate yacc table to restore || precedence
- 2026-02-25 [Snowflake] Support CREATE ICEBERG TABLE syntax
- 2026-02-25 [Snowflake] Support backslash-escaped strings in function body
- 2026-02-25 [Snowflake] Support GRANT USAGE ON FUNCTION with parameter signature
GSP Java version 4.1.0.1(2026-02-23)¶
- 2026-02-23 [Teradata] Fix objectToken when alias matches schema name
- 2026-02-23 [Snowflake] Fix phantom star column expansion in JOIN lineage
- 2026-02-23 Add PL/SQL call graph sample files with JSON output
- 2026-02-23 Add JSON schema v1.1 for call graph and impact analysis
- 2026-02-23 [Oracle] Upgrade Phase A IR to industrial-grade
- 2026-02-22 [Oracle] Add OracleBoundIRBuilder and CallGraph
- 2026-02-22 Add TSQLResolver2 adapter strategy for IBoundIRBuilder
- 2026-02-22 [BigQuery] Fix nested struct column lineage naming
- 2026-02-22 [BigQuery] Add StructFieldHint for 3-part no-alias struct access
- 2026-02-22 [BigQuery] Add FieldPath infrastructure for nested column lineage
- 2026-02-21 [Snowflake] Support nested stored procedure declarations
- 2026-02-21 [Snowflake] Support EXIT keyword in exception handlers
- 2026-02-21 [Snowflake] Fix NOT NULL constraint on variable declarations
- 2026-02-21 [BigQuery] Support MATCH_RECOGNIZE pipe operator
- 2026-02-21 [BigQuery] Support WINDOW pipe operator
- 2026-02-21 [BigQuery] Support CALL pipe operator for table-valued functions
- 2026-02-21 [BigQuery] Support TABLESAMPLE pipe operator
- 2026-02-21 [BigQuery] Support OFFSET in pipe LIMIT operator
- 2026-02-21 [Vertica] Fix CREATE EXTERNAL TABLE AS COPY FROM support
- 2026-02-21 [Vertica] Add SECURITY INVOKER/DEFINER support for CREATE PROCEDURE
- 2026-02-21 [Redshift] Fix comparison operator access in group_comparison_t
- 2026-02-21 [Redshift] Fix quantified comparison (ALL/ANY/SOME) AST
- 2026-02-20 [Snowflake] Support ASYNC keyword in parenthesized resultset assignments
- 2026-02-20 [Snowflake] Support cursor row dot notation in FOR loops
- 2026-02-20 [BigQuery] Allow expression in RAISE USING MESSAGE
- 2026-02-20 [Snowflake] Support DECLARE EXCEPTION without parameters
- 2026-02-20 [BigQuery] Add support for additional ML table functions
- 2026-02-20 [Snowflake] Fix NULL; statement NullPointerException in $$ bodies
- 2026-02-20 [BigQuery] Support FOR SYSTEM_TIME AS OF with alias in JOIN
- 2026-02-20 [Impala] Add PURGE keyword support for DROP TABLE
- 2026-02-20 [Redshift] Fix TOP clause returning null on AST
- 2026-02-20 Resolve GROUP BY alias references to source tables
GSP Java version 3.3.1.9(2025-11-23)¶
- 2025-11-23 Convert ENABLE_RESOLVER to ThreadLocal for thread safety
- 2025-11-22 Add support for PL/SQL NEW constructor with empty params
- 2025-11-20 Fix resolver error in parseExpression method
3.3.1.7 (2025-11-16)¶
- 2025-11-16: Improve UNION column propagation and prevent duplicate links
- 2025-11-16: Fix star column push down for UNION in CTE subqueries
- 2025-11-16: Fix Snowflake CREATE TABLE to support multiple table options
- 2025-11-15: Fix parse bug for lock row for access used in cursor declaration
- 2025-11-15: Fix CASE expression matching in Teradata procedures
- 2025-11-15: Fix NullPointerException in Teradata implicit table column linking
- 2025-11-15: Fix UNION column name resolution to use leftmost query
- 2025-11-15: Add SET TIME ZONE statement parsing for Teradata
- 2025-11-15: Add END_FASTEXPORT command type for Teradata
3.2.1.5 (2025-10-26)¶
- 2025-10-26: Fix DROP SECURITY POLICY parsing in IF statements
- 2025-10-26: Fix PARTITION BY expression parsing in Snowflake
- 2025-10-26: Integrate file format properties parsing and XML output
- 2025-10-26: Add parseFileFormatProperties method to TCreateTableOption
- 2025-10-26: Add file format properties list to TCreateTableOption
3.2.1.4 (2025-10-26)¶
- 2025-10-26: Add areEqualStatic method to IdentifierService
- 2025-10-26: Add static cache to IdentifierService for performance
- 2025-10-26: Refactor identifier normalization to use service pattern
- 2025-10-26: Fix multithreading bug in SqlCmdsFactory
- 2025-10-26: Improve SQL Server identifier handling and tests
- 2025-10-22: Enable catalog hierarchical and bucketed indexes
- 2025-10-21: Use SQLUtil.getIdentifierNormalName in keyForMap (temporary)
- 2025-10-21: Enhance IdentifierRules Javadoc with compatibility info
- 2025-10-20: Enhance Javadoc for IdentifierService and SQLUtil
- 2025-10-20: Remove redundant catalogStore field and USE_CALCITE_CATALOG_VIEW flag
- 2025-10-20: Refactor CatalogStore to use IdentifierService
- 2025-10-19: Add catalog documentation README index
- 2025-10-19: Add comprehensive catalog documentation for 12 major databases
- 2025-10-18: Add Oracle catalog documentation for beginners
- 2025-10-18: Fix collation case sensitivity configuration bugs
3.2.0.2 (2025-10-15)¶
- 2025-10-15: Fix parsing conversion functions as column names
- 2025-10-15: Add array indexing support for GaussDB
- 2025-10-15: Add table kind support for GaussDB CREATE TABLE
- 2025-10-10: Add GitHub Actions workflow for PR test automation
- 2025-10-10: Add INSERTED/DELETED as SQL Server reserved words
3.2.0.1 (2025-10-08)¶
- 2025-10-08: Fix json_table rewrite bug in script generator
- 2025-10-08: Remove unused findXXXCmd methods from TSqlCmds
- 2025-10-08: Refactor TSqlCmds.java into per-vendor TSqlCmds subclasses
- 2025-10-08: Document command ordering bug with real example
- 2025-10-08: Fix command ordering for DATABASE SCOPED CREDENTIAL
- 2025-10-08: Migrate MDX to modular architecture
- 2025-10-08: Unify vendor implementations for Trino, SOQL, ODBC
- 2025-10-07: Migrate Vertica to modular architecture
- 2025-10-07: Migrate Sybase to modular architecture
- 2025-10-07: Migrate SparkSQL to modular architecture
- 2025-10-07: Migrate Snowflake to modular architecture
- 2025-10-07: Migrate Redshift to modular architecture
- 2025-10-07: Migrate Presto to modular architecture
- 2025-10-07: Migrate OpenEdge to modular architecture
- 2025-10-07: Migrate Netezza to modular architecture
- 2025-10-07: Migrate Informix to modular architecture
- 2025-10-07: Migrate HANA to modular architecture
- 2025-10-07: Migrate Greenplum to modular architecture
- 2025-10-07: Migrate GaussDB to modular architecture
- 2025-10-07: Migrate DB2 to modular architecture
- 2025-10-07: Migrate Databricks to modular architecture
- 2025-10-07: Migrate Couchbase to modular architecture
- 2025-10-07: Migrate BigQuery to modular architecture
- 2025-10-07: Migrate Teradata to modular architecture
- 2025-10-07: Remove FindMssqlCmdUsedByYacc
- 2025-10-07: Migrate MySQL to modular architecture
- 2025-10-07: Migrate PostgreSQL to modular architecture
- 2025-10-07: Migrate MSSQL to modular vendor-specific architecture
- 2025-10-07: Support vendor-specific token strings in modular architecture
- 2025-10-06: Migrate MSSQL command initialization to TSqlCmdsMssql
- 2025-10-06: Refactor TSqlCmds to vendor-specific lazy-loading architecture
- 2025-10-05: Refactor: Move TSqlCmds to sqlcmds package
- 2025-10-05: Add high-impact factory methods based on profiler analysis
- 2025-10-05: Optimize Oracle package function lookup with thread-safe lazy init
- 2025-10-05: Expand factory methods for common node types
- 2025-10-04: Avoid skipping table.* when only one source exists
- 2025-10-04: Fix Teradata lexer to treat $_ identifiers correctly
- 2025-10-04: Merge pull request #550 from sqlparser/dev
- 2025-10-04: Fixed MySQL Metadata Bug.
3.1.1.3 (2025-10-02)¶
- 2025-10-02: Add getLastLineNoOfLastStatementBeenValidated() for huge file splitting
- 2025-10-02: Optimize token code comparisons in domssqlgetrawsqlstatements
3.1.1.2 (2025-09-27)¶
- 2025-09-27: Optimize isopchar and isselfchar methods in TCustomLexer
- 2025-09-27: Remove sourceBuffer of lexer
- 2025-09-27: Add test units
- 2025-09-27: Fix CTE column mapping when subquery uses SELECT *
- 2025-09-27: Fix Teradata table resolution when original name used despite alias
- 2025-09-27: Document Teradata implicit derived tables processing
3.1.1.1 (2025-09-21)¶
- 2025-09-20: Optimize showERG graph demo
- 2025-09-20: Update DataFlowAnalyzer demo
- 2025-09-19: Build pom for dlineage
- 2025-09-19: Set genDataflowGraph showLinkOnly default value to true
3.1.1.0 (2025-09-14)¶
- 2025-09-14: Feat: Add stable sqlHash for lineage statement identity
- 2025-09-14: Feat: Add stable queryId to SQL statements
- 2025-09-14: Feat: Introduce new source token management system
- 2025-09-14: feat(lexer): Implement lazy loading for token text
- 2025-09-13: tmp for lazyloading token
- 2025-09-13: Refactor: Implement lazy loading lexer architecture
- 2025-09-13: Docs: Document lexer architecture and lazy loading design
- 2025-09-13: Optimize memory usage with lazy ArrayList initialization
3.1.0.9 (2025-09-13)¶
- 2025-09-13: Fix column linking for inserted/deleted in triggers
- 2025-09-13: claude helpfile
- 2025-09-13: Add parser pool implementation without performance gains
- 2025-09-13: Add thread-safe parser pool for 10x performance gain
3.1.0.8 (2025-09-13)¶
- 2025-09-13: Refactor and harden parser build scripts
- 2025-09-13: Refactor: Move SQL grammar files to core module
3.1.0.7 (2025-09-11)¶
- 2025-09-11: Test: Verify pseudo-table resolution in triggers
- 2025-09-10: Refactor: Support chained transformations for columns
- 2025-09-08: Docs: Explain issues with varied relationship types
- 2025-09-07: Update lineage design doc
- 2025-09-07: Fix(Snowflake): Correct name of wildcard with EXCLUDE clause
- 2025-09-07: Fix duplicate output for field selection expressions
- 2025-09-07: Fix SQL generation for array access and slices
- 2025-09-07: Add type discrimination to TIndices for array vs qualified name syntax
- 2025-09-07: Fix column resolution for Oracle dblink tables
- 2025-09-06: Restructure dlineage demo
- 2025-09-06: Merge pull request #537 from sqlparser/dev
- 2025-09-06: Doc: Define modeling practices for JOIN conditions
- 2025-09-03: Clarify graphPartition sharding note in v2 doc
- 2025-09-03: Rename WEAK_COPY to MODIFIED_COPY and refine categories
- 2025-08-31: Docs: Extend v2 design with effectType rules and table/column combos
3.1.0.5 (2025-08-30)¶
- 2025-08-30: Add GROUP BY ALL modifier support to TGroupBy class
- 2025-08-30: Fix: Restrict INSERTED/DELETED column logic to SQL Server
- 2025-08-30: Docs: Warn of SQL formatter side effects on parser state
- 2025-08-30: Refactor toString method for better readability
- 2025-08-30: Fix token iteration in visitNodeByToken
- 2025-08-28: Docs: Unify and enhance data lineage specification
- 2025-08-28: Refactor: Restructure demos into Maven multi-module project
- 2025-08-28: Refactor: Move database connection logic to provider
3.1.0.2 (2025-08-15)¶
- 2025-08-15: [Dlineage] Fix a bug the data lineage of parameters in function call is not mapping correctly.
3.1.0.1 (2025-08-01)¶
- 2025-08-01: [GaussDB] Fixed a bug where the COUNT aggregate function was not properly recognized as a built-in function in the parser.
- 2025-08-01: [GaussDB] Fixed a bug where the LIKE operator incorrectly had lower precedence than the AND operator in pattern matching conditions. Updated operator precedence to ensure LIKE has higher precedence.
3.1.0.0 (2025-07-27)¶
- 2025-07-27: [Postgres] Fix a bug not materialized is not supported in WITH clause.
- 2025-07-27: [Oracle] Support default collation clause in create view/create function/create procedure/create trigger.
- 2025-07-27: [SQL Server] Fix a bug ALTER TABLE REBUILD WITH(DATA_COMPRESSION = PAGE) is not parsed correctly.
3.0.9.9 (2025-07-26)¶
- 2025-07-26: [Redshift] Fixed a performance issue with large INSERT statements; efficiently handles thousands of tuples (e.g. $1, $2, ...).
3.0.9.8 (2025-07-20)¶
- 2025-07-20: [SparkSQL] Bugfix, fix a bug position keyword can't be used as column name.
3.0.9.7 (2025-07-19)¶
- 2025-07-19: [scriptWriter] Fixed a bug where field selection syntax with parentheses (e.g. "(d).grantee") was not being generated correctly.
- 2025-07-19: [scriptWriter] Fixed a bug where column lists in DISTINCT ON clauses were not being properly generated.
3.0.9.6 (2025-07-10)¶
- 2025-07-10: [data lineage] Fixed bug in DataflowAnalyzer using SQL environment settings.
3.0.9.5 (2025-07-06)¶
- 2025-07-06: [Vertica] Support USING PARAMETERS clause in LISTAGG function.
- 2025-07-06: [Vertica] Support NULLSEQUAL operator.
- 2025-07-06: [Snowflake] Fixed bug with procedure bodies using only two consecutive tokens before semicolon.
- 2025-07-06: [SQL Server] Fix INSERTED pseudo table in CREATE TRIGGER column resolution.
- 2025-07-06: [SQL Server] Fix column in IF UPDATE() OR UPDATE() of trigger not picked up.
3.0.9.4 (2025-06-15)¶
- 2025-06-15: [PostgreSQL] Support create recursive view.
- 2025-06-15: [SQL Server] Fix can't parse partitions clause in TRUNCATE TABLE.
- 2025-06-15: [BigQuery] Add support for star column expressions in array access.
- 2025-06-15: [BigQuery] Add support for various DROP statements.
- 2025-06-15: [BigQuery] Fix length specification for BYTES datatype.
- 2025-06-15: [BigQuery] Fix IF NOT EXISTS clause in CREATE MATERIALIZED VIEW.
- 2025-06-15: [Athena] Fix NPE in ALTER TABLE RENAME PARTITION.
- 2025-06-15: [General] Fix thread-safety in TNodeFactory.
3.0.9.3 (2025-06-08)¶
- 2025-06-08: [scriptWriter] Fix bug with column.property rewrite in SQL script generation.
3.0.9.3 (2025-06-08)¶
- 2025-06-08: [PostgreSQL] Fix bug with AS datatype clause in CREATE SEQUENCE.
- 2025-06-08: [PostgerSQL] Support ALTER INDEX.
- 2025-06-08: [Teradata] Preserve both NAMED clause and AS alias in SELECT list.
- 2025-06-08: [Teradata] Support EXECUTE ... USING ... in procedures.
- 2025-06-08: [Teradata] Add FOREIGN TABLE syntax in FROM clause.
- 2025-06-08: [Teradata] Add IGNORE NULLS clause before OVER in agg functions.
- 2025-06-08: [Teradata] Fix parsing SELECT substring(..., position(...) + 5 FOR 5)
- 2025-06-08: [PostgerSQL] Support CREATE/ALTER ROLE.
- 2025-06-08: [Snowflake] Fix COMMENT keyword as column alias in SELECT.
3.0.9.3 (2025-06-07)¶
- 2025-06-07: [SparkSQL] Support LEFT/RIGHT JOIN without explicit ON.
- 2025-06-07: [SparkSQL] Support grouping sets after group by items without comma.
- 2025-06-07: [SparkSQL] Fix AS keyword wrongly required in CTAS.
- 2025-06-07: [SparkSQL] Fix parsing FILTER clauses after aggregates.
3.0.9.2 (2025-06-02)¶
- 2025-06-02: [scriptWriter] Fix bug: array types like text[] rewritten as text.
- 2025-06-02: [scriptWriter] Fix bug: IS TRUE / IS FALSE not rewritten correctly.
- 2025-06-02: [scriptWriter] Fix bug: RECURSIVE keyword missing in CTE rewrites.
- 2025-06-02: [scriptWriter] Fix bug: ORDER BY in function call arguments.
- 2025-06-02: [scriptWriter] Fix bug: parens around CTE subqueries.
3.0.9.1 (2025-05-29)¶
- 2025-05-29: [Teradata] Fix can't process .EXPORT FILE BTEQ command.
3.0.9.0 (2025-05-27)¶
- 2025-05-27: [Oracle] Support sequence option in CREATE TABLE with IDENTITY.
3.0.8.8 (2025-05-18)¶
- 2025-05-18: [API] Enhance EDbVendor: getAllVendorAliases(), getDescription(), getStatus()
- 2025-05-18: [PostgreSQL] Support JSON operators (#-, @?, @@)
- 2025-05-18: [Vertica] Fix CREATE OR REPLACE procedure parsing.
- 2025-05-18: [Netezza] Fix/Support interval datatypes (all variations)
3.0.8.8 (2025-05-18)¶
- 2025-05-18: [General] Support sqlimpact.
3.0.8.7 (2025-05-18)¶
- 2025-05-18: [GaussDB] Support LANGUAGE clause in do statement.
3.0.8.6 (2025-05-17)¶
- 2025-05-17: [General] Parser handles missing semicolons robustly (adds virtual semicolon when missing).
- 2025-05-17: [Teradata] Fix NPE for ADD_MONTHS() with subquery param.
- 2025-05-17: [API] Add getOperatorTokens() to TExpression for multi-token ops (e.g. SIMILAR TO, IS DISTINCT FROM).
- 2025-05-17: [scriptWriter] Fix group comparisons in SELECT list SQL generation.
- 2025-05-17: [GaussDB] Support distribute BY in CREATE TABLE.
- 2025-05-17: [GaussDB] Support TRY_CAST function.
- 2025-05-17: [GaussDB] Fix LOCALTIMESTAMP(n) precision param parsed as column.
- 2025-05-17: [SparkSQL] Fix can't retrieve distribute by / sort by clause.
- 2025-05-17: [Snowflake] Fix parsing of LEFT JOIN in single-quote/dollar-proc.
- 2025-05-17: [GaussDB] Fix cast(1, int) not supported.
- 2025-05-17: [scriptWriter] toScript() appends semicolon if original ended with semicolon.
3.0.8.5 (2025-05-12)¶
- 2025-05-12: [SQL Server] Improve distinguishing -- comment vs. minus.
- 2025-05-12: [SQL Server] Fix TRUNCATE TABLE with table aliases.
3.0.8.4 (2025-05-11)¶
- 2025-05-11: [Oracle] Detect package constant/variable used in INSERT for lineage.
3.0.8.3 (2025-05-11)¶
- 2025-05-11: [Snowflake] Support table index constraint.
- 2025-05-11: [scriptWriter] In PostgreSQL, special SQL functions handling parens.
3.0.8.2 (2025-05-11)¶
- 2025-05-11: [General] INSERT processed during the SQL Resolver.
3.0.8.1 (2025-05-08)¶
- 2025-05-08: [General] Fix critical OOM in TStarColumnPushDownResolver (nested UNION ALL).
3.0.8.1 (2025-05-07)¶
- 2025-05-07: [SQL Server] Fix can't parse CREATE OR ALTER FUNCTION.
3.0.8.0 (2025-05-06)¶
- 2025-05-06: [General] Merge some source code.
3.0.7.9 (2025-05-04)¶
- 2025-05-04: [PostgreSQL] Fix parsing of UNION DISTINCT clause.
3.0.7.8 (2025-05-04)¶
- 2025-05-04: [Databricks] Fix normalization of backtick-quoted identifiers.
- 2025-05-04: [SparkSQL] Fix parsing column alias lists in parentheses with EXPLODE.
3.0.7.7 (2025-05-03)¶
- 2025-05-03: [Hive] Fix LATERAL VIEW EXPLODE alias analysis.
- 2025-05-03: [PostgreSQL/toScript] Fix type cast (::) handling in script generation.
3.0.7.6 (2025-05-01)¶
- 2025-05-01: [Performance] Cached/specialized factory methods in TNodeFactory.createNode()
3.0.7.5 (2025-04-29)¶
- 2025-04-29: [Teradata] Support array element access with quoted identifiers.
- 2025-04-29: [Teradata] Fix same-name tables in different DBs treated as the same.
3.0.7.4 (2025-04-28)¶
- 2025-04-28: [SparkSQL] Fix == equality operator handling.
- 2025-04-28: [SparkSQL] Fix & bitwise AND operator handling.
3.0.7.3 (2025-04-27)¶
- 2025-04-27: [General] Performance improved.
3.0.7.2 (2025-04-20)¶
- 2025-04-20: [PostgreSQL] Support array element access on array-returning functions.
- 2025-04-20: [BigQuery] Support CREATE OR REPLACE TEMPORARY TABLE.
- 2025-04-20: [SQL Server] Fix comments with leading whitespace.
- 2025-04-20: [API] Add TRedshiftTableAttributes.
- 2025-04-20: [Redshift] Add DISTSTYLE for materialized views.
- 2025-04-20: [Teradata] Fix DAYNUMBER_OF_MONTH not recognized.
- 2025-04-20: [Teradata] Fix || precedence.
- 2025-04-20: [API] Add implicit_datatype_cast_as_t for '... AS ...' expressions.
- 2025-04-20: [API] PARSE/TRY_PARSE use getArgs() for SQL Server.
3.0.7.2 (2025-04-19)¶
- 2025-04-19: [Snowflake] Properly detect INSERT OVERWRITE clause.
- 2025-04-19: [Vertica] Fix '||' concatenate op.
- 2025-04-19: [MySQL] Support JSON_TABLE.
- 2025-04-19: [MySQL] Support column-level check constraint.
- 2025-04-19: [MySQL] Support ALTER TABLE ADD CONSTRAINT CHECK.
- 2025-04-19: [DB2] Fix TYPE keyword as valid column name in SELECT.
3.0.7.1 (2025-04-17)¶
- 2025-04-17: [General] Fix various test case failures.
3.0.7.0 (2025-04-15)¶
- 2025-04-15: [Snowflake] Fix LEFT/RIGHT join keywords treated as column aliases.
3.0.6.9 (2025-04-13)¶
- 2025-04-13: [gettablecolumn] Match table.column.property to table.* in FROM.
3.0.6.8 (2025-04-12)¶
- 2025-04-12: [BigQuery] Link array element accesses with [offset] to table columns.
- 2025-04-12: [API] Add EExpressionType.teradata_at_t AT time zone support.
- 2025-04-12: [Teradata] Extract time_zone_specification from AT clause.
- 2025-04-12: [Teradata] Add support for many named builtins.
- 2025-04-12: [Snowflake] Support ASOF JOIN.
- 2025-04-12: [SparkSQL] Support grouping set in group by.
3.0.6.7 (2025-04-12)¶
- 2025-04-12: [Hive,SparkSQL] Clarify alias rules for SELECT list.
- 2025-04-12: [Presto] Fix select trailing comma.
3.0.6.6 (2025-04-06)¶
- 2025-04-06: [Teradata] Fix "WITH DATA" clause treats "data" as column name.
- 2025-04-06: [resolver] New column-to-table algorithm takes precedence over old.
- 2025-04-06: [Sybase] Fix alias in SELECT: 'id_col=identity(5)'.
3.0.6.5 (2025-04-05)¶
- 2025-04-05: [Oracle] Fix can't parse EXECUTE PROC_A3; correctly.
- 2025-04-05: [Oracle] Fetch proc name from sqlplus EXEC.
3.0.6.4 (2025-04-05)¶
- 2025-04-05: [Snowflake] REAL keyword can be table alias.
- 2025-04-05: [Oracle] Support parens expr with property access.
- 2025-04-05: [Snowflake] Fix SWAP WITH table direction.
- 2025-04-05: [MySQL] Support EXCEPT clause.
3.0.6.3 (2025-04-04)¶
- 2025-04-04: [Databricks] Fix parens around split() in array access.
- 2025-04-04: [BigQuery] Add TArrayConcatAggFunction.
- 2025-04-04: [GaussDB] Fix 'day' param in TIMESTAMPDIFF.
- 2025-04-04: [General] Remove fake orphan column warning.
- 2025-04-04: [GaussDB] DOUBLE alias for DOUBLE PRECISION.
- 2025-04-04: [GaussDB] Fix can't parse LIMIT 1,1.
3.0.6.2 (2025-04-01)¶
- 2025-04-01: [SparkSQL] Support array access expression.
- 2025-04-01: [SparkSQL] Parsing fix: split negative numbers tokens.
- 2025-04-01: [BigQuery] Show dot after numeric in TObjectName.toString().
3.0.6.0 (2025-03-24)¶
- 2025-03-24: [Teradata] Fix duplicate derived tables in WHERE clause.
3.0.5.9 (2025-03-23)¶
- 2025-03-23: [Databricks/Hive] Support Hash (#) comments.
3.0.5.8 (2025-03-11)¶
- 2025-03-11: [column resolver] Fix bug: column inside UNNEST mislinked.
3.0.5.7 (2025-03-09)¶
- 2025-03-09: [API] ETableEffectType.tetTeradataReference renamed to tetImplicitLateralDerivedTable.
- 2025-03-09: [column resolver] Subquery columns link to subquery FROM by preference.
3.0.5.6 (2025-03-04)¶
- 2025-03-04: [demo] Remove dbConnect from gsp_demo_java.
3.0.5.5 (2025-03-02)¶
- 2025-03-02: [SQL formatter] Fix can't process Teradata Implicit Lateral Derived Table.
3.0.5.4 (2025-03-02)¶
- 2025-03-02: [Vertica] Fix localtime() number param as column.
- 2025-03-02: [Vertica] Support RENAME COLUMN in ALTER TABLE.
3.0.5.3 (2025-03-01)¶
- 2025-03-01: [column resolver] Fix SET in UPDATE to wrong table.
- 2025-03-01: [GaussDB] Support OVERWRITE in INSERT (DWS).
- 2025-03-01: [General] Remove fake orphan column warning.
- 2025-03-01: [Oracle] Resolve package/function/proc name in procedure.
3.0.5.2 (2025-03-01)¶
- 2025-03-01: [DB2] Support ARRAY[1,2,3] (DB2 10.5+).
- 2025-03-01: [DB2] Fix null exception with MERGE/USING/VALUES.
3.0.5.1 (2025-02-27)¶
- 2025-02-27: [getTableColumn] Refactor name resolution logic.
3.0.4.7 (2025-02-08)¶
- 2025-02-08: [General] Fix bugs in resolver, refactor needed.
3.0.4.5 (2025-02-06)¶
- 2025-02-06: [dlineage] Incorrect mapping for SQL Server alias.
3.0.4.5 (2025-02-06)¶
- 2025-02-06: [dlineage] Missing column link for BigQuery.
-
2025-02-06: [semantic] How GSP links unqualified columns to tables.
-
Consider this query:
SELECT append_business_key, f.worklist_field_name AS field_name, f.field_data_type FROM FIN_ICOLLECTION.ico_worklist_append_t a INNER JOIN FIN_ICOLLECTION.ico_worklist_field_info_t f ON a.append_business_key = f.worklist_field_id
- When GSP analyzes this query without extra metadata, it deduces which table an unqualified column belongs to.
- The JOIN condition (a.append_business_key) signals that append_business_key belongs to FIN_ICOLLECTION.ico_worklist_append_t.
- GSP 3.0.4.4 or later links the unqualified append_business_key in SELECT to FIN_ICOLLECTION.ico_worklist_append_t.
-
But if both tables have append_business_key, the reference is ambiguous and needs explicit qualification.
-
Changed behavior:
- Before 3.0.4.4: append_business_key was orphan column.
- Since 3.0.4.4: linked to FIN_ICOLLECTION.ico_worklist_append_t if found in JOIN.
3.0.4.3 (2025-02-02)¶
- 2025-02-02: [Vertica] Support PARTITION BY clause in CREATE TABLE.
- 2025-02-02: [Vertica] Support CREATE TABLE LIKE.
- 2025-02-02: [Vertica] Support ARRAY datatype.
- 2025-02-02: [Vertica] Window support for partitioned result in LIMIT.
- 2025-02-02: [Vertica] Fix on MERGE condition could omit parenthesis.
- 2025-02-02: [Vertica] Support ENABLED/DISABLED in PK col constraint.
- 2025-02-02: [Vertica] TEMP table fix for TableKinds.
3.0.4.2 (2025-01-25)¶
- 2025-01-25: [Vertica] Support DISABLED/ENABLED keyword in constraints.
- 2025-01-25: [Teradata] Fix TRUNC function in IN clause.
- 2025-01-25: [Vertica] Support CALL.
- 2025-01-25: [Vertica] Fix can't parse UNION DISTINCT.
- 2025-01-25: [Vertica] Support ISNULL function.
- 2025-01-25: [Vertica] Support MINUS operator.
- 2025-01-25: [Teradata] Fix CHECKSUM=ALL in CREATE TABLE.
3.0.4.1 (2025-01-20)¶
- 2025-01-20: [Evaluator] Remove outer quotes/handle escaped quotes in string.
3.0.4.0 (2025-01-19)¶
- 2025-01-19: [Evaluator] Support plsql block with loop.
- 2025-01-19: [BigQuery] Fix unable to expand star in SELECT *.
3.0.3.9 (2025-01-12)¶
- 2025-01-12: [Snowflake] Support WITH TAG in view columns.
- 2025-01-12: [SQL Server] Fix can't parse CTAS with CTE used in select.
- 2025-01-12: [Oracle] Recognize CALL after procedure.
3.0.3.8 (2025-01-11)¶
- 2025-01-11: [Snowflake] Fix double dollar delimiter for non-addition binary ops.
- 2025-01-11: [Teradata] Support partition by column in CREATE TABLE.
- 2025-01-11: [Teradata] Support partition by all but.
- 2025-01-11: [Teradata] Parse multiple params in SIGNAL SET.
3.0.3.7 (2025-01-05)¶
- 2025-01-05: [Teradata] Support sequenced/nonsequenced VALIDTIME.
- 2025-01-05: [Teradata] Fix INTERVAL ... HOUR TO MINUTE in CAST.
- 2025-01-05: [Teradata] Insert in WHEN NOT MATCHED should be assignment_t type.
- 2025-01-05: [Teradata] Recognize TTeradataBTEQCmd.bteqCmdType (BTEQ CMD).
3.0.3.7 (2025-01-04)¶
- 2025-01-04: [Snowflake] Support BEGIN; in single-quoted stored procs.
- 2025-01-04: [Snowflake] Support BEGIN; in stored procs.
- 2025-01-04: [dlineage] Add showCandidateTable option for candidate table column links.