Skip to content

7.9.2

Choose a tag to compare

@madorin madorin released this 31 Oct 23:56
· 191 commits to master since this release

Added

  • EFIBError.ErrorArgument(Code, Index): a string argument of the status
    vector, for example the constraint name of isc_unique_key_violation.
  • ListErrorMessages.ErrorMessage and GetQueryForUse (pFIBCacheQueries)
    have an overload with the database, for a transaction over several
    databases. FindDatabaseForObject (pFIBErrorHandler) is public.

Changed

  • The Delphi XE, XE6 and XE8 packages are named like those of XE2 to XE7:
    FIBPlus_XE, FIBPlus_XE6 and FIBPlus_XE8 (before: FIBPlus2011,
    FIBPlus_D20 and FIBPlus_D22), with the editors FIBPlusEditors_XE,
    FIBPlusEditors_XE6 and FIBPlusEditors_XE8, and have project groups. The
    duplicate FIBPlus_D21 and FIBPlusEditors_D21 of the XE7 packages are
    removed. Packages that require an old name must require the new one.

Fixed

Connection and transactions

  • utf8_filename in DBParams was sent, but the database name, user name,
    password and role stayed in the system code page, so non-ASCII values were
    garbled or rejected. With utf8_filename they are now sent in UTF-8, and
    TFIBDatabase.DBName keeps characters outside the system code page. The
    Firebird client still converts the file name to the system code page before
    it parses it.
  • A DBParams value over 255 bytes (several config= lines, or a long non-ASCII
    password with utf8_filename) had its one-byte length wrapped and made a
    corrupt DPB. With a Firebird 3+ client the DPB is now sent as
    isc_dpb_version2 (4-byte lengths) when a value needs it; otherwise, and for
    long lock table names in TRParams and values in the TpFIBServices
    Params, a clear error names the parameter.
  • Numeric DBParams (num_buffers, dummy_packet_interval,
    connect_timeout, old_file_size, shutdown_delay, force_write and the
    other flags) were written in one byte, so a value over 255 was cut
    (num_buffers=2048 sent 0). They are now written in 4 bytes.
  • lock_read/lock_write table names in TRParams were sent in the system
    code page; the server takes them in the charset of the connection, so a
    non-ASCII table name was not found or was a malformed string. They are now
    sent in the metadata code page of the connection, and in UTF-8 to Firebird 2.1
    to 2.5, which look them up in the stored names without converting them.
  • TFIBTransaction: a database of a multi-database transaction without its own parameters got
    the lock_read/lock_write table names in the code page of MainDatabase, and the TPB was
    not rebuilt when the metadata code page changed.
  • TFIBTransaction: lock_timeout was sent in 2 bytes, so a value from 65536
    up was cut (65546 started the transaction with a timeout of 10 seconds). It is
    sent in 4 bytes; Firebird 2.5 and later check the range.
  • TFIBDatabase.DBFileName and DBSiteName kept the bytes the server sent, so a
    non-ASCII file name from a Linux server (UTF-8) was garbled (é as é). They
    are now decoded like the other database info texts and kept in the system code page.
  • LibraryName of TFIBDatabase went through the system code page: a client
    library in a folder with a name outside it could not be loaded.
  • DBParams: a last shutdown value of one character (shutdown=2) was ignored, and an unknown
    word or a word with spaces (shutdown=force, full) set every bit of the value. The words are
    now trimmed; an unknown word or a number over 255 raises the new feParamValueInvalid.
  • macOS: FreeIBLibrary did not unload the client library, also at program exit.
  • CreateDatabase doubles a quote inside DBName, so a path such as
    D:\O'Brien\x.fdb no longer breaks the CREATE DATABASE statement.
  • QueryValue, QueryValues and Execute without ParamValues set the
    first parameter to NULL instead of 0. A cached QueryValue query no longer
    keeps the parameter values of its last call.
  • QueryValue, QueryValues and Gen_Id run the query in the database they
    are called on; before, a transaction of another database ran it there, and a
    transaction over several databases with no default database gave a nil
    query.
  • An error in QueryValue or QueryValues no longer rolls back the
    transaction passed in aTransaction with the work done in it; only the
    internal transaction is ended, and a failed commit no longer skips the
    release of the query. Gen_Id prefers the transaction passed to it.
  • DBParams: sql_dialect= without a value no longer raises an access
    violation, and a value other than 1, 2 or 3 raises feParamValueInvalid.
  • Open no longer rebuilds the DPB at every connect; it is cached until
    DBParams change, and rebuilt after a failed GenerateDPB.
  • Open no longer stops at the first error of an AddEvent(detOnConnect)
    handler such as an AutoRegister TSIBfibEventAlerter: it completes the
    connect and raises the first error at the end. At design time, a transaction
    loaded before its database no longer shows a second error after the
    connection error.
  • A handler of a database or transaction event could not unregister itself or
    free a registered component while the events were called (access violation). An
    exception in OnConnect skipped the connect notifications of the datasets; it
    is raised by Open after the connect is complete, like the other connect
    handlers.
  • A lost connection (TpFIBDatabase, laCloseConnect/laWaitRestore) did not
    release the client attachment, and a failed Commit or Rollback left the
    state tsDoCommit instead of tsActive.
  • ServerActiveTransactions listed at most 72 transactions, read the ids as 4
    bytes and leaked its list; the operation counts could read past the buffer.
  • The login prompt blocked the connects of other threads. A timer of a worker
    thread that synchronizes its event deadlocked with the main thread creating
    datasets or transactions, and the idle Timeout of a database used by other
    threads never fired; it now fires within a quarter of the Timeout after it
    elapses.
  • Busy was False while another call of the client library ran, and client
    library names that differ only in case made two library objects (Windows).
    RaiseCancelOperations no longer raises "Nothing to cancel" while another
    database of the same client library runs a call.

Queries and parameters

  • TFIBQuery fields and parameters: AsInteger of a BIGINT, a scaled number
    or a double out of the Integer range, and AsShort out of the SMALLINT
    range, returned a cut value (5000000000 gave 705032704); they raise an
    invalid data conversion error, as for INT128.
  • TFIBQuery parameters: Assign of a BLOB of more than 32767 bytes to a
    parameter that is not a BLOB sent a cut length (70000 bytes became 4464); it
    raises an error now. AsInt64 in SQL dialect 1 or 2 sent the value cut to 32
    bits; out of that range it is sent as a double. A LongWord variant over
    MaxInt was sent as a negative number when passed by reference and raised
    EVariantOverflowError when passed by value; both are sent as a BIGINT.
  • A string over 32767 bytes for a VARCHAR parameter was sent as a blob of the
    column charset subtype, so the server reported "Filter not found to convert
    type 4 to type 1" instead of a string truncation.
  • A text BLOB parameter set with AsString before Prepare read (BLOB)
    after ExecQuery; it now returns the string, as when it is set after
    Prepare.
  • A parameter set before Prepare could be converted to the server type twice,
    when another parameter was set before a new Prepare.
  • StopFetching in TFIBQuery.OnSQLFetch and BeforeFetchRecord made Next
    return nil but left Eof at False, so a while not Eof loop did not end.
    It is now a final stop: Eof is set as at the end of the data.
  • TFIBQuery fields and parameters of a date, time, number or boolean type on
    Delphi 2009 and later: AsString passed the formatted text through the
    system code page, so locale texts outside it (for example the AM/PM
    designators) became ?.
  • AsTimeZoneName of a TIME or TIMESTAMP WITH TIME ZONE value in a region
    unknown to the built-in time zone table was empty, and AsString ended with
    a blank. It is now the offset of the value (+02:00).
  • Macros: an old form macro (@Name) followed by a tab took the rest of the
    text up to the next space into its name, and one at the very end of the text
    was not replaced. A new form macro (@@Name@) without the closing @ went
    to the server as it was; it now raises "EOF in macro detected".
  • AsInteger, AsInt64 and AsShort on a BOOLEAN parameter sent an integer, and the server
    raised "Incompatible column/host variable data type"; a value other than zero is now sent as
    True, as AsBoolean reads it, before and after Prepare.
  • A parameter used twice, for a BLOB and for a VARCHAR or a column of another charset, sent
    the BLOB ID with the subtype of the other column ("Filter not found to convert type 4 to
    type 1").
  • Win64: BatchOutput to a delimited or a raw file raised an access violation, which it reports
    only as False, and left the file empty.
  • BatchInput left the stream with the parameters of the query after baStop or an error, and
    BatchOutput left it with the columns of the query; both are cleared at the end now.
  • TransactionEnding and TransactionEnded of TFIBQuery were published but never called.
    TransactionEnding now runs before the open cursor is closed at the end of the transaction,
    and TransactionEnded after the transaction ended, as in TpFIBDataSet.
  • TFIBDatabase.QueryValues of a statement without parameters that returned a row kept it in
    the query cache, while QueryValue freed it; only statements with parameters are cached now,
    and only with aCacheQuery.
  • A parameter used twice, for columns of different character sets or for a
    BLOB and a VARCHAR, was converted for the first column only, giving
    "Malformed string" errors or wrong characters on a NONE connection. Each
    occurrence now gets the description of its own server parameter, and the
    other occurrences of a BLOB parameter get its ID, subtype and character set.
  • TpFIBQuery.BlobToStrings and BlobAsString decoded the text in the system
    code page whatever the character set of the column, BlobAsString added a
    line break and BlobToStrings hid read errors. They now read the text as
    AsString does and raise read errors.
  • BatchOutputRawFile wrote the second and later BLOB columns of a row with
    the earlier BLOBs of that row in front of them.
  • CutAlias returned AS X as the alias of T AS X, so alias lookups failed
    for tables aliased with AS.
  • FormatIdentifier and EasyFormatIdentifier did not double a quote inside a
    quoted name; EquelStrings compared by a code difference of 32, so 'T0'
    matched 'TP'. It now folds only ASCII letters.
  • TableAliasForField of TFIBQuery and TpFIBDataSet returned a table
    alias that needs quotes in quotes ("MyAlias"); it now returns it unquoted,
    as the server stores it, also when read from the SQL text or a loaded
    stream. The generated SQL does not change; Field.Origin with
    forTableAliasAndFieldName changes the same way.
  • The primary key, table ID and dataset info queries of pFIBDataInfo ran in
    the default database of the transaction; they run in their own database, and
    DBPrimaryKeyFields has an optional Database parameter.
  • SQL text parsing: a -- comment ending with LF hid FROM, WHERE and ORDER BY, a -- comment containing /* started a block comment, and a statement
    starting with - or / hung.
  • A -- comment ended by a bare LF or CR before WHERE or ORDER BY no longer
    breaks the FROM clause (RecordCount, AddToWhereClause).
  • AddToWhereClause, the order and group clauses and the table list ignored
    ROWS, OFFSET/FETCH, WITH LOCK and RETURNING. SetGroupClause dropped
    HAVING and ORDER BY. WITH ... SELECT was not a select and MERGE was.
  • MainPlanClause and SetMainPlan lost or duplicated the closing bracket when
    PLAN was the last text of the statement.
  • SQLKind returned skDDL for every statement starting with S other than SET
    (SAVEPOINT, SUSPEND).
  • EXECUTE BLOCK parameters were not found after a name ending in AS (like
    GAS), and a closing quote at the very end of the text raised "EOF in string".
  • ExecProc did nothing when a line break followed EXECUTE or a comment
    preceded it, and a macro at the start of the text was not found.
  • Identifiers with # or % were not quoted in generated SQL.
  • The descending query of the limited cache broke DESCENDING, ASCENDING,
    NULLS and expressions with commas in ORDER BY.
  • FindField, FindParam and FieldByName with a quoted name that does not
    exist returned an invalid object instead of nil.
  • A raw TIME/TIMESTAMP WITH TIME ZONE parameter lost its time zone when the
    statement had macros or a null comparison rewritten to IS NULL.
  • Assigning a VARCHAR value to a BLOB parameter wrote the two length bytes
    and lost the last two characters.
  • A null parameter in a WHERE comparison prepared the statement again at every
    execute. = (:Param) with a null value gave a syntax error, and = -:Param
    was rewritten to IS NULL.
  • BatchToQuery inserted an empty row when GoToFirstRecordOnExecute is False
    and left the cursor open after a stop or an error; BatchInput refused a file
    whose charset differs only in letter case.
  • Setting ParamCheck at run time did not parse the parameters again.
  • Changing Database of a query with an open cursor left it marked open; a
    failed DDL statement of ExecuteImmediate was not reported to the SQL monitor
    and logger.
  • AsBcd of NUMERIC(9,6) and similar fields kept only four decimals and read
    stale data for a null NUMERIC(18,x); AsDateTime of a text value with a time
    failed; AsGuid of a non-text value returned a stale value.
  • Int64ToBCD of the lowest Int64 and the conversion of a BCD to a float in
    dialect 1 and 2 were inexact (0.3 read as 0.30000000000000004); variant
    comparison treated doubles within 1E-11 as equal and raised an overflow for a
    UInt64 against a negative value.
  • Array elements: a CHAR value with blanks beyond the column length was
    refused, and a UInt64 value lost precision. The query cache did not reuse a
    query for SQL with LF-only line breaks.

Datasets and fields

  • Win64: TFIBGuidField.AsGuid and AsString (GUIDAsString of StrUtil) raised an access
    violation: the destination address was kept in 32 bits.
  • TpFIBDataSet: a value out of range in a persistent float field of a
    NUMERIC stored as INTEGER or SMALLINT (for example 30000000 in a
    NUMERIC(9,2)) was stored cut (-12949672.96); it raises an error now. A
    generator value out of the INTEGER range for an INTEGER key field
    (AutoUpdateOptions) was cut; the field raises an error now.
  • TpFIBDataSetProvider: RefreshRecord of the client dataset wrote a NULL NUMERIC of the
    source as a number (0 or garbage).
  • PSGetCommandText of IProviderSupport returned an empty string on Delphi
    XE3 and later; it returns the select SQL or the pending provider command, as
    PSGetCommandTextW does on Delphi 2006 to XE2.
  • Locate on a TIMESTAMP or TIMESTAMP WITH TIME ZONE field did not find a
    value with milliseconds given as a Double (e.g. EncodeDate(...) + EncodeTime(...)), and could miss a TIMESTAMP WITH TIME ZONE value by a
    rounding difference. The values are now compared in milliseconds; only a text
    key ignores them.
  • Locate with several TIMESTAMP keys: a text key for one of them made the
    others ignore the milliseconds of the row, so a TDateTime key with
    milliseconds was not found. Only the field of the text key ignores them now.
  • AnsiCompareString as OnCompareFieldValues took every field that is not
    ftString or ftFixedChar (e.g. a UTF8 column) for equal, so DoSort gave
    a random order. A NULL in a string field was also taken for equal
    to every value. These fields and NULLs are now compared as by
    StdCompareValues.
  • CompareVariants (sorting, Locate): a varSingle variant was compared through the bytes of
    a Double, so 2 and a Single 2 were not equal.
  • CompareVariants on Delphi 2009 and later: a WideString compared with a varString
    variant, and a number compared with a numeric varString ('25'), read the bytes of the
    AnsiString as UTF-16 (wrong result or "not a valid floating point value").
  • CompareVariantsEQ (VariantRtn) returned False for two equal
    AnsiString (varString) variants on Delphi 2009 and later.
  • After DoSort, reopening the dataset without poPersistentSorting kept
    Sorted and SortedFields of the local sort, while the rows came in the
    server order. With psGetOrderInfo they are now read again from the ORDER BY
    of the query.
  • Changing psUseGuidField in PrepareOptions after the first open had no
    effect: the field stayed a TFIBStringField. The field definitions are now
    read again, as for psUseBooleanField.
  • TpFIBDataSet.CacheRefreshByArrMap read past the end of the shorter of the two field arrays.
  • TFIBDatabase.MemoSubtypes kept the sub types in a byte, so for example
    -1000 also matched the sub type 24.
  • Post called again from the dataset's own BeforePost recursed until the stack overflowed;
    it is now ignored, and a Post from AfterPost still posts.
  • SQL generation under AutoUpdateOptions.UpdateOnlyModifiedFields: an inserted row with all
    fields null was never written (No Action) although the dataset showed it as posted; it is
    now INSERT ... DEFAULT VALUES. The INSERT and UPDATE made for each post had no
    RETURNING of UseReturningFields; with rfAll an INSERT also returns the null columns
    the server filled. UseRowsClause put ROWS 1 on the INSERT and after RETURNING, which
    Firebird rejects; it now goes only on the UPDATE, before RETURNING. GenerateSQLText
    and GenerateSQLTextNoParams with skMerge made a broken statement; they now make
    UPDATE OR INSERT ... MATCHING on the key fields.
  • GenerateSQLText on a dataset without field objects failed with rfBlobFields and ignored
    ifsNoBlob and ifsOnlyBlob; it now takes the BLOB columns from the field definitions.
    skMerge with ifsOnlyBlob left the key fields out, so the MATCHING columns were missing;
    the key fields are always included for skMerge.
  • Under AutoUpdateOptions.UpdateOnlyModifiedFields, InsertSQL and UpdateSQL were assigned
    and prepared again at every post, even when the generated text was the same.
  • ApplyUpdates of a TClientDataSet over a TpFIBDataSet sent the text No Action of
    InsertSQL, UpdateSQL, DeleteSQL or an update object to the server (syntax error); the
    row now counts as applied with nothing sent, and a No Action delete runs no update object,
    as a direct post or delete.
  • CompareVariants (sorting, Locate): a number compared with a Unicode string variant (every
    string variant on Delphi 2009 and later), a Boolean, a UInt64 or an FMTBcd variant was
    taken as equal.
  • FIBPlus fields in a dataset that is not FIBPlus (e.g. persistent fields copied to a
    TClientDataSet): the first read of a TFIBStringField could raise an access violation,
    AsNativeData and AsOctetsData of the string fields wrote into the memory of that dataset,
    and TFIBWideStringField did not work there at all. TFIBDateTimeField.AsTimeStamp gave a
    wrong value in OnValidate, or raised EIntOverflow there when assigned.
    TFIBFloatField.Scale and AsFloat := read garbage, and the value of a TFIBArrayField was
    lost. GetBlobInfo, Blob_ID and ArrayID raise a clear error there.
  • DisplayFormat and EditFormat of TFIBBCDField and TpFIBClientBCDField on a rounded
    value: the zeros of the carry were dropped (0.00 on 1.296 gave 1.3), the thousand
    separators stayed where they were before the carry (#,##0.00 on 9999.996 gave 1,0000), a
    format without a decimal point kept the decimals, literals after the digits counted as
    decimals ($ #,##0.00 USD did not round), the trailing zeros of the optional # decimals
    were kept, the section was chosen before rounding (0.0;(0.0) on -0.004 gave (0.0)), an
    empty negative section was not handled, and the sign went after a leading literal ($ -1.00
    instead of -$ 1.00).
  • Calculated TFIBBCDField: AsExtended, AsInt64 and FieldModified read the TBcd of the
    value into an Int64 (access violation or a wrong value), and AsExtended := wrote an
    Int64 over it.
  • AsCurrency of TFIBBCDField and TpFIBClientBCDField: a value out of the Currency range
    (a NUMERIC(18,0) of 123456789012345678) gave a wrong number or raised EInvalidOp, and a
    value with more than 4 decimals was not rounded exactly. It is exact now and raises
    EOverflow out of the range. AsFloat and AsLargeInt don't go through Currency, and
    TFIBBCDField.Value of such a value is an FMTBcd variant.
  • TFIBBCDField.AsBCD := rescaled through floating point and wrote an out of range value;
    TpFIBClientBCDField.AsBCD and AsBCD := went through Currency (4 decimals,
    EConvertError out of its range). Both are exact now, rounded half away from zero to the
    scale of the field, and raise EOverflow out of the range.
  • TpFIBClientBCDField.AsInt64 := stored the value as already scaled (77 on a scale 2 field
    stored 0.77), TFIBBCDField.AsInt64 := and TpFIBClientBCDField.AsInt64 lost digits on
    Win64, and AsLargeInt := of both fields failed beyond 9.2E14.
  • TpFIBClientDataSet ignored the scale of a stored BCD value with fewer decimals than the
    field.
  • An unquoted lowercase table alias in AutoUpdateOptions.UpdateTableName or
    in SelectSQL was taken in lowercase, so no field matched and the generated
    statements left out every field (pfSetReadOnlyFields made all of them
    read-only). Such an alias is read as uppercase; a quoted one keeps its case.
    A quoted mixed-case UpdateTableName with an alias in SelectSQL is found.
  • SeparateBlobUpdate prepared the BLOB update statement again at every post;
    the text is compared first.
  • With a separate UpdateTransaction, the refresh after an applied insert,
    update or delete runs in UpdateTransaction.
  • An error in ApplyUpdates, or in an AutoCommit post with CachedUpdates,
    committed the half-done work of the failing row. The row is rolled back to a
    savepoint, only the rows the cache marks as applied are committed and the
    original error is raised. With AutoCommit, ApplyUpdates commits once at
    the end, and AfterPost and AfterDelete no longer commit twice.
  • With UpdateOnlyModifiedFields, PSUpdateRecord reused the statement of the
    last direct post and lost the changes of other fields; PSExecuteStatement
    takes the database of the dataset.
  • TFIBBCDField: Value := with a Currency value wrapped silently on large
    values. AsCurrency, AsFloat and Value are exact, the display text keeps
    all digits, and the setters round half away from zero and raise EOverflow
    out of range. In a dataset that is not FIBPlus it no longer reads and writes
    an Int64 over the TBcd (a heap overrun).
  • Locate on NUMERIC keys and CompareBCD compare exactly. TFIBGuidField
    returns Null for NULL and stores text in other datasets.
    TpFIBClientBCDField has the same BCD fixes.
  • CachedUpdates with poCacheCalcFields: Undelete, CanEdit of an inserted
    record and CachedUpdateStatus failed on records whose calculated fields were
    cached.
  • CachedUpdates: RevertRecord of an unmodified record and Undelete left
    UpdatesPending and CountUpdatesPending wrong, so CancelUpdates could do
    nothing; Undelete of a reverted insert did not mark the updates pending;
    RevertRecord of an edited record left its calculated fields empty until the
    cursor moved.
  • CachedUpdates: after deleting a modified record, Undelete, RevertRecord
    and CancelUpdates showed the edited values while ApplyUpdates never wrote
    them. The record now returns with its original values.
  • CachedUpdates: setting a field and then calling Cancel left
    CountUpdatesPending raised, so a later Delete or Undelete set
    UpdatesPending wrongly. The count now changes when the record is posted.
  • LoadFromStream of a CachedUpdates dataset with calculated fields and
    poCacheCalcFields returned damaged records and ApplyUpdates wrote nothing;
    after the load UpdatesPending and CountUpdatesPending show the cached
    updates of the stream.
  • Limited cache: scrolling with a nullable sort field ignored NULLS FIRST/NULLS LAST, misordered TIMESTAMP values before 1753 and failed for
    BOOLEAN sort fields; an error while fetching the last records was hidden.
  • Limited cache: GotoBookmark outside the buffered records failed for BIGINT,
    NUMERIC, BOOLEAN and GUID keys, and could go to a record whose key
    differs only in the last byte (1.5 and -1.5).
  • A failed Locate on a filtered dataset moved the cursor, so the next Next or
    Prior went to a wrong record.
  • TDataSetsContainer: a freed global container was still called, a container
    whose MasterContainer is the global one got every dataset event twice, and
    the container of a dataset overrode the global comparison even when it did not
    compare.
  • NUMERIC and DECIMAL fields of up to 9 digits read as Double were off in
    the last digit (0.7 read as 0.7000000000000001). CollateNumber of
    TFIBStringField and TFIBWideStringField returned a wrong value.
  • Sort with a wrong field name left the controls disabled, and errors of
    OnCompareFieldValues were hidden. An exception in OnCalcFields leaked a
    record buffer.
  • AsBoolean of TFIBIntegerField and TFIBSmallIntField returned False for
    negative values.
  • A filter with NOT, AND or OR on a NULL boolean operand raised an error;
    the operand now counts as False. LIKE and Locate with wildcards never
    matched masks such as %_x.
  • Loading a dataset from a stream leaked memory, a cloned sorted dataset lost the
    sort order, and reading a record beyond the record map read outside the cache.
  • TpFIBTableChangesReader kept a freed transaction when it was freed first.

Events

  • Win64: the event thread of TSIBfibEventAlerter gave the client a status vector of 32-bit
    entries, while the client writes 64-bit ones: an error while registering or cancelling events
    could overwrite the handles of the thread. The event counts have their own array now.
  • An error while registering events (an invalid database handle, a server whose events port
    can't be reached) ended the event thread without a message; it is now reported like an error
    after the registration.
  • UnRegisterEvents raised EListError when another event thread ended with an error while it
    waited for a thread to stop.
  • An event thread that ended with an error was never freed: its events stayed queued and its
    buffers leaked. It is freed on the next register or unregister or when the alerter is
    destroyed. Its error text is read with fb_interpret where the client has it.
  • An OnEventAlert handler of TSIBfibEventAlerter that called
    UnRegisterEvents, set Registered := False, closed the database or freed
    the alerter hung waiting for its own event thread. A thread is no longer
    waited for from its own handler, and the thread lists are guarded by a
    critical section. With VCLSynchronize = False, a failed event thread no
    longer reads the error text through Synchronize.
  • TSIBfibEventAlerter kept a dangling Database when the database was freed
    first, and AutoRegister did not register a connected database assigned at run
    time.

Errors and messages

  • The error message cache (ListErrorMessages, used by TpFibErrorHandler for
    the messages of FIB$ERROR_MESSAGES) was not thread safe: errors handled in
    several threads at once could raise access violations. FIB$VERSION was
    checked once per process for all databases, so the stale messages of a second
    database, or of a schema cache file loaded later, were shown; each database is
    now checked on its first use and after a load. Constraint names that differ
    only in case no longer share one cached message.
  • TpFibErrorHandler.LastError, ConstraintName, ExceptionName and
    ExceptionNumber were shared by all threads: an error in one thread changed
    them while another read them. They are now kept per thread.
  • Creating a second TpFibErrorHandler raised, and also unregistered the first
    one, which then no longer handled any error.
  • TpFibErrorHandler: when the lookup of a constraint in FIB$ERROR_MESSAGES
    failed (the table dropped, a transaction that is not active), its error
    replaced the violation, with its own LastError, ConstraintName and
    OnFIBErrorEvent. The violation now keeps the message it has without a row
    in the table.
  • TpFibErrorHandler: in a transaction over several databases, a violation in
    a database other than the default one of the transaction was looked up in
    FIB$ERROR_MESSAGES of the default database and cached under it. The lookup
    now uses the database of the failing statement. The server version that
    decides whether ExceptionName is read was also taken from the default
    database; without one, ExceptionName was Unknown and the message kept the
    name and the stack trace.
  • TpFibErrorHandler.ConstraintName was parsed from the message: a name with
    spaces or quotes was cut, and it was empty for a message in another language
    or without ShowIBMessage. It is now the exact name from the status vector,
    without the quotes and the schema that Firebird 6 adds there.
  • Server error messages (Message, IBMessage) and
    TpFibErrorHandler.ConstraintName and ExceptionName were decoded in the
    system code page, so non-ASCII names and exception texts were garbled outside
    it. They are now decoded in the charset of the connection (UTF-8 on a NONE
    connection, where the server sends the metadata charset). Firebird 2.5 sends
    the names in UTF-8 and the exception texts in the charset of the connection,
    so on a connection that is not UTF8 or NONE the names stay garbled there.
    The server errors of array fields and of TFIBBlobStream.BlobToFile now also
    give their database, for the decoding and for OnLostConnect.
  • TpFibErrorHandler: the message of a user exception was cut at an "at" in its
    text, or kept the stack trace (At procedure ...). The SQL monitor and the
    SQL logger got the message after the error handler changed it; they now show
    the server text with the stack trace.
  • EFIBClientError.IBErrorCode had the code of an earlier server error of the
    thread: after a statement timeout a client error had isc_cancelled, so
    TpFibErrorHandler took it for a cancelled statement. It is now 0.
  • Russian messages (Resources\Russian\FIB_Messages.inc): an unknown DPB or
    TPB constant raised an EConvertError ("Format ... invalid or incompatible
    with argument") instead of its message.
  • Typos and stray blanks in the English and Russian messages; two Russian
    messages (feCantUseField, feFeatureNotSupported) had a wrong grammar.
  • On Firebird 2.5 with a NONE connection, user exception texts with non-ASCII
    characters showed U+FFFD. Text that is not valid UTF-8 is decoded in the
    system code page, and the Windows texts of network errors
    (isc_arg_win32) always are.
  • TpFIBErrorHandler takes ExceptionName and ExceptionNumber from the
    status vector, so a name with a dot is not cut and Firebird 6 no longer
    gives "PUBLIC". New EFIBError.ErrorNumber reads a number argument of the
    status vector.
  • The English message of SetParamValues lost its typo ("equel").
  • CompareVariants raised EConvertError for a number compared with text
    that is not a number; that text is compared as text, a date with a date text
    as a date, and an integer with a decimal text as a number.
  • ErrorLexems written in mixed case never matched the server messages, and the
    statistics error message named the table FIB$APP_STATISIC instead of
    FIB$APP_STATISTICS.

Services

  • Security service (TpFIBSecurityService) with a Firebird 3+ client library:
    the user name, password, first, middle and last name and role were encoded in
    UTF-8 and then converted again by the client from the system code page, so
    every non-ASCII character was stored garbled (é as é). They are now sent
    in the system code page, which the client converts; on Delphi 2009 and later
    a character outside it raises "Cannot transliterate" instead of being sent as
    ?.
  • The other text parameters of the services (database, backup and file names,
    the table names of TpFIBStatisticalService, Params of the attachment) were
    sent with ? for a character outside the system code page, so the server
    reported a missing file or a wrong password. On Delphi 2009 and later they
    raise "Cannot transliterate", as the security service does.
  • Text the server sends back was decoded in the system code page: the output of
    the services (GetNextLine, GetNextChunk), TpFIBSecurityService.UserInfo,
    the attached database names and the other strings of
    TpFIBServerProperties, and TFIBDatabase.UserNames, Version,
    FBVersion and the other text database info. A Linux server sends file names
    in UTF-8 and Firebird 3+ user names are UTF-8, so non-ASCII names were
    garbled. They are now decoded as UTF-8 when the bytes are valid UTF-8, else
    in the system code page (a Windows server).
  • A service start parameter of 65536 bytes or more was dropped or sent with a
    wrong length; it raises an error now. A BufferSize of 65536 or more was cut
    to 2 bytes (65536 gave "Unexpected Output buffer value"); the service API gets
    at most 65535 bytes.
  • GetNextChunk, GetNextLine and GetNextBuf read the chunk length as a
    signed number and raised "Unexpected Output buffer value" for chunks of 32768
    bytes or more.
  • A failed service call left the service attached on the server, a configuration
    setter on an inactive service gave "invalid service handle", and the parameter
    buffer leaked when the client library could not be loaded.

Schema cache

  • A schema cache file that could not be written completely (disk full, ...)
    was left truncated, and the next Open with AutoLoadFromFile failed
    reading it. The file is now deleted instead.
  • A dataset with DataSet_ID but no row in FIB$DATASETS_INFO lost its
    KeyFields, GeneratorName, UpdateTableName, Conditions and
    Description. The repository upgrade committed the transaction of the
    application.
  • The field info of a selectable procedure was not loaded and mixed in the
    parameters of packaged procedures with the same name. Tables or fields whose
    names differ only in case shared the cached info, and validating such a cache
    could overflow the stack; a damaged schema cache file raised an error at
    connect.

Schema extract

  • DDL generated by TpFIBDBSchemaExtract (GetDDLText, GetObjectDDL) on
    Delphi XE5 and later: characters outside the system code page in names,
    defaults and procedure bodies became ?, and a DDL under 10 KB was padded
    with #0 to 10240 characters. The DDL stream is now created with
    TEncoding.Unicode.
  • Script of TpFIBDBSchemaExtract.GetDDLText: the roles, external functions,
    generators, exceptions, tables, views and database triggers were followed by
    an extra ;, the triggers of a view were created twice, the objects of a
    previous GetObjectDDL were written again, the RETURNS clause of every
    function after the first held its first parameter, identity columns lost
    GENERATED ... AS IDENTITY, the system domains MON$... of Firebird 4 and
    later were created, and index and trigger names were not quoted.
    TMetaProcedure.PackageName held the procedure body after LoadMetaData.
  • GetObjectDDL and AsDDL: the DDL of a domain had no terminator and that
    of a package ended with ;;. Before a LoadMetaData, GetObjectDDL ignored
    DDLTextOptions (for example dtoDecodeDomains), lost identity columns
    and took a packaged procedure of the same name.
  • A generator value over 2147483647 was wrong
    (TMetaGenerator.Value is Int64). When LoadOptions.DBObjects had no
    otTable, the views had no columns and their triggers were not written. A
    procedure, function or external function got the parameters of a packaged
    one with the same name, and GetObjectDDL(otUDF) could take a packaged or
    PSQL function. CREATE FUNCTION, RETURNS and COMPUTED BY had two
    spaces. The script has no empty UNIQUE, CHECKS or TRIGGERS sections.
  • Reloading or clearing the metadata leaked the previous meta objects, and
    GetObjectDDL of a database trigger leaked one object on each call.
  • TpFIBDBSchemaExtract.GetObjectDDL of a package or a PSQL function on a server before
    Firebird 3 raised "Table unknown" instead of returning an empty string.
  • TpFIBDBSchemaExtract extracts PSQL functions and packages by default
    (DefObjects), so a script whose procedures call them runs.
  • GetDDLText raised for a table with an expression index and for a DDL
    trigger, and the stub of a procedure without output parameters failed on
    Firebird 3+. TYPE OF COLUMN parameters were written as TYPE OF their
    domain, and DESCENDING UNIQUE or inactive indexes gave invalid DDL.
  • The extract lost parameter defaults, collations, the names of UNIQUE
    constraints, partial index conditions, START WITH and INCREMENT BY of
    sequences and identity columns, and INACTIVE of triggers. Grantee names are
    quoted, a non-ASCII exception message is no longer double-encoded, and
    database and DDL triggers come at the end of the script.
  • Grants of an object with 1000 or more grantees overran memory. WITH ADMIN OPTION of role grants and WITH GRANT OPTION of EXECUTE grants were lost,
    and a role or a table named like a procedure mixed their grants.
  • DECIMAL columns were written as NUMERIC, a narrower type for precisions 1
    to 4; text BLOB columns lost their CHARACTER SET; named CHECK constraints
    lost their name.
  • A package header with TYPE OF COLUMN parameters failed because it ran before
    the tables. The script no longer contains SYSDBA/masterkey (it uses the
    user of the connection, no password) nor an empty SET NAMES; quoted names
    with "" were not found by GetObjectDDL.
  • A load of the names only made one foreign key per column and wrote objects
    dropped in the meantime as empty statements.
  • The export data script looped forever for a row of 64K or more, appended to an
    existing file, used the locale time separator and wrote wrong BLOB values.

Scripter

  • TpFIBScripter with UseExecBlockForDML: an INSERT, UPDATE, DELETE or
    MERGE with RETURNING was grouped into an EXECUTE BLOCK, where it needs
    INTO, so the whole block failed. Such a statement now runs alone; the new
    TStatementDesc.HasReturning field marks it.
  • TpFIBScripter with UseExecBlockForDML: the size limit of an
    EXECUTE BLOCK counted characters, so with UTF8 and non-ASCII text a block
    could be over the 64 KB the server accepts. The limit is now in bytes of the
    connection charset, and 10 MB with a Firebird 3 or later server and client.
  • TpFIBScripter cut a statement at a -- comment when the script was added
    as one item with several lines (e.g. Script.Add of a multi-line string):
    the comment ran to the end of the item, not of the line
    (#95).
  • TpFIBScripter with SET BLOBFILE: every parameter whose name starts with H (:HIRE_DATE)
    was read from the blob file, and lowercase hex digits of a reference were read as 0. Only
    H<offset>_<size> in hex digits is a reference now. A reference past the end of the file
    loaded zeros; it raises the new feBlobFileError, with the file and the parameter.
  • TpFIBScripter, the SQL parser (SqlTxtRtns) and the SQL editor highlighting took any
    character 32 codes above a keyword letter for that letter: {DIFDEF X} was read as
    {$IFDEF X}, RDBDGET_CONTEXT was highlighted as RDB$GET_CONTEXT, and a non-ASCII letter
    could match an ASCII one. Only a..z now match A..Z.
  • TpFIBScripter.ExecuteFromFile passed a UTF-8 byte order mark to the parser, so the first
    statement failed; the mark is skipped (the file is still read in the system code page).
  • TpFIBScripter.LineCountInCurrentFile kept the line count of a file run by INPUT after it
    returned to the calling file.
  • TpFIBScripter opened the SET BLOBFILE file with the sharing mode in the
    place of the rights argument, so it was not opened for shared reading.
  • TpFIBScripter ran the {$ELSE} part of a nested directive whose outer
    directive was false; DISCONNECT without a database raised an access
    violation; directive errors reported the line before the directive.
  • DESCRIBE failed on Firebird 3+ and matched no object for an unquoted name; it
    runs COMMENT ON.

SQL monitor

  • SQL monitor: non-ASCII text could arrive garbled, through the system code
    page or a chunk of a long event cut inside a character.
  • A failing SQL log file no longer makes Open, StartTransaction, Commit,
    Rollback or Close raise; the unsaved rows are kept for the next save.
    TFIBSQLLogger saves the pending log when freed.
  • A process with a SQL monitor still alive at exit no longer hangs.

Helper units

  • Win64: StreamToVariant and StreamToVariantArray (StdFuncs) cut the
    memory addresses to 32 bits (access violation), and so did the "nested
    datasets" error of TpFIBClientDataSet with the address of its message.
  • StringAsGUID (StrUtil) rejected lowercase hex digits and read some other characters (G,
    a space, /, :, @) as 0. HexStr2Int (StdFuncs) reads lowercase hex digits.
  • Delphi 13: StringAsGUID (StrUtil) gave the implicit conversion warning W1071.
  • TCallBackList.Delete ignored the index 0 and did not free the deleted entry.
  • BCDToInt64WithScale (StdFuncs) dropped the leading digit of 19 digit values, never
    reported an overflow, and left Scale unset for a zero precision TBcd. BCDToExtended gave
    a wrong value for an integer part beyond Int64, so CompareBCD compared garbage.
  • TFIBBlobStream.BlobToFile left the blob open and SaveToFile wrote nothing
    for a stream without a table name. A full disk during a batch export left a
    truncated file without an error; a corrupt raw batch file raised conversion or
    memory errors.
  • The delimited import mishandled delimiters of several characters;
    TTestInfo.Clear caused a range error on the next use; the generator cache
    file lost values above 2147483647.

IDE, editors and packages

  • pFIBArray did not compile on Delphi 10.1 Berlin: "Invalid typecast" in
    TpFIBArray.ReadElement (#94).
  • The editors did not save text and some integer settings: the font name,
    style and charset and the syntax highlighting styles of the SQL editor, and
    the user transaction kinds of the transaction editor were lost when the IDE
    was closed (the font charset on every version, the rest on Delphi 2009 and
    later).
  • DataSet_ID property editor: when the FIB$DATASETS_INFO table did not
    exist, it refused to create it ("urDataSetInfo not included into
    Database.UseRepositories") although urDataSetInfo was in UseRepositories,
    unless all three repositories were enabled.
  • Transaction editor: a saved transaction kind whose parameters were missing
    from the registry could raise "Variant is not an array"; the check no longer
    depends on Delphi short-circuiting a Variant expression.
  • Transaction editor: loading the transaction kinds from a file turned only the first # of the
    parameters into a line break.
  • Dataset editor, AutoUpdateOptions: the generator step accepted a ..
  • SQL editor: on Delphi 2009 and later the characters U+0080 to U+00FF were
    measured as the character of the same byte in the system code page (all of
    them on a Central European or Cyrillic Windows), so the text after them was
    drawn at a wrong offset.
  • SQL editor: a mouse click in a line with characters outside Latin-1 (Cyrillic) put the caret
    in a wrong column (Delphi 2009 and later).
  • SQL editor: selecting with the mouse in an editor without lines raised an
    "index out of bounds" error.
  • SQL editor: a code completion item chosen on the empty line after the last
    line was sometimes not inserted.
  • SQL editor: a line number after a keyword was drawn in bold.
  • SQL editor: on a line longer than 65535 characters the words after that
    position were highlighted at a wrong place.
  • Conditions editor: a narrow conditions list auto-sized its column instead of
    shrinking it.
  • SQL editor: copy and paste of several lines with their sections pasted the characters outside
    the system code page as garbage, and cut the text on a double-byte code page (932, 936). On
    Delphi 2009 and later the data is now also put in UTF-16; the old MP_SYN_MEMO data still
    pastes and is still written for older editors.
  • SQL editor: a LiteralDecimalPoint outside Latin-1 split the numbers in the highlighting.
  • SQL editor: pasting text with sections raised an access violation, every paste dropped the
    sections of the editor, sections stayed at their rows when lines were inserted or deleted
    above them, and a paste of plain text did not set Modified.
  • SQL editor: undo dropped all the sections of the editor, only the text came back.
  • SQL editors, Edit in code editor: on Delphi 2005 and later the SQL tab was named without
    the designer extension (Form1.Query1.SQL instead of dfm.Form1.Query1.SQL), so the IDE
    could not find the component of the tab ("Unable to find component") and the edited text was
    not written back to the property.
  • SQL editor: pasting text copied with sections added a line break after it,
    and characters above #255 were measured in bold instead of the style of
    their token, so the caret and selection drifted on Cyrillic or CJK text.
    Each editor leaked the syntax data of its lines.
  • RegUtils.WriteToRegistry did not write ShortInt, Byte and WideString
    values.
  • The packages FIBPlus_XE2 and FIBPlus_XE4 included FIBPlus.inc in the
    package source and did not compile. The RELEASE define of the package
    projects keeps the inherited defines.
  • The condition editors showed disabled conditions as enabled and exported wrong
    data; saving a dataset to the repository failed when an SQL text contained an
    apostrophe; the key field list of AutoUpdateOptions listed fields of other
    joined tables; the table name list closed the transaction of the user.
    IsCalculatedField of the SQL editor cleared the table info cache of all
    datasets.
  • The Check SQLs verb of TpFIBQuery did not check anything and always
    reported no errors.
  • The registry key of the editors stayed open and later settings were written
    under a wrong key; the database editor reported "Unknown Error" for UNC paths.