Firebird Documentation Index → Firebird 3.0.6 Release Notes → Data Manipulation Language (DML) → DML Improvements |
![]() |
![]() |
![]() ![]() ![]() ![]() |
A collection of useful DML improvements is released with Firebird 3.
It is now possible to use a character, or character pair, other than the doubled (escaped) apostrophe, to embed a quoted string inside another string. The keyword q or Q preceding a quoted string informs the parser that certain left-right pairs or pairs of identical characters within the string are the delimiters of the embedded string literal.
Syntax
<alternate string literal> ::= { q | Q } <quote> <alternate start char> [ { <char> }... ] <alternate end char> <quote>
When <alternate start char> is '(', '{', '[' or '<', <alternate end char> is paired up with its respective “partner”, viz. ')', '}', ']' and '>'. In other cases, <alternate end char> is the same as <alternate start char>.
Inside the string, i.e., <char> items, single (not escaped) quotes could be used. Each quote will be part of the result string.
Examples
select q'{abc{def}ghi}' from rdb$database; -- result: abc{def}ghi select q'!That's a string!' from rdb$database; -- result: That's a string
New SQL:2008 compliant OFFSET and FETCH clauses provide a standard equivalent for FIRST and SKIP, and an alternative for ROWS...TO, when fetching sets from ordered output.
The OFFSET clause specifies the number of rows to skip
The FETCH clause specifies the number of rows to fetch.
As with SKIP and FIRST, OFFSET and FETCH clauses can be applied independently, in both top-level and nested query expressions. They are available in PSQL and DSQL.
Syntax Pattern
SELECT ... [ ORDER BY <expr_list> ] [ OFFSET <simple_value_expr> { ROW | ROWS } ] [ FETCH { FIRST | NEXT } [ <simple_value_expr> ] { ROW | ROWS } ONLY ]
<simple_value_expr> is a (numeric) literal, a DSQL parameter (?) or a PSQL named parameter (:namedparameter) that resolves to an integer data type.
Examples
-- 1: SELECT * FROM T1 ORDER BY COL1 OFFSET 10 ROWS; -- 2: SELECT * FROM T1 ORDER BY COL1 FETCH FIRST 10 ROWS ONLY; -- 3: SELECT * FROM ( SELECT * FROM T1 ORDER BY COL1 DESC OFFSET 1 ROW FETCH NEXT 10 ROWS ONLY ) a ORDER BY a.COL1 FETCH FIRST ROW ONLY;
The FIRST/SKIP and ROWS clauses are non-standard alternatives.
The OFFSET and/or FETCH clauses cannot be mixed with clauses from the FIRST/SKIP or ROWS alternatives in the same query expression.
Expressions and column references are not allowed within either the OFFSET or the FETCH clause.
Unlike the ROWS clause, OFFSET and FETCH are available only in SELECT statements.
The “percentage FETCH” defined in the SQL standard is not supported.
“FETCH ... WITH TIES” defined in the SQL standard is not supported.
While mixing of implicit and explict join syntaxes is not recommended at all, the parser would allows them, nevertheless. Certain “mixes” actually cause the optimizer to produce unexpected results, including “No record for fetch” errors. The same edgy styles are prohibited by other SQL engines and now they are prohibited in Firebird.
To visit some discussion on the subject, see the Tracker ticket CORE-2812.
The following style of subquery, with the parameter in the left side of a WHERE...IN (SELECT...) condition, would fail with the error “The data type of the parameter is unknown”.
This style is now accepted. For example:
SELECT <columns> FROM table_1 t1 WHERE <conditions on table_1> AND (? IN (SELECT some_col FROM table_2 t2 WHERE t1.id = t2.ref_id))
Better SQL coding practice would be to use EXISTS in these cases; however, developers were stumbling over this problem when using generated SQL from Hibernate, which used the undesirable style.
Two enhancements were added to the RETURNING clause:
When using the RETURNING clause to return a value to the client, the value can now be passed under an alias.
Example Without and With Aliases
UPDATE T1 SET F2 = F2 * 10 RETURNING OLD.F2, NEW.F2; -- without aliases UPDATE T1 SET F2 = F2 * 10 RETURNING OLD.F2 OLD_F2, NEW.F2 AS NEW_F2; -- with aliases
The keyword AS is optional.
Until this release, Firebird suffered from an infamous bug whereby a data modification operation could loop infinitely and, depending on the operation, delete all the rows in a table, continue updating the same rows ad infinitum or insert rows until the host machine ran out of resources. All DML statements were affected (INSERT, UPDATE, DELETE, MERGE). It occurred because the engine used an implicit cursor for the operations.
To ensure stability, rows to be inserted, updated or deleted had to be marked in some way in order to avoid multiple visits. Another workaround was to force the query to have a SORT in its plan, in order to materialize the cursor.
From Firebird 3, engine uses the Undo log to check whether a row was already inserted or modified by the current cursor.
This stabilisation does NOT work with SUSPEND loops in PSQL.
Global temporary tables (GTTs) are now writable even in read-only transactions. The effect is as follows.-
Writable in both ON COMMIT PRESERVE ROWS and ON COMMIT DELETE ROWS
Writable in ON COMMIT DELETE ROWS only
Also
Rollback for GTT ON COMMIT DELETE ROWS is faster
Rows do not need to be backed out on rollback
Garbage collection in GTT is not delayed by active transactions of other connections
The same refinements were also backported to Firebird 2.5.1.
Strings in DML queries are now transformed or validated to avoid passing malformed strings to the engine internals, for example, to the MON$STATEMENTS.MON$SQL_TEXT column.
The solution adopted depends on the character set of the attachment.-
NONE—non-ASCII characters are transformed to question marks
Others—the string is checked for malformed characters
The COUNT() aggregator now returns its result as BIGINT instead of INTEGER.
Optimizations made for this release included:
Performance for (table.field = :param or :param = -1) in the WHERE clause was enhanced.
Previously, when an ORDER plan was in a SELECT structure, the optimizer would choose the first index candidate that matched the ORDER BY or GROUP BY clause. This “first come” approach is not the best when multiple index choices are available. The Firebird 3 engine surveys all of the available choices and picks the most suitable index.
See Tracker ticket CORE-4285.
Previously, the execution path for UNION queries was hierarchical, often causing redundant reads. This optimization replaces the hierarchical execution path with a plainer one that improves performance.
See Tracker ticket CORE-4165.
The optimizer now allows an index walk (ORDER plan) when a suitable compound index (A, B) is available for a query condition of the style WHERE A = ? ORDER BY B.
See Tracker ticket CORE-1846.
BTR_selectivity() would walk the whole leaf level of given index b-tree to calculate index selectivity. Throughout the process, the only rescheduling would happen at a disk I/O operation. The effect was to impose long waits for AST requests from concurrent attachments, such as page lock requests, monitoring, cancellation, etc. An improvement in Firebird 3 seems to solve that problem.
See Tracker ticket CORE-4215.
Selection of SQL_INT64, SQL_DATE and SQL_TIME in dialect 1 was enabled.
See Tracker CORE-3972
Two enhancements were included in the Embedded SQL subset in this release:
Context variables added in v.3.0.4:
Firebird v.3.0.4:
Context variables WIRE_COMPRESSED
and WIRE_ENCRYPTED
were added to the SYSTEM namespace to report compression and encryption
status, respectively, of the current connection:
Compression status of the current connection.
If the connection is compressed, returns TRUE
;
if it is not compressed, returns FALSE
. Returns NULL
if the connection is embedded.
Encryption status of the current connection.
If the connection is encrypted, returns TRUE
;
if it is not encrypted, returns FALSE
. Returns NULL
if the connection is embedded.
Firebird v.3.0.4:
Context variables LOCALTIME
and LOCALTIMESTAMP
were added as synonyms for CURRENT_TIME
and CURRENT_TIMESTAMP
,
respectively, in anticipation of CURRENT_TIME
and CURRENT_TIMESTAMP
being redefined in Firebird 4 to represent the time and timestamp in UTC time, to comply
with the SQL standards.
Returns a timestamp carrying no date part. The time part registers the time of day, to thousandths of a second, when execution of the current statement began. If the statement results in multiple operations, the timestamp written to all records created or updated will be the same.
Returns a timestamp registering the date and the time of day, to thousandths of a second, when execution of the current statement began. If the statement results in multiple operations, all records created or updated will have the same timestamp.
![]() ![]() ![]() ![]() |
Firebird Documentation Index → Firebird 3.0.6 Release Notes → Data Manipulation Language (DML) → DML Improvements |