Skip to content

v1.2.0

Latest

Choose a tag to compare

@github-actions github-actions released this 19 Sep 03:55

A release about what a script can see. A write hands back the number of rows it affected, which is what a
conditional write needs, and every statement now waits for its work, so a failure can no longer reach the
console while last database error stays silent.

Added

  • store affected rows in {_rows}, on every statement that writes: insert one, insert many,
    insert ... if absent, update, upsert and delete, in the section form and the colon-free one
    alike. It keeps the number of rows the statement affected, which is how a script tells "it was already
    there" from "it was written", and how a read-modify-write becomes safe without a transaction: the count
    of a statement whose where repeats the value it read is 1 only while nobody else got there first. A
    count of 0 is a real answer, while a variable left unset means no statement answered — the statement
    was refused or skipped, it failed, or the backend could not count it exactly. See
    Affected rows for the three states, what the number means on each backend, and
    a bounded retry recipe.

Changed

  • Every statement waits. A write used to continue immediately unless it said and wait: the next line
    ran while it was still in flight, so a read could see the row as it was, and a failure only the database
    could judge went to the console instead of into last database error. Writes now behave the way reads
    always have — the lines after a statement run once its work is done, which makes the order of a script
    the order of its statements. Upgrade note: a script that relied on carrying on before a write had
    finished will now wait for it, and a write that failed is now reported in last database error where it
    used to be logged only. and wait is still accepted on every statement and does nothing, so no script
    has to change; it can simply be left out from here on.

Fixed

  • insert entity if absent on MySQL swallowed every error, not only an existing row. It was
    INSERT IGNORE, which turns errors into warnings, so a value too long for its column was stored cut
    short and a null in a not null column became that column's default — with the script told nothing.
    The insert is now sent as it is and the duplicate key is the one error the statement reads as "the row is
    there", which is what PostgreSQL and MongoDB already did. The count is unchanged: 1 written, 0 it was
    already there, and anything else fails like any other write.
  • A connection that lost the default role with no name of its own was left open for the life of the
    server.
    Nothing could resolve to it afterwards — in connection and use connection need a name, and
    it was no longer the default — so it kept its pool of ten server connections, and neither
    disconnect from all connections nor a plugin disable could reach it. make ... the default closes it
    now, the same way an unnamed connection that replaces the default already closed the one it replaced. A
    named connection keeps running and merely stops being the default. The statement waits for that
    close, so the line after it sees the new default, and it is refused inside a database transaction,
    because the connection it closes may be the one the transaction is running on.
  • A read that was refused before it ran left the previous result in its variable. A read that failed
    at the database cleared the variable, while one refused earlier — no connection, an unknown table, a
    where value the column cannot hold, a page number of zero — did not, so the previous read's row was
    still sitting there and a script could not tell "the row is gone" from "the statement did not run". Every
    refusal clears it now, which is the rule the store affected rows variable already followed: a
    statement leaves this statement's answer, or nothing.
  • A whole number that did not fit its column was stored as a different number. Skript converts a
    number into whatever type it is asked for, and every one of those conversions narrows: an int column
    turned 5000000000 into 705032704 (the low 32 bits), a tinyint column turned 300 into 44, and
    the database was handed a value that fitted, so nothing anywhere reported it. A number column is now
    read as a number and narrowed by the plugin, which refuses a value the column cannot hold with a
    message naming the column and its range — in a values block, in a variable and in a where value
    alike. A fraction written into a whole-number column is still cut towards zero, and float still keeps
    four bytes: only the case that was silently wrong changed. See
    Types.
  • A failure the database itself reported did not end the transaction it happened in. Only a statement
    refused before it was sent made a transaction rollback-only, so a constraint violation, a value the
    server refused, or a dialect refusing a statement let the body carry on, a later statement cleared the
    failure out of last database error, and the body ended by committing the half of it that had worked.
    Any statement failure now makes the transaction rollback-only: the statements after it do nothing, the
    body rolls back, and the cause stays readable.
  • Naming the connection a transaction is already running on took the statements after it out of the
    transaction.
    The switch was meant to be a no-op and was not: the frame it pushed carried no
    transaction, so the statements under it ran on a pooled connection and committed on their own — and with
    use connection the transaction itself was then left for the watchdog to end, dropping the work the
    body had already done. The frame carries the transaction now, which is what makes the switch the no-op
    it claims to be.
  • rollback database transaction cleared last database error. The automatic rollback of a failed
    body keeps the cause; the rollback a script writes does the same now, so the line after the section
    still says what went wrong.

Documentation

  • A bilingual page for the row count, and the waiting material rewritten around it: the two troubleshooting
    entries about silent write failures are gone, along with the behaviour they described.
  • The transaction timeout is written up in full: the spellings it accepts, the value it needs, when its
    clock starts, that it belongs to the transaction rather than to the connection, and what a long body or
    a statement that runs into the deadline does.
  • An audit of every page turned up the places where the docs stopped short of the code, and they are fixed
    throughout: what a pool is and what bounds waiting for one; what a size in a table declaration applies
    to; which statements store affected rows answers "was it written" for; what a list variable cannot
    carry; what a ragged insert many does; what a by id write on a missing row reports; what a limit
    that resolves to nothing does; the order paging uses and why it is not a snapshot; what a refused read
    leaves in the result variable; what a failure does to the rest of the trigger; why a table can be
    "already registered"; and four recipes that could not have worked as written.

Full Changelog: v1.1.0...v1.2.0