8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 15:23:03 +01:00

Make it possible to start multiple transactions using the same initial transaction snapshot - CORE-6018 (#193)

With this feature it's possible to create parallel (via different attachments) processes reading consistent data from a database.

For example, a backup process may create multiple threads paralleling read data from the database.

Also a web service may dispatch distributed sub services paralleling doing some processing.

That is accomplished creating a transaction with SET TRANSACTION SNAPSHOT [ AT NUMBER <snapshot number> ] or isc_tpb_at_snapshot_number.

The <snapshot number> from the first transaction may be obtained with RDB$GET_CONTEXT('SYSTEM', 'SNAPSHOT_NUMBER') or transaction info call with fb_info_tra_snapshot_number.

Also added CORE-6017 - Add transaction info fb_info_tra_snapshot_number.
This commit is contained in:
Adriano dos Santos Fernandes 2019-03-01 16:17:19 -03:00 committed by GitHub
parent 05b5d16c44
commit cfbcbeda3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 218 additions and 39 deletions

View File

@ -0,0 +1,17 @@
# Transaction at defined snapshot number
With this feature it's possible to create parallel (via different attachments) processes reading consistent data from a database.
For example, a backup process may create multiple threads paralleling reading data from the database.
Or a web service may dispatch distributed sub services paralleling doing some processing.
That is accomplished creating a transaction with `SET TRANSACTION SNAPSHOT [ AT NUMBER <snapshot number> ]` or `isc_tpb_at_snapshot_number <snapshot number length> <snapshot number>`.
The `snapshot number` from the first transaction may be obtained with `RDB$GET_CONTEXT('SYSTEM', 'SNAPSHOT_NUMBER')` or transaction info call with `fb_info_tra_snapshot_number`.
Note that the `snapshot number` passed to the new transaction must be a snapshot of an active transaction.
Author:
Adriano dos Santos Fernandes <adrianosf at gmail.com>

View File

@ -330,6 +330,7 @@ Firebird 4.0
NATIVE *
NORMALIZE_DECFLOAT *
NTILE (1)
NUMBER
OTHERS
OVERRIDING
PERCENT_RANK (1)

View File

@ -1914,6 +1914,8 @@ C --
PARAMETER (GDS__tom_chacha_key = 335545250)
INTEGER*4 GDS__bad_repl_handle
PARAMETER (GDS__bad_repl_handle = 335545251)
INTEGER*4 GDS__tra_snapshot_does_not_exist
PARAMETER (GDS__tra_snapshot_does_not_exist = 335545252)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw

View File

@ -1909,6 +1909,8 @@ const
gds_tom_chacha_key = 335545250;
isc_bad_repl_handle = 335545251;
gds_bad_repl_handle = 335545251;
isc_tra_snapshot_does_not_exist = 335545252;
gds_tra_snapshot_does_not_exist = 335545252;
isc_gfix_db_name = 335740929;
gds_gfix_db_name = 335740929;
isc_gfix_invalid_sw = 335740930;

View File

@ -64,6 +64,12 @@ public:
appendUShort(val >> 16);
}
void appendUInt64(FB_UINT64 val)
{
appendULong(val);
appendULong(val >> 32);
}
void appendUCharRepeated(UCHAR byte, int count)
{
for (int i = 0; i < count; ++i)

View File

@ -600,7 +600,7 @@ int Parser::yylexAux()
*
* This code recognizes the following token types:
*
* NUMBER: string of digits which fits into a 32-bit integer
* NUMBER32BIT: string of digits which fits into a 32-bit integer
*
* NUMBER64BIT: string of digits whose value might fit into an SINT64,
* depending on whether or not there is a preceding '-', which is to
@ -792,7 +792,7 @@ int Parser::yylexAux()
// by a set of nibbles, using 0-9, a-f, or A-F. Odd numbers
// of nibbles assume a leading '0'. The result is converted
// to an integer, and the result returned to the caller. The
// token is identified as a NUMBER if it's a 32-bit or less
// token is identified as a NUMBER32BIT if it's a 32-bit or less
// value, or a NUMBER64INT if it requires a 64-bit number.
if (c == '0' && lex.ptr + 1 < lex.end && (*lex.ptr == 'x' || *lex.ptr == 'X') &&
(classes(lex.ptr[1]) & CHR_HEX))
@ -833,7 +833,7 @@ int Parser::yylexAux()
}
// we have a valid hex token. Now give it back, either as
// an NUMBER or NUMBER64BIT.
// an NUMBER32BIT or NUMBER64BIT.
if (!hexerror)
{
// if charlen > 8 (something like FFFF FFFF 0, w/o the spaces)
@ -888,7 +888,7 @@ int Parser::yylexAux()
}
else
{
// we have an integer value. we'll return NUMBER.
// we have an integer value. we'll return NUMBER32BIT.
// but we have to make a number value to be compatible
// with existing code.
@ -933,7 +933,7 @@ int Parser::yylexAux()
}
yylval.int32Val = (SLONG) value;
return TOK_NUMBER;
return TOK_NUMBER32BIT;
} // integer value
} // if (!hexerror)...
@ -1111,7 +1111,7 @@ int Parser::yylexAux()
{
yylval.int32Val = (SLONG) number;
//printf ("parse.y %p %d\n", yylval.legacyStr, number);
return TOK_NUMBER;
return TOK_NUMBER32BIT;
}
else
{

View File

@ -8191,6 +8191,14 @@ SetTransactionNode* SetTransactionNode::dsqlPass(DsqlCompilerScratch* dsqlScratc
for (RestrictionOption** i = reserveList.begin(); i != reserveList.end(); ++i)
genTableLock(dsqlScratch, **i, lockLevel);
if (atSnapshotNumber.specified)
{
dsqlScratch->appendUChar(isc_tpb_at_snapshot_number);
static_assert(sizeof(CommitNumber) == sizeof(FB_UINT64), "sizeof(CommitNumber) == sizeof(FB_UINT64)");
dsqlScratch->appendUChar(sizeof(CommitNumber));
dsqlScratch->appendUInt64(atSnapshotNumber.value);
}
if (dsqlScratch->getBlrData().getCount() > 1) // 1 -> isc_tpb_version1
tpb.add(dsqlScratch->getBlrData().begin(), dsqlScratch->getBlrData().getCount());

View File

@ -1619,6 +1619,7 @@ public:
Nullable<USHORT> lockTimeout;
Firebird::Array<RestrictionOption*> reserveList;
Firebird::UCharBuffer tpb;
Nullable<CommitNumber> atSnapshotNumber;
};

View File

@ -1 +1 @@
56 shift/reduce conflicts, 17 reduce/reduce conflicts.
58 shift/reduce conflicts, 17 reduce/reduce conflicts.

View File

@ -335,7 +335,7 @@ using namespace Firebird;
%token <stringPtr> FLOAT_NUMBER DECIMAL_NUMBER LIMIT64_INT
%token <lim64ptr> LIMIT64_NUMBER
%token <metaNamePtr> SYMBOL
%token <int32Val> NUMBER
%token <int32Val> NUMBER32BIT
%token <intlStringPtr> STRING
%token <metaNamePtr> INTRODUCER
@ -5358,7 +5358,7 @@ tran_option($setTransactionNode)
| NO WAIT
{ setClause($setTransactionNode->wait, "[NO] WAIT", false); }
// isolation mode
| isolation_mode
| isolation_mode($setTransactionNode)
{ setClause($setTransactionNode->isoLevel, "ISOLATION LEVEL", $1); }
// misc options
| NO AUTO UNDO
@ -5378,24 +5378,38 @@ tran_option($setTransactionNode)
restr_list($setTransactionNode)
;
%type <uintVal> isolation_mode
isolation_mode
: ISOLATION LEVEL iso_mode { $$ = $3;}
%type <uintVal> isolation_mode(<setTransactionNode>)
isolation_mode($setTransactionNode)
: ISOLATION LEVEL iso_mode($setTransactionNode) { $$ = $3;}
| iso_mode
;
%type <uintVal> iso_mode
iso_mode
: snap_shot
%type <uintVal> iso_mode(<setTransactionNode>)
iso_mode($setTransactionNode)
: snap_shot($setTransactionNode) { $$ = $1; }
| READ UNCOMMITTED version_mode { $$ = $3; }
| READ COMMITTED version_mode { $$ = $3; }
;
%type <uintVal> snap_shot
snap_shot
: SNAPSHOT { $$ = SetTransactionNode::ISO_LEVEL_CONCURRENCY; }
| SNAPSHOT TABLE { $$ = SetTransactionNode::ISO_LEVEL_CONSISTENCY; }
| SNAPSHOT TABLE STABILITY { $$ = SetTransactionNode::ISO_LEVEL_CONSISTENCY; }
%type <uintVal> snap_shot(<setTransactionNode>)
snap_shot($setTransactionNode)
: SNAPSHOT
{ $$ = SetTransactionNode::ISO_LEVEL_CONCURRENCY; }
| SNAPSHOT AT NUMBER snapshot_number
{
setClause($setTransactionNode->atSnapshotNumber, "SNAPSHOT AT NUMBER", (CommitNumber) $4);
$$ = SetTransactionNode::ISO_LEVEL_CONCURRENCY;
}
| SNAPSHOT TABLE
{ $$ = SetTransactionNode::ISO_LEVEL_CONSISTENCY; }
| SNAPSHOT TABLE STABILITY
{ $$ = SetTransactionNode::ISO_LEVEL_CONSISTENCY; }
;
%type <int64Val> snapshot_number
snapshot_number
: NUMBER32BIT { $$ = $1; }
| NUMBER64BIT { $$ = $1.number; }
;
%type <uintVal> version_mode
@ -7371,7 +7385,7 @@ u_numeric_constant
%type <valueExprNode> ul_numeric_constant
ul_numeric_constant
: NUMBER
: NUMBER32BIT
{ $$ = MAKE_const_slong($1); }
| FLOAT_NUMBER
{ $$ = MAKE_constant($1->c_str(), CONSTANT_DOUBLE); }
@ -7511,7 +7525,7 @@ signed_short_integer
%type <int32Val> nonneg_short_integer
nonneg_short_integer
: NUMBER
: NUMBER32BIT
{
if ($1 > SHRT_POS_MAX)
yyabandon(YYPOSNARG(1), -842, isc_expec_short); // Short integer expected
@ -7522,7 +7536,7 @@ nonneg_short_integer
%type <int32Val> neg_short_integer
neg_short_integer
: NUMBER
: NUMBER32BIT
{
if ($1 > SHRT_NEG_MAX)
yyabandon(YYPOSNARG(1), -842, isc_expec_short); // Short integer expected
@ -7544,7 +7558,7 @@ pos_short_integer
%type <int32Val> unsigned_short_integer
unsigned_short_integer
: NUMBER
: NUMBER32BIT
{
if ($1 > SHRT_UNSIGNED_MAX)
yyabandon(YYPOSNARG(1), -842, isc_expec_ushort); // Unsigned short integer expected
@ -7561,7 +7575,7 @@ signed_long_integer
%type <int32Val> long_integer
long_integer
: NUMBER { $$ = $1;}
: NUMBER32BIT { $$ = $1;}
;
@ -8796,6 +8810,7 @@ non_reserved_word
| NATIVE
| NORMALIZE_DECFLOAT
| NTILE
| NUMBER
| OLDEST
| OTHERS
| OVERRIDING

View File

@ -244,6 +244,7 @@
#define isc_tpb_no_auto_undo 20
#define isc_tpb_lock_timeout 21
#define isc_tpb_read_consistency 22
#define isc_tpb_at_snapshot_number 23
/************************/

View File

@ -953,6 +953,7 @@ static const struct {
{"tom_rsa_verify", 335545249},
{"tom_chacha_key", 335545250},
{"bad_repl_handle", 335545251},
{"tra_snapshot_does_not_exist", 335545252},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},

View File

@ -987,6 +987,7 @@ const ISC_STATUS isc_tom_rsa_sign = 335545248L;
const ISC_STATUS isc_tom_rsa_verify = 335545249L;
const ISC_STATUS isc_tom_chacha_key = 335545250L;
const ISC_STATUS isc_bad_repl_handle = 335545251L;
const ISC_STATUS isc_tra_snapshot_does_not_exist = 335545252L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@ -1461,7 +1462,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
const ISC_STATUS isc_err_max = 1405;
const ISC_STATUS isc_err_max = 1406;
#else /* c definitions */
@ -2418,6 +2419,7 @@ const ISC_STATUS isc_err_max = 1405;
#define isc_tom_rsa_verify 335545249L
#define isc_tom_chacha_key 335545250L
#define isc_bad_repl_handle 335545251L
#define isc_tra_snapshot_does_not_exist 335545252L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
@ -2892,7 +2894,7 @@ const ISC_STATUS isc_err_max = 1405;
#define isc_trace_switch_param_miss 337182758L
#define isc_trace_param_act_notcompat 337182759L
#define isc_trace_mandatory_switch_miss 337182760L
#define isc_err_max 1405
#define isc_err_max 1406
#endif

View File

@ -956,6 +956,7 @@ Data source : @4"}, /* eds_statement */
{335545249, "Verifying RSA-signed data"}, /* tom_rsa_verify */
{335545250, "Invalid key length @1, need 16 or 32"}, /* tom_chacha_key */
{335545251, "invalid replicator handle"}, /* bad_repl_handle */
{335545252, "Transaction's base snapshot number does not exist"}, /* tra_snapshot_does_not_exist */
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */

View File

@ -952,6 +952,7 @@ static const struct {
{335545249, -901}, /* 929 tom_rsa_verify */
{335545250, -901}, /* 930 tom_chacha_key */
{335545251, -901}, /* 931 bad_repl_handle */
{335545252, -901}, /* 932 tra_snapshot_does_not_exist */
{335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */

View File

@ -952,6 +952,7 @@ static const struct {
{335545249, "22023"}, // 929 tom_rsa_verify
{335545250, "22023"}, // 930 tom_chacha_key
{335545251, "08003"}, // 931 bad_repl_handle
{335545252, "0B000"}, // 932 tra_snapshot_does_not_exist
{335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw

View File

@ -1166,6 +1166,10 @@ void INF_transaction_info(const jrd_tra* transaction,
memcpy(buffer, transaction->tra_attachment->att_database->dbb_database_name.c_str(), length);
break;
case fb_info_tra_snapshot_number:
length = INF_convert(static_cast<SINT64>(transaction->tra_snapshot_number), buffer);
break;
default:
buffer[0] = item;
item = isc_info_error;

View File

@ -394,6 +394,7 @@ enum info_db_provider
#define isc_info_tra_access 9
#define isc_info_tra_lock_timeout 10
#define fb_info_tra_dbpath 11
#define fb_info_tra_snapshot_number 12
// isc_info_tra_isolation responses
#define isc_info_tra_consistency 1

View File

@ -759,8 +759,7 @@ void TipCache::remapSnapshots(bool sync)
}
SnapshotHandle TipCache::beginSnapshot(thread_db* tdbb, AttNumber attachmentId, CommitNumber *commitNumber_out)
SnapshotHandle TipCache::beginSnapshot(thread_db* tdbb, AttNumber attachmentId, CommitNumber& commitNumber)
{
// Can only be called on initialized TipCache
fb_assert(m_tpcHeader);
@ -772,16 +771,38 @@ SnapshotHandle TipCache::beginSnapshot(thread_db* tdbb, AttNumber attachmentId,
// Remap snapshot list if it has been grown by someone else
remapSnapshots(false);
if (commitNumber != 0)
{
SnapshotList* snapshots = m_snapshots->getHeader();
ULONG slotsUsed = snapshots->slots_used.load(std::memory_order_relaxed);
bool found = false;
for (SnapshotHandle slotNumber = 0; slotNumber < slotsUsed; ++slotNumber)
{
if (snapshots->slots[slotNumber].attachment_id.load(std::memory_order_relaxed) != 0 &&
snapshots->slots[slotNumber].snapshot.load(std::memory_order_relaxed) == commitNumber)
{
found = true;
break;
}
}
if (!found)
ERR_post(Arg::Gds(isc_tra_snapshot_does_not_exist));
}
SnapshotHandle slotNumber = allocateSnapshotSlot();
// Note, that allocateSnapshotSlot might remap memory and thus invalidate pointers
SnapshotList* snapshots = m_snapshots->getHeader();
// Store snapshot commit number and return handle
SnapshotData *slot = snapshots->slots + slotNumber;
SnapshotData* slot = snapshots->slots + slotNumber;
*commitNumber_out = m_tpcHeader->getHeader()->latest_commit_number.load(std::memory_order_acquire);
slot->snapshot.store(*commitNumber_out, std::memory_order_release);
if (commitNumber == 0)
commitNumber = m_tpcHeader->getHeader()->latest_commit_number.load(std::memory_order_acquire);
slot->snapshot.store(commitNumber, std::memory_order_release);
// Only assign attachment_id after we completed all other work
slot->attachment_id.store(attachmentId, std::memory_order_release);

View File

@ -118,9 +118,9 @@ public:
void updateOldestTransaction(thread_db* tdbb, TraNumber oldest, TraNumber oldestSnapshot);
// Create snapshot. The snapshot shall use only versions committed
// before commitNumber_out. Snapshots inhibit GC to some extent.
// before commitNumber (the latest CN when it's 0). Snapshots inhibit GC to some extent.
// When snapshot is no longer needed you call endSnapshot.
SnapshotHandle beginSnapshot(thread_db* tdbb, AttNumber attachmentId, CommitNumber *commitNumber_out);
SnapshotHandle beginSnapshot(thread_db* tdbb, AttNumber attachmentId, CommitNumber& commitNumber);
// Deallocate snapshot.
void endSnapshot(thread_db* tdbb, SnapshotHandle handle, AttNumber attachmentId);

View File

@ -171,10 +171,11 @@ void TRA_setup_request_snapshot(Jrd::thread_db* tdbb, Jrd::jrd_req* request, boo
// we need to set up statement snapshot for read consistency and own it
request->req_snapshot.m_owner = request;
request->req_snapshot.m_number = 0;
request->req_snapshot.m_handle =
tdbb->getDatabase()->dbb_tip_cache->beginSnapshot(tdbb,
tdbb->getAttachment()->att_attachment_id, &request->req_snapshot.m_number);
tdbb->getAttachment()->att_attachment_id, request->req_snapshot.m_number);
}
@ -1283,8 +1284,10 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction, Jrd::TraceTr
}
++transaction->tra_use_count;
if (transaction->tra_lock)
LCK_release(tdbb, transaction->tra_lock);
--transaction->tra_use_count;
// release the sparse bit map used for commit retain transaction
@ -2732,6 +2735,7 @@ static void transaction_options(thread_db* tdbb,
TriState wait, lock_timeout;
TriState isolation, read_only, rec_version, read_consistency;
bool anylock_write = false;
bool shared_snapshot = false;
++tpb;
@ -2745,6 +2749,14 @@ static void transaction_options(thread_db* tdbb,
ERR_post(Arg::Gds(isc_bad_tpb_content) <<
Arg::Gds(isc_tpb_multiple_txn_isolation));
if (shared_snapshot)
{
ERR_post(
Arg::Gds(isc_bad_tpb_content) <<
Arg::Gds(isc_tpb_conflicting_options) <<
Arg::Str("isc_tpb_consistency") << Arg::Str("isc_tpb_at_snapshot_number"));
}
transaction->tra_flags |= TRA_degree3;
transaction->tra_flags &= ~TRA_read_committed;
break;
@ -2763,6 +2775,14 @@ static void transaction_options(thread_db* tdbb,
ERR_post(Arg::Gds(isc_bad_tpb_content) <<
Arg::Gds(isc_tpb_multiple_txn_isolation));
if (shared_snapshot)
{
ERR_post(
Arg::Gds(isc_bad_tpb_content) <<
Arg::Gds(isc_tpb_conflicting_options) <<
Arg::Str("isc_tpb_read_committed") << Arg::Str("isc_tpb_at_snapshot_number"));
}
transaction->tra_flags &= ~TRA_degree3;
transaction->tra_flags |= TRA_read_committed;
break;
@ -3143,6 +3163,70 @@ static void transaction_options(thread_db* tdbb,
}
break;
case isc_tpb_at_snapshot_number:
{
const char* option_name = "isc_tpb_at_snapshot_number";
if (shared_snapshot)
{
ERR_post(
Arg::Gds(isc_bad_tpb_content) <<
Arg::Gds(isc_tpb_multiple_spec) << Arg::Str(option_name));
}
if (transaction->tra_flags & TRA_read_committed)
{
ERR_post(
Arg::Gds(isc_bad_tpb_content) <<
Arg::Gds(isc_tpb_conflicting_options) <<
Arg::Str(option_name) << Arg::Str("isc_tpb_read_committed"));
}
if (transaction->tra_flags & TRA_degree3)
{
ERR_post(
Arg::Gds(isc_bad_tpb_content) <<
Arg::Gds(isc_tpb_conflicting_options) <<
Arg::Str(option_name) << Arg::Str("isc_tpb_consistency"));
}
if (tpb >= end)
{
ERR_post(
Arg::Gds(isc_bad_tpb_content) <<
Arg::Gds(isc_tpb_missing_len) << Arg::Str(option_name));
}
const USHORT len = *tpb++;
if (tpb >= end && len > 0)
{
ERR_post(
Arg::Gds(isc_bad_tpb_content) <<
Arg::Gds(isc_tpb_missing_value) << Arg::Num(len) << Arg::Str(option_name));
}
if (end - tpb < len || len == 0)
{
ERR_post(
Arg::Gds(isc_bad_tpb_content) <<
Arg::Gds(isc_tpb_corrupt_len) << Arg::Num(len) << Arg::Str(option_name));
}
shared_snapshot = true;
transaction->tra_snapshot_number = isc_portable_integer(tpb, len);
if (transaction->tra_snapshot_number == 0)
{
ERR_post(
Arg::Gds(isc_bad_tpb_content) <<
Arg::Str(option_name));
}
tpb += len;
}
break;
default:
ERR_post(Arg::Gds(isc_bad_tpb_form));
}
@ -3326,9 +3410,16 @@ static void transaction_start(thread_db* tdbb, jrd_tra* trans)
if (!(trans->tra_flags & TRA_read_committed))
{
trans->tra_snapshot_handle =
dbb->dbb_tip_cache->beginSnapshot(tdbb,
attachment->att_attachment_id, &trans->tra_snapshot_number);
try
{
trans->tra_snapshot_handle = dbb->dbb_tip_cache->beginSnapshot(
tdbb, attachment->att_attachment_id, trans->tra_snapshot_number);
}
catch (const Firebird::Exception&)
{
LCK_release(tdbb, lock);
throw;
}
}
// Next task is to find the oldest active transaction on the system. This

View File

@ -1,7 +1,7 @@
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
--
('2019-01-14 20:23:00', 'JRD', 0, 932)
('2019-03-01 12:35:00', 'JRD', 0, 933)
('2015-03-17 18:33:00', 'QLI', 1, 533)
('2018-03-17 12:00:00', 'GFIX', 3, 136)
('1996-11-07 13:39:40', 'GPRE', 4, 1)

View File

@ -1039,6 +1039,7 @@ Data source : @4', NULL, NULL)
('tom_rsa_verify', NULL, 'SysFunction.cpp', NULL, 0, 929, NULL, 'Verifying RSA-signed data', NULL, NULL);
('tom_chacha_key', NULL, 'SysFunction.cpp', NULL, 0, 930, NULL, 'Invalid key length @1, need 16 or 32', NULL, NULL);
('bad_repl_handle', NULL, 'jrd.cpp', NULL, 0, 931, NULL, 'invalid replicator handle', NULL, NULL);
('tra_snapshot_does_not_exist', NULL, 'tpc.cpp', NULL, 0, 932, NULL, 'Transaction''s base snapshot number does not exist', NULL, NULL);
-- QLI
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);

View File

@ -938,6 +938,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
(-901, '22', '023', 0, 929, 'tom_rsa_verify', NULL, NULL)
(-901, '22', '023', 0, 930, 'tom_chacha_key', NULL, NULL)
(-901, '08', '003', 0, 931, 'bad_repl_handle', NULL, NULL)
(-901, '0B', '000', 0, 932, 'tra_snapshot_does_not_exist', NULL, NULL)
-- GFIX
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)

View File

@ -317,6 +317,7 @@ static const TOK tokens[] =
{TOK_NULLIF, "NULLIF", true},
{TOK_NULL, "NULL", false},
{TOK_NULLS, "NULLS", true},
{TOK_NUMBER, "NUMBER", true},
{TOK_NUMERIC, "NUMERIC", false},
{TOK_OCTET_LENGTH, "OCTET_LENGTH", false},
{TOK_OF, "OF", false},