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

Improvement CORE-5921 : Provide information about Global Commit Number, Commit Number of currently used database snapshot (if any) and Commit Numbers assigned to the committed transactions.

This commit is contained in:
hvlad 2018-09-23 15:00:59 +03:00
parent f463db457b
commit fded677e95
6 changed files with 112 additions and 0 deletions

View File

@ -733,6 +733,37 @@ Example:
select * from x order by rand(); select * from x order by rand();
--------------------
RDB$GET_TRANSACTION_CN
--------------------
(FB4 extension)
Function:
Returns commit number of given transaction.
Note, engine internally uses unsigned 8-bit integer for commit numbers,
while SQL language have no unsigned integers, thus one should be ready
to see negative numbers here (it is possible only if engine commits more
than 2^32 transactions since last database start, as global commit number
is reset at each restart).
There are some "special" values used for non-committed transactions and
transactions, committed before database was started:
0 - transaction is active,
1 - transaction committed before database started
-2 - transaction is dead (rolled back)
-1 - transaction is in limbo
See also README.read_consistency.md
Format:
RDB$SYSTEM_PRIVILEGE( <number> )
Examples:
select rdb$get_transaction_cn(current_transaction) from rdb$database;
select rdb$get_transaction_cn(123) from rdb$database;
-------------------- --------------------
RDB$SYSTEM_PRIVILEGE RDB$SYSTEM_PRIVILEGE
-------------------- --------------------

View File

@ -102,6 +102,13 @@ Usage:
| same as of CURRENT_ROLE pseudo-variable | same as of CURRENT_ROLE pseudo-variable
| |
ENGINE_VERSION | Engine version number, e.g. "2.1.0" (since V2.1) ENGINE_VERSION | Engine version number, e.g. "2.1.0" (since V2.1)
|
GLOBAL_CN | Most current value of global Commit Number counter
|
SNAPSHOT_CN | Value of Commit Number of currently database snapshot: either
| transaction level (for SNAPSHOT or CONSISTENCY transaction),
| or request level (for READ COMMITTED READ CONSISTENCY
| transaction). NULL, if snapshot is not exist.
Notes: Notes:
To prevent DoS attacks against Firebird Server you are not allowed to have To prevent DoS attacks against Firebird Server you are not allowed to have

View File

@ -630,6 +630,7 @@ using namespace Firebird;
%token <metaNamePtr> VARBINARY %token <metaNamePtr> VARBINARY
%token <metaNamePtr> WINDOW %token <metaNamePtr> WINDOW
%token <metaNamePtr> CONSISTENCY %token <metaNamePtr> CONSISTENCY
%token <metaNamePtr> RDB_GET_TRANSACTION_CN
// external connections pool management // external connections pool management
%token <metaNamePtr> CONNECTIONS %token <metaNamePtr> CONNECTIONS
@ -7787,6 +7788,7 @@ system_function_std_syntax
| POWER | POWER
| RAND | RAND
| RDB_GET_CONTEXT | RDB_GET_CONTEXT
| RDB_GET_TRANSACTION_CN
| RDB_ROLE_IN_USE | RDB_ROLE_IN_USE
| RDB_SET_CONTEXT | RDB_SET_CONTEXT
| REPLACE | REPLACE

View File

@ -46,6 +46,7 @@
#include "../jrd/mov_proto.h" #include "../jrd/mov_proto.h"
#include "../jrd/pag_proto.h" #include "../jrd/pag_proto.h"
#include "../jrd/tra_proto.h" #include "../jrd/tra_proto.h"
#include "../jrd/tpc_proto.h"
#include "../jrd/scl_proto.h" #include "../jrd/scl_proto.h"
#include "../common/os/guid.h" #include "../common/os/guid.h"
#include "../jrd/license.h" #include "../jrd/license.h"
@ -169,6 +170,7 @@ void setParamsDblDec(DataTypeUtilBase* dataTypeUtil, const SysFunction* function
void setParamsDecFloat(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsDecFloat(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
void setParamsFromList(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsFromList(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
void setParamsInteger(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsInteger(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
void setParamsInt64(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
void setParamsSecondInteger(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsSecondInteger(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args);
// specific setParams functions // specific setParams functions
@ -235,6 +237,7 @@ dsc* evlFloor(thread_db* tdbb, const SysFunction* function, const NestValueArray
dsc* evlGenUuid(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlGenUuid(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlGetContext(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlGetContext(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlSetContext(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlSetContext(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlGetTranCN(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlHash(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlHash(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlLeft(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlLeft(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlLnLog10(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlLnLog10(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
@ -276,6 +279,7 @@ const char
// SYSTEM namespace: global and database wise items // SYSTEM namespace: global and database wise items
ENGINE_VERSION[] = "ENGINE_VERSION", ENGINE_VERSION[] = "ENGINE_VERSION",
DATABASE_NAME[] = "DB_NAME", DATABASE_NAME[] = "DB_NAME",
GLOBAL_CN_NAME[] = "GLOBAL_CN",
EXT_CONN_POOL_SIZE[] = "EXT_CONN_POOL_SIZE", EXT_CONN_POOL_SIZE[] = "EXT_CONN_POOL_SIZE",
EXT_CONN_POOL_IDLE[] = "EXT_CONN_POOL_IDLE_COUNT", EXT_CONN_POOL_IDLE[] = "EXT_CONN_POOL_IDLE_COUNT",
EXT_CONN_POOL_ACTIVE[] = "EXT_CONN_POOL_ACTIVE_COUNT", EXT_CONN_POOL_ACTIVE[] = "EXT_CONN_POOL_ACTIVE_COUNT",
@ -298,6 +302,7 @@ const char
ISOLATION_LEVEL_NAME[] = "ISOLATION_LEVEL", ISOLATION_LEVEL_NAME[] = "ISOLATION_LEVEL",
LOCK_TIMEOUT_NAME[] = "LOCK_TIMEOUT", LOCK_TIMEOUT_NAME[] = "LOCK_TIMEOUT",
READ_ONLY_NAME[] = "READ_ONLY", READ_ONLY_NAME[] = "READ_ONLY",
SNAPSHOT_CN_NAME[] = "SNAPSHOT_CN",
// DDL_TRIGGER namespace // DDL_TRIGGER namespace
DDL_EVENT_NAME[] = "DDL_EVENT", DDL_EVENT_NAME[] = "DDL_EVENT",
EVENT_TYPE_NAME[] = "EVENT_TYPE", EVENT_TYPE_NAME[] = "EVENT_TYPE",
@ -473,6 +478,16 @@ void setParamsInteger(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc*
} }
void setParamsInt64(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args)
{
for (int i = 0; i < argsCount; ++i)
{
if (args[i]->isUnknown())
args[i]->makeInt64(0);
}
}
void setParamsSecondInteger(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args) void setParamsSecondInteger(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args)
{ {
if (argsCount >= 2) if (argsCount >= 2)
@ -2685,6 +2700,24 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar
resultStr.printf("%" SLONGFORMAT, transaction->tra_lock_timeout); resultStr.printf("%" SLONGFORMAT, transaction->tra_lock_timeout);
else if (nameStr == READ_ONLY_NAME) else if (nameStr == READ_ONLY_NAME)
resultStr = (transaction->tra_flags & TRA_readonly) ? TRUE_VALUE : FALSE_VALUE; resultStr = (transaction->tra_flags & TRA_readonly) ? TRUE_VALUE : FALSE_VALUE;
else if (nameStr == GLOBAL_CN_NAME)
resultStr.printf("%" SQUADFORMAT, dbb->dbb_tip_cache->getGlobalCommitNumber());
else if (nameStr == SNAPSHOT_CN_NAME)
{
if (!(transaction->tra_flags & TRA_read_committed))
resultStr.printf("%" SQUADFORMAT, transaction->tra_snapshot_number);
else if ((transaction->tra_flags & TRA_read_committed) &&
(transaction->tra_flags & TRA_read_consistency))
{
jrd_req* snapshot_req = request->req_snapshot.m_owner;
if (snapshot_req)
resultStr.printf("%" SQUADFORMAT, snapshot_req->req_snapshot.m_number);
else
return NULL;
}
else
return NULL;
}
else if (nameStr == EXT_CONN_POOL_SIZE) else if (nameStr == EXT_CONN_POOL_SIZE)
resultStr.printf("%d", EDS::Manager::getConnPool()->getMaxCount()); resultStr.printf("%d", EDS::Manager::getConnPool()->getMaxCount());
else if (nameStr == EXT_CONN_POOL_IDLE) else if (nameStr == EXT_CONN_POOL_IDLE)
@ -2890,6 +2923,38 @@ dsc* evlSetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar
} }
dsc* evlGetTranCN(thread_db* tdbb, const SysFunction* function, const NestValueArray& args,
impure_value* impure)
{
fb_assert(args.getCount() == 1);
Database* dbb = tdbb->getDatabase();
jrd_req* request = tdbb->getRequest();
request->req_flags &= ~req_null;
const dsc* value = EVL_expr(tdbb, request, args[0]);
if (request->req_flags & req_null)
return NULL;
TraNumber traNum = MOV_get_int64(tdbb, value, 0);
if (traNum > dbb->dbb_next_transaction)
{
request->req_flags |= req_null;
return NULL;
}
CommitNumber cn = dbb->dbb_tip_cache->snapshotState(tdbb, traNum);
dsc result;
result.makeInt64(0, (SINT64*)&cn);
EVL_make_value(tdbb, &result, impure);
request->req_flags &= ~req_null;
return &impure->vlu_desc;
}
dsc* evlHash(thread_db* tdbb, const SysFunction*, const NestValueArray& args, dsc* evlHash(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
impure_value* impure) impure_value* impure)
{ {
@ -4565,6 +4630,7 @@ const SysFunction SysFunction::functions[] =
{"QUANTIZE", 2, 2, setParamsDecFloat, makeDecFloatResult, evlQuantize, NULL}, {"QUANTIZE", 2, 2, setParamsDecFloat, makeDecFloatResult, evlQuantize, NULL},
{"RAND", 0, 0, NULL, makeDoubleResult, evlRand, NULL}, {"RAND", 0, 0, NULL, makeDoubleResult, evlRand, NULL},
{RDB_GET_CONTEXT, 2, 2, setParamsGetSetContext, makeGetSetContext, evlGetContext, NULL}, {RDB_GET_CONTEXT, 2, 2, setParamsGetSetContext, makeGetSetContext, evlGetContext, NULL},
{"RDB$GET_TRANSACTION_CN", 1, 1, setParamsInt64, makeInt64Result, evlGetTranCN, NULL},
{"RDB$ROLE_IN_USE", 1, 1, setParamsAsciiVal, makeBooleanResult, evlRoleInUse, NULL}, {"RDB$ROLE_IN_USE", 1, 1, setParamsAsciiVal, makeBooleanResult, evlRoleInUse, NULL},
{RDB_SET_CONTEXT, 3, 3, setParamsGetSetContext, makeGetSetContext, evlSetContext, NULL}, {RDB_SET_CONTEXT, 3, 3, setParamsGetSetContext, makeGetSetContext, evlSetContext, NULL},
{"RDB$SYSTEM_PRIVILEGE", 1, 1, NULL, makeBooleanResult, evlSystemPrivilege, NULL}, {"RDB$SYSTEM_PRIVILEGE", 1, 1, NULL, makeBooleanResult, evlSystemPrivilege, NULL},

View File

@ -140,6 +140,11 @@ public:
//void assignLatestTransactionId(TraNumber number); //void assignLatestTransactionId(TraNumber number);
void assignLatestAttachmentId(AttNumber number); void assignLatestAttachmentId(AttNumber number);
CommitNumber getGlobalCommitNumber() const
{
return m_tpcHeader->getHeader()->latest_commit_number.load(std::memory_order_acquire);
}
private: private:
class GlobalTpcHeader : public Firebird::MemoryHeader class GlobalTpcHeader : public Firebird::MemoryHeader
{ {

View File

@ -355,6 +355,7 @@ static const TOK tokens[] =
{TOK_DB_KEY, "RDB$DB_KEY", false}, {TOK_DB_KEY, "RDB$DB_KEY", false},
{TOK_RDB_ERROR, "RDB$ERROR", false}, {TOK_RDB_ERROR, "RDB$ERROR", false},
{TOK_RDB_GET_CONTEXT, "RDB$GET_CONTEXT", false}, {TOK_RDB_GET_CONTEXT, "RDB$GET_CONTEXT", false},
{TOK_RDB_GET_TRANSACTION_CN, "RDB$GET_TRANSACTION_CN", false},
{TOK_RDB_RECORD_VERSION, "RDB$RECORD_VERSION", false}, {TOK_RDB_RECORD_VERSION, "RDB$RECORD_VERSION", false},
{TOK_RDB_ROLE_IN_USE, "RDB$ROLE_IN_USE", false}, {TOK_RDB_ROLE_IN_USE, "RDB$ROLE_IN_USE", false},
{TOK_RDB_SET_CONTEXT, "RDB$SET_CONTEXT", false}, {TOK_RDB_SET_CONTEXT, "RDB$SET_CONTEXT", false},