diff --git a/README.md b/README.md index d31461ec44e..f7ebf9e5535 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ [![Build Status (GitHub)](https://github.com/FirebirdSQL/firebird/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/FirebirdSQL/firebird/actions/workflows/main.yml?query=branch%3Amaster) [![Build Status (AppVeyor)](https://ci.appveyor.com/api/projects/status/github/FirebirdSQL/firebird?branch=master&svg=true)](https://ci.appveyor.com/project/FirebirdSQL/firebird) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/FirebirdSQL/firebird) # Firebird README diff --git a/builds/install/arch-specific/android/BuildFinalPackage.sh b/builds/install/arch-specific/android/BuildFinalPackage.sh index 94518b77e20..c07c9d37a1d 100755 --- a/builds/install/arch-specific/android/BuildFinalPackage.sh +++ b/builds/install/arch-specific/android/BuildFinalPackage.sh @@ -45,6 +45,23 @@ $ANDROID_HOME/platform-tools/adb -s $AndroidDeviceName push gen/$InitialDebugTar $ANDROID_HOME/platform-tools/adb -s $AndroidDeviceName shell "(cd $AndroidDir && tar xvf $InitialDebugTar)" $ANDROID_HOME/platform-tools/adb -s $AndroidDeviceName shell "(cd $AndroidDir/firebird && ./common_test --log_level=error && ./libEngine14_test --log_level=error && ./isql_test --log_level=error)" $ANDROID_HOME/platform-tools/adb -s $AndroidDeviceName shell "(cd $AndroidDir/firebird && ./AfterUntar.sh)" + +# Verify ICU works +$ANDROID_HOME/platform-tools/adb -s $AndroidDeviceName shell <nul $(API_H_FILE): $(IDL_FILE) $(CLOOP) $(IDL_FILE) c++ $@ IDL_FB_INTERFACES_H Firebird I -$(RPL_AWK): $(RPL_AWK_SRC) +$(RPL_AWK): $(RPL_AWK_SRC) $(UTL_TMP_DIR) # NMAKE strips trailing backslash during macro substitution that's why it is here and not in definition. $(CPP) /Fe$@ /Fo$(UTL_TMP_DIR)\ $(RPL_AWK_SRC) -$(RPL_GREP): $(RPL_GREP_SRC) +$(RPL_GREP): $(RPL_GREP_SRC) $(UTL_TMP_DIR) $(CPP) /Fe$@ /Fo$(UTL_TMP_DIR)\ $(RPL_GREP_SRC) $(FB_GEN_DIR)\iberror.pas: $(ERR_CONSTS_PAS) $(FB_ROOT_PATH)\src\include\firebird\impl\msg\*.h diff --git a/doc/README.trace_services b/doc/README.trace_services index a21aec216fc..f88a337adea 100644 --- a/doc/README.trace_services +++ b/doc/README.trace_services @@ -1,4 +1,4 @@ - + Trace and audit services. Firebird 2.5 offers new trace and audit facilities. These new abilities allow @@ -12,7 +12,7 @@ engine. List of events to trace, which data items to trace and placement of trace output is specified by trace configuration when trace session is created. There are two kinds of trace sessions : system audit and user trace. - + System audit session is started by the engine itself and obtains configuration from the text file. The name of this file is set via new setting in firebird.conf ("AuditTraceConfigFile") and by default has empty value, i.e. no system audit @@ -44,7 +44,7 @@ session. When application reads part of the output so output size stay less than When application decides to stop its trace session it just does detach from service. Also there is ability to manage trace sessions (suspend\resume\stop). -Administrators are allowed to manage any trace session while ordinary users are +Administrators are allowed to manage any trace session while ordinary users are allowed to manage their own trace sessions only. If user trace session was created by ordinary user it will trace only @@ -65,9 +65,9 @@ plugin is responsible for logging these events in some form. There is "standard" implementation of trace plugin, fbtrace.dll (.so) located in \plugins folder. - - There is new specialized standalone utility to work with trace services : + + There is new specialized standalone utility to work with trace services : fbtracemgr. It has the following command line switches : Action switches : @@ -94,20 +94,20 @@ Also, it prints usage screen if run without parameters. Examples - + I. Sample configuration files for user trace sessions: - + a) Trace prepare, free and execution of all statements within connection 12345 database { - enabled true - connection_id 12345 - log_statement_prepare true - log_statement_free true - log_statement_start true - log_statement_finish true - time_threshold 0 + enabled = true + connection_id = 12345 + log_statement_prepare= true + log_statement_free = true + log_statement_start = true + log_statement_finish = true + time_threshold = 0 } b) Trace all connections of given user to database mydatabase.fdb @@ -116,28 +116,28 @@ b) Trace all connections of given user to database mydatabase.fdb database = %[\\/]mydatabase.fdb { - enabled true - include_filter (%)(INSERT|UPDATE|DELETE)(%) - log_statement_finish true - log_procedure_finish true - log_trigger_finish true - print_plan true - print_perf true - time_threshold 0 + enabled = true + include_filter = (%)(INSERT|UPDATE|DELETE)(%) + log_statement_finish = true + log_procedure_finish = true + log_trigger_finish = true + print_plan = true + print_perf = true + time_threshold = 0 } - + c) Trace connections and transactions in all databases except of security database database { - enabled true - log_connections true - log_transactions true + enabled = true + log_connections = true + log_transactions = true } database = security.db { - enabled false + enabled = false } @@ -148,27 +148,27 @@ a) Start user trace named "My trace" using configuration file fbtrace.conf and r its output on the screen : fbtracemgr -se service_mgr -start -name "My trace" -config fbtrace.conf - + To stop this trace session press Ctrl+C at fbtracemgr console window. Or, in -another console : list sessions and look for interesting session ID (b) and stop it +another console : list sessions and look for interesting session ID (b) and stop it using this found ID (e). b) List trace sessions fbtracemgr -se service_mgr -list - + c) Suspend trace session with ID 1 fbtracemgr -se service_mgr -suspend -id 1 - + d) Resume trace session with ID 1 fbtracemgr -se service_mgr -resume -id 1 - + e) Stop trace session with ID 1 fbtracemgr -se service_mgr -stop -id 1 - + There are three general use cases : diff --git a/doc/Using_OO_API.md b/doc/Using_OO_API.md index 4347c488fc4..cf543d3a84a 100644 --- a/doc/Using_OO_API.md +++ b/doc/Using_OO_API.md @@ -2101,3 +2101,44 @@ struct FbVarChar This document is currently missing 2 types of plugins – ExternalEngine and Trace. Information about them will be made available in next release of it. + +# Trace plugin + +_TODO_ + +# Trace objects + +_TODO_ + +# Trace performance statistics + +Trace plugin may retrieve various performance statistics available using the `getPerfStats()` method of the trace object, which returns a pointer to the `IPerformanceStats` interface. + +```cpp +IPerformanceStats* stats = statement->getPerfStats(); +``` + +The returned pointer may be `nullptr` if the corresponding trace object is not in the terminate state yet (i.e. still active / being executed). + + PerformanceStats interface: + +- ISC_UINT64 getElapsedTime() - returns the elapsed time, in milliseconds +- ISC_UINT64 getFetchedRecords() - returns number of records fetched during execution +- IPerformanceCounters* getCounters(unsigned group) - returns the requested performance counters group + +The following groups of performance counters are currently supported: + +- COUNTER_GROUP_PAGES - per-pagespace counters +- COUNTER_GROUP_TABLES - per-table counters + +If `getCounters()` is called with a counter group not supported by the implementation, `nullptr` is returned. + + PerformanceCounters interface: + +- unsigned getObjectCount() - returns number of objects (e.g. tables) containing non-zero performance counters +- unsigned getMaxCounterIndex() - returns maximum index number of the performance counters supported by the implementation (it's the same for all objects of the same group) +- unsigned getObjectId(unsigned index) - returns ID of the specified object +- const char* getObjectName(unsigned index) - returns name of the specified object +- const ISC_INT64* getObjectCounters(unsigned index) - returns pointer to the vector of performance counters (containing getMaxCounterIndex() + 1 elements) of the specified object + +The returned pointer to the vector (as well as the whole instance of `PerformanceStats`) is valid until the object used to obtain the statistics (using the `getPerfStats()` method) is destroyed. diff --git a/doc/sql.extensions/README.listagg b/doc/sql.extensions/README.listagg index 03b432fbdd6..2faa53ebeaf 100644 --- a/doc/sql.extensions/README.listagg +++ b/doc/sql.extensions/README.listagg @@ -50,7 +50,7 @@ INSERT INTO TEST_T values(3, 'C', 'A', 'L', true, 'Ж'); INSERT INTO TEST_T values(4, 'D', 'B', 'K', true, 'Й'); COMMIT; -SELECT LISTAGG (ALL COL4, ':') AS FROM TEST_T; +SELECT LISTAGG (ALL COL4, ':') FROM TEST_T; ======= J:I:L:K diff --git a/doc/sql.extensions/README.percentile_disc_cont.md b/doc/sql.extensions/README.percentile_disc_cont.md new file mode 100644 index 00000000000..47997023665 --- /dev/null +++ b/doc/sql.extensions/README.percentile_disc_cont.md @@ -0,0 +1,187 @@ +# PERCENTILE_DISC and PERCENTILE_CONT functions + +The `PERCENTILE_CONT` and `PERCENTILE_DISC` functions are known as inverse distribution functions. +These functions operate on an ordered set. Both functions can be used as aggregate or window functions. + +## PERCENTILE_DISC + +`PERCENTILE_DISC` is an inverse distribution function that assumes a discrete distribution model. +It takes a percentile value and a sort specification and returns an element from the set. +Nulls are ignored in the calculation. + +Syntax for the `PERCENTILE_DISC` function as an aggregate function. + +``` +PERCENTILE_DISC() WITHIN GROUP (ORDER BY [ASC | DESC]) +``` + +Syntax for the `PERCENTILE_DISC` function as an window function. + +``` +PERCENTILE_DISC() WITHIN GROUP (ORDER BY [ASC | DESC]) + OVER (PARTITION BY ) +``` + +The first argument `` must evaluate to a numeric value between 0 and 1, because it is a percentile value. +This expression must be constant within each aggregate group. +The `ORDER BY` clause takes a single expression that can be of any type that can be sorted. + +The function `PERCENTILE_DISC` returns a value of the same type as the argument in `ORDER BY`. + +For a given percentile value `P`, `PERCENTILE_DISC` sorts the values of the expression in the `ORDER BY` clause and +returns the value with the smallest `CUME_DIST` value (with respect to the same sort specification) +that is greater than or equal to `P`. + +### Analytic Example + +```sql +SELECT + DEPT_NO, + SALARY, + CUME_DIST() OVER(PARTITION BY DEPT_NO ORDER BY SALARY) AS "CUME_DIST", + PERCENTILE_DISC(0.5) WITHIN GROUP(ORDER BY SALARY) + OVER(PARTITION BY DEPT_NO) AS MEDIAN_DISC +FROM EMPLOYEE +WHERE DEPT_NO < 600 +ORDER BY 1, 2; +``` + +``` +DEPT_NO SALARY CUME_DIST MEDIAN_DISC +======= ===================== ======================= ===================== +000 53793.00 0.5000000000000000 53793.00 +000 212850.00 1.000000000000000 53793.00 +100 44000.00 0.5000000000000000 44000.00 +100 111262.50 1.000000000000000 44000.00 +110 61637.81 0.5000000000000000 61637.81 +110 68805.00 1.000000000000000 61637.81 +115 6000000.00 0.5000000000000000 6000000.00 +115 7480000.00 1.000000000000000 6000000.00 +120 22935.00 0.3333333333333333 33620.63 +120 33620.63 0.6666666666666666 33620.63 +120 39224.06 1.000000000000000 33620.63 +121 110000.00 1.000000000000000 110000.00 +123 38500.00 1.000000000000000 38500.00 +125 33000.00 1.000000000000000 33000.00 +130 86292.94 0.5000000000000000 86292.94 +130 102750.00 1.000000000000000 86292.94 +140 100914.00 1.000000000000000 100914.00 +180 42742.50 0.5000000000000000 42742.50 +180 64635.00 1.000000000000000 42742.50 +``` + +## PERCENTILE_CONT + +`PERCENTILE_CONT` is an inverse distribution function that assumes a continuous distribution model. +It takes a percentile value and a sort specification and returns an element from the set. +Nulls are ignored in the calculation. + +Syntax for the `PERCENTILE_CONT` function as an aggregate function. + +``` +PERCENTILE_CONT() WITHIN GROUP (ORDER BY [ASC | DESC]) +``` + +Syntax for the `PERCENTILE_CONT` function as an window function. + +``` +PERCENTILE_CONT() WITHIN GROUP (ORDER BY [ASC | DESC]) + OVER (PARTITION BY ) +``` + +The first argument `` must evaluate to a numeric value between 0 and 1, because it is a percentile value. +This expression must be constant within each aggregate group. +The `ORDER BY` clause takes a single expression, which must be of numeric type to perform interpolation. + +The `PERCENTILE_CONT` function returns a value of type `DOUBLE PRECISION` or `DECFLOAT(34)` depending on the type +of the argument in the `ORDER BY` clause. A value of type `DECFLOAT(34)` is returned if `ORDER BY` contains +an expression of one of the types `INT128`, `NUMERIC(38, x)` or `DECFLOAT(16 | 34)`, otherwise - `DOUBLE PRECISION`. + +The result of `PERCENTILE_CONT` is computed by linear interpolation between values after ordering them. +Using the percentile value (`P`) and the number of rows (`N`) in the aggregation group, you can compute +the row number you are interested in after ordering the rows with respect to the sort specification. +This row number (`RN`) is computed according to the formula `RN = (1 + (P * (N - 1))`. +The final result of the aggregate function is computed by linear interpolation between the values from rows +at row numbers `CRN = CEILING(RN)` and `FRN = FLOOR(RN)`. + +``` +function f(N) ::= value of expression from row at N + +if (CRN = FRN = RN) then + return f(RN) +else + return (CRN - RN) * f(FRN) + (RN - FRN) * f(CRN) +``` + +### Analytic Example + +```sql +SELECT + DEPT_NO, + SALARY, + PERCENT_RANK() OVER(PARTITION BY DEPT_NO ORDER BY SALARY) AS "PERCENT_RANK", + PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY SALARY) + OVER(PARTITION BY DEPT_NO) AS MEDIAN_CONT +FROM EMPLOYEE +WHERE DEPT_NO < 600 +ORDER BY 1, 2; +``` + +``` +DEPT_NO SALARY PERCENT_RANK MEDIAN_CONT +======= ===================== ======================= ======================= +000 53793.00 0.000000000000000 133321.5000000000 +000 212850.00 1.000000000000000 133321.5000000000 +100 44000.00 0.000000000000000 77631.25000000000 +100 111262.50 1.000000000000000 77631.25000000000 +110 61637.81 0.000000000000000 65221.40500000000 +110 68805.00 1.000000000000000 65221.40500000000 +115 6000000.00 0.000000000000000 6740000.000000000 +115 7480000.00 1.000000000000000 6740000.000000000 +120 22935.00 0.000000000000000 33620.63000000000 +120 33620.63 0.5000000000000000 33620.63000000000 +120 39224.06 0.2500000000000000 33620.63000000000 +121 110000.00 0.000000000000000 110000.0000000000 +123 38500.00 0.000000000000000 38500.00000000000 +125 33000.00 0.000000000000000 33000.00000000000 +130 86292.94 0.000000000000000 94521.47000000000 +130 102750.00 1.000000000000000 94521.47000000000 +140 100914.00 0.000000000000000 100914.0000000000 +180 42742.50 0.000000000000000 53688.75000000000 +180 64635.00 1.000000000000000 53688.75000000000 +``` + +## An example of using both aggregate functions + +```sql +SELECT + DEPT_NO, + PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY SALARY) AS MEDIAN_CONT, + PERCENTILE_DISC(0.5) WITHIN GROUP(ORDER BY SALARY) AS MEDIAN_DISC +FROM EMPLOYEE +GROUP BY DEPT_NO; +``` + +``` +DEPT_NO MEDIAN_CONT MEDIAN_DISC +======= ======================= ===================== +000 133321.5000000000 53793.00 +100 77631.25000000000 44000.00 +110 65221.40500000000 61637.81 +115 6740000.000000000 6000000.00 +120 33620.63000000000 33620.63 +121 110000.0000000000 110000.00 +123 38500.00000000000 38500.00 +125 33000.00000000000 33000.00 +130 94521.47000000000 86292.94 +140 100914.0000000000 100914.00 +180 53688.75000000000 42742.50 +600 66450.00000000000 27000.00 +621 71619.75000000000 62550.00 +622 53167.50000000000 53167.50 +623 60000.00000000000 60000.00 +670 71268.75000000000 31275.00 +671 81810.19000000000 81810.19 +672 45647.50000000000 35000.00 +900 92791.31500000000 69482.63 +``` diff --git a/extern/icu/tzdata/be.zip b/extern/icu/tzdata/be.zip index 8f2df2bf69d..0b67b5c835b 100644 Binary files a/extern/icu/tzdata/be.zip and b/extern/icu/tzdata/be.zip differ diff --git a/extern/icu/tzdata/le.zip b/extern/icu/tzdata/le.zip index cd7d698a57e..08c0fe324a8 100644 Binary files a/extern/icu/tzdata/le.zip and b/extern/icu/tzdata/le.zip differ diff --git a/extern/icu/tzdata/version.txt b/extern/icu/tzdata/version.txt index ef468adcecf..cb3be9ab63e 100644 --- a/extern/icu/tzdata/version.txt +++ b/extern/icu/tzdata/version.txt @@ -1 +1 @@ -2025b +2025c diff --git a/src/alice/tdr.cpp b/src/alice/tdr.cpp index 7b3ef05adc5..c8dc9b4d31c 100644 --- a/src/alice/tdr.cpp +++ b/src/alice/tdr.cpp @@ -296,7 +296,6 @@ void TDR_list_limbo(FB_API_HANDLE handle, const TEXT* name, const SINT64 switche if (item == isc_info_end) break; - const USHORT length = (USHORT) p.getClumpLength(); switch (item) { case isc_info_limbo: diff --git a/src/burp/backup.epp b/src/burp/backup.epp index 2cbb866d51d..b69e1b55f72 100644 --- a/src/burp/backup.epp +++ b/src/burp/backup.epp @@ -1940,6 +1940,7 @@ void put_relation( burp_rel* relation) burp_fld* unaligned = NULL; burp_fld* aligned4 = NULL; burp_fld* aligned8 = NULL; + burp_fld* aligned16 = NULL; burp_fld* fields = get_fields(relation); @@ -1951,7 +1952,13 @@ void put_relation( burp_rel* relation) USHORT l = field->fld_length; if (field->fld_type == blr_varying) l += sizeof(USHORT); - if (!(l & 7)) + + if (!(l & 15)) + { + field->fld_next = aligned16; + aligned16 = field; + } + else if (!(l & 7)) { field->fld_next = aligned8; aligned8 = field; @@ -2005,6 +2012,13 @@ void put_relation( burp_rel* relation) relation->rel_fields = field; } + while ((field = aligned16)) + { + aligned16 = field->fld_next; + field->fld_next = relation->rel_fields; + relation->rel_fields = field; + } + // Now write the fields in what will become physical backup order for (field = relation->rel_fields; field; field = field->fld_next) diff --git a/src/burp/burp.cpp b/src/burp/burp.cpp index a8086d659fe..a1b7f4d4598 100644 --- a/src/burp/burp.cpp +++ b/src/burp/burp.cpp @@ -1843,7 +1843,6 @@ void BURP_print_warning(const Firebird::IStatus* status, bool printErrorAsWarnin return; BurpMaster master; - BurpGlobals* tdgbl = master.get(); // print the warning message SCHAR s[1024]; diff --git a/src/burp/restore.epp b/src/burp/restore.epp index 1aecf4f1cb0..87a2ef423ed 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -132,7 +132,7 @@ bool get_collation(BurpGlobals* tdgbl); SLONG get_compressed(BurpGlobals* tdgbl, UCHAR* buffer, SLONG length); void get_data(BurpGlobals* tdgbl, burp_rel*, WriteRelationReq* req); bool get_exception(BurpGlobals* tdgbl); -burp_fld* get_field(BurpGlobals* tdgbl, burp_rel*); +burp_fld* get_field(BurpGlobals* tdgbl, burp_rel*, USHORT id); bool get_field_dimensions(BurpGlobals* tdgbl); bool get_files(BurpGlobals* tdgbl); bool get_filter(BurpGlobals* tdgbl); @@ -1332,7 +1332,7 @@ SLONG get_compressed(BurpGlobals* tdgbl, UCHAR* buffer, SLONG length) // msg 202: adjusting a decompression length error: invalid length %d was adjusted to %d count = -length; } - const UCHAR c = *p = get(tdgbl); + *p = get(tdgbl); ++p; length -= -count; } @@ -3806,7 +3806,7 @@ bool get_exception(BurpGlobals* tdgbl) } -burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation) +burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation, USHORT id) { /************************************** * @@ -3865,6 +3865,9 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation) // ODS 14 X.RDB$FIELD_SOURCE_SCHEMA_NAME.NULL = TRUE; + X.RDB$FIELD_ID.NULL = FALSE; + X.RDB$FIELD_ID = id; + if (relation->rel_name.schema.hasData()) { strcpy(X.RDB$SCHEMA_NAME, relation->rel_name.schema.c_str()); @@ -4084,6 +4087,9 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation) X.RDB$NULL_FLAG.NULL = TRUE; X.RDB$COLLATION_ID.NULL = TRUE; + X.RDB$FIELD_ID.NULL = FALSE; + X.RDB$FIELD_ID = id; + skip_init(&scan_next_attr); while (get_attribute(&attribute, tdgbl) != att_end) { @@ -8249,6 +8255,7 @@ bool get_relation(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTask* t // Eat up misc. records burp_fld* field = NULL; burp_fld** ptr = &relation->rel_fields; + USHORT id = 0; rec_type record; while (get_record(&record, tdgbl) != rec_data) @@ -8277,7 +8284,7 @@ bool get_relation(BurpGlobals* tdgbl, Coordinator* coord, RestoreRelationTask* t return true; case rec_field: - *ptr = field = get_field (tdgbl, relation); + *ptr = field = get_field(tdgbl, relation, id++); if (!field) return false; ptr = &field->fld_next; diff --git a/src/common/ParserTokens.h b/src/common/ParserTokens.h index 588252b429c..4440ccf55ff 100644 --- a/src/common/ParserTokens.h +++ b/src/common/ParserTokens.h @@ -373,6 +373,8 @@ PARSER_TOKEN(TOK_PARAMETER, "PARAMETER", false) PARSER_TOKEN(TOK_PARTITION, "PARTITION", true) PARSER_TOKEN(TOK_PASSWORD, "PASSWORD", true) PARSER_TOKEN(TOK_PERCENT_RANK, "PERCENT_RANK", true) +PARSER_TOKEN(TOK_PERCENTILE_CONT, "PERCENTILE_CONT", true) +PARSER_TOKEN(TOK_PERCENTILE_DISC, "PERCENTILE_DISC", true) PARSER_TOKEN(TOK_PI, "PI", true) PARSER_TOKEN(TOK_PKCS_1_5, "PKCS_1_5", true) PARSER_TOKEN(TOK_PLACING, "PLACING", true) diff --git a/src/common/ThreadStart.cpp b/src/common/ThreadStart.cpp index 2b1faded1b9..c066d4c526e 100644 --- a/src/common/ThreadStart.cpp +++ b/src/common/ThreadStart.cpp @@ -119,7 +119,6 @@ Thread Thread::start(ThreadEntryPoint* routine, void* arg, int priority_arg, Han **************************************/ pthread_t thread; pthread_t* p_thread = p_handle ? p_handle : &thread; - pthread_attr_t pattr; int state; #if defined (LINUX) || defined (FREEBSD) @@ -132,6 +131,7 @@ Thread Thread::start(ThreadEntryPoint* routine, void* arg, int priority_arg, Han Firebird::system_call_failed::raise("pthread_detach", state); } #else + pthread_attr_t pattr; state = pthread_attr_init(&pattr); if (state) Firebird::system_call_failed::raise("pthread_attr_init", state); diff --git a/src/common/TimeZones.h b/src/common/TimeZones.h index 655f213c94d..a49ade14e74 100644 --- a/src/common/TimeZones.h +++ b/src/common/TimeZones.h @@ -1,6 +1,6 @@ // The content of this file is generated with help of update-ids utility Do not edit. -static const char* BUILTIN_TIME_ZONE_VERSION = "2025b"; +static const char* BUILTIN_TIME_ZONE_VERSION = "2025c"; // Do not change order of items in this array! The index corresponds to a TimeZone ID, which must be fixed! static const char* BUILTIN_TIME_ZONE_LIST[] = { diff --git a/src/common/classes/DbImplementation.cpp b/src/common/classes/DbImplementation.cpp index dea39dd8112..9fb78c56da9 100644 --- a/src/common/classes/DbImplementation.cpp +++ b/src/common/classes/DbImplementation.cpp @@ -31,44 +31,44 @@ namespace { -static constexpr UCHAR CpuIntel = 0; -static constexpr UCHAR CpuAmd = 1; -static constexpr UCHAR CpuUltraSparc = 2; -static constexpr UCHAR CpuPowerPc = 3; -static constexpr UCHAR CpuPowerPc64 = 4; -static constexpr UCHAR CpuMipsel = 5; -static constexpr UCHAR CpuMips = 6; -static constexpr UCHAR CpuArm = 7; -static constexpr UCHAR CpuIa64 = 8; -static constexpr UCHAR CpuS390 = 9; -static constexpr UCHAR CpuS390x = 10; -static constexpr UCHAR CpuSh = 11; -static constexpr UCHAR CpuSheb = 12; -static constexpr UCHAR CpuHppa = 13; -static constexpr UCHAR CpuAlpha = 14; -static constexpr UCHAR CpuArm64 = 15; -static constexpr UCHAR CpuPowerPc64el = 16; -static constexpr UCHAR CpuM68k = 17; -static constexpr UCHAR CpuRiscV64 = 18; -static constexpr UCHAR CpuMips64el = 19; -static constexpr UCHAR CpuLoongArch = 20; - -static constexpr UCHAR OsWindows = 0; -static constexpr UCHAR OsLinux = 1; -static constexpr UCHAR OsDarwin = 2; -static constexpr UCHAR OsSolaris = 3; -static constexpr UCHAR OsHpux = 4; -static constexpr UCHAR OsAix = 5; -static constexpr UCHAR OsMms = 6; -static constexpr UCHAR OsFreeBsd = 7; -static constexpr UCHAR OsNetBsd = 8; - -static constexpr UCHAR CcMsvc = 0; -static constexpr UCHAR CcGcc = 1; -static constexpr UCHAR CcXlc = 2; -static constexpr UCHAR CcAcc = 3; -static constexpr UCHAR CcSunStudio = 4; -static constexpr UCHAR CcIcc = 5; +[[maybe_unused]] static constexpr UCHAR CpuIntel = 0; +[[maybe_unused]] static constexpr UCHAR CpuAmd = 1; +[[maybe_unused]] static constexpr UCHAR CpuUltraSparc = 2; +[[maybe_unused]] static constexpr UCHAR CpuPowerPc = 3; +[[maybe_unused]] static constexpr UCHAR CpuPowerPc64 = 4; +[[maybe_unused]] static constexpr UCHAR CpuMipsel = 5; +[[maybe_unused]] static constexpr UCHAR CpuMips = 6; +[[maybe_unused]] static constexpr UCHAR CpuArm = 7; +[[maybe_unused]] static constexpr UCHAR CpuIa64 = 8; +[[maybe_unused]] static constexpr UCHAR CpuS390 = 9; +[[maybe_unused]] static constexpr UCHAR CpuS390x = 10; +[[maybe_unused]] static constexpr UCHAR CpuSh = 11; +[[maybe_unused]] static constexpr UCHAR CpuSheb = 12; +[[maybe_unused]] static constexpr UCHAR CpuHppa = 13; +[[maybe_unused]] static constexpr UCHAR CpuAlpha = 14; +[[maybe_unused]] static constexpr UCHAR CpuArm64 = 15; +[[maybe_unused]] static constexpr UCHAR CpuPowerPc64el = 16; +[[maybe_unused]] static constexpr UCHAR CpuM68k = 17; +[[maybe_unused]] static constexpr UCHAR CpuRiscV64 = 18; +[[maybe_unused]] static constexpr UCHAR CpuMips64el = 19; +[[maybe_unused]] static constexpr UCHAR CpuLoongArch = 20; + +[[maybe_unused]] static constexpr UCHAR OsWindows = 0; +[[maybe_unused]] static constexpr UCHAR OsLinux = 1; +[[maybe_unused]] static constexpr UCHAR OsDarwin = 2; +[[maybe_unused]] static constexpr UCHAR OsSolaris = 3; +[[maybe_unused]] static constexpr UCHAR OsHpux = 4; +[[maybe_unused]] static constexpr UCHAR OsAix = 5; +[[maybe_unused]] static constexpr UCHAR OsMms = 6; +[[maybe_unused]] static constexpr UCHAR OsFreeBsd = 7; +[[maybe_unused]] static constexpr UCHAR OsNetBsd = 8; + +[[maybe_unused]] static constexpr UCHAR CcMsvc = 0; +[[maybe_unused]] static constexpr UCHAR CcGcc = 1; +[[maybe_unused]] static constexpr UCHAR CcXlc = 2; +[[maybe_unused]] static constexpr UCHAR CcAcc = 3; +[[maybe_unused]] static constexpr UCHAR CcSunStudio = 4; +[[maybe_unused]] static constexpr UCHAR CcIcc = 5; static constexpr UCHAR EndianLittle = 0; static constexpr UCHAR EndianBig = 1; diff --git a/src/common/classes/InternalMessageBuffer.cpp b/src/common/classes/InternalMessageBuffer.cpp index 5980b5583b9..2a2f82d961b 100644 --- a/src/common/classes/InternalMessageBuffer.cpp +++ b/src/common/classes/InternalMessageBuffer.cpp @@ -76,7 +76,6 @@ MetadataFromBlr::MetadataFromBlr(unsigned aBlrLength, const unsigned char* aBlr, fb_assert(!(count & 1)); count /= 2; - unsigned offset = 0; items.grow(count); for (unsigned index = 0; index < count; index++) diff --git a/src/common/classes/alloc.cpp b/src/common/classes/alloc.cpp index 8a1cfcfc1f1..4bb831d0d64 100644 --- a/src/common/classes/alloc.cpp +++ b/src/common/classes/alloc.cpp @@ -171,7 +171,6 @@ void corrupt(const char* text) noexcept } Firebird::Mutex* cache_mutex = NULL; -int dev_zero_fd = 0; #if defined(WIN_NT) size_t get_page_size() diff --git a/src/common/config/config.cpp b/src/common/config/config.cpp index a78de76ce10..0589fbd435d 100644 --- a/src/common/config/config.cpp +++ b/src/common/config/config.cpp @@ -624,13 +624,13 @@ bool Config::getDefaultValue(unsigned int key, string& str) #define DECLARE_GLOBAL_KEY(KEY) \ static_assert(entries[KEY].is_global, "Requires global key"); \ - const ConfigKey key = KEY; \ - const Config* config = getDefaultConfig(); + [[maybe_unused]] const ConfigKey key = KEY; \ + [[maybe_unused]] const Config* config = getDefaultConfig(); #define DECLARE_PER_DB_KEY(KEY) \ static_assert(!entries[KEY].is_global, "Requires per-database key"); \ - const ConfigKey key = KEY; \ - const Config* config = this; + [[maybe_unused]] const ConfigKey key = KEY; \ + [[maybe_unused]] const Config* config = this; int Config::getServerMode() { diff --git a/src/common/pretty.cpp b/src/common/pretty.cpp index 2b669fb8db0..44b883b7755 100644 --- a/src/common/pretty.cpp +++ b/src/common/pretty.cpp @@ -115,21 +115,6 @@ constexpr const char *sdl_table[] = NULL }; -constexpr const char *map_strings[] = -{ - "FIELD2", - "FIELD1", - "MESSAGE", - "TERMINATOR", - "TERMINATING_FIELD", - "OPAQUE", - "TRANSPARENT", - "TAG", - "SUB_FORM", - "ITEM_INDEX", - "SUB_FIELD" -}; - //____________________________________________________________ // // Pretty print create database parameter buffer thru callback routine. diff --git a/src/common/xdr.cpp b/src/common/xdr.cpp index adc4c47689b..73eb6a7eba0 100644 --- a/src/common/xdr.cpp +++ b/src/common/xdr.cpp @@ -91,8 +91,6 @@ inline bool_t PUTLONG(xdr_t* xdrs, const SLONG* lp) return xdrs->x_putbytes(reinterpret_cast(&l), 4); } -static SCHAR zeros[4] = { 0, 0, 0, 0 }; - bool_t xdr_hyper( xdr_t* xdrs, void* pi64) { diff --git a/src/dsql/AggNodes.cpp b/src/dsql/AggNodes.cpp index 4d86f3c82d7..a10c7368ada 100644 --- a/src/dsql/AggNodes.cpp +++ b/src/dsql/AggNodes.cpp @@ -359,6 +359,11 @@ AggNode* AggNode::pass2(thread_db* tdbb, CompilerScratch* csb) return this; } +void AggNode::makeSortDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) +{ + arg->getDesc(tdbb, csb, desc); +} + void AggNode::aggInit(thread_db* tdbb, Request* request) const { impure_value_ex* impure = request->getImpure(impureOffset); @@ -597,7 +602,7 @@ void AnyValueAggNode::aggPass(thread_db* tdbb, Request* request, dsc* desc) cons { const auto argValue = EVL_expr(tdbb, request, arg); - if (!argValue) + if (argValue) EVL_make_value(tdbb, argValue, impure); } @@ -935,8 +940,12 @@ DmlNode* ListAggNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* ListAggNode* node = FB_NEW_POOL(pool) ListAggNode(pool, (blrOp == blr_agg_list_distinct)); node->arg = PAR_parse_value(tdbb, csb); node->delimiter = PAR_parse_value(tdbb, csb); - if (csb->csb_blr_reader.peekByte() == blr_sort) - node->sort = PAR_sort(tdbb, csb, blr_sort, true); + if (csb->csb_blr_reader.peekByte() == blr_within_group_order) + { + csb->csb_blr_reader.getByte(); // skip blr_within_group_order + if (const auto count = csb->csb_blr_reader.getByte()) + node->sort = PAR_sort_internal(tdbb, csb, true, count); + } return node; } @@ -966,7 +975,7 @@ void ListAggNode::genBlr(DsqlCompilerScratch* dsqlScratch) { AggNode::genBlr(dsqlScratch); if (dsqlOrderClause) - GEN_sort(dsqlScratch, blr_sort, dsqlOrderClause); + GEN_sort(dsqlScratch, blr_within_group_order, dsqlOrderClause); } bool ListAggNode::setParameterType(DsqlCompilerScratch* dsqlScratch, @@ -1094,6 +1103,398 @@ AggNode* ListAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/ return node; } +//-------------------- + + +static AggNode::RegisterFactory1 percentileContAggInfo( + "PERCENTILE_CONT", PercentileAggNode::TYPE_PERCENTILE_CONT); +static AggNode::RegisterFactory1 percentileDiscAggInfo( + "PERCENTILE_DISC", PercentileAggNode::TYPE_PERCENTILE_DISC); + +PercentileAggNode::PercentileAggNode(MemoryPool& pool, PercentileType aType, ValueExprNode* aArg, + ValueListNode* aOrderClause) + : AggNode(pool, + (aType == PercentileAggNode::TYPE_PERCENTILE_CONT ? percentileContAggInfo : percentileDiscAggInfo), + false, false, aArg), + type(aType), + valueArg(nullptr), + dsqlOrderClause(aOrderClause) +{ + if (dsqlOrderClause) + valueArg = nodeAs(dsqlOrderClause->items[0])->value; +} + +void PercentileAggNode::parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned /*count*/) +{ + arg = PAR_parse_value(tdbb, csb); + valueArg = PAR_parse_value(tdbb, csb); + if (csb->csb_blr_reader.peekByte() == blr_within_group_order) + { + csb->csb_blr_reader.getByte(); // skip blr_within_group_order + if (const auto count = csb->csb_blr_reader.getByte()) + sort = PAR_sort_internal(tdbb, csb, true, count); + } +} + +bool PercentileAggNode::dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const +{ + if (!AggNode::dsqlMatch(dsqlScratch, other, ignoreMapCast)) + return false; + + const PercentileAggNode* o = nodeAs(other); + fb_assert(o); + return PASS1_node_match(dsqlScratch, dsqlOrderClause, o->dsqlOrderClause, ignoreMapCast); +} + +void PercentileAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) +{ + fb_assert(dsqlOrderClause); + if (dsqlOrderClause->items.getCount() != 1) + { + ERR_post(Arg::Gds(isc_percetile_only_one_sort_item)); + } + + if (type == TYPE_PERCENTILE_DISC) + { + // same type as order by argument + DsqlDescMaker::fromNode(dsqlScratch, desc, valueArg, true); + } + else + { + DsqlDescMaker::fromNode(dsqlScratch, desc, valueArg, true); + if (desc->isDecOrInt128()) + { + desc->makeDecimal128(); + desc->setNullable(true); + } + else + { + desc->makeDouble(); + desc->setNullable(true); + } + } +} + +void PercentileAggNode::genBlr(DsqlCompilerScratch* dsqlScratch) +{ + AggNode::genBlr(dsqlScratch); + if (dsqlOrderClause) + GEN_sort(dsqlScratch, blr_within_group_order, dsqlOrderClause); +} + +void PercentileAggNode::makeSortDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) +{ + valueArg->getDesc(tdbb, csb, desc); +} + +void PercentileAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) +{ + if (type == TYPE_PERCENTILE_DISC) + { + // same type as order by argument + valueArg->getDesc(tdbb, csb, desc); + } + else + { + valueArg->getDesc(tdbb, csb, desc); + if (desc->isDecOrInt128()) + { + desc->makeDecimal128(); + desc->setNullable(true); + } + else + { + desc->makeDouble(); + desc->setNullable(true); + } + } +} + +ValueExprNode* PercentileAggNode::copy(thread_db* tdbb, NodeCopier& copier) const +{ + PercentileAggNode* node = FB_NEW_POOL(*tdbb->getDefaultPool()) PercentileAggNode(*tdbb->getDefaultPool(), type); + + node->nodScale = nodScale; + node->arg = copier.copy(tdbb, arg); + node->valueArg = copier.copy(tdbb, valueArg); + node->sort = sort->copy(tdbb, copier); + + return node; +} + +AggNode* PercentileAggNode::pass2(thread_db* tdbb, CompilerScratch* csb) +{ + AggNode::pass2(tdbb, csb); + + // impure area for calculate border + percentileImpureOffset = csb->allocImpure(); + + return this; +} + +bool PercentileAggNode::dsqlInvalidReferenceFinder(InvalidReferenceFinder& visitor) +{ + bool invalid = false; + + if (!visitor.insideOwnMap) + { + // We are not in an aggregate from the same scope_level so + // check for valid fields inside this aggregate + invalid |= ExprNode::dsqlInvalidReferenceFinder(visitor); + } + + if (!visitor.insideHigherMap) + { + NodeRefsHolder holder(visitor.dsqlScratch->getPool()); + getChildren(holder, true); + + for (auto i : holder.refs) + { + // If there's another aggregate with the same scope_level or + // an higher one then it's a invalid aggregate, because + // aggregate-functions from the same context can't + // be part of each other. + if (Aggregate2Finder::find(visitor.dsqlScratch->getPool(), visitor.context->ctx_scope_level, + FIELD_MATCH_TYPE_EQUAL, false, *i)) + { + // Nested aggregate functions are not allowed + ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << + Arg::Gds(isc_dsql_agg_nested_err)); + } + } + + if (visitor.visit(**holder.refs.begin())) + { + // The percent argument must be constant within group + ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << + Arg::Gds(isc_argmustbe_const_within_group) << + ((type == TYPE_PERCENTILE_CONT) ? Arg::Str("PERCENTILE_CONT") : Arg::Str("PERCENTILE_DISC"))); + } + } + + return invalid; +} + +string PercentileAggNode::internalPrint(NodePrinter& printer) const +{ + AggNode::internalPrint(printer); + + NODE_PRINT(printer, type); + + return "PercentileAggNode"; +} + + +void PercentileAggNode::aggInit(thread_db* tdbb, Request* request) const +{ + AggNode::aggInit(tdbb, request); + + impure_value_ex* impure = request->getImpure(impureOffset); + impure->vlu_desc.dsc_dtype = 0; + impure->vlux_count = 0; + + PercentileImpure* percentileImpure = request->getImpure(percentileImpureOffset); + percentileImpure->vlux_count = 0; + percentileImpure->rn = 0; + percentileImpure->crn = 0; + percentileImpure->frn = 0; +} + +bool PercentileAggNode::aggPass(thread_db* tdbb, Request* request) const +{ + dsc* percenteDesc = nullptr; + percenteDesc = EVL_expr(tdbb, request, arg); + if (!percenteDesc) + return false; + + dsc* desc = nullptr; + desc = EVL_expr(tdbb, request, valueArg); + if (!desc) + return false; + + PercentileImpure* percentileImpure = request->getImpure(percentileImpureOffset); + if (percentileImpure->vlux_count++ == 0) // first call to aggPass() + { + if ((type == TYPE_PERCENTILE_CONT) && !desc->isNumeric()) + ERRD_post(Arg::Gds(isc_argmustbe_numeric_function) << Arg::Str("PERCENTILE_CONT")); + + if (desc->isBlob()) + ERRD_post(Arg::Gds(isc_blobnotsup) << Arg::Str("ORDER BY")); + + const auto percentileValue = MOV_get_double(tdbb, percenteDesc); + if ((percentileValue < 0) || (percentileValue > 1)) + { + if (type == TYPE_PERCENTILE_DISC) + ERRD_post(Arg::Gds(isc_sysf_argmustbe_range_inc0_1) << Arg::Str("PERCENTILE_DISC")); + else + ERRD_post(Arg::Gds(isc_sysf_argmustbe_range_inc0_1) << Arg::Str("PERCENTILE_CONT")); + } + + percentileImpure->percentile = percentileValue; + } + + if (sort) + { + fb_assert(asb); + // "Put" the value to sort. + impure_agg_sort* asbImpure = request->getImpure(asb->impure); + UCHAR* data; + asbImpure->iasb_sort->put(tdbb, reinterpret_cast(&data)); + + MOVE_CLEAR(data, asb->length); + + auto descOrder = asb->descOrder.begin(); + auto keyItem = asb->keyItems.begin(); + + for (auto& nodeOrder : sort->expressions) + { + dsc toDesc = *(descOrder++); + toDesc.dsc_address = data + (IPTR) toDesc.dsc_address; + if (const auto fromDsc = EVL_expr(tdbb, request, nodeOrder)) + { + if (IS_INTL_DATA(fromDsc)) + { + INTL_string_to_key(tdbb, INTL_TEXT_TO_INDEX(fromDsc->getTextType()), + fromDsc, &toDesc, INTL_KEY_UNIQUE); + } + else + MOV_move(tdbb, fromDsc, &toDesc); + } + else + *(data + keyItem->getSkdOffset()) = TRUE; + + // The first key for NULLS FIRST/LAST, the second key for the sorter + keyItem += 2; + } + + dsc toDesc = asb->desc; + toDesc.dsc_address = data + (IPTR) toDesc.dsc_address; + MOV_move(tdbb, desc, &toDesc); + + return true; + } + + return true; +} + +void PercentileAggNode::aggPass(thread_db* tdbb, Request* request, dsc* desc) const +{ + impure_value_ex* impure = request->getImpure(impureOffset); + PercentileImpure* percentileImpure = request->getImpure(percentileImpureOffset); + + if (type == TYPE_PERCENTILE_DISC) + { + if (impure->vlux_count++ == 0) + { + // calculate only ones + percentileImpure->rn = percentileImpure->percentile * percentileImpure->vlux_count; + percentileImpure->crn = MAX(static_cast(ceil(percentileImpure->rn)), 1); + } + + if (impure->vlux_count == percentileImpure->crn) + EVL_make_value(tdbb, desc, impure); + + } + else + { + if (impure->vlux_count++ == 0) + { + // calculate only ones + percentileImpure->rn = 1 + percentileImpure->percentile * (percentileImpure->vlux_count - 1); + percentileImpure->crn = static_cast(ceil(percentileImpure->rn)); + percentileImpure->frn = static_cast(floor(percentileImpure->rn)); + + if (desc->isDecOrInt128()) + { + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + Firebird::Decimal128 d128; + d128.set(0, decSt, 0); + impure->make_decimal128(d128); + } + else + impure->make_double(0); + } + + if (percentileImpure->crn == percentileImpure->frn) + { + if (impure->vlux_count == percentileImpure->frn) + { + if (desc->isDecOrInt128()) + { + const auto value = MOV_get_dec128(tdbb, desc); + impure->make_decimal128(value); + } + else + { + const auto value = MOV_get_double(tdbb, desc); + impure->make_double(value); + } + } + } + else + { + if (impure->vlux_count == percentileImpure->frn) + { + if (desc->isDecOrInt128()) + { + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + const auto value = MOV_get_dec128(tdbb, desc); + Firebird::Decimal128 d128; + d128.set(percentileImpure->crn - percentileImpure->rn, decSt); + const auto part = impure->vlu_misc.vlu_dec128.add(decSt, value.mul(decSt, d128)); + impure->make_decimal128(part); + } + else + { + const auto value = MOV_get_double(tdbb, desc); + impure->vlu_misc.vlu_double += value * (percentileImpure->crn - percentileImpure->rn); + } + } + + if (impure->vlux_count == percentileImpure->crn) + { + if (desc->isDecOrInt128()) + { + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + const auto value = MOV_get_dec128(tdbb, desc); + Firebird::Decimal128 d128; + d128.set(percentileImpure->rn - percentileImpure->frn, decSt); + const auto part = impure->vlu_misc.vlu_dec128.add(decSt, value.mul(decSt, d128)); + impure->make_decimal128(part); + } + else + { + const auto value = MOV_get_double(tdbb, desc); + impure->vlu_misc.vlu_double += value * (percentileImpure->rn - percentileImpure->frn); + } + } + } + } +} + +dsc* PercentileAggNode::aggExecute(thread_db* tdbb, Request* request) const +{ + impure_value_ex* impure = request->getImpure(impureOffset); + + if (!impure->vlux_count || !impure->vlu_desc.dsc_dtype) + return nullptr; + + return &impure->vlu_desc; +} + +AggNode* PercentileAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/ +{ + AggNode* node = FB_NEW_POOL(dsqlScratch->getPool()) PercentileAggNode(dsqlScratch->getPool(), type, + doDsqlPass(dsqlScratch, arg), + doDsqlPass(dsqlScratch, dsqlOrderClause) ); + + PASS1_set_parameter_type(dsqlScratch, node->arg, + [&](dsc* desc) { desc->makeDouble(); }, + false); + + return node; +} + //-------------------- diff --git a/src/dsql/AggNodes.h b/src/dsql/AggNodes.h index b9a186b698e..defcd89e3e4 100644 --- a/src/dsql/AggNodes.h +++ b/src/dsql/AggNodes.h @@ -134,6 +134,69 @@ class ListAggNode final : public AggNode NestConst dsqlOrderClause; }; +class PercentileAggNode final : public AggNode +{ +public: + enum PercentileType : UCHAR + { + TYPE_PERCENTILE_CONT, + TYPE_PERCENTILE_DISC + }; + + struct PercentileImpure + { + SINT64 vlux_count; + double percentile; + double rn; + SINT64 crn; + SINT64 frn; + }; + + explicit PercentileAggNode(MemoryPool& pool, PercentileType aType, ValueExprNode* aArg = nullptr, + ValueListNode* aOrderClause = nullptr); + + void parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned count) override; + + unsigned getCapabilities() const override + { + return CAP_WANTS_AGG_CALLS; + } + + bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const override; + + void getChildren(NodeRefsHolder& holder, bool dsql) const override + { + AggNode::getChildren(holder, dsql); + holder.add(valueArg); + } + + bool dsqlInvalidReferenceFinder(InvalidReferenceFinder& visitor) override; + + Firebird::string internalPrint(NodePrinter& printer) const override; + void make(DsqlCompilerScratch* dsqlScratch, dsc* desc) override; + void genBlr(DsqlCompilerScratch* dsqlScratch) override; + + void makeSortDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) override; + + void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) override; + ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier) const override; + AggNode* pass2(thread_db* tdbb, CompilerScratch* csb) override; + + void aggInit(thread_db* tdbb, Request* request) const override; + bool aggPass(thread_db* tdbb, Request* request) const override; + void aggPass(thread_db* tdbb, Request* request, dsc* desc) const override; + dsc* aggExecute(thread_db* tdbb, Request* request) const override; + +protected: + AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/ override; + +private: + const PercentileType type; + NestConst valueArg; + NestConst dsqlOrderClause; + ULONG percentileImpureOffset = 0; +}; + class CountAggNode final : public AggNode { public: diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 4e8c5c9f4cf..9097c30658e 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -1446,10 +1446,6 @@ void CommentOnNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) SCL_check_view(tdbb, name, SCL_alter); break; - case obj_procedure: - SCL_check_procedure(tdbb, name, SCL_alter); - break; - case obj_trigger: { const auto relationName = getTriggerRelationName(tdbb, transaction, name); @@ -1461,7 +1457,19 @@ void CommentOnNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) } case obj_udf: - SCL_check_function(tdbb, name, SCL_alter); + case obj_procedure: + if (name.package.hasData()) + { + const auto package = name.getSchemaAndPackage(); + SCL_check_package(tdbb, package, SCL_alter); + } + else + { + if (objType == obj_udf) + SCL_check_function(tdbb, name, SCL_alter); + else + SCL_check_procedure(tdbb, name, SCL_alter); + } break; case obj_blob_filter: diff --git a/src/dsql/DsqlBatch.cpp b/src/dsql/DsqlBatch.cpp index 916d0dfe791..92929547daa 100644 --- a/src/dsql/DsqlBatch.cpp +++ b/src/dsql/DsqlBatch.cpp @@ -694,7 +694,6 @@ Firebird::IBatchCompletionState* DsqlBatch::execute(thread_db* tdbb) continue; } - const bool start = startRequest; if (startRequest) { EXE_unwind(tdbb, req); diff --git a/src/dsql/DsqlStatements.cpp b/src/dsql/DsqlStatements.cpp index 21facd79f09..d656534fc5e 100644 --- a/src/dsql/DsqlStatements.cpp +++ b/src/dsql/DsqlStatements.cpp @@ -149,8 +149,6 @@ void DsqlDmlStatement::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, n GEN_statement(scratch, node); - unsigned messageNumber = 0; - // have the access method compile the statement #ifdef DSQL_DEBUG diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index 2601077f574..7d74b33b55f 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -2814,7 +2814,6 @@ dsc* ArithmeticNode::addSqlTime(thread_db* tdbb, const dsc* desc, impure_value* fb_assert(blrOp == blr_add || blrOp == blr_subtract); dsc* result = &value->vlu_desc; - Attachment* const attachment = tdbb->getAttachment(); fb_assert(value->vlu_desc.isTime() || desc->isTime()); @@ -8229,7 +8228,6 @@ void LiteralNode::fixMinSInt64(MemoryPool& pool) { // MIN_SINT64 should be stored as BIGINT, not 128-bit integer - const UCHAR* s = litDesc.dsc_address; const char* minSInt64 = "9223372036854775808"; bool hasDot = false; int scale = 0; @@ -8267,7 +8265,6 @@ void LiteralNode::fixMinSInt128(MemoryPool& pool) { // MIN_SINT128 should be stored as INT128, not decfloat - const UCHAR* s = litDesc.dsc_address; const char* const minSInt128 = "170141183460469231731687303715884105728"; const char* minPtr = minSInt128; bool hasDot = false; @@ -10158,7 +10155,6 @@ string RecordKeyNode::internalPrint(NodePrinter& printer) const // Resolve a dbkey to an available context. ValueExprNode* RecordKeyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { - thread_db* tdbb = JRD_get_thread_data(); DsqlContextStack contexts; ValueExprNode* node = nullptr; @@ -13634,8 +13630,6 @@ dsc* UdfCallNode::execute(thread_db* tdbb, Request* request) const { const_cast(function.getObject())->checkReload(tdbb); - Jrd::Attachment* attachment = tdbb->getAttachment(); - const ULONG inMsgLength = function->getInputFormat() ? function->getInputFormat()->fmt_length : 0; const ULONG outMsgLength = function->getOutputFormat()->fmt_length; UCHAR* const inMsg = FB_ALIGN(impure + sizeof(impure_value), FB_ALIGNMENT); diff --git a/src/dsql/ExprNodes.h b/src/dsql/ExprNodes.h index f23be19b0c2..01ad4e853c2 100644 --- a/src/dsql/ExprNodes.h +++ b/src/dsql/ExprNodes.h @@ -228,8 +228,9 @@ class BoolAsValueNode final : public TypedNodepar_name = parameter->par_alias = "BOOL"; } void genBlr(DsqlCompilerScratch* dsqlScratch) override; diff --git a/src/dsql/Nodes.h b/src/dsql/Nodes.h index f769b4b33ed..8c0baa6ebda 100644 --- a/src/dsql/Nodes.h +++ b/src/dsql/Nodes.h @@ -1092,6 +1092,8 @@ class AggNode : public TypedNode return NULL; } + virtual void makeSortDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc); + virtual void aggInit(thread_db* tdbb, Request* request) const = 0; // pure, but defined virtual void aggFinish(thread_db* tdbb, Request* request) const; virtual bool aggPass(thread_db* tdbb, Request* request) const; diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index b3c50644f9c..7f084ad3d05 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -2389,6 +2389,9 @@ string EraseNode::internalPrint(NodePrinter& printer) const // RETURNING specified. void EraseNode::genBlr(DsqlCompilerScratch* dsqlScratch) { + if (dsqlScratch->recordKeyMessage) + GEN_port(dsqlScratch, dsqlScratch->recordKeyMessage); + std::optional tableNumber; const bool skipLocked = dsqlRse && dsqlRse->hasSkipLocked(); @@ -6524,7 +6527,6 @@ void LocalDeclarationsNode::genBlr(DsqlCompilerScratch* dsqlScratch) // EXECUTE BLOCK needs "ports", which creates DSQL messages using the client charset. // Sub routine doesn't need ports and should generate BLR as declared in its metadata. const bool isSubRoutine = dsqlScratch->flags & DsqlCompilerScratch::FLAG_SUB_ROUTINE; - const auto& variables = isSubRoutine ? dsqlScratch->outputVariables : dsqlScratch->variables; Array declaredVariables; @@ -11243,7 +11245,6 @@ static RseNode* dsqlPassCursorReference(DsqlCompilerScratch* dsqlScratch, const { DEV_BLKCHK(dsqlScratch, dsql_type_req); - thread_db* tdbb = JRD_get_thread_data(); // Use scratch pool because none of created object is stored anywhere MemoryPool& pool = dsqlScratch->getPool(); @@ -11865,7 +11866,6 @@ static StmtNode* pass1ExpandView(thread_db* tdbb, CompilerScratch* csb, StreamTy jrd_rel* relation = csb->csb_rpt[orgStream].csb_relation; vec* fields = relation->rel_fields; - dsc desc; USHORT id = 0, newId = 0; vec::iterator ptr = fields->begin(); diff --git a/src/dsql/make.cpp b/src/dsql/make.cpp index 0928ccd182f..dfde9062099 100644 --- a/src/dsql/make.cpp +++ b/src/dsql/make.cpp @@ -522,8 +522,6 @@ dsql_par* MAKE_parameter(dsql_msg* message, bool sqlda_flag, bool null_flag, } } - thread_db* tdbb = JRD_get_thread_data(); - if (message->msg_parameter == MAX_USHORT) { string msg; diff --git a/src/dsql/parse-conflicts.txt b/src/dsql/parse-conflicts.txt index d18086526cc..93a526691e0 100644 --- a/src/dsql/parse-conflicts.txt +++ b/src/dsql/parse-conflicts.txt @@ -1 +1 @@ -134 shift/reduce conflicts, 13 reduce/reduce conflicts. +134 shift/reduce conflicts, 19 reduce/reduce conflicts. diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 28fc1e12163..3f432b65ebd 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -709,17 +709,21 @@ using namespace Firebird; %token CALL %token CURRENT_SCHEMA %token DOWNTO +%token ERROR %token FORMAT %token GENERATE_SERIES %token GREATEST %token LEAST +%token LISTAGG %token LTRIM %token NAMED_ARG_ASSIGN +%token PERCENTILE_CONT +%token PERCENTILE_DISC %token RTRIM %token SCHEMA %token SEARCH_PATH +%token TRUNCATE %token UNLIST -%token LISTAGG %token WITHIN // precedence declarations for expression evaluation @@ -2394,12 +2398,6 @@ sql_security_clause | SQL SECURITY INVOKER { $$ = false; } ; -%type sql_security_clause_opt -sql_security_clause_opt - : /* nothing */ { $$ = TriState::empty(); } - | sql_security_clause { $$ = $1; } - ; - %type publication_state publication_state : ENABLE PUBLICATION { $$ = true; } @@ -2413,7 +2411,7 @@ gtt_table_clause $$ = newNode($1); $$->relationType = std::nullopt; } - '(' table_elements($2) ')' gtt_ops($2) + '(' table_elements($2) ')' gtt_subclauses_opt($2) { $$ = $2; if (!$$->relationType.has_value()) @@ -2421,16 +2419,21 @@ gtt_table_clause } ; -%type gtt_ops() -gtt_ops($createRelationNode) - : gtt_op($createRelationNode) - | gtt_ops ',' gtt_op($createRelationNode) +%type gtt_subclauses_opt() +gtt_subclauses_opt($createRelationNode) + : // nothing by default. Will be set "on commit delete rows" in dsqlPass + | gtt_subclauses($createRelationNode) ; -%type gtt_op() -gtt_op($createRelationNode) - : // nothing by default. Will be set "on commit delete rows" in dsqlPass - | sql_security_clause_opt +%type gtt_subclauses() +gtt_subclauses($createRelationNode) + : gtt_subclause($createRelationNode) + | gtt_subclauses ',' gtt_subclause($createRelationNode) + ; + +%type gtt_subclause() +gtt_subclause($createRelationNode) + : sql_security_clause { setClause($createRelationNode->ssDefiner, "SQL SECURITY", $1); } | ON COMMIT DELETE ROWS { setClause($createRelationNode->relationType, "ON COMMIT DELETE ROWS", rel_global_temp_delete); } @@ -4726,6 +4729,8 @@ keyword_or_column | WITHIN | LISTAGG | TRUNCATE + | PERCENTILE_CONT + | PERCENTILE_DISC ; col_opt @@ -8618,6 +8623,10 @@ aggregate_function_prefix { $$ = newNode(BinAggNode::TYPE_BIN_XOR, $4); } | BIN_XOR_AGG '(' DISTINCT value ')' { $$ = newNode(BinAggNode::TYPE_BIN_XOR_DISTINCT, $4); } + | PERCENTILE_CONT '(' value ')' within_group_specification + { $$ = newNode(PercentileAggNode::TYPE_PERCENTILE_CONT, $3, $5); } + | PERCENTILE_DISC '(' value ')' within_group_specification + { $$ = newNode(PercentileAggNode::TYPE_PERCENTILE_DISC, $3, $5); } ; %type listagg_set_function @@ -8666,25 +8675,25 @@ overflow_behavior %type listagg_truncation_filler_opt listagg_truncation_filler_opt - : /*nothing*/ { $$ = MAKE_str_constant(newIntlString("..."), lex.charSetId); } + : /* nothing */ { $$ = MAKE_str_constant(newIntlString("..."), lex.charSetId); } | listagg_truncation_filler { $$ = $1; } ; -%type listagg_truncation_filler +%type listagg_truncation_filler listagg_truncation_filler - : sql_string + : sql_string { $$ = MAKE_str_constant($1, lex.charSetId); } ; %type listagg_count_indication listagg_count_indication - : WITH COUNT { $$ = true; } + : WITH COUNT { $$ = true; } | WITHOUT COUNT { $$ = false; } ; %type within_group_specification_opt within_group_specification_opt - : /* nothing */ { $$ = newNode(0); } - | within_group_specification { $$ = $1; } + : /* nothing */ { $$ = nullptr; } + | within_group_specification { $$ = $1; } ; %type within_group_specification @@ -10064,6 +10073,8 @@ non_reserved_word | FORMAT | GENERATE_SERIES | OWNER + | PERCENTILE_CONT + | PERCENTILE_DISC | SEARCH_PATH | SCHEMA | UNLIST diff --git a/src/dsql/pass1.cpp b/src/dsql/pass1.cpp index eef4683975e..cad9b6cc039 100644 --- a/src/dsql/pass1.cpp +++ b/src/dsql/pass1.cpp @@ -279,8 +279,6 @@ bool InvalidReferenceFinder::visit(ExprNode* node) if (!node) return false; - bool invalid = false; - // ASF: What we do in this function is the verification of all fields/dbkeys (or any parent // expression involving them) are present in the passed node list. // That makes valid: @@ -732,7 +730,7 @@ void PASS1_ambiguity_check(DsqlCompilerScratch* dsqlScratch, bool PASS1_compare_alias(const QualifiedName& contextAlias, const QualifiedName& lookupAlias) { - return lookupAlias == contextAlias || lookupAlias.schema.isEmpty() && lookupAlias.object == contextAlias.object; + return lookupAlias == contextAlias || (lookupAlias.schema.isEmpty() && lookupAlias.object == contextAlias.object); } @@ -1443,8 +1441,6 @@ void PASS1_expand_select_node(DsqlCompilerScratch* dsqlScratch, ExprNode* node, if (context->ctx_relation) { - thread_db* const tdbb = JRD_get_thread_data(); - for (dsql_fld* field = context->ctx_relation->rel_fields; field; field = field->fld_next) { DEV_BLKCHK(field, dsql_type_fld); diff --git a/src/gpre/gpre.cpp b/src/gpre/gpre.cpp index e07542d7225..24e04b6829e 100644 --- a/src/gpre/gpre.cpp +++ b/src/gpre/gpre.cpp @@ -2484,8 +2484,8 @@ static void pass2( SLONG start_position) SLONG current = 1 + start_position; SLONG column = 0; - const SSHORT comment_start_len = static_cast(strlen(comment_start)); #if defined(GPRE_COBOL) + const SSHORT comment_start_len = static_cast(strlen(comment_start)); SSHORT to_skip = 0; #endif diff --git a/src/gpre/obj_cxx.cpp b/src/gpre/obj_cxx.cpp index b863f2cf3e6..dcc2735d45b 100644 --- a/src/gpre/obj_cxx.cpp +++ b/src/gpre/obj_cxx.cpp @@ -135,7 +135,6 @@ static const TEXT* global_status_name = 0; constexpr int INDENT = 3; static constexpr const char* NULL_STRING = "NULL"; -static constexpr const char* NULL_STATUS = "NULL"; static constexpr const char* NULL_SQLDA = "NULL"; static constexpr const char* GDS_INCLUDE = ""; diff --git a/src/include/firebird/FirebirdInterface.idl b/src/include/firebird/FirebirdInterface.idl index 06601ffa6ef..4bce83e70a4 100644 --- a/src/include/firebird/FirebirdInterface.idl +++ b/src/include/firebird/FirebirdInterface.idl @@ -1364,6 +1364,9 @@ interface TraceTransaction : Versioned version: // 3.0.4 -> 3.0.5 int64 getInitialID(); int64 getPreviousID(); + +version: // 5.0 -> 6.0 + PerformanceStats getPerfStats(); } interface TraceParams : Versioned @@ -1379,6 +1382,9 @@ interface TraceStatement : Versioned { int64 getStmtID(); PerformanceInfo* getPerf(); + +version: // 5.0 -> 6.0 + PerformanceStats getPerfStats(); } interface TraceSQLStatement : TraceStatement @@ -1421,6 +1427,9 @@ version: // 4.0 -> 5.0 int64 getStmtID(); const string getPlan(); const string getExplainedPlan(); + +version: // 5.0 -> 6.0 + PerformanceStats getPerfStats(); } interface TraceFunction : Versioned @@ -1434,6 +1443,9 @@ version: // 4.0 -> 5.0 int64 getStmtID(); const string getPlan(); const string getExplainedPlan(); + +version: // 5.0 -> 6.0 + PerformanceStats getPerfStats(); } interface TraceTrigger : Versioned @@ -1456,6 +1468,9 @@ version: // 4.0 -> 5.0 int64 getStmtID(); const string getPlan(); const string getExplainedPlan(); + +version: // 5.0 -> 6.0 + PerformanceStats getPerfStats(); } interface TraceServiceConnection : TraceConnection @@ -1480,6 +1495,9 @@ interface TraceSweepInfo : Versioned int64 getOAT(); int64 getNext(); PerformanceInfo* getPerf(); + +version: // 5.0 -> 6.0 + PerformanceStats getPerfStats(); } interface TraceLogWriter : ReferenceCounted @@ -1876,3 +1894,50 @@ interface ProfilerStats : Versioned { uint64 getElapsedTicks(); } + +// Extendable replacement for struct PerformanceInfo + +interface PerformanceCounters : Versioned +{ + // Page-level performance counters (grouped per tablespace) + const uint PAGE_FETCHES = 0; + const uint PAGE_READS = 1; + const uint PAGE_MARKS = 2; + const uint PAGE_WRITES = 3; + + // Record-level performance counters (grouped per table) + const uint RECORD_SEQ_READS = 0; + const uint RECORD_IDX_READS = 1; + const uint RECORD_UPDATES = 2; + const uint RECORD_INSERTS = 3; + const uint RECORD_DELETES = 4; + const uint RECORD_BACKOUTS = 5; + const uint RECORD_PURGES = 6; + const uint RECORD_EXPUNGES = 7; + const uint RECORD_LOCKS = 8; + const uint RECORD_WAITS = 9; + const uint RECORD_CONFLICTS = 10; + const uint RECORD_BACK_READS = 11; + const uint RECORD_FRAGMENT_READS = 12; + const uint RECORD_RPT_READS = 13; + const uint RECORD_IMGC = 14; + + uint getObjectCount(); + uint getMaxCounterIndex(); + + uint getObjectId(uint index); + const string getObjectName(uint index); + const int64* getObjectCounters(uint index); +} + +interface PerformanceStats : Versioned +{ + const uint COUNTER_GROUP_PAGES = 0; + const uint COUNTER_GROUP_TABLES = 1; + + uint64 getElapsedTime(); // in milliseconds + uint64 getFetchedRecords(); + + PerformanceCounters getCounters(uint group); +} + diff --git a/src/include/firebird/IdlFbInterfaces.h b/src/include/firebird/IdlFbInterfaces.h index 43f3041054d..ea71d25e6bc 100644 --- a/src/include/firebird/IdlFbInterfaces.h +++ b/src/include/firebird/IdlFbInterfaces.h @@ -143,6 +143,8 @@ namespace Firebird class IProfilerPlugin; class IProfilerSession; class IProfilerStats; + class IPerformanceCounters; + class IPerformanceStats; // Interfaces declarations @@ -5458,7 +5460,7 @@ namespace Firebird } }; -#define FIREBIRD_ITRACE_TRANSACTION_VERSION 3u +#define FIREBIRD_ITRACE_TRANSACTION_VERSION 4u class ITraceTransaction : public IVersioned { @@ -5472,6 +5474,7 @@ namespace Firebird PerformanceInfo* (CLOOP_CARG *getPerf)(ITraceTransaction* self) CLOOP_NOEXCEPT; ISC_INT64 (CLOOP_CARG *getInitialID)(ITraceTransaction* self) CLOOP_NOEXCEPT; ISC_INT64 (CLOOP_CARG *getPreviousID)(ITraceTransaction* self) CLOOP_NOEXCEPT; + IPerformanceStats* (CLOOP_CARG *getPerfStats)(ITraceTransaction* self) CLOOP_NOEXCEPT; }; protected: @@ -5542,6 +5545,16 @@ namespace Firebird ISC_INT64 ret = static_cast(this->cloopVTable)->getPreviousID(this); return ret; } + + IPerformanceStats* getPerfStats() + { + if (cloopVTable->version < 4) + { + return 0; + } + IPerformanceStats* ret = static_cast(this->cloopVTable)->getPerfStats(this); + return ret; + } }; #define FIREBIRD_ITRACE_PARAMS_VERSION 3u @@ -5596,7 +5609,7 @@ namespace Firebird } }; -#define FIREBIRD_ITRACE_STATEMENT_VERSION 2u +#define FIREBIRD_ITRACE_STATEMENT_VERSION 3u class ITraceStatement : public IVersioned { @@ -5605,6 +5618,7 @@ namespace Firebird { ISC_INT64 (CLOOP_CARG *getStmtID)(ITraceStatement* self) CLOOP_NOEXCEPT; PerformanceInfo* (CLOOP_CARG *getPerf)(ITraceStatement* self) CLOOP_NOEXCEPT; + IPerformanceStats* (CLOOP_CARG *getPerfStats)(ITraceStatement* self) CLOOP_NOEXCEPT; }; protected: @@ -5631,9 +5645,19 @@ namespace Firebird PerformanceInfo* ret = static_cast(this->cloopVTable)->getPerf(this); return ret; } + + IPerformanceStats* getPerfStats() + { + if (cloopVTable->version < 3) + { + return 0; + } + IPerformanceStats* ret = static_cast(this->cloopVTable)->getPerfStats(this); + return ret; + } }; -#define FIREBIRD_ITRACE_SQLSTATEMENT_VERSION 3u +#define FIREBIRD_ITRACE_SQLSTATEMENT_VERSION 4u class ITraceSQLStatement : public ITraceStatement { @@ -5691,7 +5715,7 @@ namespace Firebird } }; -#define FIREBIRD_ITRACE_BLRSTATEMENT_VERSION 3u +#define FIREBIRD_ITRACE_BLRSTATEMENT_VERSION 4u class ITraceBLRStatement : public ITraceStatement { @@ -5823,7 +5847,7 @@ namespace Firebird } }; -#define FIREBIRD_ITRACE_PROCEDURE_VERSION 3u +#define FIREBIRD_ITRACE_PROCEDURE_VERSION 4u class ITraceProcedure : public IVersioned { @@ -5836,6 +5860,7 @@ namespace Firebird ISC_INT64 (CLOOP_CARG *getStmtID)(ITraceProcedure* self) CLOOP_NOEXCEPT; const char* (CLOOP_CARG *getPlan)(ITraceProcedure* self) CLOOP_NOEXCEPT; const char* (CLOOP_CARG *getExplainedPlan)(ITraceProcedure* self) CLOOP_NOEXCEPT; + IPerformanceStats* (CLOOP_CARG *getPerfStats)(ITraceProcedure* self) CLOOP_NOEXCEPT; }; protected: @@ -5898,9 +5923,19 @@ namespace Firebird const char* ret = static_cast(this->cloopVTable)->getExplainedPlan(this); return ret; } + + IPerformanceStats* getPerfStats() + { + if (cloopVTable->version < 4) + { + return 0; + } + IPerformanceStats* ret = static_cast(this->cloopVTable)->getPerfStats(this); + return ret; + } }; -#define FIREBIRD_ITRACE_FUNCTION_VERSION 3u +#define FIREBIRD_ITRACE_FUNCTION_VERSION 4u class ITraceFunction : public IVersioned { @@ -5914,6 +5949,7 @@ namespace Firebird ISC_INT64 (CLOOP_CARG *getStmtID)(ITraceFunction* self) CLOOP_NOEXCEPT; const char* (CLOOP_CARG *getPlan)(ITraceFunction* self) CLOOP_NOEXCEPT; const char* (CLOOP_CARG *getExplainedPlan)(ITraceFunction* self) CLOOP_NOEXCEPT; + IPerformanceStats* (CLOOP_CARG *getPerfStats)(ITraceFunction* self) CLOOP_NOEXCEPT; }; protected: @@ -5982,9 +6018,19 @@ namespace Firebird const char* ret = static_cast(this->cloopVTable)->getExplainedPlan(this); return ret; } + + IPerformanceStats* getPerfStats() + { + if (cloopVTable->version < 4) + { + return 0; + } + IPerformanceStats* ret = static_cast(this->cloopVTable)->getPerfStats(this); + return ret; + } }; -#define FIREBIRD_ITRACE_TRIGGER_VERSION 3u +#define FIREBIRD_ITRACE_TRIGGER_VERSION 4u class ITraceTrigger : public IVersioned { @@ -5999,6 +6045,7 @@ namespace Firebird ISC_INT64 (CLOOP_CARG *getStmtID)(ITraceTrigger* self) CLOOP_NOEXCEPT; const char* (CLOOP_CARG *getPlan)(ITraceTrigger* self) CLOOP_NOEXCEPT; const char* (CLOOP_CARG *getExplainedPlan)(ITraceTrigger* self) CLOOP_NOEXCEPT; + IPerformanceStats* (CLOOP_CARG *getPerfStats)(ITraceTrigger* self) CLOOP_NOEXCEPT; }; protected: @@ -6077,6 +6124,16 @@ namespace Firebird const char* ret = static_cast(this->cloopVTable)->getExplainedPlan(this); return ret; } + + IPerformanceStats* getPerfStats() + { + if (cloopVTable->version < 4) + { + return 0; + } + IPerformanceStats* ret = static_cast(this->cloopVTable)->getPerfStats(this); + return ret; + } }; #define FIREBIRD_ITRACE_SERVICE_CONNECTION_VERSION 3u @@ -6174,7 +6231,7 @@ namespace Firebird } }; -#define FIREBIRD_ITRACE_SWEEP_INFO_VERSION 2u +#define FIREBIRD_ITRACE_SWEEP_INFO_VERSION 3u class ITraceSweepInfo : public IVersioned { @@ -6186,6 +6243,7 @@ namespace Firebird ISC_INT64 (CLOOP_CARG *getOAT)(ITraceSweepInfo* self) CLOOP_NOEXCEPT; ISC_INT64 (CLOOP_CARG *getNext)(ITraceSweepInfo* self) CLOOP_NOEXCEPT; PerformanceInfo* (CLOOP_CARG *getPerf)(ITraceSweepInfo* self) CLOOP_NOEXCEPT; + IPerformanceStats* (CLOOP_CARG *getPerfStats)(ITraceSweepInfo* self) CLOOP_NOEXCEPT; }; protected: @@ -6230,6 +6288,16 @@ namespace Firebird PerformanceInfo* ret = static_cast(this->cloopVTable)->getPerf(this); return ret; } + + IPerformanceStats* getPerfStats() + { + if (cloopVTable->version < 3) + { + return 0; + } + IPerformanceStats* ret = static_cast(this->cloopVTable)->getPerfStats(this); + return ret; + } }; #define FIREBIRD_ITRACE_LOG_WRITER_VERSION 4u @@ -7538,6 +7606,131 @@ namespace Firebird } }; +#define FIREBIRD_IPERFORMANCE_COUNTERS_VERSION 2u + + class IPerformanceCounters : public IVersioned + { + public: + struct VTable : public IVersioned::VTable + { + unsigned (CLOOP_CARG *getObjectCount)(IPerformanceCounters* self) CLOOP_NOEXCEPT; + unsigned (CLOOP_CARG *getMaxCounterIndex)(IPerformanceCounters* self) CLOOP_NOEXCEPT; + unsigned (CLOOP_CARG *getObjectId)(IPerformanceCounters* self, unsigned index) CLOOP_NOEXCEPT; + const char* (CLOOP_CARG *getObjectName)(IPerformanceCounters* self, unsigned index) CLOOP_NOEXCEPT; + const ISC_INT64* (CLOOP_CARG *getObjectCounters)(IPerformanceCounters* self, unsigned index) CLOOP_NOEXCEPT; + }; + + protected: + IPerformanceCounters(DoNotInherit) + : IVersioned(DoNotInherit()) + { + } + + ~IPerformanceCounters() + { + } + + public: + static CLOOP_CONSTEXPR unsigned VERSION = FIREBIRD_IPERFORMANCE_COUNTERS_VERSION; + + static CLOOP_CONSTEXPR unsigned PAGE_FETCHES = 0; + static CLOOP_CONSTEXPR unsigned PAGE_READS = 1; + static CLOOP_CONSTEXPR unsigned PAGE_MARKS = 2; + static CLOOP_CONSTEXPR unsigned PAGE_WRITES = 3; + static CLOOP_CONSTEXPR unsigned RECORD_SEQ_READS = 0; + static CLOOP_CONSTEXPR unsigned RECORD_IDX_READS = 1; + static CLOOP_CONSTEXPR unsigned RECORD_UPDATES = 2; + static CLOOP_CONSTEXPR unsigned RECORD_INSERTS = 3; + static CLOOP_CONSTEXPR unsigned RECORD_DELETES = 4; + static CLOOP_CONSTEXPR unsigned RECORD_BACKOUTS = 5; + static CLOOP_CONSTEXPR unsigned RECORD_PURGES = 6; + static CLOOP_CONSTEXPR unsigned RECORD_EXPUNGES = 7; + static CLOOP_CONSTEXPR unsigned RECORD_LOCKS = 8; + static CLOOP_CONSTEXPR unsigned RECORD_WAITS = 9; + static CLOOP_CONSTEXPR unsigned RECORD_CONFLICTS = 10; + static CLOOP_CONSTEXPR unsigned RECORD_BACK_READS = 11; + static CLOOP_CONSTEXPR unsigned RECORD_FRAGMENT_READS = 12; + static CLOOP_CONSTEXPR unsigned RECORD_RPT_READS = 13; + static CLOOP_CONSTEXPR unsigned RECORD_IMGC = 14; + + unsigned getObjectCount() + { + unsigned ret = static_cast(this->cloopVTable)->getObjectCount(this); + return ret; + } + + unsigned getMaxCounterIndex() + { + unsigned ret = static_cast(this->cloopVTable)->getMaxCounterIndex(this); + return ret; + } + + unsigned getObjectId(unsigned index) + { + unsigned ret = static_cast(this->cloopVTable)->getObjectId(this, index); + return ret; + } + + const char* getObjectName(unsigned index) + { + const char* ret = static_cast(this->cloopVTable)->getObjectName(this, index); + return ret; + } + + const ISC_INT64* getObjectCounters(unsigned index) + { + const ISC_INT64* ret = static_cast(this->cloopVTable)->getObjectCounters(this, index); + return ret; + } + }; + +#define FIREBIRD_IPERFORMANCE_STATS_VERSION 2u + + class IPerformanceStats : public IVersioned + { + public: + struct VTable : public IVersioned::VTable + { + ISC_UINT64 (CLOOP_CARG *getElapsedTime)(IPerformanceStats* self) CLOOP_NOEXCEPT; + ISC_UINT64 (CLOOP_CARG *getFetchedRecords)(IPerformanceStats* self) CLOOP_NOEXCEPT; + IPerformanceCounters* (CLOOP_CARG *getCounters)(IPerformanceStats* self, unsigned group) CLOOP_NOEXCEPT; + }; + + protected: + IPerformanceStats(DoNotInherit) + : IVersioned(DoNotInherit()) + { + } + + ~IPerformanceStats() + { + } + + public: + static CLOOP_CONSTEXPR unsigned VERSION = FIREBIRD_IPERFORMANCE_STATS_VERSION; + + static CLOOP_CONSTEXPR unsigned COUNTER_GROUP_PAGES = 0; + static CLOOP_CONSTEXPR unsigned COUNTER_GROUP_TABLES = 1; + + ISC_UINT64 getElapsedTime() + { + ISC_UINT64 ret = static_cast(this->cloopVTable)->getElapsedTime(this); + return ret; + } + + ISC_UINT64 getFetchedRecords() + { + ISC_UINT64 ret = static_cast(this->cloopVTable)->getFetchedRecords(this); + return ret; + } + + IPerformanceCounters* getCounters(unsigned group) + { + IPerformanceCounters* ret = static_cast(this->cloopVTable)->getCounters(this, group); + return ret; + } + }; + // Interfaces implementations template @@ -17637,6 +17830,7 @@ namespace Firebird this->getPerf = &Name::cloopgetPerfDispatcher; this->getInitialID = &Name::cloopgetInitialIDDispatcher; this->getPreviousID = &Name::cloopgetPreviousIDDispatcher; + this->getPerfStats = &Name::cloopgetPerfStatsDispatcher; } } vTable; @@ -17733,6 +17927,19 @@ namespace Firebird return static_cast(0); } } + + static IPerformanceStats* CLOOP_CARG cloopgetPerfStatsDispatcher(ITraceTransaction* self) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getPerfStats(); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } }; template > > @@ -17755,6 +17962,7 @@ namespace Firebird virtual PerformanceInfo* getPerf() = 0; virtual ISC_INT64 getInitialID() = 0; virtual ISC_INT64 getPreviousID() = 0; + virtual IPerformanceStats* getPerfStats() = 0; }; template @@ -17854,6 +18062,7 @@ namespace Firebird this->version = Base::VERSION; this->getStmtID = &Name::cloopgetStmtIDDispatcher; this->getPerf = &Name::cloopgetPerfDispatcher; + this->getPerfStats = &Name::cloopgetPerfStatsDispatcher; } } vTable; @@ -17885,6 +18094,19 @@ namespace Firebird return static_cast(0); } } + + static IPerformanceStats* CLOOP_CARG cloopgetPerfStatsDispatcher(ITraceStatement* self) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getPerfStats(); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } }; template > > @@ -17902,6 +18124,7 @@ namespace Firebird virtual ISC_INT64 getStmtID() = 0; virtual PerformanceInfo* getPerf() = 0; + virtual IPerformanceStats* getPerfStats() = 0; }; template @@ -17919,6 +18142,7 @@ namespace Firebird this->version = Base::VERSION; this->getStmtID = &Name::cloopgetStmtIDDispatcher; this->getPerf = &Name::cloopgetPerfDispatcher; + this->getPerfStats = &Name::cloopgetPerfStatsDispatcher; this->getText = &Name::cloopgetTextDispatcher; this->getPlan = &Name::cloopgetPlanDispatcher; this->getInputs = &Name::cloopgetInputsDispatcher; @@ -18020,6 +18244,19 @@ namespace Firebird return static_cast(0); } } + + static IPerformanceStats* CLOOP_CARG cloopgetPerfStatsDispatcher(ITraceStatement* self) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getPerfStats(); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } }; template > > > > @@ -18057,6 +18294,7 @@ namespace Firebird this->version = Base::VERSION; this->getStmtID = &Name::cloopgetStmtIDDispatcher; this->getPerf = &Name::cloopgetPerfDispatcher; + this->getPerfStats = &Name::cloopgetPerfStatsDispatcher; this->getData = &Name::cloopgetDataDispatcher; this->getDataLength = &Name::cloopgetDataLengthDispatcher; this->getText = &Name::cloopgetTextDispatcher; @@ -18130,6 +18368,19 @@ namespace Firebird return static_cast(0); } } + + static IPerformanceStats* CLOOP_CARG cloopgetPerfStatsDispatcher(ITraceStatement* self) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getPerfStats(); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } }; template > > > > @@ -18329,6 +18580,7 @@ namespace Firebird this->getStmtID = &Name::cloopgetStmtIDDispatcher; this->getPlan = &Name::cloopgetPlanDispatcher; this->getExplainedPlan = &Name::cloopgetExplainedPlanDispatcher; + this->getPerfStats = &Name::cloopgetPerfStatsDispatcher; } } vTable; @@ -18412,6 +18664,19 @@ namespace Firebird return static_cast(0); } } + + static IPerformanceStats* CLOOP_CARG cloopgetPerfStatsDispatcher(ITraceProcedure* self) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getPerfStats(); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } }; template > > @@ -18433,6 +18698,7 @@ namespace Firebird virtual ISC_INT64 getStmtID() = 0; virtual const char* getPlan() = 0; virtual const char* getExplainedPlan() = 0; + virtual IPerformanceStats* getPerfStats() = 0; }; template @@ -18455,6 +18721,7 @@ namespace Firebird this->getStmtID = &Name::cloopgetStmtIDDispatcher; this->getPlan = &Name::cloopgetPlanDispatcher; this->getExplainedPlan = &Name::cloopgetExplainedPlanDispatcher; + this->getPerfStats = &Name::cloopgetPerfStatsDispatcher; } } vTable; @@ -18551,6 +18818,19 @@ namespace Firebird return static_cast(0); } } + + static IPerformanceStats* CLOOP_CARG cloopgetPerfStatsDispatcher(ITraceFunction* self) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getPerfStats(); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } }; template > > @@ -18573,6 +18853,7 @@ namespace Firebird virtual ISC_INT64 getStmtID() = 0; virtual const char* getPlan() = 0; virtual const char* getExplainedPlan() = 0; + virtual IPerformanceStats* getPerfStats() = 0; }; template @@ -18596,6 +18877,7 @@ namespace Firebird this->getStmtID = &Name::cloopgetStmtIDDispatcher; this->getPlan = &Name::cloopgetPlanDispatcher; this->getExplainedPlan = &Name::cloopgetExplainedPlanDispatcher; + this->getPerfStats = &Name::cloopgetPerfStatsDispatcher; } } vTable; @@ -18705,6 +18987,19 @@ namespace Firebird return static_cast(0); } } + + static IPerformanceStats* CLOOP_CARG cloopgetPerfStatsDispatcher(ITraceTrigger* self) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getPerfStats(); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } }; template > > @@ -18728,6 +19023,7 @@ namespace Firebird virtual ISC_INT64 getStmtID() = 0; virtual const char* getPlan() = 0; virtual const char* getExplainedPlan() = 0; + virtual IPerformanceStats* getPerfStats() = 0; }; template @@ -19049,6 +19345,7 @@ namespace Firebird this->getOAT = &Name::cloopgetOATDispatcher; this->getNext = &Name::cloopgetNextDispatcher; this->getPerf = &Name::cloopgetPerfDispatcher; + this->getPerfStats = &Name::cloopgetPerfStatsDispatcher; } } vTable; @@ -19119,6 +19416,19 @@ namespace Firebird return static_cast(0); } } + + static IPerformanceStats* CLOOP_CARG cloopgetPerfStatsDispatcher(ITraceSweepInfo* self) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getPerfStats(); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } }; template > > @@ -19139,6 +19449,7 @@ namespace Firebird virtual ISC_INT64 getOAT() = 0; virtual ISC_INT64 getNext() = 0; virtual PerformanceInfo* getPerf() = 0; + virtual IPerformanceStats* getPerfStats() = 0; }; template @@ -21698,6 +22009,196 @@ namespace Firebird virtual ISC_UINT64 getElapsedTicks() = 0; }; + + template + class IPerformanceCountersBaseImpl : public Base + { + public: + typedef IPerformanceCounters Declaration; + + IPerformanceCountersBaseImpl(DoNotInherit = DoNotInherit()) + { + static struct VTableImpl : Base::VTable + { + VTableImpl() + { + this->version = Base::VERSION; + this->getObjectCount = &Name::cloopgetObjectCountDispatcher; + this->getMaxCounterIndex = &Name::cloopgetMaxCounterIndexDispatcher; + this->getObjectId = &Name::cloopgetObjectIdDispatcher; + this->getObjectName = &Name::cloopgetObjectNameDispatcher; + this->getObjectCounters = &Name::cloopgetObjectCountersDispatcher; + } + } vTable; + + this->cloopVTable = &vTable; + } + + static unsigned CLOOP_CARG cloopgetObjectCountDispatcher(IPerformanceCounters* self) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getObjectCount(); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } + + static unsigned CLOOP_CARG cloopgetMaxCounterIndexDispatcher(IPerformanceCounters* self) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getMaxCounterIndex(); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } + + static unsigned CLOOP_CARG cloopgetObjectIdDispatcher(IPerformanceCounters* self, unsigned index) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getObjectId(index); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } + + static const char* CLOOP_CARG cloopgetObjectNameDispatcher(IPerformanceCounters* self, unsigned index) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getObjectName(index); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } + + static const ISC_INT64* CLOOP_CARG cloopgetObjectCountersDispatcher(IPerformanceCounters* self, unsigned index) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getObjectCounters(index); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } + }; + + template > > + class IPerformanceCountersImpl : public IPerformanceCountersBaseImpl + { + protected: + IPerformanceCountersImpl(DoNotInherit = DoNotInherit()) + { + } + + public: + virtual ~IPerformanceCountersImpl() + { + } + + virtual unsigned getObjectCount() = 0; + virtual unsigned getMaxCounterIndex() = 0; + virtual unsigned getObjectId(unsigned index) = 0; + virtual const char* getObjectName(unsigned index) = 0; + virtual const ISC_INT64* getObjectCounters(unsigned index) = 0; + }; + + template + class IPerformanceStatsBaseImpl : public Base + { + public: + typedef IPerformanceStats Declaration; + + IPerformanceStatsBaseImpl(DoNotInherit = DoNotInherit()) + { + static struct VTableImpl : Base::VTable + { + VTableImpl() + { + this->version = Base::VERSION; + this->getElapsedTime = &Name::cloopgetElapsedTimeDispatcher; + this->getFetchedRecords = &Name::cloopgetFetchedRecordsDispatcher; + this->getCounters = &Name::cloopgetCountersDispatcher; + } + } vTable; + + this->cloopVTable = &vTable; + } + + static ISC_UINT64 CLOOP_CARG cloopgetElapsedTimeDispatcher(IPerformanceStats* self) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getElapsedTime(); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } + + static ISC_UINT64 CLOOP_CARG cloopgetFetchedRecordsDispatcher(IPerformanceStats* self) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getFetchedRecords(); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } + + static IPerformanceCounters* CLOOP_CARG cloopgetCountersDispatcher(IPerformanceStats* self, unsigned group) CLOOP_NOEXCEPT + { + try + { + return static_cast(self)->Name::getCounters(group); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } + }; + + template > > + class IPerformanceStatsImpl : public IPerformanceStatsBaseImpl + { + protected: + IPerformanceStatsImpl(DoNotInherit = DoNotInherit()) + { + } + + public: + virtual ~IPerformanceStatsImpl() + { + } + + virtual ISC_UINT64 getElapsedTime() = 0; + virtual ISC_UINT64 getFetchedRecords() = 0; + virtual IPerformanceCounters* getCounters(unsigned group) = 0; + }; }; diff --git a/src/include/firebird/impl/blr.h b/src/include/firebird/impl/blr.h index bb7825e3d4a..4fc7669a807 100644 --- a/src/include/firebird/impl/blr.h +++ b/src/include/firebird/impl/blr.h @@ -507,10 +507,12 @@ // Table value function #define blr_table_value_fun (unsigned char) 229 +// subcodes of blr_table_value_fun #define blr_table_value_fun_unlist (unsigned char) 1 #define blr_table_value_fun_gen_series (unsigned char) 2 #define blr_for_range (unsigned char) 230 +// subcodes of blr_for_range #define blr_for_range_variable (unsigned char) 1 #define blr_for_range_initial_value (unsigned char) 2 #define blr_for_range_final_value (unsigned char) 3 @@ -523,9 +525,11 @@ #define blr_gen_id3 (unsigned char) 231 #define blr_default2 (unsigned char) 232 #define blr_current_schema (unsigned char) 233 -#define blr_flags (unsigned char) 234 +#define blr_flags (unsigned char) 234 // subcodes of blr_flags #define blr_flags_search_system_schema (unsigned char) 1 +#define blr_within_group_order (unsigned char) 235 + #endif // FIREBIRD_IMPL_BLR_H diff --git a/src/include/firebird/impl/msg/jrd.h b/src/include/firebird/impl/msg/jrd.h index 7ba26ca0ac2..d146ea1562e 100644 --- a/src/include/firebird/impl/msg/jrd.h +++ b/src/include/firebird/impl/msg/jrd.h @@ -1000,3 +1000,7 @@ FB_IMPL_MSG(JRD, 997, invalid_unqualified_name_list, -901, "HY", "000", "Invalid FB_IMPL_MSG(JRD, 998, no_user_att_while_restore, -901, "HY", "000", "User attachments are not allowed for the database being restored") FB_IMPL_MSG(JRD, 999, genseq_stepmustbe_nonzero, -833, "42", "000", "Argument STEP must be different than zero for function @1") FB_IMPL_MSG(JRD, 1000, argmustbe_exact_function, -833, "42", "000", "Arguments for @1 function must be exact numeric types") +FB_IMPL_MSG(JRD, 1001, sysf_argmustbe_range_inc0_1, -833, "42", "000", "Argument for @1 must be in the range [0, 1]") +FB_IMPL_MSG(JRD, 1002, argmustbe_numeric_function, -833, "42", "000", "Argument for @1 function must be numeric types") +FB_IMPL_MSG(JRD, 1003, percetile_only_one_sort_item, -833, "42", "000", "The PERCENTILE_DISC and PERENTILE_CONT functions support only one sort item in WITHIN GROUP") +FB_IMPL_MSG(JRD, 1004, argmustbe_const_within_group, -833, "42", "000", "Argument for @1 function must be constant within each group") diff --git a/src/include/gen/Firebird.pas b/src/include/gen/Firebird.pas index 4fdd5a676e3..36acac61a1e 100644 --- a/src/include/gen/Firebird.pas +++ b/src/include/gen/Firebird.pas @@ -114,6 +114,8 @@ IReplicatedSession = class; IProfilerPlugin = class; IProfilerSession = class; IProfilerStats = class; + IPerformanceCounters = class; + IPerformanceStats = class; FbException = class(Exception) public @@ -611,11 +613,13 @@ ISC_TIMESTAMP_TZ_EX = record ITraceTransaction_getPerfPtr = function(this: ITraceTransaction): PerformanceInfoPtr; cdecl; ITraceTransaction_getInitialIDPtr = function(this: ITraceTransaction): Int64; cdecl; ITraceTransaction_getPreviousIDPtr = function(this: ITraceTransaction): Int64; cdecl; + ITraceTransaction_getPerfStatsPtr = function(this: ITraceTransaction): IPerformanceStats; cdecl; ITraceParams_getCountPtr = function(this: ITraceParams): Cardinal; cdecl; ITraceParams_getParamPtr = function(this: ITraceParams; idx: Cardinal): paramdscPtr; cdecl; ITraceParams_getTextUTF8Ptr = function(this: ITraceParams; status: IStatus; idx: Cardinal): PAnsiChar; cdecl; ITraceStatement_getStmtIDPtr = function(this: ITraceStatement): Int64; cdecl; ITraceStatement_getPerfPtr = function(this: ITraceStatement): PerformanceInfoPtr; cdecl; + ITraceStatement_getPerfStatsPtr = function(this: ITraceStatement): IPerformanceStats; cdecl; ITraceSQLStatement_getTextPtr = function(this: ITraceSQLStatement): PAnsiChar; cdecl; ITraceSQLStatement_getPlanPtr = function(this: ITraceSQLStatement): PAnsiChar; cdecl; ITraceSQLStatement_getInputsPtr = function(this: ITraceSQLStatement): ITraceParams; cdecl; @@ -636,6 +640,7 @@ ISC_TIMESTAMP_TZ_EX = record ITraceProcedure_getStmtIDPtr = function(this: ITraceProcedure): Int64; cdecl; ITraceProcedure_getPlanPtr = function(this: ITraceProcedure): PAnsiChar; cdecl; ITraceProcedure_getExplainedPlanPtr = function(this: ITraceProcedure): PAnsiChar; cdecl; + ITraceProcedure_getPerfStatsPtr = function(this: ITraceProcedure): IPerformanceStats; cdecl; ITraceFunction_getFuncNamePtr = function(this: ITraceFunction): PAnsiChar; cdecl; ITraceFunction_getInputsPtr = function(this: ITraceFunction): ITraceParams; cdecl; ITraceFunction_getResultPtr = function(this: ITraceFunction): ITraceParams; cdecl; @@ -643,6 +648,7 @@ ISC_TIMESTAMP_TZ_EX = record ITraceFunction_getStmtIDPtr = function(this: ITraceFunction): Int64; cdecl; ITraceFunction_getPlanPtr = function(this: ITraceFunction): PAnsiChar; cdecl; ITraceFunction_getExplainedPlanPtr = function(this: ITraceFunction): PAnsiChar; cdecl; + ITraceFunction_getPerfStatsPtr = function(this: ITraceFunction): IPerformanceStats; cdecl; ITraceTrigger_getTriggerNamePtr = function(this: ITraceTrigger): PAnsiChar; cdecl; ITraceTrigger_getRelationNamePtr = function(this: ITraceTrigger): PAnsiChar; cdecl; ITraceTrigger_getActionPtr = function(this: ITraceTrigger): Integer; cdecl; @@ -651,6 +657,7 @@ ISC_TIMESTAMP_TZ_EX = record ITraceTrigger_getStmtIDPtr = function(this: ITraceTrigger): Int64; cdecl; ITraceTrigger_getPlanPtr = function(this: ITraceTrigger): PAnsiChar; cdecl; ITraceTrigger_getExplainedPlanPtr = function(this: ITraceTrigger): PAnsiChar; cdecl; + ITraceTrigger_getPerfStatsPtr = function(this: ITraceTrigger): IPerformanceStats; cdecl; ITraceServiceConnection_getServiceIDPtr = function(this: ITraceServiceConnection): Pointer; cdecl; ITraceServiceConnection_getServiceMgrPtr = function(this: ITraceServiceConnection): PAnsiChar; cdecl; ITraceServiceConnection_getServiceNamePtr = function(this: ITraceServiceConnection): PAnsiChar; cdecl; @@ -663,6 +670,7 @@ ISC_TIMESTAMP_TZ_EX = record ITraceSweepInfo_getOATPtr = function(this: ITraceSweepInfo): Int64; cdecl; ITraceSweepInfo_getNextPtr = function(this: ITraceSweepInfo): Int64; cdecl; ITraceSweepInfo_getPerfPtr = function(this: ITraceSweepInfo): PerformanceInfoPtr; cdecl; + ITraceSweepInfo_getPerfStatsPtr = function(this: ITraceSweepInfo): IPerformanceStats; cdecl; ITraceLogWriter_writePtr = function(this: ITraceLogWriter; buf: Pointer; size: Cardinal): Cardinal; cdecl; ITraceLogWriter_write_sPtr = function(this: ITraceLogWriter; status: IStatus; buf: Pointer; size: Cardinal): Cardinal; cdecl; ITraceInitInfo_getConfigTextPtr = function(this: ITraceInitInfo): PAnsiChar; cdecl; @@ -770,6 +778,14 @@ ISC_TIMESTAMP_TZ_EX = record IProfilerSession_afterRecordSourceGetRecordPtr = procedure(this: IProfilerSession; statementId: Int64; requestId: Int64; cursorId: Cardinal; recSourceId: Cardinal; stats: IProfilerStats); cdecl; IProfilerSession_defineStatement2Ptr = procedure(this: IProfilerSession; status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; schemaName: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); cdecl; IProfilerStats_getElapsedTicksPtr = function(this: IProfilerStats): QWord; cdecl; + IPerformanceCounters_getObjectCountPtr = function(this: IPerformanceCounters): Cardinal; cdecl; + IPerformanceCounters_getMaxCounterIndexPtr = function(this: IPerformanceCounters): Cardinal; cdecl; + IPerformanceCounters_getObjectIdPtr = function(this: IPerformanceCounters; index: Cardinal): Cardinal; cdecl; + IPerformanceCounters_getObjectNamePtr = function(this: IPerformanceCounters; index: Cardinal): PAnsiChar; cdecl; + IPerformanceCounters_getObjectCountersPtr = function(this: IPerformanceCounters; index: Cardinal): Int64Ptr; cdecl; + IPerformanceStats_getElapsedTimePtr = function(this: IPerformanceStats): QWord; cdecl; + IPerformanceStats_getFetchedRecordsPtr = function(this: IPerformanceStats): QWord; cdecl; + IPerformanceStats_getCountersPtr = function(this: IPerformanceStats; group: Cardinal): IPerformanceCounters; cdecl; VersionedVTable = class version: NativeInt; @@ -3052,10 +3068,11 @@ TraceTransactionVTable = class(VersionedVTable) getPerf: ITraceTransaction_getPerfPtr; getInitialID: ITraceTransaction_getInitialIDPtr; getPreviousID: ITraceTransaction_getPreviousIDPtr; + getPerfStats: ITraceTransaction_getPerfStatsPtr; end; ITraceTransaction = class(IVersioned) - const VERSION = 3; + const VERSION = 4; const ISOLATION_CONSISTENCY = Cardinal(1); const ISOLATION_CONCURRENCY = Cardinal(2); const ISOLATION_READ_COMMITTED_RECVER = Cardinal(3); @@ -3069,6 +3086,7 @@ ITraceTransaction = class(IVersioned) function getPerf(): PerformanceInfoPtr; function getInitialID(): Int64; function getPreviousID(): Int64; + function getPerfStats(): IPerformanceStats; end; ITraceTransactionImpl = class(ITraceTransaction) @@ -3081,6 +3099,7 @@ ITraceTransactionImpl = class(ITraceTransaction) function getPerf(): PerformanceInfoPtr; virtual; abstract; function getInitialID(): Int64; virtual; abstract; function getPreviousID(): Int64; virtual; abstract; + function getPerfStats(): IPerformanceStats; virtual; abstract; end; TraceParamsVTable = class(VersionedVTable) @@ -3108,13 +3127,15 @@ ITraceParamsImpl = class(ITraceParams) TraceStatementVTable = class(VersionedVTable) getStmtID: ITraceStatement_getStmtIDPtr; getPerf: ITraceStatement_getPerfPtr; + getPerfStats: ITraceStatement_getPerfStatsPtr; end; ITraceStatement = class(IVersioned) - const VERSION = 2; + const VERSION = 3; function getStmtID(): Int64; function getPerf(): PerformanceInfoPtr; + function getPerfStats(): IPerformanceStats; end; ITraceStatementImpl = class(ITraceStatement) @@ -3122,6 +3143,7 @@ ITraceStatementImpl = class(ITraceStatement) function getStmtID(): Int64; virtual; abstract; function getPerf(): PerformanceInfoPtr; virtual; abstract; + function getPerfStats(): IPerformanceStats; virtual; abstract; end; TraceSQLStatementVTable = class(TraceStatementVTable) @@ -3133,7 +3155,7 @@ TraceSQLStatementVTable = class(TraceStatementVTable) end; ITraceSQLStatement = class(ITraceStatement) - const VERSION = 3; + const VERSION = 4; function getText(): PAnsiChar; function getPlan(): PAnsiChar; @@ -3147,6 +3169,7 @@ ITraceSQLStatementImpl = class(ITraceSQLStatement) function getStmtID(): Int64; virtual; abstract; function getPerf(): PerformanceInfoPtr; virtual; abstract; + function getPerfStats(): IPerformanceStats; virtual; abstract; function getText(): PAnsiChar; virtual; abstract; function getPlan(): PAnsiChar; virtual; abstract; function getInputs(): ITraceParams; virtual; abstract; @@ -3161,7 +3184,7 @@ TraceBLRStatementVTable = class(TraceStatementVTable) end; ITraceBLRStatement = class(ITraceStatement) - const VERSION = 3; + const VERSION = 4; function getData(): BytePtr; function getDataLength(): Cardinal; @@ -3173,6 +3196,7 @@ ITraceBLRStatementImpl = class(ITraceBLRStatement) function getStmtID(): Int64; virtual; abstract; function getPerf(): PerformanceInfoPtr; virtual; abstract; + function getPerfStats(): IPerformanceStats; virtual; abstract; function getData(): BytePtr; virtual; abstract; function getDataLength(): Cardinal; virtual; abstract; function getText(): PAnsiChar; virtual; abstract; @@ -3229,10 +3253,11 @@ TraceProcedureVTable = class(VersionedVTable) getStmtID: ITraceProcedure_getStmtIDPtr; getPlan: ITraceProcedure_getPlanPtr; getExplainedPlan: ITraceProcedure_getExplainedPlanPtr; + getPerfStats: ITraceProcedure_getPerfStatsPtr; end; ITraceProcedure = class(IVersioned) - const VERSION = 3; + const VERSION = 4; function getProcName(): PAnsiChar; function getInputs(): ITraceParams; @@ -3240,6 +3265,7 @@ ITraceProcedure = class(IVersioned) function getStmtID(): Int64; function getPlan(): PAnsiChar; function getExplainedPlan(): PAnsiChar; + function getPerfStats(): IPerformanceStats; end; ITraceProcedureImpl = class(ITraceProcedure) @@ -3251,6 +3277,7 @@ ITraceProcedureImpl = class(ITraceProcedure) function getStmtID(): Int64; virtual; abstract; function getPlan(): PAnsiChar; virtual; abstract; function getExplainedPlan(): PAnsiChar; virtual; abstract; + function getPerfStats(): IPerformanceStats; virtual; abstract; end; TraceFunctionVTable = class(VersionedVTable) @@ -3261,10 +3288,11 @@ TraceFunctionVTable = class(VersionedVTable) getStmtID: ITraceFunction_getStmtIDPtr; getPlan: ITraceFunction_getPlanPtr; getExplainedPlan: ITraceFunction_getExplainedPlanPtr; + getPerfStats: ITraceFunction_getPerfStatsPtr; end; ITraceFunction = class(IVersioned) - const VERSION = 3; + const VERSION = 4; function getFuncName(): PAnsiChar; function getInputs(): ITraceParams; @@ -3273,6 +3301,7 @@ ITraceFunction = class(IVersioned) function getStmtID(): Int64; function getPlan(): PAnsiChar; function getExplainedPlan(): PAnsiChar; + function getPerfStats(): IPerformanceStats; end; ITraceFunctionImpl = class(ITraceFunction) @@ -3285,6 +3314,7 @@ ITraceFunctionImpl = class(ITraceFunction) function getStmtID(): Int64; virtual; abstract; function getPlan(): PAnsiChar; virtual; abstract; function getExplainedPlan(): PAnsiChar; virtual; abstract; + function getPerfStats(): IPerformanceStats; virtual; abstract; end; TraceTriggerVTable = class(VersionedVTable) @@ -3296,10 +3326,11 @@ TraceTriggerVTable = class(VersionedVTable) getStmtID: ITraceTrigger_getStmtIDPtr; getPlan: ITraceTrigger_getPlanPtr; getExplainedPlan: ITraceTrigger_getExplainedPlanPtr; + getPerfStats: ITraceTrigger_getPerfStatsPtr; end; ITraceTrigger = class(IVersioned) - const VERSION = 3; + const VERSION = 4; const TYPE_ALL = Cardinal(0); const TYPE_BEFORE = Cardinal(1); const TYPE_AFTER = Cardinal(2); @@ -3312,6 +3343,7 @@ ITraceTrigger = class(IVersioned) function getStmtID(): Int64; function getPlan(): PAnsiChar; function getExplainedPlan(): PAnsiChar; + function getPerfStats(): IPerformanceStats; end; ITraceTriggerImpl = class(ITraceTrigger) @@ -3325,6 +3357,7 @@ ITraceTriggerImpl = class(ITraceTrigger) function getStmtID(): Int64; virtual; abstract; function getPlan(): PAnsiChar; virtual; abstract; function getExplainedPlan(): PAnsiChar; virtual; abstract; + function getPerfStats(): IPerformanceStats; virtual; abstract; end; TraceServiceConnectionVTable = class(TraceConnectionVTable) @@ -3389,16 +3422,18 @@ TraceSweepInfoVTable = class(VersionedVTable) getOAT: ITraceSweepInfo_getOATPtr; getNext: ITraceSweepInfo_getNextPtr; getPerf: ITraceSweepInfo_getPerfPtr; + getPerfStats: ITraceSweepInfo_getPerfStatsPtr; end; ITraceSweepInfo = class(IVersioned) - const VERSION = 2; + const VERSION = 3; function getOIT(): Int64; function getOST(): Int64; function getOAT(): Int64; function getNext(): Int64; function getPerf(): PerformanceInfoPtr; + function getPerfStats(): IPerformanceStats; end; ITraceSweepInfoImpl = class(ITraceSweepInfo) @@ -3409,6 +3444,7 @@ ITraceSweepInfoImpl = class(ITraceSweepInfo) function getOAT(): Int64; virtual; abstract; function getNext(): Int64; virtual; abstract; function getPerf(): PerformanceInfoPtr; virtual; abstract; + function getPerfStats(): IPerformanceStats; virtual; abstract; end; TraceLogWriterVTable = class(ReferenceCountedVTable) @@ -4025,6 +4061,77 @@ IProfilerStatsImpl = class(IProfilerStats) function getElapsedTicks(): QWord; virtual; abstract; end; + PerformanceCountersVTable = class(VersionedVTable) + getObjectCount: IPerformanceCounters_getObjectCountPtr; + getMaxCounterIndex: IPerformanceCounters_getMaxCounterIndexPtr; + getObjectId: IPerformanceCounters_getObjectIdPtr; + getObjectName: IPerformanceCounters_getObjectNamePtr; + getObjectCounters: IPerformanceCounters_getObjectCountersPtr; + end; + + IPerformanceCounters = class(IVersioned) + const VERSION = 2; + const PAGE_FETCHES = Cardinal(0); + const PAGE_READS = Cardinal(1); + const PAGE_MARKS = Cardinal(2); + const PAGE_WRITES = Cardinal(3); + const RECORD_SEQ_READS = Cardinal(0); + const RECORD_IDX_READS = Cardinal(1); + const RECORD_UPDATES = Cardinal(2); + const RECORD_INSERTS = Cardinal(3); + const RECORD_DELETES = Cardinal(4); + const RECORD_BACKOUTS = Cardinal(5); + const RECORD_PURGES = Cardinal(6); + const RECORD_EXPUNGES = Cardinal(7); + const RECORD_LOCKS = Cardinal(8); + const RECORD_WAITS = Cardinal(9); + const RECORD_CONFLICTS = Cardinal(10); + const RECORD_BACK_READS = Cardinal(11); + const RECORD_FRAGMENT_READS = Cardinal(12); + const RECORD_RPT_READS = Cardinal(13); + const RECORD_IMGC = Cardinal(14); + + function getObjectCount(): Cardinal; + function getMaxCounterIndex(): Cardinal; + function getObjectId(index: Cardinal): Cardinal; + function getObjectName(index: Cardinal): PAnsiChar; + function getObjectCounters(index: Cardinal): Int64Ptr; + end; + + IPerformanceCountersImpl = class(IPerformanceCounters) + constructor create; + + function getObjectCount(): Cardinal; virtual; abstract; + function getMaxCounterIndex(): Cardinal; virtual; abstract; + function getObjectId(index: Cardinal): Cardinal; virtual; abstract; + function getObjectName(index: Cardinal): PAnsiChar; virtual; abstract; + function getObjectCounters(index: Cardinal): Int64Ptr; virtual; abstract; + end; + + PerformanceStatsVTable = class(VersionedVTable) + getElapsedTime: IPerformanceStats_getElapsedTimePtr; + getFetchedRecords: IPerformanceStats_getFetchedRecordsPtr; + getCounters: IPerformanceStats_getCountersPtr; + end; + + IPerformanceStats = class(IVersioned) + const VERSION = 2; + const COUNTER_GROUP_PAGES = Cardinal(0); + const COUNTER_GROUP_TABLES = Cardinal(1); + + function getElapsedTime(): QWord; + function getFetchedRecords(): QWord; + function getCounters(group: Cardinal): IPerformanceCounters; + end; + + IPerformanceStatsImpl = class(IPerformanceStats) + constructor create; + + function getElapsedTime(): QWord; virtual; abstract; + function getFetchedRecords(): QWord; virtual; abstract; + function getCounters(group: Cardinal): IPerformanceCounters; virtual; abstract; + end; + {$IFNDEF NO_FBCLIENT} function fb_get_master_interface : IMaster; cdecl; external 'fbclient'; {$ENDIF} @@ -5848,6 +5955,10 @@ IProfilerStatsImpl = class(IProfilerStats) isc_no_user_att_while_restore = 335545318; isc_genseq_stepmustbe_nonzero = 335545319; isc_argmustbe_exact_function = 335545320; + isc_sysf_argmustbe_range_inc0_1 = 335545321; + isc_argmustbe_numeric_function = 335545322; + isc_percetile_only_one_sort_item = 335545323; + isc_argmustbe_const_within_group = 335545324; isc_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; isc_gfix_incmp_sw = 335740932; @@ -9100,6 +9211,16 @@ function ITraceTransaction.getPreviousID(): Int64; end; end; +function ITraceTransaction.getPerfStats(): IPerformanceStats; +begin + if (vTable.version < 4) then begin + Result := nil; + end + else begin + Result := TraceTransactionVTable(vTable).getPerfStats(Self); + end; +end; + function ITraceParams.getCount(): Cardinal; begin Result := TraceParamsVTable(vTable).getCount(Self); @@ -9132,6 +9253,16 @@ function ITraceStatement.getPerf(): PerformanceInfoPtr; Result := TraceStatementVTable(vTable).getPerf(Self); end; +function ITraceStatement.getPerfStats(): IPerformanceStats; +begin + if (vTable.version < 3) then begin + Result := nil; + end + else begin + Result := TraceStatementVTable(vTable).getPerfStats(Self); + end; +end; + function ITraceSQLStatement.getText(): PAnsiChar; begin Result := TraceSQLStatementVTable(vTable).getText(Self); @@ -9247,6 +9378,16 @@ function ITraceProcedure.getExplainedPlan(): PAnsiChar; end; end; +function ITraceProcedure.getPerfStats(): IPerformanceStats; +begin + if (vTable.version < 4) then begin + Result := nil; + end + else begin + Result := TraceProcedureVTable(vTable).getPerfStats(Self); + end; +end; + function ITraceFunction.getFuncName(): PAnsiChar; begin Result := TraceFunctionVTable(vTable).getFuncName(Self); @@ -9297,6 +9438,16 @@ function ITraceFunction.getExplainedPlan(): PAnsiChar; end; end; +function ITraceFunction.getPerfStats(): IPerformanceStats; +begin + if (vTable.version < 4) then begin + Result := nil; + end + else begin + Result := TraceFunctionVTable(vTable).getPerfStats(Self); + end; +end; + function ITraceTrigger.getTriggerName(): PAnsiChar; begin Result := TraceTriggerVTable(vTable).getTriggerName(Self); @@ -9352,6 +9503,16 @@ function ITraceTrigger.getExplainedPlan(): PAnsiChar; end; end; +function ITraceTrigger.getPerfStats(): IPerformanceStats; +begin + if (vTable.version < 4) then begin + Result := nil; + end + else begin + Result := TraceTriggerVTable(vTable).getPerfStats(Self); + end; +end; + function ITraceServiceConnection.getServiceID(): Pointer; begin Result := TraceServiceConnectionVTable(vTable).getServiceID(Self); @@ -9412,6 +9573,16 @@ function ITraceSweepInfo.getPerf(): PerformanceInfoPtr; Result := TraceSweepInfoVTable(vTable).getPerf(Self); end; +function ITraceSweepInfo.getPerfStats(): IPerformanceStats; +begin + if (vTable.version < 3) then begin + Result := nil; + end + else begin + Result := TraceSweepInfoVTable(vTable).getPerfStats(Self); + end; +end; + function ITraceLogWriter.write(buf: Pointer; size: Cardinal): Cardinal; begin Result := TraceLogWriterVTable(vTable).write(Self, buf, size); @@ -10049,6 +10220,46 @@ function IProfilerStats.getElapsedTicks(): QWord; Result := ProfilerStatsVTable(vTable).getElapsedTicks(Self); end; +function IPerformanceCounters.getObjectCount(): Cardinal; +begin + Result := PerformanceCountersVTable(vTable).getObjectCount(Self); +end; + +function IPerformanceCounters.getMaxCounterIndex(): Cardinal; +begin + Result := PerformanceCountersVTable(vTable).getMaxCounterIndex(Self); +end; + +function IPerformanceCounters.getObjectId(index: Cardinal): Cardinal; +begin + Result := PerformanceCountersVTable(vTable).getObjectId(Self, index); +end; + +function IPerformanceCounters.getObjectName(index: Cardinal): PAnsiChar; +begin + Result := PerformanceCountersVTable(vTable).getObjectName(Self, index); +end; + +function IPerformanceCounters.getObjectCounters(index: Cardinal): Int64Ptr; +begin + Result := PerformanceCountersVTable(vTable).getObjectCounters(Self, index); +end; + +function IPerformanceStats.getElapsedTime(): QWord; +begin + Result := PerformanceStatsVTable(vTable).getElapsedTime(Self); +end; + +function IPerformanceStats.getFetchedRecords(): QWord; +begin + Result := PerformanceStatsVTable(vTable).getFetchedRecords(Self); +end; + +function IPerformanceStats.getCounters(group: Cardinal): IPerformanceCounters; +begin + Result := PerformanceStatsVTable(vTable).getCounters(Self, group); +end; + var IVersionedImpl_vTable: VersionedVTable; @@ -15428,6 +15639,16 @@ function ITraceTransactionImpl_getPreviousIDDispatcher(this: ITraceTransaction): end end; +function ITraceTransactionImpl_getPerfStatsDispatcher(this: ITraceTransaction): IPerformanceStats; cdecl; +begin + Result := nil; + try + Result := ITraceTransactionImpl(this).getPerfStats(); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + var ITraceTransactionImpl_vTable: TraceTransactionVTable; @@ -15494,6 +15715,16 @@ function ITraceStatementImpl_getPerfDispatcher(this: ITraceStatement): Performan end end; +function ITraceStatementImpl_getPerfStatsDispatcher(this: ITraceStatement): IPerformanceStats; cdecl; +begin + Result := nil; + try + Result := ITraceStatementImpl(this).getPerfStats(); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + var ITraceStatementImpl_vTable: TraceStatementVTable; @@ -15522,6 +15753,16 @@ function ITraceSQLStatementImpl_getPerfDispatcher(this: ITraceSQLStatement): Per end end; +function ITraceSQLStatementImpl_getPerfStatsDispatcher(this: ITraceSQLStatement): IPerformanceStats; cdecl; +begin + Result := nil; + try + Result := ITraceSQLStatementImpl(this).getPerfStats(); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + function ITraceSQLStatementImpl_getTextDispatcher(this: ITraceSQLStatement): PAnsiChar; cdecl; begin Result := nil; @@ -15600,6 +15841,16 @@ function ITraceBLRStatementImpl_getPerfDispatcher(this: ITraceBLRStatement): Per end end; +function ITraceBLRStatementImpl_getPerfStatsDispatcher(this: ITraceBLRStatement): IPerformanceStats; cdecl; +begin + Result := nil; + try + Result := ITraceBLRStatementImpl(this).getPerfStats(); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + function ITraceBLRStatementImpl_getDataDispatcher(this: ITraceBLRStatement): BytePtr; cdecl; begin Result := nil; @@ -15774,6 +16025,16 @@ function ITraceProcedureImpl_getExplainedPlanDispatcher(this: ITraceProcedure): end end; +function ITraceProcedureImpl_getPerfStatsDispatcher(this: ITraceProcedure): IPerformanceStats; cdecl; +begin + Result := nil; + try + Result := ITraceProcedureImpl(this).getPerfStats(); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + var ITraceProcedureImpl_vTable: TraceProcedureVTable; @@ -15852,6 +16113,16 @@ function ITraceFunctionImpl_getExplainedPlanDispatcher(this: ITraceFunction): PA end end; +function ITraceFunctionImpl_getPerfStatsDispatcher(this: ITraceFunction): IPerformanceStats; cdecl; +begin + Result := nil; + try + Result := ITraceFunctionImpl(this).getPerfStats(); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + var ITraceFunctionImpl_vTable: TraceFunctionVTable; @@ -15940,6 +16211,16 @@ function ITraceTriggerImpl_getExplainedPlanDispatcher(this: ITraceTrigger): PAns end end; +function ITraceTriggerImpl_getPerfStatsDispatcher(this: ITraceTrigger): IPerformanceStats; cdecl; +begin + Result := nil; + try + Result := ITraceTriggerImpl(this).getPerfStats(); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + var ITraceTriggerImpl_vTable: TraceTriggerVTable; @@ -16174,6 +16455,16 @@ function ITraceSweepInfoImpl_getPerfDispatcher(this: ITraceSweepInfo): Performan end end; +function ITraceSweepInfoImpl_getPerfStatsDispatcher(this: ITraceSweepInfo): IPerformanceStats; cdecl; +begin + Result := nil; + try + Result := ITraceSweepInfoImpl(this).getPerfStats(); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + var ITraceSweepInfoImpl_vTable: TraceSweepInfoVTable; @@ -17543,6 +17834,102 @@ constructor IProfilerStatsImpl.create; vTable := IProfilerStatsImpl_vTable; end; +function IPerformanceCountersImpl_getObjectCountDispatcher(this: IPerformanceCounters): Cardinal; cdecl; +begin + Result := 0; + try + Result := IPerformanceCountersImpl(this).getObjectCount(); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + +function IPerformanceCountersImpl_getMaxCounterIndexDispatcher(this: IPerformanceCounters): Cardinal; cdecl; +begin + Result := 0; + try + Result := IPerformanceCountersImpl(this).getMaxCounterIndex(); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + +function IPerformanceCountersImpl_getObjectIdDispatcher(this: IPerformanceCounters; index: Cardinal): Cardinal; cdecl; +begin + Result := 0; + try + Result := IPerformanceCountersImpl(this).getObjectId(index); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + +function IPerformanceCountersImpl_getObjectNameDispatcher(this: IPerformanceCounters; index: Cardinal): PAnsiChar; cdecl; +begin + Result := nil; + try + Result := IPerformanceCountersImpl(this).getObjectName(index); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + +function IPerformanceCountersImpl_getObjectCountersDispatcher(this: IPerformanceCounters; index: Cardinal): Int64Ptr; cdecl; +begin + Result := nil; + try + Result := IPerformanceCountersImpl(this).getObjectCounters(index); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + +var + IPerformanceCountersImpl_vTable: PerformanceCountersVTable; + +constructor IPerformanceCountersImpl.create; +begin + vTable := IPerformanceCountersImpl_vTable; +end; + +function IPerformanceStatsImpl_getElapsedTimeDispatcher(this: IPerformanceStats): QWord; cdecl; +begin + Result := 0; + try + Result := IPerformanceStatsImpl(this).getElapsedTime(); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + +function IPerformanceStatsImpl_getFetchedRecordsDispatcher(this: IPerformanceStats): QWord; cdecl; +begin + Result := 0; + try + Result := IPerformanceStatsImpl(this).getFetchedRecords(); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + +function IPerformanceStatsImpl_getCountersDispatcher(this: IPerformanceStats; group: Cardinal): IPerformanceCounters; cdecl; +begin + Result := nil; + try + Result := IPerformanceStatsImpl(this).getCounters(group); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + +var + IPerformanceStatsImpl_vTable: PerformanceStatsVTable; + +constructor IPerformanceStatsImpl.create; +begin + vTable := IPerformanceStatsImpl_vTable; +end; + constructor FbException.create(status: IStatus); begin inherited Create('FbException'); @@ -18308,7 +18695,7 @@ initialization ITraceDatabaseConnectionImpl_vTable.getDatabaseName := @ITraceDatabaseConnectionImpl_getDatabaseNameDispatcher; ITraceTransactionImpl_vTable := TraceTransactionVTable.create; - ITraceTransactionImpl_vTable.version := 3; + ITraceTransactionImpl_vTable.version := 4; ITraceTransactionImpl_vTable.getTransactionID := @ITraceTransactionImpl_getTransactionIDDispatcher; ITraceTransactionImpl_vTable.getReadOnly := @ITraceTransactionImpl_getReadOnlyDispatcher; ITraceTransactionImpl_vTable.getWait := @ITraceTransactionImpl_getWaitDispatcher; @@ -18316,6 +18703,7 @@ initialization ITraceTransactionImpl_vTable.getPerf := @ITraceTransactionImpl_getPerfDispatcher; ITraceTransactionImpl_vTable.getInitialID := @ITraceTransactionImpl_getInitialIDDispatcher; ITraceTransactionImpl_vTable.getPreviousID := @ITraceTransactionImpl_getPreviousIDDispatcher; + ITraceTransactionImpl_vTable.getPerfStats := @ITraceTransactionImpl_getPerfStatsDispatcher; ITraceParamsImpl_vTable := TraceParamsVTable.create; ITraceParamsImpl_vTable.version := 3; @@ -18324,14 +18712,16 @@ initialization ITraceParamsImpl_vTable.getTextUTF8 := @ITraceParamsImpl_getTextUTF8Dispatcher; ITraceStatementImpl_vTable := TraceStatementVTable.create; - ITraceStatementImpl_vTable.version := 2; + ITraceStatementImpl_vTable.version := 3; ITraceStatementImpl_vTable.getStmtID := @ITraceStatementImpl_getStmtIDDispatcher; ITraceStatementImpl_vTable.getPerf := @ITraceStatementImpl_getPerfDispatcher; + ITraceStatementImpl_vTable.getPerfStats := @ITraceStatementImpl_getPerfStatsDispatcher; ITraceSQLStatementImpl_vTable := TraceSQLStatementVTable.create; - ITraceSQLStatementImpl_vTable.version := 3; + ITraceSQLStatementImpl_vTable.version := 4; ITraceSQLStatementImpl_vTable.getStmtID := @ITraceSQLStatementImpl_getStmtIDDispatcher; ITraceSQLStatementImpl_vTable.getPerf := @ITraceSQLStatementImpl_getPerfDispatcher; + ITraceSQLStatementImpl_vTable.getPerfStats := @ITraceSQLStatementImpl_getPerfStatsDispatcher; ITraceSQLStatementImpl_vTable.getText := @ITraceSQLStatementImpl_getTextDispatcher; ITraceSQLStatementImpl_vTable.getPlan := @ITraceSQLStatementImpl_getPlanDispatcher; ITraceSQLStatementImpl_vTable.getInputs := @ITraceSQLStatementImpl_getInputsDispatcher; @@ -18339,9 +18729,10 @@ initialization ITraceSQLStatementImpl_vTable.getExplainedPlan := @ITraceSQLStatementImpl_getExplainedPlanDispatcher; ITraceBLRStatementImpl_vTable := TraceBLRStatementVTable.create; - ITraceBLRStatementImpl_vTable.version := 3; + ITraceBLRStatementImpl_vTable.version := 4; ITraceBLRStatementImpl_vTable.getStmtID := @ITraceBLRStatementImpl_getStmtIDDispatcher; ITraceBLRStatementImpl_vTable.getPerf := @ITraceBLRStatementImpl_getPerfDispatcher; + ITraceBLRStatementImpl_vTable.getPerfStats := @ITraceBLRStatementImpl_getPerfStatsDispatcher; ITraceBLRStatementImpl_vTable.getData := @ITraceBLRStatementImpl_getDataDispatcher; ITraceBLRStatementImpl_vTable.getDataLength := @ITraceBLRStatementImpl_getDataLengthDispatcher; ITraceBLRStatementImpl_vTable.getText := @ITraceBLRStatementImpl_getTextDispatcher; @@ -18359,16 +18750,17 @@ initialization ITraceContextVariableImpl_vTable.getVarValue := @ITraceContextVariableImpl_getVarValueDispatcher; ITraceProcedureImpl_vTable := TraceProcedureVTable.create; - ITraceProcedureImpl_vTable.version := 3; + ITraceProcedureImpl_vTable.version := 4; ITraceProcedureImpl_vTable.getProcName := @ITraceProcedureImpl_getProcNameDispatcher; ITraceProcedureImpl_vTable.getInputs := @ITraceProcedureImpl_getInputsDispatcher; ITraceProcedureImpl_vTable.getPerf := @ITraceProcedureImpl_getPerfDispatcher; ITraceProcedureImpl_vTable.getStmtID := @ITraceProcedureImpl_getStmtIDDispatcher; ITraceProcedureImpl_vTable.getPlan := @ITraceProcedureImpl_getPlanDispatcher; ITraceProcedureImpl_vTable.getExplainedPlan := @ITraceProcedureImpl_getExplainedPlanDispatcher; + ITraceProcedureImpl_vTable.getPerfStats := @ITraceProcedureImpl_getPerfStatsDispatcher; ITraceFunctionImpl_vTable := TraceFunctionVTable.create; - ITraceFunctionImpl_vTable.version := 3; + ITraceFunctionImpl_vTable.version := 4; ITraceFunctionImpl_vTable.getFuncName := @ITraceFunctionImpl_getFuncNameDispatcher; ITraceFunctionImpl_vTable.getInputs := @ITraceFunctionImpl_getInputsDispatcher; ITraceFunctionImpl_vTable.getResult := @ITraceFunctionImpl_getResultDispatcher; @@ -18376,9 +18768,10 @@ initialization ITraceFunctionImpl_vTable.getStmtID := @ITraceFunctionImpl_getStmtIDDispatcher; ITraceFunctionImpl_vTable.getPlan := @ITraceFunctionImpl_getPlanDispatcher; ITraceFunctionImpl_vTable.getExplainedPlan := @ITraceFunctionImpl_getExplainedPlanDispatcher; + ITraceFunctionImpl_vTable.getPerfStats := @ITraceFunctionImpl_getPerfStatsDispatcher; ITraceTriggerImpl_vTable := TraceTriggerVTable.create; - ITraceTriggerImpl_vTable.version := 3; + ITraceTriggerImpl_vTable.version := 4; ITraceTriggerImpl_vTable.getTriggerName := @ITraceTriggerImpl_getTriggerNameDispatcher; ITraceTriggerImpl_vTable.getRelationName := @ITraceTriggerImpl_getRelationNameDispatcher; ITraceTriggerImpl_vTable.getAction := @ITraceTriggerImpl_getActionDispatcher; @@ -18387,6 +18780,7 @@ initialization ITraceTriggerImpl_vTable.getStmtID := @ITraceTriggerImpl_getStmtIDDispatcher; ITraceTriggerImpl_vTable.getPlan := @ITraceTriggerImpl_getPlanDispatcher; ITraceTriggerImpl_vTable.getExplainedPlan := @ITraceTriggerImpl_getExplainedPlanDispatcher; + ITraceTriggerImpl_vTable.getPerfStats := @ITraceTriggerImpl_getPerfStatsDispatcher; ITraceServiceConnectionImpl_vTable := TraceServiceConnectionVTable.create; ITraceServiceConnectionImpl_vTable.version := 3; @@ -18411,12 +18805,13 @@ initialization ITraceStatusVectorImpl_vTable.getText := @ITraceStatusVectorImpl_getTextDispatcher; ITraceSweepInfoImpl_vTable := TraceSweepInfoVTable.create; - ITraceSweepInfoImpl_vTable.version := 2; + ITraceSweepInfoImpl_vTable.version := 3; ITraceSweepInfoImpl_vTable.getOIT := @ITraceSweepInfoImpl_getOITDispatcher; ITraceSweepInfoImpl_vTable.getOST := @ITraceSweepInfoImpl_getOSTDispatcher; ITraceSweepInfoImpl_vTable.getOAT := @ITraceSweepInfoImpl_getOATDispatcher; ITraceSweepInfoImpl_vTable.getNext := @ITraceSweepInfoImpl_getNextDispatcher; ITraceSweepInfoImpl_vTable.getPerf := @ITraceSweepInfoImpl_getPerfDispatcher; + ITraceSweepInfoImpl_vTable.getPerfStats := @ITraceSweepInfoImpl_getPerfStatsDispatcher; ITraceLogWriterImpl_vTable := TraceLogWriterVTable.create; ITraceLogWriterImpl_vTable.version := 4; @@ -18600,6 +18995,20 @@ initialization IProfilerStatsImpl_vTable.version := 2; IProfilerStatsImpl_vTable.getElapsedTicks := @IProfilerStatsImpl_getElapsedTicksDispatcher; + IPerformanceCountersImpl_vTable := PerformanceCountersVTable.create; + IPerformanceCountersImpl_vTable.version := 2; + IPerformanceCountersImpl_vTable.getObjectCount := @IPerformanceCountersImpl_getObjectCountDispatcher; + IPerformanceCountersImpl_vTable.getMaxCounterIndex := @IPerformanceCountersImpl_getMaxCounterIndexDispatcher; + IPerformanceCountersImpl_vTable.getObjectId := @IPerformanceCountersImpl_getObjectIdDispatcher; + IPerformanceCountersImpl_vTable.getObjectName := @IPerformanceCountersImpl_getObjectNameDispatcher; + IPerformanceCountersImpl_vTable.getObjectCounters := @IPerformanceCountersImpl_getObjectCountersDispatcher; + + IPerformanceStatsImpl_vTable := PerformanceStatsVTable.create; + IPerformanceStatsImpl_vTable.version := 2; + IPerformanceStatsImpl_vTable.getElapsedTime := @IPerformanceStatsImpl_getElapsedTimeDispatcher; + IPerformanceStatsImpl_vTable.getFetchedRecords := @IPerformanceStatsImpl_getFetchedRecordsDispatcher; + IPerformanceStatsImpl_vTable.getCounters := @IPerformanceStatsImpl_getCountersDispatcher; + finalization IVersionedImpl_vTable.destroy; IReferenceCountedImpl_vTable.destroy; @@ -18699,5 +19108,7 @@ finalization IProfilerPluginImpl_vTable.destroy; IProfilerSessionImpl_vTable.destroy; IProfilerStatsImpl_vTable.destroy; + IPerformanceCountersImpl_vTable.destroy; + IPerformanceStatsImpl_vTable.destroy; end. diff --git a/src/intl/charsets/cs_koi8u.h b/src/intl/charsets/cs_koi8u.h index 6c8866774d8..27f85da5c69 100644 --- a/src/intl/charsets/cs_koi8u.h +++ b/src/intl/charsets/cs_koi8u.h @@ -7,7 +7,6 @@ -------------------------------------------- */ -static const int UNICODE_REPLACEMENT_CHARACTER = 0xFFFD; static const int CANT_MAP_CHARACTER = 0; static const USHORT to_unicode_map[256] = { diff --git a/src/isql/isql.epp b/src/isql/isql.epp index a2c5c8225ee..daab2b9d08f 100644 --- a/src/isql/isql.epp +++ b/src/isql/isql.epp @@ -158,7 +158,6 @@ constexpr int INT64_LEN = 21; // NUMERIC(18,2) = -92233720368547758.08 //constexpr int QUAD_LEN = 19; constexpr int FLOAT_LEN = 14; // -1.2345678E+38 constexpr int DOUBLE_LEN = 23; // -1.234567890123456E+300 -constexpr int DATE_LEN = 11; // 11 for date only constexpr int DATETIME_LEN = 25; // 25 for date-time constexpr int DATETIME_TZ_LEN = DATETIME_LEN - 1 + 1 + TimeZoneUtil::MAX_LEN; // DATETIME_LEN should be 24 constexpr int TIME_ONLY_LEN = 13; // 13 for time only @@ -167,8 +166,6 @@ constexpr int DATE_ONLY_LEN = 11; constexpr int BOOLEAN_LEN = 7; // constexpr int UNKNOWN_LEN = 20; // Unknown type: %d -constexpr int MAX_TERMS = 10; // max # of terms in an interactive cmd - constexpr const char* ISQL_COUNTERS_SET = "CurrentMemory, MaxMemory, RealTime, UserTime, Buffers, Reads, Writes, Fetches"; constexpr int ISQL_COUNTERS = 8; @@ -177,7 +174,7 @@ constexpr const char* UNKNOWN = "*unknown*"; namespace IcuUtil { // Duplicate from ICU to not need to link ISQL with it. It's used by U8_NEXT_UNSAFE. - static constexpr uint8_t utf8_countTrailBytes[256] = { + [[maybe_unused]] static constexpr uint8_t utf8_countTrailBytes[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -2432,7 +2429,6 @@ static processing_state add_row(const QualifiedMetaString& tabname) unsigned type = msg->getType(fbStatus, i); if (ISQL_errmsg(fbStatus)) return (SKIP); - const bool nullable = msg->isNullable(fbStatus, i); if (ISQL_errmsg(fbStatus)) return (SKIP); unsigned varLength; @@ -3145,7 +3141,7 @@ static processing_state bulk_insert_hack(const char* command) const char* lastPos = insert; Extender extender; // Used only for multi-line tuples. - for (unsigned i = 0, textFieldIter = 0; i < n_cols && !done; ++i) + for (unsigned i = 0; i < n_cols && !done; ++i) { unsigned offset = message->getNullOffset(fbStatus, i); if (ISQL_errmsg(fbStatus)) @@ -3160,7 +3156,6 @@ static processing_state bulk_insert_hack(const char* command) unsigned type = message->getType(fbStatus, i); if (ISQL_errmsg(fbStatus)) return (SKIP); - const bool nullable = message->isNullable(fbStatus, i); if (ISQL_errmsg(fbStatus)) return (SKIP); diff --git a/src/isql/show.epp b/src/isql/show.epp index 6f190c5bac6..23d09259305 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -4303,7 +4303,6 @@ static processing_state show_func(const QualifiedMetaString& name) } bool first_param = true; - const SSHORT default_charset = ISQL_get_default_char_set_id(); FOR ARG IN RDB$FUNCTION_ARGUMENTS CROSS FLD IN RDB$FIELDS diff --git a/src/jrd/BlobUtil.cpp b/src/jrd/BlobUtil.cpp index 1dec99daf97..18ca4a4270c 100644 --- a/src/jrd/BlobUtil.cpp +++ b/src/jrd/BlobUtil.cpp @@ -67,7 +67,6 @@ IExternalResultSet* BlobUtilPackage::cancelBlobProcedure(ThrowStatusExceptionWra IExternalContext* context, const BlobMessage::Type* in, void*) { const auto tdbb = JRD_get_thread_data(); - const auto transaction = tdbb->getTransaction(); const auto blobId = *(bid*) &in->blob; @@ -102,7 +101,6 @@ void BlobUtilPackage::isWritableFunction(ThrowStatusExceptionWrapper* status, IExternalContext* context, const BlobMessage::Type* in, BooleanMessage::Type* out) { const auto tdbb = JRD_get_thread_data(); - const auto transaction = tdbb->getTransaction(); const auto blobId = *(bid*) &in->blob; @@ -161,7 +159,6 @@ void BlobUtilPackage::seekFunction(ThrowStatusExceptionWrapper* status, IExternalContext* context, const SeekInput::Type* in, SeekOutput::Type* out) { const auto tdbb = JRD_get_thread_data(); - const auto transaction = tdbb->getTransaction(); const auto blob = getBlobFromHandle(tdbb, in->handle); if (!(in->mode >= 0 && in->mode <= 2)) @@ -185,7 +182,6 @@ void BlobUtilPackage::readDataFunction(ThrowStatusExceptionWrapper* status, status_exception::raise(Arg::Gds(isc_random) << "Length must be NULL or greater than 0"); const auto tdbb = JRD_get_thread_data(); - const auto transaction = tdbb->getTransaction(); const auto blob = getBlobFromHandle(tdbb, in->handle); if (in->lengthNull) diff --git a/src/jrd/Monitoring.cpp b/src/jrd/Monitoring.cpp index ea09c3daa32..7e56fa88388 100644 --- a/src/jrd/Monitoring.cpp +++ b/src/jrd/Monitoring.cpp @@ -1042,8 +1042,6 @@ void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Atta if (!attachment->att_user) return; - const auto* dbb = attachment->att_database; - record.reset(rel_mon_attachments); PathName attName(attachment->att_filename); @@ -1451,36 +1449,39 @@ void Monitoring::putStatistics(SnapshotData::DumpRecord& record, const RuntimeSt // logical I/O statistics (table wise) - for (auto iter(statistics.getRelCounters()); iter; ++iter) + for (const auto& counts : statistics.getTableCounters()) { + if (counts.isEmpty()) + continue; + const auto rec_stat_id = getGlobalId(fb_utils::genUniqueId()); record.reset(rel_mon_tab_stats); record.storeGlobalId(f_mon_tab_stat_id, id); record.storeInteger(f_mon_tab_stat_group, stat_group); - record.storeTableIdSchemaName(f_mon_tab_sch_name, (*iter).getRelationId()); - record.storeTableIdObjectName(f_mon_tab_name, (*iter).getRelationId()); + record.storeTableIdSchemaName(f_mon_tab_sch_name, counts.getGroupId()); + record.storeTableIdObjectName(f_mon_tab_name, counts.getGroupId()); record.storeGlobalId(f_mon_tab_rec_stat_id, rec_stat_id); record.write(); record.reset(rel_mon_rec_stats); record.storeGlobalId(f_mon_rec_stat_id, rec_stat_id); record.storeInteger(f_mon_rec_stat_group, stat_group); - record.storeInteger(f_mon_rec_seq_reads, (*iter)[RecordStatType::SEQ_READS]); - record.storeInteger(f_mon_rec_idx_reads, (*iter)[RecordStatType::IDX_READS]); - record.storeInteger(f_mon_rec_inserts, (*iter)[RecordStatType::INSERTS]); - record.storeInteger(f_mon_rec_updates, (*iter)[RecordStatType::UPDATES]); - record.storeInteger(f_mon_rec_deletes, (*iter)[RecordStatType::DELETES]); - record.storeInteger(f_mon_rec_backouts, (*iter)[RecordStatType::BACKOUTS]); - record.storeInteger(f_mon_rec_purges, (*iter)[RecordStatType::PURGES]); - record.storeInteger(f_mon_rec_expunges, (*iter)[RecordStatType::EXPUNGES]); - record.storeInteger(f_mon_rec_locks, (*iter)[RecordStatType::LOCKS]); - record.storeInteger(f_mon_rec_waits, (*iter)[RecordStatType::WAITS]); - record.storeInteger(f_mon_rec_conflicts, (*iter)[RecordStatType::CONFLICTS]); - record.storeInteger(f_mon_rec_bkver_reads, (*iter)[RecordStatType::BACK_READS]); - record.storeInteger(f_mon_rec_frg_reads, (*iter)[RecordStatType::FRAGMENT_READS]); - record.storeInteger(f_mon_rec_rpt_reads, (*iter)[RecordStatType::RPT_READS]); - record.storeInteger(f_mon_rec_imgc, (*iter)[RecordStatType::IMGC]); + record.storeInteger(f_mon_rec_seq_reads, counts[RecordStatType::SEQ_READS]); + record.storeInteger(f_mon_rec_idx_reads, counts[RecordStatType::IDX_READS]); + record.storeInteger(f_mon_rec_inserts, counts[RecordStatType::INSERTS]); + record.storeInteger(f_mon_rec_updates, counts[RecordStatType::UPDATES]); + record.storeInteger(f_mon_rec_deletes, counts[RecordStatType::DELETES]); + record.storeInteger(f_mon_rec_backouts, counts[RecordStatType::BACKOUTS]); + record.storeInteger(f_mon_rec_purges, counts[RecordStatType::PURGES]); + record.storeInteger(f_mon_rec_expunges, counts[RecordStatType::EXPUNGES]); + record.storeInteger(f_mon_rec_locks, counts[RecordStatType::LOCKS]); + record.storeInteger(f_mon_rec_waits, counts[RecordStatType::WAITS]); + record.storeInteger(f_mon_rec_conflicts, counts[RecordStatType::CONFLICTS]); + record.storeInteger(f_mon_rec_bkver_reads, counts[RecordStatType::BACK_READS]); + record.storeInteger(f_mon_rec_frg_reads, counts[RecordStatType::FRAGMENT_READS]); + record.storeInteger(f_mon_rec_rpt_reads, counts[RecordStatType::RPT_READS]); + record.storeInteger(f_mon_rec_imgc, counts[RecordStatType::IMGC]); record.write(); } } diff --git a/src/jrd/ProfilerManager.cpp b/src/jrd/ProfilerManager.cpp index 1c45579bd9b..52265e5f4bf 100644 --- a/src/jrd/ProfilerManager.cpp +++ b/src/jrd/ProfilerManager.cpp @@ -258,7 +258,6 @@ IExternalResultSet* ProfilerPackage::cancelSessionProcedure(ThrowStatusException return nullptr; } - const auto* transaction = tdbb->getTransaction(); const auto profilerManager = attachment->getProfilerManager(tdbb); profilerManager->cancelSession(); diff --git a/src/jrd/RecordSourceNodes.cpp b/src/jrd/RecordSourceNodes.cpp index 46042cafdaa..5e892959c32 100644 --- a/src/jrd/RecordSourceNodes.cpp +++ b/src/jrd/RecordSourceNodes.cpp @@ -2840,8 +2840,6 @@ void WindowSourceNode::collectStreams(SortedStreamList& streamList) const RecordSource* WindowSourceNode::compile(thread_db* tdbb, Optimizer* opt, bool /*innerSubStream*/) { - const auto csb = opt->getCompilerScratch(); - return FB_NEW_POOL(*tdbb->getDefaultPool()) WindowedStream(tdbb, opt, windows, opt->compile(rse, NULL)); } @@ -4311,8 +4309,6 @@ void TableValueFunctionSourceNode::setDefaultNameField(DsqlCompilerScratch* /*ds { const auto nameFunc = tableValueFunctionContext->funName; - auto i = 0U; - if ((nameFunc == UnlistFunctionSourceNode::FUNC_NAME) || (nameFunc == GenSeriesFunctionSourceNode::FUNC_NAME)) { diff --git a/src/jrd/Relation.cpp b/src/jrd/Relation.cpp index 4a40f874761..9713d45344b 100644 --- a/src/jrd/Relation.cpp +++ b/src/jrd/Relation.cpp @@ -214,7 +214,6 @@ void jrd_rel::retainPages(thread_db* tdbb, TraNumber oldNumber, TraNumber newNum if (!rel_pages_inst) return; - const SINT64 inst_id = oldNumber; FB_SIZE_T pos; if (!rel_pages_inst->find(oldNumber, pos)) return; diff --git a/src/jrd/Relation.h b/src/jrd/Relation.h index 63dd4256e86..cfd6a93cdc9 100644 --- a/src/jrd/Relation.h +++ b/src/jrd/Relation.h @@ -404,6 +404,7 @@ inline constexpr ULONG REL_jrd_view = 0x8000; // relation is VIEW inline constexpr ULONG REL_gc_blocking = 0x10000; // request to downgrade\release gc lock inline constexpr ULONG REL_gc_disabled = 0x20000; // gc is disabled temporarily inline constexpr ULONG REL_gc_lockneed = 0x40000; // gc lock should be acquired +inline constexpr ULONG REL_rescan = 0x100000; // rescan request was submitted while relation being scanning /// class jrd_rel diff --git a/src/jrd/RuntimeStatistics.cpp b/src/jrd/RuntimeStatistics.cpp index 95630662623..d4ce6474d6f 100644 --- a/src/jrd/RuntimeStatistics.cpp +++ b/src/jrd/RuntimeStatistics.cpp @@ -33,52 +33,75 @@ namespace Jrd { GlobalPtr RuntimeStatistics::dummy; -void RuntimeStatistics::adjustRelStats(const RuntimeStatistics& baseStats, const RuntimeStatistics& newStats) +void RuntimeStatistics::adjust(const RuntimeStatistics& baseStats, const RuntimeStatistics& newStats) { - if (baseStats.relChgNumber == newStats.relChgNumber) + if (baseStats.allChgNumber == newStats.allChgNumber) return; - relChgNumber++; + allChgNumber++; + for (size_t i = 0; i < GLOBAL_ITEMS; ++i) + values[i] += newStats.values[i] - baseStats.values[i]; + + if (baseStats.pageChgNumber != newStats.pageChgNumber) + { + pageChgNumber++; + pageCounters.adjust(baseStats.pageCounters, newStats.pageCounters); + } + + if (baseStats.tabChgNumber != newStats.tabChgNumber) + { + tabChgNumber++; + tableCounters.adjust(baseStats.tableCounters, newStats.tableCounters); + } +} - auto locate = [this](SLONG relId) -> FB_SIZE_T +void RuntimeStatistics::adjustPageStats(RuntimeStatistics& baseStats, const RuntimeStatistics& newStats) +{ + if (baseStats.allChgNumber == newStats.allChgNumber) + return; + + allChgNumber++; + for (size_t i = 0; i < PAGE_TOTAL_ITEMS; ++i) { - FB_SIZE_T pos; - if (!rel_counts.find(relId, pos)) - rel_counts.insert(pos, RelationCounts(relId)); - return pos; - }; + const SINT64 delta = newStats.values[i] - baseStats.values[i]; - auto baseIter = baseStats.rel_counts.begin(), newIter = newStats.rel_counts.begin(); - const auto baseEnd = baseStats.rel_counts.end(), newEnd = newStats.rel_counts.end(); + values[i] += delta; + baseStats.values[i] += delta; + } +} + +template +void RuntimeStatistics::GroupedCountsArray::adjust(const GroupedCountsArray& baseStats, const GroupedCountsArray& newStats) +{ + auto baseIter = baseStats.m_counts.begin(), newIter = newStats.m_counts.begin(); + const auto baseEnd = baseStats.m_counts.end(), newEnd = newStats.m_counts.end(); - // The loop below assumes that newStats cannot miss relations existing in baseStats, + // The loop below assumes that newStats cannot miss objects existing in baseStats, // this must be always the case as long as newStats is an incremented version of baseStats while (newIter != newEnd || baseIter != baseEnd) { if (baseIter == baseEnd) { - // Relation exists in newStats but missing in baseStats - const auto newRelId = newIter->getRelationId(); - rel_counts[locate(newRelId)] += *newIter++; + // Object exists in newStats but missing in baseStats + const auto newId = newIter->getGroupId(); + (*this)[newId] += *newIter++; } else if (newIter != newEnd) { - const auto baseRelId = baseIter->getRelationId(); - const auto newRelId = newIter->getRelationId(); + const auto baseId = baseIter->getGroupId(); + const auto newId = newIter->getGroupId(); - if (newRelId == baseRelId) + if (newId == baseId) { - // Relation exists in both newStats and baseStats - fb_assert(baseRelId == newRelId); - const auto pos = locate(baseRelId); - rel_counts[pos] -= *baseIter++; - rel_counts[pos] += *newIter++; + // Object exists in both newStats and baseStats + (*this)[newId] += *newIter++; + (*this)[newId] -= *baseIter++; } - else if (newRelId < baseRelId) + else if (newId < baseId) { - // Relation exists in newStats but missing in baseStats - rel_counts[locate(newRelId)] += *newIter++; + // Object exists in newStats but missing in baseStats + (*this)[newId] += *newIter++; } else fb_assert(false); // should never happen @@ -88,114 +111,23 @@ void RuntimeStatistics::adjustRelStats(const RuntimeStatistics& baseStats, const } } -PerformanceInfo* RuntimeStatistics::computeDifference(Attachment* att, - const RuntimeStatistics& new_stat, - PerformanceInfo& dest, - TraceCountsArray& temp, - ObjectsArray& tempNames) +void RuntimeStatistics::setToDiff(const RuntimeStatistics& newStats) { - // NOTE: we do not initialize dest.pin_time. This must be done by the caller - - // Calculate database-level statistics for (size_t i = 0; i < GLOBAL_ITEMS; i++) - values[i] = new_stat.values[i] - values[i]; + values[i] = newStats.values[i] - values[i]; - dest.pin_counters = values; - - // Calculate relation-level statistics - temp.clear(); - tempNames.clear(); - - // This loop assumes that base array is smaller than new one - RelCounters::iterator base_cnts = rel_counts.begin(); - bool base_found = (base_cnts != rel_counts.end()); - - for (const auto& new_cnts : new_stat.rel_counts) + for (const auto& newCounts : newStats.pageCounters) { - const SLONG rel_id = new_cnts.getRelationId(); - - if (base_found && base_cnts->getRelationId() == rel_id) - { - // Point TraceCounts to counts array from baseline object - if (base_cnts->setToDiff(new_cnts)) - { - jrd_rel* const relation = - rel_id < static_cast(att->att_relations->count()) ? - (*att->att_relations)[rel_id] : NULL; - - TraceCounts traceCounts; - traceCounts.trc_relation_id = rel_id; - traceCounts.trc_counters = base_cnts->getCounterVector(); - - if (relation) - { - auto& tempName = tempNames.add(); - tempName = relation->rel_name.toQuotedString(); - traceCounts.trc_relation_name = tempName.c_str(); - } - else - traceCounts.trc_relation_name = nullptr; - - temp.add(traceCounts); - } - - ++base_cnts; - base_found = (base_cnts != rel_counts.end()); - } - else - { - jrd_rel* const relation = - rel_id < static_cast(att->att_relations->count()) ? - (*att->att_relations)[rel_id] : NULL; - - // Point TraceCounts to counts array from object with updated counters - TraceCounts traceCounts; - traceCounts.trc_relation_id = rel_id; - traceCounts.trc_counters = new_cnts.getCounterVector(); - - if (relation) - { - auto& tempName = tempNames.add(); - tempName = relation->rel_name.toQuotedString(); - traceCounts.trc_relation_name = tempName.c_str(); - } - else - traceCounts.trc_relation_name = nullptr; - - temp.add(traceCounts); - } - }; - - dest.pin_count = temp.getCount(); - dest.pin_tables = temp.begin(); - - return &dest; -} - -void RuntimeStatistics::adjust(const RuntimeStatistics& baseStats, const RuntimeStatistics& newStats) -{ - if (baseStats.allChgNumber == newStats.allChgNumber) - return; - - allChgNumber++; - for (size_t i = 0; i < GLOBAL_ITEMS; ++i) - values[i] += newStats.values[i] - baseStats.values[i]; - - adjustRelStats(baseStats, newStats); -} - -void RuntimeStatistics::adjustPageStats(RuntimeStatistics& baseStats, const RuntimeStatistics& newStats) -{ - if (baseStats.allChgNumber == newStats.allChgNumber) - return; + const auto pageSpaceId = newCounts.getGroupId(); + if (!pageCounters[pageSpaceId].setToDiff(newCounts)) + pageCounters.remove(pageSpaceId); + } - allChgNumber++; - for (size_t i = 0; i < PAGE_TOTAL_ITEMS; ++i) + for (const auto& newCounts : newStats.tableCounters) { - const SINT64 delta = newStats.values[i] - baseStats.values[i]; - - values[i] += delta; - baseStats.values[i] += delta; + const auto relationId = newCounts.getGroupId(); + if (!tableCounters[relationId].setToDiff(newCounts)) + tableCounters.remove(relationId); } } diff --git a/src/jrd/RuntimeStatistics.h b/src/jrd/RuntimeStatistics.h index d340cd0d079..3db58932ab0 100644 --- a/src/jrd/RuntimeStatistics.h +++ b/src/jrd/RuntimeStatistics.h @@ -29,19 +29,11 @@ #include "../common/classes/init.h" #include "../common/classes/tree.h" #include "../common/classes/File.h" +#include "../jrd/ini.h" +#include "../jrd/pag.h" #include -namespace Firebird -{ - -// declared in firebird/Interface.h -struct TraceCounts; -struct PerformanceInfo; - -} // namespace Firebird - - namespace Jrd { class Attachment; @@ -49,7 +41,6 @@ class Database; class thread_db; class jrd_rel; -typedef Firebird::HalfStaticArray TraceCountsArray; // Runtime statistics @@ -92,7 +83,7 @@ class RuntimeStatistics : protected Firebird::AutoStorage // // dimitr: Currently, they include page-level and record-level counters. // However, this is not strictly required to maintain global record-level counters, - // as they may be aggregated from the rel_counts array on demand. This would slow down + // as they may be aggregated from the tableCounters array on demand. This would slow down // the retrieval of counters but save some CPU cycles inside tdbb->bumpStats(). // As long as public struct PerformanceInfo don't include record-level counters, // this is not going to affect any existing applications/plugins. @@ -135,6 +126,24 @@ class RuntimeStatistics : protected Firebird::AutoStorage return *this; } + bool setToDiff(const CountsVector& other) + { + bool ret = false; + + for (size_t i = 0; i < m_counters.size(); i++) + { + if ( (m_counters[i] = other.m_counters[i] - m_counters[i]) ) + ret = true; + } + + return ret; + } + + static unsigned getVectorCapacity() + { + return (unsigned) SIZE; + } + const SINT64* getCounterVector() const { return m_counters.data(); @@ -156,104 +165,187 @@ class RuntimeStatistics : protected Firebird::AutoStorage std::array m_counters = {}; }; - // Performance counters for individual table - - class RelationCounts : public CountsVector + template + class CountsGroup : public CountsVector { public: - explicit RelationCounts(SLONG relation_id) - : m_relation_id(relation_id) + typedef Key ID; + + explicit CountsGroup(ID id) + : m_id(id) + {} + + ID getGroupId() const { + return m_id; } - SLONG getRelationId() const + CountsGroup& operator+=(const CountsGroup& other) { - return m_relation_id; + fb_assert(m_id == other.m_id); + CountsVector::operator+=(other); + return *this; } - bool setToDiff(const RelationCounts& other) + CountsGroup& operator-=(const CountsGroup& other) { - fb_assert(m_relation_id == other.m_relation_id); + fb_assert(m_id == other.m_id); + CountsVector::operator-=(other); + return *this; + } - bool ret = false; + bool setToDiff(const CountsGroup& other) + { + fb_assert(m_id == other.m_id); + return CountsVector::setToDiff(other); + } - for (size_t i = 0; i < m_counters.size(); i++) + inline static const ID& generate(const CountsGroup& item) + { + return item.m_id; + } + + private: + ID m_id; + }; + + template + class GroupedCountsArray + { + typedef typename Counts::ID ID; + typedef Firebird::SortedArray< + Counts, Firebird::EmptyStorage, ID, Counts> SortedCountsArray; + typedef typename SortedCountsArray::const_iterator ConstIterator; + + public: + GroupedCountsArray(MemoryPool& pool, FB_SIZE_T capacity) + : m_counts(pool, capacity) + {} + + GroupedCountsArray(MemoryPool& pool, const GroupedCountsArray& other) + : m_counts(pool, other.m_counts.getCapacity()) + {} + + Counts& operator[](ID id) + { + if ((m_lastPos != (FB_SIZE_T) ~0 && m_counts[m_lastPos].getGroupId() == id) || + // if m_lastPos is mispositioned + m_counts.find(id, m_lastPos)) { - if ( (m_counters[i] = other.m_counters[i] - m_counters[i]) ) - ret = true; + return m_counts[m_lastPos]; } - return ret; + Counts counts(id); + m_counts.insert(m_lastPos, counts); + return m_counts[m_lastPos]; } - RelationCounts& operator+=(const RelationCounts& other) + unsigned getCount() const { - fb_assert(m_relation_id == other.m_relation_id); - CountsVector::operator+=(other); - return *this; + return m_counts.getCount(); } - RelationCounts& operator-=(const RelationCounts& other) + static unsigned getVectorCapacity() { - fb_assert(m_relation_id == other.m_relation_id); - CountsVector::operator-=(other); - return *this; + return Counts::getVectorCapacity(); + } + + void remove(ID id) + { + if ((m_lastPos != (FB_SIZE_T) ~0 && m_counts[m_lastPos].getGroupId() == id) || + // if m_lastPos is mispositioned + m_counts.find(id, m_lastPos)) + { + m_counts.remove(m_lastPos); + m_lastPos = (FB_SIZE_T) ~0; + } + } + + void reset() + { + m_counts.clear(); + m_lastPos = (FB_SIZE_T) ~0; } - inline static const SLONG& generate(const RelationCounts& item) + ConstIterator begin() const { - return item.m_relation_id; + return m_counts.begin(); } + ConstIterator end() const + { + return m_counts.end(); + } + + void adjust(const GroupedCountsArray& baseStats, const GroupedCountsArray& newStats); + private: - SLONG m_relation_id; + SortedCountsArray m_counts; + FB_SIZE_T m_lastPos = (FB_SIZE_T) ~0; }; - typedef Firebird::SortedArray, - SLONG, RelationCounts> RelCounters; - public: + typedef GroupedCountsArray > PageCounters; + typedef GroupedCountsArray > TableCounters; + RuntimeStatistics() - : Firebird::AutoStorage(), rel_counts(getPool()) + : Firebird::AutoStorage(), + pageCounters(getPool(), DB_PAGE_SPACE + 1), + tableCounters(getPool(), rel_MAX) { reset(); } explicit RuntimeStatistics(MemoryPool& pool) - : Firebird::AutoStorage(pool), rel_counts(getPool()) + : Firebird::AutoStorage(pool), + pageCounters(getPool(), DB_PAGE_SPACE + 1), + tableCounters(getPool(), rel_MAX) { reset(); } RuntimeStatistics(const RuntimeStatistics& other) - : Firebird::AutoStorage(), rel_counts(getPool()) + : Firebird::AutoStorage(), + pageCounters(getPool(), other.pageCounters), + tableCounters(getPool(), other.tableCounters) { memcpy(values, other.values, sizeof(values)); - rel_counts = other.rel_counts; + + pageCounters = other.pageCounters; + tableCounters = other.tableCounters; allChgNumber = other.allChgNumber; - relChgNumber = other.relChgNumber; + pageChgNumber = other.pageChgNumber; + tabChgNumber = other.tabChgNumber; } RuntimeStatistics(MemoryPool& pool, const RuntimeStatistics& other) - : Firebird::AutoStorage(pool), rel_counts(getPool()) + : Firebird::AutoStorage(pool), + pageCounters(getPool(), other.pageCounters), + tableCounters(getPool(), other.tableCounters) { memcpy(values, other.values, sizeof(values)); - rel_counts = other.rel_counts; + + pageCounters = other.pageCounters; + tableCounters = other.tableCounters; allChgNumber = other.allChgNumber; - relChgNumber = other.relChgNumber; + pageChgNumber = other.pageChgNumber; + tabChgNumber = other.tabChgNumber; } ~RuntimeStatistics() = default; void reset() { - memset(values, 0, sizeof values); - rel_counts.clear(); - rel_last_pos = (FB_SIZE_T) ~0; + memset(values, 0, sizeof(values)); + + pageCounters.reset(); + tableCounters.reset(); + allChgNumber = 0; - relChgNumber = 0; + pageChgNumber = 0; + tabChgNumber = 0; } const SINT64& operator[](const PageStatType type) const @@ -262,11 +354,17 @@ class RuntimeStatistics : protected Firebird::AutoStorage return values[index]; } - void bumpValue(const PageStatType type, SINT64 delta = 1) + void bumpValue(const PageStatType type, ULONG pageSpaceId, SINT64 delta = 1) { + ++allChgNumber; const auto index = static_cast(type); values[index] += delta; - ++allChgNumber; + + if (isValid()) // optimization for non-trivial data access + { + ++pageChgNumber; + pageCounters[pageSpaceId][type] += delta; + } } const SINT64& operator[](const RecordStatType type) const @@ -279,42 +377,28 @@ class RuntimeStatistics : protected Firebird::AutoStorage { SINT64 value = 0; - for (const auto& counts : rel_counts) + for (const auto& counts : tableCounters) value += counts[type]; return value; } - void bumpValue(const RecordStatType type, SINT64 delta = 1) + void bumpValue(const RecordStatType type, SLONG relationId, SINT64 delta = 1) { + ++allChgNumber; const auto index = static_cast(type); values[PAGE_TOTAL_ITEMS + index] += delta; - ++allChgNumber; - } - void bumpValue(const RecordStatType type, SLONG relation_id, SINT64 delta = 1) - { - ++allChgNumber; - ++relChgNumber; - - if ((rel_last_pos != (FB_SIZE_T)~0 && rel_counts[rel_last_pos].getRelationId() == relation_id) || - // if rel_last_pos is mispositioned - rel_counts.find(relation_id, rel_last_pos)) - { - rel_counts[rel_last_pos][type] += delta; - } - else + if (isValid()) // optimization for non-trivial data access { - RelationCounts counts(relation_id); - counts[type] += delta; - rel_counts.insert(rel_last_pos, counts); + ++tabChgNumber; + tableCounters[relationId][type] += delta; } } // Calculate difference between counts stored in this object and current // counts of given request. Counts stored in object are destroyed. - Firebird::PerformanceInfo* computeDifference(Attachment* att, const RuntimeStatistics& new_stat, - Firebird::PerformanceInfo& dest, TraceCountsArray& temp, Firebird::ObjectsArray& tempNames); + void setToDiff(const RuntimeStatistics& newStats); // Add difference between newStats and baseStats to our counters // (newStats and baseStats must be "in-sync") @@ -331,16 +415,27 @@ class RuntimeStatistics : protected Firebird::AutoStorage memcpy(values, other.values, sizeof(values)); allChgNumber = other.allChgNumber; - if (relChgNumber != other.relChgNumber) + if (pageChgNumber != other.pageChgNumber) { - rel_counts = other.rel_counts; - relChgNumber = other.relChgNumber; + pageCounters = other.pageCounters; + pageChgNumber = other.pageChgNumber; + } + + if (tabChgNumber != other.tabChgNumber) + { + tableCounters = other.tableCounters; + tabChgNumber = other.tabChgNumber; } } return *this; } + bool isValid() const + { + return (this != &dummy); + } + static RuntimeStatistics* getDummy() { return &dummy; @@ -364,62 +459,28 @@ class RuntimeStatistics : protected Firebird::AutoStorage SINT64 m_counter = 0; }; - template class Iterator + const PageCounters& getPageCounters() const { - public: - explicit Iterator(const T& counts) - : m_iter(counts.begin()), m_end(counts.end()) - { - advance(); - } - - void operator++() - { - m_iter++; - advance(); - } - - typename T::const_reference operator*() const - { - return *m_iter; - } - - operator bool() const - { - return (m_iter != m_end); - } - - private: - typename T::const_iterator m_iter; - const typename T::const_iterator m_end; - - void advance() - { - while (m_iter != m_end && m_iter->isEmpty()) - m_iter++; - } - }; - - typedef Iterator RelationIterator; + return pageCounters; + } - RelationIterator getRelCounters() const + const TableCounters& getTableCounters() const { - return RelationIterator(rel_counts); + return tableCounters; } private: - void adjustRelStats(const RuntimeStatistics& baseStats, const RuntimeStatistics& newStats); - SINT64 values[GLOBAL_ITEMS]; - RelCounters rel_counts; - FB_SIZE_T rel_last_pos; + PageCounters pageCounters; + TableCounters tableCounters; - // These three numbers are used in adjust() and assign() methods as "generation" + // These numbers are used in adjust() and assign() methods as "generation" // values in order to avoid costly operations when two instances of RuntimeStatistics // contain equal counters values. This is intended to use *only* with the // same pair of class instances, as in Request. ULONG allChgNumber; // incremented when any counter changes - ULONG relChgNumber; // incremented when relation counter changes + ULONG pageChgNumber; // incremented when page counter changes + ULONG tabChgNumber; // incremented when table counter changes // This dummy RuntimeStatistics is used instead of missing elements in tdbb, // helping us to avoid conditional checks in time-critical places of code. diff --git a/src/jrd/align.h b/src/jrd/align.h index bda7d99bece..44a380ce854 100644 --- a/src/jrd/align.h +++ b/src/jrd/align.h @@ -143,11 +143,11 @@ static inline constexpr USHORT type_lengths[DTYPE_TYPE_MAX] = sizeof(ISC_QUAD), /* dtype_blob */ sizeof(ISC_QUAD), /* dtype_array */ sizeof(SINT64), /* dtype_int64 */ - sizeof(RecordNumber::Packed), /*dtype_dbkey */ + sizeof(RecordNumber::Packed), /* dtype_dbkey */ sizeof(UCHAR), /* dtype_boolean */ sizeof(Firebird::Decimal64), /* dtype_dec64 */ - sizeof(Firebird::Decimal128), /*dtype_dec128 */ - sizeof(Firebird::Int128), /* dtype_int128 */ + sizeof(Firebird::Decimal128), /* dtype_dec128 */ + sizeof(Firebird::Int128), /* dtype_int128 */ sizeof(ISC_TIME_TZ), /* dtype_sql_time_tz */ sizeof(ISC_TIMESTAMP_TZ), /* dtype_timestamp_tz */ sizeof(ISC_TIME_TZ_EX), /* dtype_ex_time_tz */ diff --git a/src/jrd/blp.h b/src/jrd/blp.h index ef29ce55567..797bfa94b38 100644 --- a/src/jrd/blp.h +++ b/src/jrd/blp.h @@ -196,8 +196,8 @@ static inline constexpr struct {"cursor_stmt", cursor_stmt}, {"current_timestamp2", byte_line}, {"current_time2", byte_line}, - {"agg_list", two}, // 170 - {"agg_list_distinct", two}, + {"agg_list", list_function}, // 170 + {"agg_list_distinct", list_function}, {"modify2", modify2}, {"erase2", erase2}, // New BLR in FB1 @@ -229,7 +229,7 @@ static inline constexpr struct {"partition_by", partition_by}, {"continue_loop", byte_line}, {"procedure4", procedure4}, - {"agg_function", function}, + {"agg_function", agg_function}, {"substring_similar", three}, // 200 {"bool_as_value", one}, {"coalesce", byte_args}, @@ -267,5 +267,6 @@ static inline constexpr struct {"default2", default2}, {"current_schema", zero}, {NULL, NULL}, // flags - part of header + {NULL, NULL}, // blr_within_group_order - part of blr_agg_list[_distinct] and blr_agg_function {0, 0} }; diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 1fc07ca7660..5554dd4910c 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -2811,7 +2811,6 @@ static void compress(thread_db* tdbb, constexpr UCHAR desc_end_value_prefix = 0x01; // ~0xFE constexpr UCHAR desc_end_value_check = 0x00; // ~0xFF; - const Database* dbb = tdbb->getDatabase(); bool first_key = true; VaryStr buffer; size_t multiKeyLength; @@ -5670,7 +5669,6 @@ static void generate_jump_nodes(thread_db* tdbb, btree_page* page, const UCHAR* const startpoint = page->btr_nodes + page->btr_jump_size; const UCHAR* const endpoint = (UCHAR*) page + page->btr_length; const UCHAR* halfpoint = (UCHAR*) page + (BTR_SIZE + page->btr_jump_size + page->btr_length) / 2; - const UCHAR* const excludePointer = (UCHAR*) page + excludeOffset; IndexJumpNode jumpNode; IndexNode node; diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 4617dd51df6..0e28477dbb4 100644 --- a/src/jrd/build_no.h +++ b/src/jrd/build_no.h @@ -3,16 +3,16 @@ *** DO NOT EDIT *** TO CHANGE ANY INFORMATION IN HERE PLEASE EDIT src/misc/writeBuildNum.sh - FORMAL BUILD NUMBER:1357 + FORMAL BUILD NUMBER:1387 */ -#define PRODUCT_VER_STRING "6.0.0.1357" -#define FILE_VER_STRING "WI-T6.0.0.1357" -#define LICENSE_VER_STRING "WI-T6.0.0.1357" -#define FILE_VER_NUMBER 6, 0, 0, 1357 +#define PRODUCT_VER_STRING "6.0.0.1387" +#define FILE_VER_STRING "WI-T6.0.0.1387" +#define LICENSE_VER_STRING "WI-T6.0.0.1387" +#define FILE_VER_NUMBER 6, 0, 0, 1387 #define FB_MAJOR_VER "6" #define FB_MINOR_VER "0" #define FB_REV_NO "0" -#define FB_BUILD_NO "1357" +#define FB_BUILD_NO "1387" #define FB_BUILD_TYPE "T" #define FB_BUILD_SUFFIX "Firebird 6.0 Initial" diff --git a/src/jrd/cch.cpp b/src/jrd/cch.cpp index d660ce17bf1..6a84fe15da3 100644 --- a/src/jrd/cch.cpp +++ b/src/jrd/cch.cpp @@ -930,9 +930,10 @@ void CCH_fetch_page(thread_db* tdbb, WIN* window, const bool read_shadow) pag* page = bdb->bdb_buffer; bdb->bdb_incarnation = ++bcb->bcb_page_incarnation; - tdbb->bumpStats(PageStatType::READS); + const ULONG pageSpaceId = bdb->bdb_page.getPageSpaceID(); + tdbb->bumpStats(PageStatType::READS, pageSpaceId); - PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(bdb->bdb_page.getPageSpaceID()); + const auto pageSpace = dbb->dbb_page_manager.findPageSpace(pageSpaceId); fb_assert(pageSpace); jrd_file* file = pageSpace->file; @@ -1011,7 +1012,7 @@ void CCH_fetch_page(thread_db* tdbb, WIN* window, const bool read_shadow) { diff_page = bm->getPageIndex(tdbb, bdb->bdb_page.getPageNum()); NBAK_TRACE(("Reading page %d:%06d, state=%d, diff page=%d", - bdb->bdb_page.getPageSpaceID(), bdb->bdb_page.getPageNum(), (int) backupState, diff_page)); + pageSpaceId, bdb->bdb_page.getPageNum(), (int) backupState, diff_page)); } // In merge mode, if we are reading past beyond old end of file and page is in .delta file @@ -1021,7 +1022,7 @@ void CCH_fetch_page(thread_db* tdbb, WIN* window, const bool read_shadow) fb_assert(bdb->bdb_page == window->win_page); NBAK_TRACE(("Reading page %d:%06d, state=%d, diff page=%d from DISK", - bdb->bdb_page.getPageSpaceID(), bdb->bdb_page.getPageNum(), (int) backupState, diff_page)); + pageSpaceId, bdb->bdb_page.getPageNum(), (int) backupState, diff_page)); // Read page from disk as normal Pio io(file, bdb, isTempPage, read_shadow, pageSpace); @@ -1701,14 +1702,16 @@ void CCH_mark(thread_db* tdbb, WIN* window, bool mark_system, bool must_write) SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); - tdbb->bumpStats(PageStatType::MARKS); + + const ULONG pageSpaceId = window->win_page.getPageSpaceID(); + tdbb->bumpStats(PageStatType::MARKS, pageSpaceId); BufferControl* bcb = dbb->dbb_bcb; if (!(bdb->bdb_flags & BDB_writer)) BUGCHECK(208); // msg 208 page not accessed for write - CCH_TRACE(("MARK %d:%06d", window->win_page.getPageSpaceID(), window->win_page.getPageNum())); + CCH_TRACE(("MARK %d:%06d", pageSpaceId, window->win_page.getPageNum())); // A LATCH_mark is needed before the BufferDesc can be marked. // This prevents a write while the page is being modified. @@ -2485,7 +2488,6 @@ bool CCH_write_all_shadows(thread_db* tdbb, Shadow* shadow, BufferDesc* bdb, Ods if (bdb->bdb_page == HEADER_PAGE_NUMBER) { // fixup header for shadow file - jrd_file* shadow_file = sdw->sdw_file; header_page* header = (header_page*) page; PageSpace* pageSpaceID = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); @@ -2718,7 +2720,6 @@ static void flushAll(thread_db* tdbb, USHORT flush_flag) const bool all_flag = (flush_flag & FLUSH_ALL) != 0; const bool sweep_flag = (flush_flag & FLUSH_SWEEP) != 0; const bool release_flag = (flush_flag & FLUSH_RLSE) != 0; - const bool write_thru = release_flag; { Sync bcbSync(&bcb->bcb_syncObject, FB_FUNCTION); @@ -3805,6 +3806,8 @@ static BufferDesc* get_buffer(thread_db* tdbb, const PageNumber page, SyncType s BufferControl* bcb = dbb->dbb_bcb; Attachment* att = tdbb->getAttachment(); + const ULONG pageSpaceId = page.getPageSpaceID(); + if (att && att->att_bdb_cache) { if (BufferDesc* bdb = att->att_bdb_cache->get(page)) @@ -3814,7 +3817,7 @@ static BufferDesc* get_buffer(thread_db* tdbb, const PageNumber page, SyncType s if (bdb->bdb_page == page) { recentlyUsed(bdb); - tdbb->bumpStats(PageStatType::FETCHES); + tdbb->bumpStats(PageStatType::FETCHES, pageSpaceId); return bdb; } @@ -3857,7 +3860,7 @@ static BufferDesc* get_buffer(thread_db* tdbb, const PageNumber page, SyncType s if (bdb->bdb_page == page) { recentlyUsed(bdb); - tdbb->bumpStats(PageStatType::FETCHES); + tdbb->bumpStats(PageStatType::FETCHES, pageSpaceId); cacheBuffer(att, bdb); return bdb; } @@ -3897,7 +3900,7 @@ static BufferDesc* get_buffer(thread_db* tdbb, const PageNumber page, SyncType s { bdb->downgrade(syncType); recentlyUsed(bdb); - tdbb->bumpStats(PageStatType::FETCHES); + tdbb->bumpStats(PageStatType::FETCHES, pageSpaceId); cacheBuffer(att, bdb); return bdb; } @@ -3941,7 +3944,7 @@ static BufferDesc* get_buffer(thread_db* tdbb, const PageNumber page, SyncType s else recentlyUsed(bdb); } - tdbb->bumpStats(PageStatType::FETCHES); + tdbb->bumpStats(PageStatType::FETCHES, pageSpaceId); cacheBuffer(att, bdb); return bdb; } @@ -3959,7 +3962,7 @@ static BufferDesc* get_buffer(thread_db* tdbb, const PageNumber page, SyncType s continue; } recentlyUsed(bdb2); - tdbb->bumpStats(PageStatType::FETCHES); + tdbb->bumpStats(PageStatType::FETCHES, pageSpaceId); cacheBuffer(att, bdb2); } else @@ -4914,7 +4917,8 @@ static bool write_page(thread_db* tdbb, BufferDesc* bdb, FbStatusVector* const s // I won't wipe out the if() itself to allow my changes be verified easily by others if (true) { - tdbb->bumpStats(PageStatType::WRITES); + const ULONG pageSpaceId = bdb->bdb_page.getPageSpaceID(); + tdbb->bumpStats(PageStatType::WRITES, pageSpaceId); // write out page to main database file, and to any // shadows, making a special case of the header page @@ -4952,8 +4956,7 @@ static bool write_page(thread_db* tdbb, BufferDesc* bdb, FbStatusVector* const s gds__trace(buffer); #endif - PageSpace* pageSpace = - dbb->dbb_page_manager.findPageSpace(bdb->bdb_page.getPageSpaceID()); + const auto pageSpace = dbb->dbb_page_manager.findPageSpace(pageSpaceId); fb_assert(pageSpace); const bool isTempPage = pageSpace->isTemporary(); diff --git a/src/jrd/cmp.cpp b/src/jrd/cmp.cpp index 031515c5170..a94dd1570c4 100644 --- a/src/jrd/cmp.cpp +++ b/src/jrd/cmp.cpp @@ -292,7 +292,6 @@ IndexLock* CMP_get_index_lock(thread_db* tdbb, jrd_rel* relation, USHORT id) * **************************************/ SET_TDBB(tdbb); - Database* dbb = tdbb->getDatabase(); DEV_BLKCHK(relation, type_rel); diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 8c0cf546351..b76345b78c4 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -6275,8 +6275,15 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ DFW_post_work(transaction, dfw_scan_relation, nullptr, nullptr, relation->rel_id); // signal others about new format presence - LCK_lock(tdbb, relation->rel_rescan_lock, LCK_EX, LCK_WAIT); LCK_release(tdbb, relation->rel_rescan_lock); + { + // Use temp lock to avoid AST call + Lock tmpLock(tdbb, sizeof(SLONG), LCK_rel_rescan); + tmpLock.setKey(relation->rel_id); + + LCK_lock(tdbb, &tmpLock, LCK_EX, LCK_WAIT); + LCK_release(tdbb, &tmpLock); + } break; } diff --git a/src/jrd/dyn_util.epp b/src/jrd/dyn_util.epp index 7c962d9223c..e67219ec7d5 100644 --- a/src/jrd/dyn_util.epp +++ b/src/jrd/dyn_util.epp @@ -287,8 +287,8 @@ bool DYN_UTIL_check_unique_name_nothrow(thread_db* tdbb, jrd_tra* transaction, { fb_assert(object_name.schema.isEmpty()); - static const CachedRequestId schemaHandleId; - requestHandle.reset(tdbb, schemaHandleId); + static const CachedRequestId filterHandleId; + requestHandle.reset(tdbb, filterHandleId); FOR(REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) FIL IN RDB$FILTERS diff --git a/src/jrd/extds/ExtDS.cpp b/src/jrd/extds/ExtDS.cpp index 15ee3112d59..bc788ec62e6 100644 --- a/src/jrd/extds/ExtDS.cpp +++ b/src/jrd/extds/ExtDS.cpp @@ -394,7 +394,6 @@ Connection* Provider::getBoundConnection(Jrd::thread_db* tdbb, const Firebird::PathName& dbName, Firebird::ClumpletReader& dpb, TraScope tra_scope, bool isCurrentAtt) { - Database* dbb = tdbb->getDatabase(); Attachment* att = tdbb->getAttachment(); CryptHash ch; if (!isCurrentAtt) diff --git a/src/jrd/idx.cpp b/src/jrd/idx.cpp index 86f889d2bc2..ae5a42e693e 100644 --- a/src/jrd/idx.cpp +++ b/src/jrd/idx.cpp @@ -573,7 +573,6 @@ bool IndexCreateTask::handler(WorkItem& _item) const bool isPrimary = (idx->idx_flags & idx_primary); const bool isForeign = (idx->idx_flags & idx_foreign); const UCHAR pad = isDescending ? -1 : 0; - bool key_is_null = false; primary.rpb_number.compose(dbb->dbb_max_records, dbb->dbb_dp_per_pp, 0, 0, item->m_ppSequence); primary.rpb_number.decrement(); @@ -847,7 +846,6 @@ void IDX_create_index(thread_db* tdbb, **************************************/ SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); - Jrd::Attachment* attachment = tdbb->getAttachment(); if (relation->rel_file) { @@ -865,7 +863,6 @@ void IDX_create_index(thread_db* tdbb, fb_assert(transaction); const bool isDescending = (idx->idx_flags & idx_descending); - const bool isPrimary = (idx->idx_flags & idx_primary); const bool isForeign = (idx->idx_flags & idx_foreign); // hvlad: in ODS11 empty string and NULL values can have the same binary @@ -1687,8 +1684,6 @@ static idx_e check_duplicates(thread_db* tdbb, * a unique index or a foreign key. * **************************************/ - DSC desc1, desc2; - SET_TDBB(tdbb); idx_e result = idx_e_ok; diff --git a/src/jrd/inf.cpp b/src/jrd/inf.cpp index 7d0d42b9eb6..60f0b6a29bd 100644 --- a/src/jrd/inf.cpp +++ b/src/jrd/inf.cpp @@ -273,11 +273,11 @@ void INF_database_info(thread_db* tdbb, resultBuffer.clear(); FB_SIZE_T bufferLength = 0; - for (auto iter(recordStats->getRelCounters()); iter; ++iter) + for (const auto& counts : recordStats->getTableCounters()) { - if (const SINT64 n = (*iter)[type]) + if (const SINT64 n = counts[type]) { - const USHORT relationId = (*iter).getRelationId(); + const USHORT relationId = counts.getGroupId(); const USHORT length = INF_convert(n, numBuffer); const FB_SIZE_T newBufferLength = bufferLength + length + sizeof(USHORT); resultBuffer.grow(newBufferLength); diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index dcbddf62e9d..b05b5ccbabb 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -282,7 +282,7 @@ const Attachment* JAttachment::getHandle() const noexcept void JAttachment::addRef() { - const int v = ++refCounter; + [[maybe_unused]] const int v = ++refCounter; #ifdef DEBUG_ATT_COUNTERS ReferenceCounterDebugger* my = ReferenceCounterDebugger::get(DEB_AR_JATT); const char* point = my ? my->rcd_point : " "; diff --git a/src/jrd/jrd.h b/src/jrd/jrd.h index 2e3644c89cc..d6b2896c0db 100644 --- a/src/jrd/jrd.h +++ b/src/jrd/jrd.h @@ -612,44 +612,35 @@ class thread_db final : public Firebird::ThreadData tdbb_flags |= TDBB_sweeper; } - void bumpStats(const PageStatType type, SINT64 delta = 1) + void bumpStats(const PageStatType type, ULONG pageSpaceId, SINT64 delta = 1) { - reqStat->bumpValue(type, delta); - traStat->bumpValue(type, delta); - attStat->bumpValue(type, delta); + fb_assert(pageSpaceId != INVALID_PAGE_SPACE); + + // [0] element stores statistics for temporary page spaces + if (PageSpace::isTemporary(pageSpaceId)) + pageSpaceId = 0; + + reqStat->bumpValue(type, pageSpaceId, delta); + traStat->bumpValue(type, pageSpaceId, delta); + attStat->bumpValue(type, pageSpaceId, delta); if ((tdbb_flags & TDBB_async) && !attachment) - dbbStat->bumpValue(type, delta); + dbbStat->bumpValue(type, pageSpaceId, delta); - // else dbbStat is adjusted from attStat, see Attachment::mergeAsyncStats() + // else dbbStat is adjusted from attStat, see Attachment::mergeStats() } - void bumpStats(const RecordStatType type, SLONG relation_id, SINT64 delta = 1) + void bumpStats(const RecordStatType type, SLONG relationId, SINT64 delta = 1) { - // We don't bump counters for dbbStat here, they're merged from attStats on demand - - reqStat->bumpValue(type, delta); - traStat->bumpValue(type, delta); - attStat->bumpValue(type, delta); - - const RuntimeStatistics* const dummyStat = RuntimeStatistics::getDummy(); - // We expect that at least attStat is present (not a dummy object) - fb_assert(attStat != dummyStat); - - // Relation statistics is a quite complex beast, so a conditional check - // does not hurt. It also allows to avoid races while accessing the static - // dummy object concurrently. + fb_assert(attStat != RuntimeStatistics::getDummy()); - if (reqStat != dummyStat) - reqStat->bumpValue(type, relation_id, delta); + reqStat->bumpValue(type, relationId, delta); + traStat->bumpValue(type, relationId, delta); + attStat->bumpValue(type, relationId, delta); - if (traStat != dummyStat) - traStat->bumpValue(type, relation_id, delta); - - if (attStat != dummyStat) - attStat->bumpValue(type, relation_id, delta); + // We don't bump counters for dbbStat here, they're merged from attStats on demand } ISC_STATUS getCancelState(ISC_STATUS* secondary = NULL); diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 09c38b34d04..4ef5bd33973 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -127,6 +127,7 @@ static void save_trigger_data(thread_db*, TrigVector**, jrd_rel*, Statement*, bl const QualifiedName*, FB_UINT64, SSHORT, USHORT, const MetaName&, const string&, const bid*, TriState ssDefiner); static void scan_partners(thread_db*, jrd_rel*); +static void scan_relation(thread_db*, jrd_rel*); static bool verify_TRG_ignore_perm(thread_db*, const QualifiedName&); @@ -243,7 +244,7 @@ void MET_get_domain(thread_db* tdbb, MemoryPool& csbPool, const QualifiedName& n } -MetaName MET_get_relation_field(thread_db* tdbb, MemoryPool& csbPool, const QualifiedName& relationName, +void MET_get_relation_field(thread_db* tdbb, MemoryPool& csbPool, const QualifiedName& relationName, const MetaName& fieldName, dsc* desc, FieldInfo* fieldInfo) { /************************************** @@ -320,8 +321,6 @@ MetaName MET_get_relation_field(thread_db* tdbb, MemoryPool& csbPool, const Qual fieldName.toQuotedString() << relationName.toQuotedString()); } - - return sourceName; } @@ -3917,6 +3916,27 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) * Scan a relation for view RecordSelExpr, computed by expressions, missing * expressions, and validation expressions. * + **************************************/ + + while (!(relation->rel_flags & (REL_scanned | REL_deleted))) + { + scan_relation(tdbb, relation); + } +} + + +static void scan_relation(thread_db* tdbb, jrd_rel* relation) +{ +/************************************** + * + * s c a n _ r e l a t i o n + * + ************************************** + * + * Functional description + * Scan a relation for view RecordSelExpr, computed by expressions, missing + * expressions, and validation expressions. + * **************************************/ SET_TDBB(tdbb); TrigVector* triggers[TRIGGER_MAX]; @@ -3935,10 +3955,13 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) try { - if (relation->rel_flags & (REL_scanned | REL_deleted)) - return; + fb_assert(!(relation->rel_flags & (REL_scanned | REL_deleted))); relation->rel_flags |= REL_being_scanned; + + LCK_lock(tdbb, relation->rel_rescan_lock, LCK_SR, LCK_WAIT); + relation->rel_flags &= ~REL_rescan; + dependencies = (relation->rel_flags & REL_get_dependencies) ? true : false; relation->rel_flags &= ~REL_get_dependencies; @@ -3950,12 +3973,16 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) AutoCacheRequest request(tdbb, irq_r_fields, IRQ_REQUESTS); CompilerScratch* csb = NULL; + bool found = false; + FOR(REQUEST_HANDLE request) REL IN RDB$RELATIONS CROSS SCH IN RDB$SCHEMAS WITH REL.RDB$RELATION_ID EQ relation->rel_id AND SCH.RDB$SCHEMA_NAME EQ REL.RDB$SCHEMA_NAME { + found = true; + // Pick up relation level stuff relation->rel_current_fmt = REL.RDB$FORMAT; vec* vector = relation->rel_fields = @@ -4228,13 +4255,39 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) delete csb; + if (!found && !(relation->rel_flags & REL_scanned)) + { + // Relation was not found in RDB$RELATIONS. It could be system virtual relation + // defined in INI. + + if (relation->isSystem() && relation->isVirtual()) + { + relation->rel_flags |= REL_scanned; + } + else + { + fb_assert(false); + + string name(relation->rel_name.toQuotedString()); + if (name.isEmpty()) + name.printf("", relation->rel_id); + + ERR_post(Arg::Gds(isc_relnotdef) << Arg::Str(name)); + } + } + // We have just loaded the triggers onto the local vector triggers. // It's now time to place them at their rightful place inside the relation block. relation->replaceTriggers(tdbb, triggers); - LCK_lock(tdbb, relation->rel_rescan_lock, LCK_SR, LCK_WAIT); relation->rel_flags &= ~REL_being_scanned; + if (relation->rel_flags & REL_rescan) + { + LCK_release(tdbb, relation->rel_rescan_lock); + relation->rel_flags &= ~(REL_scanned | REL_rescan); + } + relation->rel_current_format = NULL; } // try @@ -4542,8 +4595,13 @@ static int rescan_ast_relation(void* ast_object) AsyncContextHolder tdbb(dbb, FB_FUNCTION, relation->rel_rescan_lock); - LCK_release(tdbb, relation->rel_rescan_lock); - relation->rel_flags &= ~REL_scanned; + if (relation->rel_flags & REL_being_scanned) + relation->rel_flags |= REL_rescan; + else + { + LCK_release(tdbb, relation->rel_rescan_lock); + relation->rel_flags &= ~REL_scanned; + } } catch (const Firebird::Exception&) {} // no-op diff --git a/src/jrd/met_proto.h b/src/jrd/met_proto.h index fba22677afd..d178125b777 100644 --- a/src/jrd/met_proto.h +++ b/src/jrd/met_proto.h @@ -144,7 +144,7 @@ void MET_trigger_msg(Jrd::thread_db*, Firebird::string&, const Jrd::QualifiedNa void MET_update_shadow(Jrd::thread_db*, Jrd::Shadow*, USHORT); void MET_update_transaction(Jrd::thread_db*, Jrd::jrd_tra*, const bool); void MET_get_domain(Jrd::thread_db*, MemoryPool& csbPool, const Jrd::QualifiedName&, dsc*, Jrd::FieldInfo*); -Jrd::MetaName MET_get_relation_field(Jrd::thread_db*, MemoryPool& csbPool, +void MET_get_relation_field(Jrd::thread_db*, MemoryPool& csbPool, const Jrd::QualifiedName&, const Jrd::MetaName&, dsc*, Jrd::FieldInfo*); void MET_update_partners(Jrd::thread_db*); diff --git a/src/jrd/nbak.cpp b/src/jrd/nbak.cpp index be471beb9dd..098e5eb8ed4 100644 --- a/src/jrd/nbak.cpp +++ b/src/jrd/nbak.cpp @@ -162,7 +162,6 @@ BackupManager::StateWriteGuard::StateWriteGuard(thread_db* tdbb, Jrd::WIN* windo : m_tdbb(tdbb), m_window(NULL), m_success(false) { Database* const dbb = tdbb->getDatabase(); - Jrd::Attachment* const att = tdbb->getAttachment(); dbb->dbb_backup_manager->beginFlush(); CCH_flush(tdbb, FLUSH_ALL, 0); // Flush local cache to release all dirty pages @@ -186,7 +185,6 @@ BackupManager::StateWriteGuard::StateWriteGuard(thread_db* tdbb, Jrd::WIN* windo BackupManager::StateWriteGuard::~StateWriteGuard() { Database* const dbb = m_tdbb->getDatabase(); - Jrd::Attachment* const att = m_tdbb->getAttachment(); // It is important to set state into nbak_state_unknown *before* release of state lock, // otherwise someone could acquire state lock, fetch and modify some page before state will diff --git a/src/jrd/ods.cpp b/src/jrd/ods.cpp index baae1a0f13c..5a4f2d605c4 100644 --- a/src/jrd/ods.cpp +++ b/src/jrd/ods.cpp @@ -26,14 +26,6 @@ using namespace Firebird; -namespace -{ - constexpr FB_SIZE_T NEXT_INDEX = 0; - constexpr FB_SIZE_T OIT_INDEX = 1; - constexpr FB_SIZE_T OAT_INDEX = 2; - constexpr FB_SIZE_T OST_INDEX = 3; -} - namespace Ods { bool isSupported(const header_page* hdr) noexcept diff --git a/src/jrd/optimizer/InnerJoin.cpp b/src/jrd/optimizer/InnerJoin.cpp index c356fa5e898..c88be88cad7 100644 --- a/src/jrd/optimizer/InnerJoin.cpp +++ b/src/jrd/optimizer/InnerJoin.cpp @@ -198,20 +198,22 @@ void InnerJoin::estimateCost(unsigned position, // likely cardinality under-estimation. const bool avoidHashJoin = (streamCardinality <= MINIMUM_CARDINALITY && !stream->baseIndexes); - auto currentCardinality = candidate->unique ? - MINIMUM_CARDINALITY : streamCardinality * candidate->selectivity; - auto currentCost = candidate->cost; + auto currentCardinality = streamCardinality * candidate->selectivity; // Given the "first-rows" mode specified (or implied) // and unless an external sort is to be applied afterwards, // fake the expected cardinality to look as low as possible - // to estimate the cost just for a single row being produced + // to estimate the cost just for a single row being produced. + // The same rule is used if the retrieval is unique. - if ((!sort || candidate->navigated) && optimizer->favorFirstRows()) + const bool firstRows = (optimizer->favorFirstRows() && + (!sortPtr || !*sortPtr || candidate->navigated)); + + if ((candidate->unique || firstRows) && currentCardinality > MINIMUM_CARDINALITY) currentCardinality = MINIMUM_CARDINALITY; // Calculate the nested loop cost, it's our default option - const auto loopCost = currentCost * cardinality; + const auto loopCost = candidate->cost * cardinality; cost = loopCost; // Consider whether the current stream can be hash-joined to the prior ones. diff --git a/src/jrd/optimizer/Optimizer.cpp b/src/jrd/optimizer/Optimizer.cpp index c7ae78e32f0..7007aa09d5d 100644 --- a/src/jrd/optimizer/Optimizer.cpp +++ b/src/jrd/optimizer/Optimizer.cpp @@ -1525,7 +1525,7 @@ void Optimizer::generateAggregateSort(AggNode* aggNode) fb_assert(prevKey); ULONG length = prevKey ? ROUNDUP(prevKey->getSkdOffset() + prevKey->getSkdLength(), sizeof(SLONG)) : 0; - aggNode->arg->getDesc(tdbb, csb, desc); + aggNode->makeSortDesc(tdbb, csb, desc); if (desc->dsc_dtype >= dtype_aligned) length = FB_ALIGN(length, type_alignments[desc->dsc_dtype]); @@ -3165,8 +3165,6 @@ bool Optimizer::getEquiJoinKeys(NestConst& node1, string Optimizer::getStreamName(StreamType stream) { const auto tail = &csb->csb_rpt[stream]; - const auto* relation = tail->csb_relation; - const auto* procedure = tail->csb_procedure; const auto* alias = tail->csb_alias; string name = tail->getName().toQuotedString(); diff --git a/src/jrd/os/posix/unix.cpp b/src/jrd/os/posix/unix.cpp index 538e7436383..f3d37aeb1ad 100644 --- a/src/jrd/os/posix/unix.cpp +++ b/src/jrd/os/posix/unix.cpp @@ -419,8 +419,6 @@ void PIO_force_write(jrd_file* file, const bool forceWrite) if (forceWrite != oldForce) { - const int control = forceWrite ? SYNC : 0; - #ifdef FCNTL_SYNC_BROKEN maybeCloseFile(file->fil_desc); @@ -470,7 +468,7 @@ ULONG PIO_get_number_of_pages(const jrd_file* file, const USHORT pagesize) ************************************** * * Functional description - * Compute number of pages in file, based only on file size. + * Compute number of full-size pages in file, based only on file size. * **************************************/ diff --git a/src/jrd/os/win32/winnt.cpp b/src/jrd/os/win32/winnt.cpp index a7733d59891..5b1898d7a96 100644 --- a/src/jrd/os/win32/winnt.cpp +++ b/src/jrd/os/win32/winnt.cpp @@ -740,7 +740,7 @@ ULONG PIO_get_number_of_pages(const jrd_file* file, const USHORT pagesize) ************************************** * * Functional description - * Compute number of pages in file, based only on file size. + * Compute number of full-size pages in file, based only on file size. * **************************************/ HANDLE hFile = file->fil_desc; @@ -752,7 +752,7 @@ ULONG PIO_get_number_of_pages(const jrd_file* file, const USHORT pagesize) nt_error("GetFileSize", file, isc_io_access_err, 0); const ULONGLONG ullFileSize = (((ULONGLONG) dwFileSizeHigh) << 32) + dwFileSizeLow; - return (ULONG) ((ullFileSize + pagesize - 1) / pagesize); + return ullFileSize / pagesize; } diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index f5b0ee8e2de..7ae70dbf9cb 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -1151,6 +1151,16 @@ void PAG_header_init(thread_db* tdbb) if (header->hdr_page_size < MIN_PAGE_SIZE || header->hdr_page_size > MAX_PAGE_SIZE) ERR_post(Arg::Gds(isc_bad_db_format) << Arg::Str(attachment->att_filename)); + if (header->hdr_page_size % MIN_PAGE_SIZE != 0) + ERR_post(Arg::Gds(isc_bad_db_format) << Arg::Str(attachment->att_filename)); + + // Pagespace is already created at this point, so validate the database file + // to contain at least one full page + const auto pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); + fb_assert(pageSpace && pageSpace->file); + if (!PIO_get_number_of_pages(pageSpace->file, header->hdr_page_size)) + ERR_post(Arg::Gds(isc_bad_db_format) << Arg::Str(attachment->att_filename)); + dbb->dbb_ods_version = ods_version; dbb->dbb_minor_version = header->hdr_ods_minor; diff --git a/src/jrd/recsrc/FilteredStream.cpp b/src/jrd/recsrc/FilteredStream.cpp index ead4bda7332..f41c1f3e11f 100644 --- a/src/jrd/recsrc/FilteredStream.cpp +++ b/src/jrd/recsrc/FilteredStream.cpp @@ -39,12 +39,9 @@ using namespace Jrd; FilteredStream::FilteredStream(CompilerScratch* csb, RecordSource* next, BoolExprNode* boolean, double selectivity) : RecordSource(csb), + m_invariant(false), m_next(next), - m_boolean(boolean), - m_anyBoolean(NULL), - m_ansiAny(false), - m_ansiAll(false), - m_ansiNot(false) + m_boolean(boolean) { fb_assert(m_next && m_boolean); @@ -59,6 +56,19 @@ FilteredStream::FilteredStream(CompilerScratch* csb, RecordSource* next, m_cardinality = cardinality; } +FilteredStream::FilteredStream(CompilerScratch* csb, RecordSource* next, + BoolExprNode* boolean) + : RecordSource(csb), + m_invariant(true), + m_next(next), + m_boolean(boolean) +{ + fb_assert(m_next && m_boolean); + + m_impure = csb->allocImpure(); + m_cardinality = next->getCardinality(); +} + void FilteredStream::internalOpen(thread_db* tdbb) const { Request* const request = tdbb->getRequest(); diff --git a/src/jrd/recsrc/RecordSource.cpp b/src/jrd/recsrc/RecordSource.cpp index 56fa4a72bf1..bda4279a9ea 100644 --- a/src/jrd/recsrc/RecordSource.cpp +++ b/src/jrd/recsrc/RecordSource.cpp @@ -196,7 +196,6 @@ void RecordSource::printInversion(thread_db* tdbb, const InversionNode* inversio const index_desc& idx = retrieval->irb_desc; const USHORT segCount = idx.idx_count; - const USHORT minSegs = MIN(retrieval->irb_lower_count, retrieval->irb_upper_count); const USHORT maxSegs = MAX(retrieval->irb_lower_count, retrieval->irb_upper_count); const bool equality = (retrieval->irb_generic & irb_equality); diff --git a/src/jrd/recsrc/RecordSource.h b/src/jrd/recsrc/RecordSource.h index 2b81225ec63..9d5d3f3e579 100644 --- a/src/jrd/recsrc/RecordSource.h +++ b/src/jrd/recsrc/RecordSource.h @@ -584,7 +584,7 @@ namespace Jrd { public: FilteredStream(CompilerScratch* csb, RecordSource* next, - BoolExprNode* boolean, double selectivity = 0); + BoolExprNode* boolean, double selectivity); void close(thread_db* tdbb) const override; @@ -611,11 +611,13 @@ namespace Jrd } protected: + FilteredStream(CompilerScratch* csb, RecordSource* next, BoolExprNode* boolean); + void internalGetPlan(thread_db* tdbb, PlanEntry& planEntry, unsigned level, bool recurse) const override; void internalOpen(thread_db* tdbb) const override; bool internalGetRecord(thread_db* tdbb) const override; - bool m_invariant = false; + const bool m_invariant; private: Firebird::TriState evaluateBoolean(thread_db* tdbb) const; @@ -623,9 +625,9 @@ namespace Jrd NestConst m_next; NestConst const m_boolean; NestConst m_anyBoolean; - bool m_ansiAny; - bool m_ansiAll; - bool m_ansiNot; + bool m_ansiAny = false; + bool m_ansiAll = false; + bool m_ansiNot = false; }; class PreFilteredStream : public FilteredStream @@ -634,9 +636,7 @@ namespace Jrd PreFilteredStream(CompilerScratch* csb, RecordSource* next, BoolExprNode* boolean) : FilteredStream(csb, next, boolean) - { - m_invariant = true; - } + {} }; class SortedStream : public RecordSource @@ -1626,32 +1626,14 @@ namespace Jrd struct Impure final : public TableValueFunctionScan::Impure { - union - { - SINT64 vlu_int64; - Firebird::Int128 vlu_int128; - } m_start; - - union - { - SINT64 vlu_int64; - Firebird::Int128 vlu_int128; - } m_finish; - - union - { - SINT64 vlu_int64; - Firebird::Int128 vlu_int128; - } m_step; - - union - { - SINT64 vlu_int64; - Firebird::Int128 vlu_int128; - } m_result; + impure_value m_start; + impure_value m_finish; + impure_value m_step; + impure_value m_result; - UCHAR m_dtype; + USHORT m_flags; SCHAR m_scale; + SCHAR m_stepSign; }; public: diff --git a/src/jrd/recsrc/TableValueFunctionScan.cpp b/src/jrd/recsrc/TableValueFunctionScan.cpp index 637d5f49cb6..b0b5bbe30b3 100644 --- a/src/jrd/recsrc/TableValueFunctionScan.cpp +++ b/src/jrd/recsrc/TableValueFunctionScan.cpp @@ -407,54 +407,43 @@ void GenSeriesFunctionScan::internalOpen(thread_db* tdbb) const const auto impure = request->getImpure(m_impure); impure->m_recordBuffer = nullptr; - // common scale - impure->m_scale = MIN(MIN(startDesc->dsc_scale, finishDesc->dsc_scale), stepDesc->dsc_scale); - // common type - impure->m_dtype = MAX(MAX(startDesc->dsc_dtype, finishDesc->dsc_dtype), stepDesc->dsc_dtype); + ArithmeticNode::getDescDialect3(tdbb, &impure->m_result.vlu_desc, *startDesc, *stepDesc, blr_add, &impure->m_scale, &impure->m_flags); - if (impure->m_dtype != dtype_int128) - { - const auto start = MOV_get_int64(tdbb, startDesc, impure->m_scale); - const auto finish = MOV_get_int64(tdbb, finishDesc, impure->m_scale); - const auto step = MOV_get_int64(tdbb, stepDesc, impure->m_scale); + SLONG zero = 0; + dsc zeroDesc; + zeroDesc.makeLong(0, &zero); + impure->m_stepSign = MOV_compare(tdbb, stepDesc, &zeroDesc); - if (step == 0) - status_exception::raise(Arg::Gds(isc_genseq_stepmustbe_nonzero) << Arg::Str(m_name)); + if (impure->m_stepSign == 0) + status_exception::raise(Arg::Gds(isc_genseq_stepmustbe_nonzero) << Arg::Str(m_name)); - // validate parameter value - if (((step > 0) && (start > finish)) || - ((step < 0) && (start < finish))) - { - return; - } - - impure->m_start.vlu_int64 = start; - impure->m_finish.vlu_int64 = finish; - impure->m_step.vlu_int64 = step; - impure->m_result.vlu_int64 = start; - } - else + const auto boundaryComparison = MOV_compare(tdbb, startDesc, finishDesc); + // validate parameter value + if (((impure->m_stepSign > 0) && (boundaryComparison > 0)) || + ((impure->m_stepSign < 0) && (boundaryComparison < 0))) { - const auto start = MOV_get_int128(tdbb, startDesc, impure->m_scale); - const auto finish = MOV_get_int128(tdbb, finishDesc, impure->m_scale); - const auto step = MOV_get_int128(tdbb, stepDesc, impure->m_scale); + return; + } - if (step.sign() == 0) - status_exception::raise(Arg::Gds(isc_genseq_stepmustbe_nonzero) << Arg::Str(m_name)); + EVL_make_value(tdbb, startDesc, &impure->m_start); + EVL_make_value(tdbb, finishDesc, &impure->m_finish); + EVL_make_value(tdbb, stepDesc, &impure->m_step); - // validate parameter value - if (((step.sign() > 0) && (start.compare(finish) > 0)) || - ((step.sign() < 0) && (start.compare(finish) < 0))) - { - return; - } - - impure->m_start.vlu_int128 = start; - impure->m_finish.vlu_int128 = finish; - impure->m_step.vlu_int128 = step; - impure->m_result.vlu_int128 = start; + switch (impure->m_result.vlu_desc.dsc_dtype) + { + case dtype_int64: + impure->m_result.vlu_desc.dsc_address = reinterpret_cast(&impure->m_result.vlu_misc.vlu_int64); + break; + case dtype_int128: + impure->m_result.vlu_desc.dsc_address = reinterpret_cast(&impure->m_result.vlu_misc.vlu_int128); + break; + default: + fb_assert(false); } + // result = start + MOV_move(tdbb, startDesc, &impure->m_result.vlu_desc); + impure->irsb_flags |= irsb_open; VIO_record(tdbb, rpb, m_format, &pool); @@ -505,51 +494,40 @@ bool GenSeriesFunctionScan::nextBuffer(thread_db* tdbb) const const auto request = tdbb->getRequest(); const auto impure = request->getImpure(m_impure); - if (impure->m_dtype != dtype_int128) + const auto comparison = MOV_compare(tdbb, &impure->m_result.vlu_desc, &impure->m_finish.vlu_desc); + if (((impure->m_stepSign > 0) && (comparison <= 0)) || + ((impure->m_stepSign < 0) && (comparison >= 0))) { - auto result = impure->m_result.vlu_int64; - const auto finish = impure->m_finish.vlu_int64; - const auto step = impure->m_step.vlu_int64; + Record* const record = request->req_rpb[m_stream].rpb_record; - if (((step > 0) && (result <= finish)) || - ((step < 0) && (result >= finish))) - { - Record* const record = request->req_rpb[m_stream].rpb_record; + auto toDesc = m_format->fmt_desc.begin(); - auto toDesc = m_format->fmt_desc.begin(); - - dsc fromDesc; - fromDesc.makeInt64(impure->m_scale, &result); - assignParameter(tdbb, &fromDesc, toDesc, 0, record); + assignParameter(tdbb, &impure->m_result.vlu_desc, toDesc, 0, record); - result += step; - impure->m_result.vlu_int64 = result; - - return true; + // evaluate next result + try + { + impure_value nextValue; + + ArithmeticNode::add(tdbb, + &impure->m_step.vlu_desc, + &impure->m_result.vlu_desc, + &nextValue, + blr_add, + false, + impure->m_scale, + impure->m_flags); + + MOV_move(tdbb, &nextValue.vlu_desc, &impure->m_result.vlu_desc); } - } - else - { - auto result = impure->m_result.vlu_int128; - const auto finish = impure->m_finish.vlu_int128; - const auto step = impure->m_step.vlu_int128; - - if (((step.sign() > 0) && (result.compare(finish) <= 0)) || - ((step.sign() < 0) && (result.compare(finish) >= 0))) + catch (const status_exception&) { - Record* const record = request->req_rpb[m_stream].rpb_record; - - auto toDesc = m_format->fmt_desc.begin(); - - dsc fromDesc; - fromDesc.makeInt128(impure->m_scale, &result); - assignParameter(tdbb, &fromDesc, toDesc, 0, record); - - result = result.add(step); - impure->m_result.vlu_int128 = result; - - return true; + tdbb->tdbb_status_vector->clearException(); + // stop evaluate next result + impure->m_stepSign = 0; } + + return true; } return false; diff --git a/src/jrd/replication/Applier.cpp b/src/jrd/replication/Applier.cpp index c9e9f39419a..02fc6d2e431 100644 --- a/src/jrd/replication/Applier.cpp +++ b/src/jrd/replication/Applier.cpp @@ -446,8 +446,6 @@ void Applier::process(thread_db* tdbb, ULONG length, const UCHAR* data) void Applier::startTransaction(thread_db* tdbb, TraNumber traNum) { - const auto attachment = tdbb->getAttachment(); - if (m_txnMap.exist(traNum)) raiseError("Transaction %" SQUADFORMAT" already exists", traNum); diff --git a/src/jrd/sdw.cpp b/src/jrd/sdw.cpp index aa6a1ef8b37..3a0c48aa0a9 100644 --- a/src/jrd/sdw.cpp +++ b/src/jrd/sdw.cpp @@ -1043,7 +1043,6 @@ static bool check_for_file(thread_db* tdbb, const SCHAR* name, USHORT length) **************************************/ SET_TDBB(tdbb); - const Database* dbb = tdbb->getDatabase(); const Firebird::PathName path(name, length); try { diff --git a/src/jrd/shut.cpp b/src/jrd/shut.cpp index ce7e5351203..18a487d1812 100644 --- a/src/jrd/shut.cpp +++ b/src/jrd/shut.cpp @@ -40,8 +40,6 @@ using namespace Jrd; using namespace Firebird; -constexpr SSHORT SHUT_WAIT_TIME = 5; - // Shutdown lock data union shutdown_data { diff --git a/src/jrd/sqz.cpp b/src/jrd/sqz.cpp index aa8027e2157..5ebcc7db49d 100644 --- a/src/jrd/sqz.cpp +++ b/src/jrd/sqz.cpp @@ -108,7 +108,6 @@ Compressor::Compressor(MemoryPool& pool, bool allowLongRuns, bool allowUnpacked, m_allowUnpacked(allowUnpacked) { const auto end = data + length; - const auto input = data; while (auto count = end - data) { diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index ba658f45dc2..d9935f022e2 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -79,8 +79,6 @@ #include "firebird/impl/msg_helper.h" -constexpr int DYN_MSG_FAC = FB_IMPL_MSG_FACILITY_DYN; - using namespace Jrd; using namespace Ods; using namespace Firebird; @@ -4330,7 +4328,7 @@ void TraceSweepEvent::endSweepRelation(jrd_rel* relation) fb_utils::query_performance_counter() - m_relation_clock, 0); - m_sweep_info.setPerf(stats.getPerf()); + m_sweep_info.setStats(&stats); TraceConnectionImpl conn(att); TraceManager* trace_mgr = att->att_trace_manager; @@ -4364,7 +4362,6 @@ void TraceSweepEvent::report(ntrace_process_state_t state) if (!m_need_trace) return; - const Database* dbb = m_tdbb->getDatabase(); TraceManager* trace_mgr = att->att_trace_manager; TraceConnectionImpl conn(att); @@ -4373,11 +4370,9 @@ void TraceSweepEvent::report(ntrace_process_state_t state) if (state != ITracePlugin::SWEEP_STATE_PROGRESS) m_base_stats.reset(); - const jrd_tra* tran = m_tdbb->getTransaction(); - TraceRuntimeStats stats(att, &m_base_stats, &att->att_stats, finiTime, 0); - m_sweep_info.setPerf(stats.getPerf()); + m_sweep_info.setStats(&stats); trace_mgr->event_sweep(&conn, &m_sweep_info, state); if (state == ITracePlugin::SWEEP_STATE_FAILED || state == ITracePlugin::SWEEP_STATE_FINISHED) diff --git a/src/jrd/trace/TraceDSQLHelpers.h b/src/jrd/trace/TraceDSQLHelpers.h index 3d3f0cd78cf..1941edcac42 100644 --- a/src/jrd/trace/TraceDSQLHelpers.h +++ b/src/jrd/trace/TraceDSQLHelpers.h @@ -173,7 +173,7 @@ class TraceDSQLExecute fb_utils::query_performance_counter() - m_start_clock, m_dsqlRequest->req_fetch_rowcount); - TraceSQLStatementImpl stmt(m_dsqlRequest, stats.getPerf(), m_data); + TraceSQLStatementImpl stmt(m_dsqlRequest, &stats, m_data); TraceManager::event_dsql_execute(m_attachment, m_dsqlRequest->req_transaction, &stmt, false, result); m_dsqlRequest->req_fetch_baseline = NULL; @@ -233,7 +233,7 @@ class TraceDSQLFetch &m_dsqlRequest->getRequest()->req_stats, m_dsqlRequest->req_fetch_elapsed, m_dsqlRequest->req_fetch_rowcount); - TraceSQLStatementImpl stmt(m_dsqlRequest, stats.getPerf(), nullptr); + TraceSQLStatementImpl stmt(m_dsqlRequest, &stats, nullptr); TraceManager::event_dsql_execute(m_attachment, m_dsqlRequest->req_transaction, &stmt, false, result); diff --git a/src/jrd/trace/TraceJrdHelpers.h b/src/jrd/trace/TraceJrdHelpers.h index 2dbbfdabd97..994116042ec 100644 --- a/src/jrd/trace/TraceJrdHelpers.h +++ b/src/jrd/trace/TraceJrdHelpers.h @@ -75,7 +75,7 @@ class TraceTransactionEnd fb_utils::query_performance_counter() - m_start_clock, 0); TraceConnectionImpl conn(attachment); - TraceTransactionImpl tran(m_transaction, stats.getPerf(), m_prevID); + TraceTransactionImpl tran(m_transaction, &stats, m_prevID); attachment->att_trace_manager->event_transaction_end(&conn, &tran, m_commit, m_retain, result); m_baseline = NULL; @@ -205,7 +205,7 @@ class TraceProcExecute TraceConnectionImpl conn(attachment); TraceTransactionImpl tran(transaction); - TraceProcedureImpl proc(m_request, stats.getPerf()); + TraceProcedureImpl proc(m_request, &stats); const auto trace_mgr = attachment->att_trace_manager; trace_mgr->event_proc_execute(&conn, &tran, &proc, false, result); @@ -268,7 +268,7 @@ class TraceProcFetch TraceConnectionImpl conn(attachment); TraceTransactionImpl tran(transaction); - TraceProcedureImpl proc(m_request, stats.getPerf()); + TraceProcedureImpl proc(m_request, &stats); const auto trace_mgr = attachment->att_trace_manager; trace_mgr->event_proc_execute(&conn, &tran, &proc, false, result); @@ -402,7 +402,7 @@ class TraceFuncExecute TraceTransactionImpl tran(transaction); TraceDscFromMsg inputs(m_request->getStatement()->function->getInputFormat(), m_inMsg, m_inMsgLength); - TraceFunctionImpl func(m_request, stats.getPerf(), inputs, value); + TraceFunctionImpl func(m_request, &stats, inputs, value); const auto trace_mgr = attachment->att_trace_manager; trace_mgr->event_func_execute(&conn, &tran, &func, false, result); @@ -566,7 +566,7 @@ class TraceTrigExecute TraceConnectionImpl conn(attachment); TraceTransactionImpl tran(transaction); - TraceTriggerImpl trig(m_which, m_request, stats.getPerf()); + TraceTriggerImpl trig(m_which, m_request, &stats); const auto trace_mgr = attachment->att_trace_manager; trace_mgr->event_trigger_execute(&conn, &tran, &trig, false, result); @@ -689,7 +689,7 @@ class TraceBlrExecute TraceConnectionImpl conn(m_tdbb->getAttachment()); TraceTransactionImpl tran(m_tdbb->getTransaction()); - TraceBLRStatementImpl stmt(m_request->getStatement(), stats.getPerf()); + TraceBLRStatementImpl stmt(m_request->getStatement(), &stats); TraceManager* trace_mgr = m_tdbb->getAttachment()->att_trace_manager; trace_mgr->event_blr_execute(&conn, &tran, &stmt, result); diff --git a/src/jrd/trace/TraceManager.cpp b/src/jrd/trace/TraceManager.cpp index c1ee9e8bd10..0a2f0857745 100644 --- a/src/jrd/trace/TraceManager.cpp +++ b/src/jrd/trace/TraceManager.cpp @@ -43,11 +43,6 @@ using namespace Firebird; -namespace -{ - static const char* const NTRACE_PREFIX = "fbtrace"; -} - namespace Jrd { GlobalPtr TraceManager::storageInstance; diff --git a/src/jrd/trace/TraceObjects.cpp b/src/jrd/trace/TraceObjects.cpp index 6b2d4f251df..28651d45e39 100644 --- a/src/jrd/trace/TraceObjects.cpp +++ b/src/jrd/trace/TraceObjects.cpp @@ -261,16 +261,6 @@ const char* TraceSQLStatementImpl::getTextUTF8() return m_textUTF8.c_str(); } -PerformanceInfo* TraceSQLStatementImpl::getPerf() -{ - return m_perf; -} - -ITraceParams* TraceSQLStatementImpl::getInputs() -{ - return &m_inputs; -} - /// TraceSQLStatementImpl::DSQLParamsImpl @@ -633,24 +623,61 @@ const char* TraceServiceImpl::getRemoteProcessName() /// TraceRuntimeStats -TraceRuntimeStats::TraceRuntimeStats(Attachment* att, RuntimeStatistics* baseline, RuntimeStatistics* stats, - SINT64 clock, SINT64 records_fetched) +TraceRuntimeStats::TraceRuntimeStats(Attachment* attachment, + RuntimeStatistics* baseline, RuntimeStatistics* stats, + SINT64 clock, SINT64 recordsFetched) { + memset(&m_info, 0, sizeof(m_info)); m_info.pin_time = clock * 1000 / fb_utils::query_performance_frequency(); - m_info.pin_records_fetched = records_fetched; + m_info.pin_records_fetched = recordsFetched; + m_info.pin_counters = m_globalCounters; if (baseline && stats) - baseline->computeDifference(att, *stats, m_info, m_counts, m_tempNames); + { + baseline->setToDiff(*stats); + + m_globalCounters[PerformanceInfo::FETCHES] = (*baseline)[PageStatType::FETCHES]; + m_globalCounters[PerformanceInfo::READS] = (*baseline)[PageStatType::READS]; + m_globalCounters[PerformanceInfo::MARKS] = (*baseline)[PageStatType::MARKS]; + m_globalCounters[PerformanceInfo::WRITES] = (*baseline)[PageStatType::WRITES]; + + auto getTablespaceName = [&](unsigned id) -> Firebird::string + { + return ""; // TODO + }; + + m_pageCounters.reset(&baseline->getPageCounters(), getTablespaceName); + + auto getTableName = [&](unsigned id) -> Firebird::string + { + if (attachment->att_relations && id < attachment->att_relations->count()) + { + if (const auto relation = (*attachment->att_relations)[id]) + return relation->rel_name.toQuotedString(); + } + + return ""; + }; + + m_tableCounters.reset(&baseline->getTableCounters(), getTableName); + + m_info.pin_count = m_tableCounters.getObjectCount(); + m_legacyCounts.resize(m_info.pin_count); + m_info.pin_tables = m_legacyCounts.begin(); + + for (unsigned i = 0; i < m_info.pin_count; i++) + { + m_info.pin_tables[i].trc_relation_id = m_tableCounters.getObjectId(i); + m_info.pin_tables[i].trc_relation_name = m_tableCounters.getObjectName(i); + m_info.pin_tables[i].trc_counters = m_tableCounters.getObjectCounters(i); + } + } else { - // Report all zero counts for the moment. - memset(&m_info, 0, sizeof(m_info)); - m_info.pin_counters = m_dummy_counts; + memset(m_globalCounters, 0, sizeof(m_globalCounters)); } } -SINT64 TraceRuntimeStats::m_dummy_counts[RuntimeStatistics::GLOBAL_ITEMS] = {0}; - /// TraceStatusVectorImpl diff --git a/src/jrd/trace/TraceObjects.h b/src/jrd/trace/TraceObjects.h index f20cd8b0038..36a7ec8ca64 100644 --- a/src/jrd/trace/TraceObjects.h +++ b/src/jrd/trace/TraceObjects.h @@ -96,6 +96,127 @@ class StatementHolder }; +class TraceRuntimeStats : + public Firebird::AutoIface > +{ + static constexpr unsigned GLOBAL_COUNTERS = 4; // PerformanceInfo::{FETCHES|READS|MARKS|WRITES} + + template + class GenericCounters : + public Firebird::AutoIface, Firebird::CheckStatusWrapper> > + { + public: + GenericCounters() = default; + ~GenericCounters() = default; + + void reset(const T* counters, std::function getName) + { + m_counts = counters; + m_names.clear(); + + for (const auto& counts : *m_counts) + m_names.add(getName(counts.getGroupId())); + } + + // PerformanceCounts implementation + unsigned getObjectCount() + { + return m_counts ? m_counts->getCount() : 0; + } + + unsigned getMaxCounterIndex() + { + return T::getVectorCapacity() - 1; + } + + unsigned getObjectId(unsigned index) + { + if (m_counts && index < m_counts->getCount()) + { + const auto iter = m_counts->begin() + index; + return iter->getGroupId(); + } + + return 0; + } + + const char* getObjectName(unsigned index) + { + if (index < m_names.getCount()) + return m_names[index].c_str(); + + return nullptr; + } + + const SINT64* getObjectCounters(unsigned index) + { + if (m_counts && index < m_counts->getCount()) + { + const auto iter = m_counts->begin() + index; + return iter->getCounterVector(); + } + + return nullptr; + } + + private: + Firebird::ObjectsArray m_names; + const T* m_counts = nullptr; + }; + + typedef GenericCounters PageCounters; + typedef GenericCounters TableCounters; + +public: + TraceRuntimeStats(Attachment* att, RuntimeStatistics* baseline, RuntimeStatistics* stats, + SINT64 clock, SINT64 recordsFetched); + + // PerformanceStats implementation + FB_UINT64 getElapsedTime() + { + return m_info.pin_time; + } + + FB_UINT64 getFetchedRecords() + { + return m_info.pin_records_fetched; + } + + Firebird::IPerformanceCounters* getCounters(unsigned group) + { + Firebird::IPerformanceCounters* counters = nullptr; + + switch (group) + { + case IPerformanceStats::COUNTER_GROUP_PAGES: + counters = &m_pageCounters; + break; + + case IPerformanceStats::COUNTER_GROUP_TABLES: + counters = &m_tableCounters; + break; + + default: + fb_assert(false); + } + + return counters; + } + + Firebird::PerformanceInfo* getInfo() + { + return &m_info; + } + +private: + Firebird::PerformanceInfo m_info; + PageCounters m_pageCounters; + TableCounters m_tableCounters; + SINT64 m_globalCounters[GLOBAL_COUNTERS]; + Firebird::HalfStaticArray m_legacyCounts; +}; + + class TraceConnectionImpl : public Firebird::AutoIface > { @@ -127,10 +248,10 @@ class TraceTransactionImpl : public Firebird::AutoIface > { public: - TraceTransactionImpl(const jrd_tra* tran, Firebird::PerformanceInfo* perf = NULL, ISC_INT64 prevID = 0) : + TraceTransactionImpl(const jrd_tra* tran, TraceRuntimeStats* stats = nullptr, ISC_INT64 prevID = 0) : m_tran(tran), - m_perf(perf), - m_prevID(prevID) + m_prevID(prevID), + m_stats(stats) {} // TraceTransaction implementation @@ -138,14 +259,27 @@ class TraceTransactionImpl : FB_BOOLEAN getReadOnly(); int getWait(); unsigned getIsolation(); - Firebird::PerformanceInfo* getPerf() { return m_perf; } ISC_INT64 getInitialID(); - ISC_INT64 getPreviousID() { return m_prevID; } + + ISC_INT64 getPreviousID() + { + return m_prevID; + } + + Firebird::PerformanceInfo* getPerf() + { + return m_stats ? m_stats->getInfo() : nullptr; + } + + Firebird::IPerformanceStats* getPerfStats() + { + return m_stats; + } private: const jrd_tra* const m_tran; - Firebird::PerformanceInfo* const m_perf; const ISC_INT64 m_prevID; + TraceRuntimeStats* const m_stats; }; @@ -161,8 +295,16 @@ class BLRPrinter : {} // TraceBLRStatement implementation - const unsigned char* getData() { return m_blr; } - unsigned getDataLength() { return m_length; } + const unsigned char* getData() + { + return m_blr; + } + + unsigned getDataLength() + { + return m_length; + } + const char* getText() { if (m_text.empty() && getDataLength()) @@ -189,18 +331,30 @@ class BLRPrinter : class TraceBLRStatementImpl : public BLRPrinter { public: - TraceBLRStatementImpl(const Statement* stmt, Firebird::PerformanceInfo* perf) : + TraceBLRStatementImpl(const Statement* stmt, TraceRuntimeStats* stats) : BLRPrinter(stmt->blr.begin(), stmt->blr.getCount()), m_stmt(stmt), - m_perf(perf) + m_stats(stats) {} - ISC_INT64 getStmtID() { return m_stmt->getStatementId(); } - Firebird::PerformanceInfo* getPerf() { return m_perf; } + ISC_INT64 getStmtID() + { + return m_stmt->getStatementId(); + } + + Firebird::PerformanceInfo* getPerf() + { + return m_stats ? m_stats->getInfo() : nullptr; + } + + Firebird::IPerformanceStats* getPerfStats() + { + return m_stats; + } private: const Statement* const m_stmt; - Firebird::PerformanceInfo* const m_perf; + TraceRuntimeStats* const m_stats; }; @@ -211,8 +365,9 @@ class TraceFailedBLRStatement : public BLRPrinter BLRPrinter(blr, length) {} - ISC_INT64 getStmtID() { return 0; } - Firebird::PerformanceInfo* getPerf() { return NULL; } + ISC_INT64 getStmtID() { return 0; } + Firebird::PerformanceInfo* getPerf() { return nullptr; } + Firebird::IPerformanceStats* getPerfStats() { return nullptr; } }; @@ -221,20 +376,23 @@ class TraceSQLStatementImpl : public StatementHolder { public: - TraceSQLStatementImpl(DsqlRequest* stmt, Firebird::PerformanceInfo* perf, const UCHAR* inputBuffer) : + TraceSQLStatementImpl(DsqlRequest* stmt, TraceRuntimeStats* stats, const UCHAR* inputBuffer) : StatementHolder(stmt ? stmt->getStatement() : nullptr), m_stmt(stmt), - m_perf(perf), - m_inputs(stmt, inputBuffer) + m_inputs(stmt, inputBuffer), + m_stats(stats) {} // TraceSQLStatement implementation ISC_INT64 getStmtID(); - Firebird::PerformanceInfo* getPerf(); - Firebird::ITraceParams* getInputs(); const char* getText(); const char* getTextUTF8(); + Firebird::ITraceParams* getInputs() + { + return &m_inputs; + } + const char* getPlan() { return ensurePlan(false); @@ -245,6 +403,16 @@ class TraceSQLStatementImpl : return ensurePlan(true); } + Firebird::PerformanceInfo* getPerf() + { + return m_stats ? m_stats->getInfo() : nullptr; + } + + Firebird::IPerformanceStats* getPerfStats() + { + return m_stats; + } + private: class DSQLParamsImpl : public Firebird::AutoIface > @@ -252,8 +420,7 @@ class TraceSQLStatementImpl : public: explicit DSQLParamsImpl(DsqlRequest* const stmt, const UCHAR* const inputBuffer) : m_stmt(stmt), m_buffer(inputBuffer) - { - } + {} FB_SIZE_T getCount(); const paramdsc* getParam(FB_SIZE_T idx); @@ -269,9 +436,9 @@ class TraceSQLStatementImpl : }; DsqlRequest* const m_stmt; - Firebird::PerformanceInfo* const m_perf; DSQLParamsImpl m_inputs; Firebird::string m_textUTF8; + TraceRuntimeStats* const m_stats; }; @@ -284,13 +451,14 @@ class TraceFailedSQLStatement : {} // TraceSQLStatement implementation - ISC_INT64 getStmtID() { return 0; } - Firebird::PerformanceInfo* getPerf() { return NULL; } - Firebird::ITraceParams* getInputs() { return NULL; } - const char* getText() { return m_text.c_str(); } - const char* getPlan() { return ""; } + ISC_INT64 getStmtID() { return 0; } + Firebird::ITraceParams* getInputs() { return nullptr; } + const char* getText() { return m_text.c_str(); } + const char* getPlan() { return ""; } const char* getTextUTF8(); - const char* getExplainedPlan() { return ""; } + const char* getExplainedPlan() { return ""; } + Firebird::PerformanceInfo* getPerf() { return nullptr; } + Firebird::IPerformanceStats* getPerfStats() { return nullptr; } private: Firebird::string& m_text; @@ -444,15 +612,15 @@ class TraceProcedureImpl : TraceProcedureImpl(const Firebird::string& name, const Statement* statement) : StatementHolder(statement), m_name(name), - m_perf(nullptr), - m_inputs(nullptr, nullptr) + m_inputs(nullptr, nullptr), + m_stats(nullptr) {} - TraceProcedureImpl(Request* request, Firebird::PerformanceInfo* perf) : + TraceProcedureImpl(Request* request, TraceRuntimeStats* stats) : StatementHolder(request), m_name(getName()), - m_perf(perf), - m_inputs(request->req_proc_caller, request->req_proc_inputs) + m_inputs(request->req_proc_caller, request->req_proc_inputs), + m_stats(stats) {} // TraceProcedure implementation @@ -466,11 +634,6 @@ class TraceProcedureImpl : return m_inputs; } - Firebird::PerformanceInfo* getPerf() - { - return m_perf; - }; - ISC_INT64 getStmtID() { return getId(); @@ -486,10 +649,20 @@ class TraceProcedureImpl : return ensurePlan(true); } + Firebird::PerformanceInfo* getPerf() + { + return m_stats ? m_stats->getInfo() : nullptr; + } + + Firebird::IPerformanceStats* getPerfStats() + { + return m_stats; + } + private: const Firebird::string m_name; - Firebird::PerformanceInfo* const m_perf; TraceDscFromValues m_inputs; + TraceRuntimeStats* const m_stats; }; @@ -501,18 +674,18 @@ class TraceFunctionImpl : TraceFunctionImpl(const Firebird::string& name, const Statement* statement) : StatementHolder(statement), m_name(name), - m_perf(nullptr), m_inputs(nullptr), - m_value(nullptr) + m_value(nullptr), + m_stats(nullptr) {} - TraceFunctionImpl(Request* request, Firebird::PerformanceInfo* perf, + TraceFunctionImpl(Request* request, TraceRuntimeStats* stats, Firebird::ITraceParams* inputs, const dsc* value) : StatementHolder(request), m_name(getName()), - m_perf(perf), m_inputs(inputs), - m_value(value) + m_value(value), + m_stats(stats) {} // TraceFunction implementation @@ -531,11 +704,6 @@ class TraceFunctionImpl : return m_value; } - Firebird::PerformanceInfo* getPerf() - { - return m_perf; - }; - ISC_INT64 getStmtID() { return getId(); @@ -551,11 +719,21 @@ class TraceFunctionImpl : return ensurePlan(true); } + Firebird::PerformanceInfo* getPerf() + { + return m_stats ? m_stats->getInfo() : nullptr; + }; + + Firebird::IPerformanceStats* getPerfStats() + { + return m_stats; + }; + private: Firebird::string m_name; - Firebird::PerformanceInfo* const m_perf; Firebird::ITraceParams* const m_inputs; TraceDscFromDsc m_value; + TraceRuntimeStats* const m_stats; }; @@ -571,17 +749,17 @@ class TraceTriggerImpl : m_relationName(relationName), m_which(which), m_action(action), - m_perf(nullptr) + m_stats(nullptr) {} - TraceTriggerImpl(int which, const Request* request, Firebird::PerformanceInfo* perf) : + TraceTriggerImpl(int which, const Request* request, TraceRuntimeStats* stats) : StatementHolder(request), m_name(getName()), m_relationName((request->req_rpb.hasData() && request->req_rpb[0].rpb_relation) ? request->req_rpb[0].rpb_relation->rel_name.toQuotedString() : ""), m_which(which), m_action(request->req_trigger_action), - m_perf(perf) + m_stats(stats) {} // TraceTrigger implementation @@ -605,11 +783,6 @@ class TraceTriggerImpl : return m_action; } - Firebird::PerformanceInfo* getPerf() - { - return m_perf; - } - ISC_INT64 getStmtID() { return getId(); @@ -625,12 +798,22 @@ class TraceTriggerImpl : return ensurePlan(true); } + Firebird::PerformanceInfo* getPerf() + { + return m_stats ? m_stats->getInfo() : nullptr; + }; + + Firebird::IPerformanceStats* getPerfStats() + { + return m_stats; + }; + private: const Firebird::string m_name; const Firebird::string m_relationName; const int m_which; const int m_action; - Firebird::PerformanceInfo* const m_perf; + TraceRuntimeStats* const m_stats; }; @@ -662,22 +845,6 @@ class TraceServiceImpl : }; -class TraceRuntimeStats -{ -public: - TraceRuntimeStats(Attachment* att, RuntimeStatistics* baseline, RuntimeStatistics* stats, - SINT64 clock, SINT64 records_fetched); - - Firebird::PerformanceInfo* getPerf() { return &m_info; } - -private: - Firebird::PerformanceInfo m_info; - TraceCountsArray m_counts; - Firebird::ObjectsArray m_tempNames; - static SINT64 m_dummy_counts[RuntimeStatistics::GLOBAL_ITEMS]; // Zero-initialized array with zero counts -}; - - class TraceInitInfoImpl : public Firebird::AutoIface > { @@ -759,14 +926,7 @@ class TraceSweepImpl : public Firebird::AutoIface > { public: - TraceSweepImpl() - { - m_oit = 0; - m_ost = 0; - m_oat = 0; - m_next = 0; - m_perf = 0; - } + TraceSweepImpl() = default; void update(const Ods::header_page* header) { @@ -776,23 +936,32 @@ class TraceSweepImpl : m_next = header->hdr_next_transaction; } - void setPerf(Firebird::PerformanceInfo* perf) + void setStats(TraceRuntimeStats* stats) { - m_perf = perf; + m_stats = stats; } ISC_INT64 getOIT() { return m_oit; }; ISC_INT64 getOST() { return m_ost; }; ISC_INT64 getOAT() { return m_oat; }; ISC_INT64 getNext() { return m_next; }; - Firebird::PerformanceInfo* getPerf() { return m_perf; }; + + Firebird::PerformanceInfo* getPerf() + { + return m_stats ? m_stats->getInfo() : nullptr; + }; + + Firebird::IPerformanceStats* getPerfStats() + { + return m_stats; + }; private: - TraNumber m_oit; - TraNumber m_ost; - TraNumber m_oat; - TraNumber m_next; - Firebird::PerformanceInfo* m_perf; + TraNumber m_oit = 0; + TraNumber m_ost = 0; + TraNumber m_oat = 0; + TraNumber m_next = 0; + TraceRuntimeStats* m_stats = nullptr; }; } // namespace Jrd diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index 67c74a6dcb0..74849637b0b 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -429,7 +429,6 @@ bool SweepTask::handler(WorkItem& _item) RelInfo* relInfo = item->m_relInfo; Database* dbb = tdbb->getDatabase(); - Attachment* att = tdbb->getAttachment(); /*relation = (*att->att_relations)[relInfo->rel_id]; if (relation)*/ @@ -3597,13 +3596,16 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j if ((!rc1 || MOV_get_long(tdbb, &desc1, 0) == 0)) { - dsc desc3, desc4; + dsc desc3, desc4, desc5, desc6; bool rc2 = EVL_field(NULL, new_rpb->rpb_record, f_rfr_null_flag, &desc2); bool rc3 = EVL_field(NULL, org_rpb->rpb_record, f_rfr_sname, &desc3); bool rc4 = EVL_field(NULL, new_rpb->rpb_record, f_rfr_sname, &desc4); + bool rc5 = EVL_field(NULL, org_rpb->rpb_record, f_rfr_field_source_schema, &desc5); + bool rc6 = EVL_field(NULL, new_rpb->rpb_record, f_rfr_field_source_schema, &desc6); if ((rc2 && MOV_get_long(tdbb, &desc2, 0) != 0) || - (rc3 && rc4 && MOV_compare(tdbb, &desc3, &desc4))) + (rc3 && rc4 && MOV_compare(tdbb, &desc3, &desc4)) || + (rc5 && rc6 && MOV_compare(tdbb, &desc5, &desc6))) { EVL_field(0, new_rpb->rpb_record, f_rfr_schema, &schemaDesc); EVL_field(0, new_rpb->rpb_record, f_rfr_rname, &desc1); diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index aa39c7255f2..066d01c76ae 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -9,7 +9,7 @@ BuildType=T MajorVer=6 MinorVer=0 RevNo=0 -BuildNum=1357 +BuildNum=1387 NowAt=`pwd` cd `dirname $0` diff --git a/src/remote/client/interface.cpp b/src/remote/client/interface.cpp index 6c2d7b6067b..fc4b6d739ac 100644 --- a/src/remote/client/interface.cpp +++ b/src/remote/client/interface.cpp @@ -5027,8 +5027,6 @@ bool ResultSet::fetch(CheckStatusWrapper* status, void* buffer, P_FETCH operatio if (relative && adjustment) { - const bool isAhead = (statement->rsr_fetch_operation == fetch_next); - PACKET* packet = &rdb->rdb_packet; packet->p_operation = op_fetch_scroll; P_SQLDATA* sqldata = &packet->p_sqldata; diff --git a/src/remote/remote.cpp b/src/remote/remote.cpp index 299b8cb01aa..7de4d2ded74 100644 --- a/src/remote/remote.cpp +++ b/src/remote/remote.cpp @@ -125,7 +125,6 @@ const ParametersSet connectParam = constexpr SLONG DUMMY_INTERVAL = 60; // seconds -constexpr int ATTACH_FAILURE_SPACE = 16 * 1024; // bytes void REMOTE_cleanup_transaction( Rtr* transaction) diff --git a/src/remote/server/server.cpp b/src/remote/server/server.cpp index 6cea42401fa..3a3ca2281ed 100644 --- a/src/remote/server/server.cpp +++ b/src/remote/server/server.cpp @@ -1078,8 +1078,6 @@ class CryptKeyTypeManager : public PermanentStorage class CryptKeyType; public: - static const unsigned BITS64 = sizeof(FB_UINT64) * 8u; - class SpecificPlugins { public: diff --git a/src/utilities/gstat/dba.epp b/src/utilities/gstat/dba.epp index c9e08be3a34..53baa567a85 100644 --- a/src/utilities/gstat/dba.epp +++ b/src/utilities/gstat/dba.epp @@ -635,10 +635,13 @@ int gstat(Firebird::UtilSvc* uSvc) } } + if (uSvc->utf8FileNames()) + ISC_utf8ToSystem(fileName); + expandDatabaseName(fileName, tempStr, NULL); fileName = tempStr; - const dba_fil* file = db_open(fileName.c_str(), fileName.length()); + db_open(fileName.c_str(), fileName.length()); alignas(DIRECT_IO_BLOCK_SIZE) SCHAR temp[MAX(RAW_HEADER_SIZE, DIRECT_IO_BLOCK_SIZE)]; tddba->page_size = MAX(RAW_HEADER_SIZE, DIRECT_IO_BLOCK_SIZE); @@ -1072,9 +1075,10 @@ int gstat(Firebird::UtilSvc* uSvc) uSvc->printf(false, " Pointer pages: %ld, data page slots: %ld\n", relation->rel_pointer_pages, relation->rel_slots); - const double average = (relation->rel_data_pages) ? + const auto nonEmptyPages = relation->rel_data_pages - relation->rel_empty_pages; + const double average = nonEmptyPages ? (double) relation->rel_total_space * 100 / - ((double) relation->rel_data_pages * (tddba->page_size - DPG_SIZE)) : 0.0; + ((double) nonEmptyPages * (tddba->page_size - DPG_SIZE)) : 0.0; uSvc->printf(false, " Data pages: %ld, average fill: %.0f%%\n", relation->rel_data_pages, average); @@ -1379,7 +1383,6 @@ static void analyze_data( dba_rel* relation, bool sw_record) ++relation->rel_slots; if (*ptr) { - ++relation->rel_data_pages; if (!analyze_data_page(relation, (const data_page*) db_read(*ptr), sw_record)) { dba_print(false, 18, SafeArg() << *ptr); @@ -1419,6 +1422,8 @@ static bool analyze_data_page( dba_rel* relation, const data_page* page, bool sw if (page->dpg_header.pag_type != pag_data) return false; + ++relation->rel_data_pages; + if (sw_record) { memcpy(tddba->buffer2, (const SCHAR*) page, tddba->page_size); @@ -1432,7 +1437,7 @@ static bool analyze_data_page( dba_rel* relation, const data_page* page, bool sw { if (tail->dpg_offset && tail->dpg_length) { - space += tail->dpg_length; + space += FB_ALIGN(tail->dpg_length, ODS_ALIGNMENT); if (sw_record) { diff --git a/src/utilities/nbackup/nbackup.cpp b/src/utilities/nbackup/nbackup.cpp index 9d597a44d79..211a2c05ac9 100644 --- a/src/utilities/nbackup/nbackup.cpp +++ b/src/utilities/nbackup/nbackup.cpp @@ -82,12 +82,6 @@ #define O_LARGEFILE 0 #endif -// How much we align memory when reading database header. -// Sector alignment of memory is necessary to use unbuffered IO on Windows. -// Actually, sectors may be bigger than 1K, but let's be consistent with -// JRD regarding the matter for the moment. -constexpr FB_SIZE_T SECTOR_ALIGNMENT = PAGE_ALIGNMENT; - using namespace Firebird; namespace diff --git a/src/utilities/ntrace/TracePluginImpl.cpp b/src/utilities/ntrace/TracePluginImpl.cpp index a962af94748..5447402550d 100644 --- a/src/utilities/ntrace/TracePluginImpl.cpp +++ b/src/utilities/ntrace/TracePluginImpl.cpp @@ -629,56 +629,78 @@ void TracePluginImpl::logRecordError(const char* action, ITraceConnection* conne logRecord(action); } -void TracePluginImpl::appendGlobalCounts(const PerformanceInfo* info) +void TracePluginImpl::appendGlobalCounts(IPerformanceStats* stats) { string temp; - temp.printf("%7" QUADFORMAT"d ms", info->pin_time); + temp.printf("%7" QUADFORMAT"d ms", stats->getElapsedTime()); record.append(temp); - ntrace_counter_t cnt; + const auto pageCounters = stats->getCounters(IPerformanceStats::COUNTER_GROUP_PAGES); + fb_assert(pageCounters); - if ((cnt = info->pin_counters[PerformanceInfo::READS]) != 0) + if (const auto count = pageCounters->getObjectCount()) { - temp.printf(", %" QUADFORMAT"d read(s)", cnt); - record.append(temp); - } + // Holds counters: IPerformanceCounters::PAGE_{FETCHES|READS|MARKS|WRITES} + static constexpr unsigned GLOBAL_COUNTERS = 4; + SINT64 globalCounters[GLOBAL_COUNTERS] = {0}; - if ((cnt = info->pin_counters[PerformanceInfo::WRITES]) != 0) - { - temp.printf(", %" QUADFORMAT"d write(s)", cnt); - record.append(temp); - } + for (unsigned i = 0; i < count; i++) + { + const auto counters = pageCounters->getObjectCounters(i); + for (unsigned j = 0; j < GLOBAL_COUNTERS; j++) + globalCounters[j] += counters[j]; + } - if ((cnt = info->pin_counters[PerformanceInfo::FETCHES]) != 0) - { - temp.printf(", %" QUADFORMAT"d fetch(es)", cnt); - record.append(temp); - } + if (const auto cnt = globalCounters[IPerformanceCounters::PAGE_READS]) + { + temp.printf(", %" QUADFORMAT"d read(s)", cnt); + record.append(temp); + } - if ((cnt = info->pin_counters[PerformanceInfo::MARKS]) != 0) - { - temp.printf(", %" QUADFORMAT"d mark(s)", cnt); - record.append(temp); + if (const auto cnt = globalCounters[IPerformanceCounters::PAGE_WRITES]) + { + temp.printf(", %" QUADFORMAT"d write(s)", cnt); + record.append(temp); + } + + if (const auto cnt = globalCounters[IPerformanceCounters::PAGE_FETCHES]) + { + temp.printf(", %" QUADFORMAT"d fetch(es)", cnt); + record.append(temp); + } + + if (const auto cnt = globalCounters[IPerformanceCounters::PAGE_MARKS]) + { + temp.printf(", %" QUADFORMAT"d mark(s)", cnt); + record.append(temp); + } } record.append(NEWLINE); } -void TracePluginImpl::appendTableCounts(const PerformanceInfo *info) +void TracePluginImpl::appendTableCounts(IPerformanceStats* stats) { - if (!config.print_perf || info->pin_count == 0) + if (!config.print_perf) return; - const TraceCounts* trc = info->pin_tables; - const TraceCounts* trc_end = trc + info->pin_count; + const auto tableCounters = stats->getCounters(IPerformanceStats::COUNTER_GROUP_TABLES); + fb_assert(tableCounters); + + const auto count = tableCounters->getObjectCount(); + if (!count) + return; FB_SIZE_T max_len = 0; - for (; trc < trc_end; trc++) + for (unsigned i = 0; i < count; i++) { - FB_SIZE_T len = fb_strlen(trc->trc_relation_name); - if (max_len < len) - max_len = len; + if (const auto relName = tableCounters->getObjectName(i)) + { + const FB_SIZE_T len = fb_strlen(relName); + if (max_len < len) + max_len = len; + } } if (max_len < 32) @@ -691,24 +713,45 @@ void TracePluginImpl::appendTableCounts(const PerformanceInfo *info) record.append(NEWLINE); string temp; - for (trc = info->pin_tables; trc < trc_end; trc++) + for (unsigned i = 0; i < count; i++) { - record.append(trc->trc_relation_name); - record.append(max_len - fb_strlen(trc->trc_relation_name), ' '); - for (int j = 0; j <= TraceCounts::EXPUNGES; j++) + const auto relName = tableCounters->getObjectName(i); + if (relName && *relName) + { + record.append(relName); + record.append(max_len - fb_strlen(relName), ' '); + } + else + { + temp.printf("Table id <%u>", tableCounters->getObjectId(i)); + record.append(temp); + record.append(max_len - temp.length(), ' '); + } + + const auto counters = tableCounters->getObjectCounters(i); + + string line; + bool nonZero = false; + for (unsigned j = IPerformanceCounters::RECORD_SEQ_READS; + j <= IPerformanceCounters::RECORD_EXPUNGES; j++) { - if (trc->trc_counters[j] == 0) + if (counters[j] == 0) { - record.append(10, ' '); + line.append(10, ' '); } else { - //fb_utils::exactNumericToStr(trc->trc_counters[j], 0, temp); + //fb_utils::exactNumericToStr(counterVector[j], 0, temp); //record.append(' ', 10 - temp.length()); - temp.printf("%10" QUADFORMAT"d", trc->trc_counters[j]); - record.append(temp); + temp.printf("%10" QUADFORMAT"d", counters[j]); + line.append(temp); + nonZero = true; } } + + if (nonZero) + record.append(line); + record.append(NEWLINE); } } @@ -1494,11 +1537,10 @@ void TracePluginImpl::log_event_transaction_end(ITraceDatabaseConnection* connec } } - PerformanceInfo* info = transaction->getPerf(); - if (info) + if (const auto stats = transaction->getPerfStats()) { - appendGlobalCounts(info); - appendTableCounts(info); + appendGlobalCounts(stats); + appendTableCounts(stats); } const char* event_type; @@ -1596,8 +1638,8 @@ void TracePluginImpl::log_event_proc_execute(ITraceDatabaseConnection* connectio return; // Do not log operation if it is below time threshold - const PerformanceInfo* info = started ? NULL : procedure->getPerf(); - if (config.time_threshold && info && info->pin_time < config.time_threshold) + IPerformanceStats* const stats = started ? nullptr : procedure->getPerfStats(); + if (config.time_threshold && stats && stats->getElapsedTime() < config.time_threshold) return; ITraceParams* params = procedure->getInputs(); @@ -1608,16 +1650,17 @@ void TracePluginImpl::log_event_proc_execute(ITraceDatabaseConnection* connectio record.append(NEWLINE); } - if (info) + if (stats) { - if (info->pin_records_fetched) + if (const auto cnt = stats->getFetchedRecords()) { string temp; - temp.printf("%" QUADFORMAT"d records fetched" NEWLINE, info->pin_records_fetched); + temp.printf("%" QUADFORMAT"d records fetched" NEWLINE, cnt); record.append(temp); } - appendGlobalCounts(info); - appendTableCounts(info); + + appendGlobalCounts(stats); + appendTableCounts(stats); } const char* event_type; @@ -1677,8 +1720,8 @@ void TracePluginImpl::log_event_func_execute(ITraceDatabaseConnection* connectio return; // Do not log operation if it is below time threshold - const PerformanceInfo* info = started ? NULL : function->getPerf(); - if (config.time_threshold && info && info->pin_time < config.time_threshold) + IPerformanceStats* const stats = started ? nullptr : function->getPerfStats(); + if (config.time_threshold && stats && stats->getElapsedTime() < config.time_threshold) return; ITraceParams* params = function->getInputs(); @@ -1699,16 +1742,17 @@ void TracePluginImpl::log_event_func_execute(ITraceDatabaseConnection* connectio } } - if (info) + if (stats) { - if (info->pin_records_fetched) + if (const auto cnt = stats->getFetchedRecords()) { string temp; - temp.printf("%" QUADFORMAT"d records fetched" NEWLINE, info->pin_records_fetched); + temp.printf("%" QUADFORMAT"d records fetched" NEWLINE, cnt); record.append(temp); } - appendGlobalCounts(info); - appendTableCounts(info); + + appendGlobalCounts(stats); + appendTableCounts(stats); } const char* event_type; @@ -1767,14 +1811,14 @@ void TracePluginImpl::log_event_trigger_execute(ITraceDatabaseConnection* connec return; // Do not log operation if it is below time threshold - const PerformanceInfo* info = started ? NULL : trigger->getPerf(); - if (config.time_threshold && info && info->pin_time < config.time_threshold) + IPerformanceStats* const stats = started ? nullptr : trigger->getPerfStats(); + if (config.time_threshold && stats && stats->getElapsedTime() < config.time_threshold) return; - if (info) + if (stats) { - appendGlobalCounts(info); - appendTableCounts(info); + appendGlobalCounts(stats); + appendTableCounts(stats); } const char* event_type; @@ -1920,8 +1964,8 @@ void TracePluginImpl::log_event_dsql_execute(ITraceDatabaseConnection* connectio return; // Do not log operation if it is below time threshold - const PerformanceInfo* info = started ? NULL : statement->getPerf(); - if (config.time_threshold && info && info->pin_time < config.time_threshold) + IPerformanceStats* const stats = started ? nullptr : statement->getPerfStats(); + if (config.time_threshold && stats && stats->getElapsedTime() < config.time_threshold) return; if (restart) @@ -1939,14 +1983,14 @@ void TracePluginImpl::log_event_dsql_execute(ITraceDatabaseConnection* connectio record.append(NEWLINE); } - if (info) + if (stats) { string temp; - temp.printf("%" QUADFORMAT"d records fetched" NEWLINE, info->pin_records_fetched); + temp.printf("%" QUADFORMAT"d records fetched" NEWLINE, stats->getFetchedRecords()); record.append(temp); - appendGlobalCounts(info); - appendTableCounts(info); + appendGlobalCounts(stats); + appendTableCounts(stats); } string event_type; @@ -2058,16 +2102,19 @@ void TracePluginImpl::log_event_blr_execute(ITraceDatabaseConnection* connection ITraceTransaction* transaction, ITraceBLRStatement* statement, ntrace_result_t req_result) { - PerformanceInfo *info = statement->getPerf(); + const auto stats = statement->getPerfStats(); // Do not log operation if it is below time threshold - if (config.time_threshold && info->pin_time < config.time_threshold) + if (config.time_threshold && stats && stats->getElapsedTime() < config.time_threshold) return; if (config.log_blr_requests) { - appendGlobalCounts(info); - appendTableCounts(info); + if (stats) + { + appendGlobalCounts(stats); + appendTableCounts(stats); + } const char* event_type; switch (req_result) @@ -2440,11 +2487,10 @@ void TracePluginImpl::log_event_sweep(ITraceDatabaseConnection* connection, ITra ); } - PerformanceInfo* info = sweep->getPerf(); - if (info) + if (const auto stats = sweep->getPerfStats()) { - appendGlobalCounts(info); - appendTableCounts(info); + appendGlobalCounts(stats); + appendTableCounts(stats); } const char* event_type = NULL; diff --git a/src/utilities/ntrace/TracePluginImpl.h b/src/utilities/ntrace/TracePluginImpl.h index e84330599b1..4025af881ff 100644 --- a/src/utilities/ntrace/TracePluginImpl.h +++ b/src/utilities/ntrace/TracePluginImpl.h @@ -178,8 +178,8 @@ class TracePluginImpl final : GdsCodesArray include_codes; GdsCodesArray exclude_codes; - void appendGlobalCounts(const Firebird::PerformanceInfo* info); - void appendTableCounts(const Firebird::PerformanceInfo* info); + void appendGlobalCounts(Firebird::IPerformanceStats* stats); + void appendTableCounts(Firebird::IPerformanceStats* stats); void appendParams(Firebird::ITraceParams* params); void appendServiceQueryParams(size_t send_item_length, const ntrace_byte_t* send_items, size_t recv_item_length, const ntrace_byte_t* recv_items); diff --git a/src/utilities/ntrace/fbtrace.conf b/src/utilities/ntrace/fbtrace.conf index a8c6a359df7..daf0bd2a1d1 100644 --- a/src/utilities/ntrace/fbtrace.conf +++ b/src/utilities/ntrace/fbtrace.conf @@ -11,15 +11,15 @@ # expression which is matched against fully qualified database path name. # # For log file name Sed syntax for substitutions is supported. -# I.e. \0 - whole matched string, \1 ... \9 - parenthesis subexpressions. +# I.e. \0 - whole matched string, \1 ... \9 - parenthesis subexpressions. # \\ is backslash. # -# String values should be enclosed into double quotes if contains +# String values should be enclosed into double quotes if contains # spaces embedded, for example: # log_filename "C:\\Documents and Settings\\Firebird\\My Documents\\trace.log" # include_filter "Database Stats" # -# To enter curvy brackets { } somewhere in a configuration dup them: {{ }}. +# To enter braces { } in a configuration value, double them: {{ }}. # For example - to enter this regular expression # database = (%[\\/](e[[:DIGIT:]]{2}).fdb) # type @@ -41,72 +41,72 @@ database # Operations log file name. For use by system audit trace only #log_filename = name - # Maximum size of log file (megabytes). Used by system audit trace for + # Maximum size of log file (megabytes). Used by system audit trace for # log's rotation : when current log file reached this limit it is renamed - # using current date and time and new log file is created. Value of zero + # using current date and time and new log file is created. Value of zero # means that the log file size is unlimited and rotation will never happen. #max_log_size = 0 - # SQL query filters. + # SQL query filters. # - # Only SQL statements falling under given regular expression are reported + # Only SQL statements falling under given regular expression are reported # in the log. - #include_filter + #include_filter = - # SQL statements falling under given regular expression are NOT reported + # SQL statements falling under given regular expression are NOT reported # in the log. - #exclude_filter + #exclude_filter = - # Put attach/detach log records + # Put attach/detach log records #log_connections = false - # Trace only given connection id. If zero - trace all connections + # Trace only given connection id. If zero - trace all connections #connection_id = 0 - # Put transaction start/end records + # Put transaction start/end records #log_transactions = false - # Put sql statement prepare records + # Put sql statement prepare records #log_statement_prepare = false - # Put sql statement free records + # Put sql statement free records #log_statement_free = false - # Put sql statement execution start records + # Put sql statement execution start records #log_statement_start = false - - # Put sql statement execution finish\fetch to eof records + + # Put sql statement execution finish\fetch to eof records #log_statement_finish = false # Put record when stored procedure is being compiled #log_procedure_compile = false - # Put record when stored procedure is start execution + # Put record when stored procedure is start execution #log_procedure_start = false - # Put record when stored procedure is finish execution + # Put record when stored procedure is finish execution #log_procedure_finish = false # Put record when stored function is being compiled #log_function_compile = false - # Put record when stored function is start execution + # Put record when stored function is start execution #log_function_start = false - # Put record when stored function is finish execution + # Put record when stored function is finish execution #log_function_finish = false # Put record when trigger is being compiled #log_trigger_compile = false - # Put trigger execute records + # Put trigger execute records #log_trigger_start = false - # Put trigger execute records + # Put trigger execute records #log_trigger_finish = false @@ -125,11 +125,11 @@ database # Include filter. If empty, trace all errors\warnings events. # Else trace event if any code from list is found in status-vector. - #include_gds_codes + #include_gds_codes = # Exclude filter. If empty, trace all errors\warnings events. # Else trace event if no code from list is found in status-vector. - #exclude_gds_codes + #exclude_gds_codes = # Put trace session init and finish messages #log_initfini = true @@ -148,13 +148,13 @@ database #print_perf = false - # Put blr requests compile/execute records + # Put blr requests compile/execute records #log_blr_requests = false # Print blr requests or not #print_blr = false - # Put dyn requests execute records + # Put dyn requests execute records #log_dyn_requests = false # Print dyn requests or not @@ -164,19 +164,19 @@ database # Put xxx_finish record only if its timing exceeds this number of milliseconds #time_threshold = 100 - # Maximum length of SQL string logged + # Maximum length of SQL string logged #max_sql_length = 300 - # Maximum length of blr request logged + # Maximum length of blr request logged #max_blr_length = 500 - # Maximum length of dyn request logged + # Maximum length of dyn request logged #max_dyn_length = 500 - # Maximum length of individual string argument we log + # Maximum length of individual string argument we log #max_arg_length = 80 - # Maximum number of query arguments to put in log + # Maximum number of query arguments to put in log #max_arg_count = 30 } @@ -184,7 +184,7 @@ database # default services section # -# List of names of currently existing Firebird services (to use with service +# List of names of currently existing Firebird services (to use with service # filters below) : # Backup Database # Restore Database @@ -209,7 +209,7 @@ database # Display User with Admin Info # Validate Database # -services +services { # Do we trace services events or not #enabled = false @@ -217,19 +217,19 @@ services # Operations log file name. For use by system audit trace only #log_filename = name - # Maximum size of log file (megabytes). Used by system audit trace for - # log's rotation + # Maximum size of log file (megabytes). Used by system audit trace for + # log's rotation #max_log_size = 0 # Services filters. # - # Only services whose names fall under given regular expression are + # Only services whose names fall under given regular expression are # reported in the log. - #include_filter + #include_filter = - # Services whose names fall under given regular expression are NOT + # Services whose names fall under given regular expression are NOT # reported in the log. - #exclude_filter + #exclude_filter = # Put service attach, detach and start records #log_services = false @@ -249,11 +249,11 @@ services # Include filter. If empty, trace all errors\warnings events. # Else trace event if any code from list is found in status-vector. - #include_gds_codes + #include_gds_codes = # Exclude filter. If empty, trace all errors\warnings events. # Else trace event if no code from list is found in status-vector. - #exclude_gds_codes + #exclude_gds_codes = # Put trace session init and finish messages #log_initfini = true @@ -271,7 +271,7 @@ database = %[\\/]my_database.fdb # Enable logging for test.fdb, azk2.fdb and rulez.fdb in any directory -# into log file name matching database name - test.log, azk2.log and +# into log file name matching database name - test.log, azk2.log and # rulez.log appropriately # database = %[\\/](test|azk2|rulez).fdb diff --git a/src/yvalve/gds.cpp b/src/yvalve/gds.cpp index ce575729601..e114def3ad7 100644 --- a/src/yvalve/gds.cpp +++ b/src/yvalve/gds.cpp @@ -327,6 +327,7 @@ constexpr int op_invoke_function = 33; constexpr int op_invsel_procedure = 34; constexpr int op_table_value_fun = 35; constexpr int op_for_range = 36; +constexpr int op_within_group_order = 37; static constexpr UCHAR // generic print formats @@ -433,7 +434,9 @@ static constexpr UCHAR default2[] = { op_line, op_indent, op_byte, op_literal, op_line, op_indent, op_byte, op_literal, op_line, op_indent, op_byte, op_literal, - op_pad, op_line, 0}; + op_pad, op_line, 0 }, + list_function[] = { op_line, op_verb, op_verb, op_within_group_order, 0 }, + agg_function[] = { op_byte, op_literal, op_byte, op_line, op_args, op_within_group_order, 0 }; #include "../jrd/blp.h" @@ -4432,6 +4435,20 @@ static void blr_print_verb(gds_ctl* control, SSHORT level) break; } + case op_within_group_order: + { + if (control->ctl_blr_reader.peekByte() == blr_within_group_order) + { + blr_indent(control, level); + blr_print_blr(control, control->ctl_blr_reader.getByte()); + n = blr_print_byte(control); + blr_print_line(control, (SSHORT) offset); + while (--n >= 0) + blr_print_verb(control, level + 1); + } + break; + } + default: fb_assert(false); break; diff --git a/src/yvalve/utl.cpp b/src/yvalve/utl.cpp index 2f14933d3c1..25610b6a13e 100644 --- a/src/yvalve/utl.cpp +++ b/src/yvalve/utl.cpp @@ -602,8 +602,6 @@ YAttachment* UtilInterface::executeCreateDatabase2( return NULL; } - bool v3Error = false; - if (!stmtEaten) { att->execute(status, crdbTrans, statement.length(), statement.c_str(), dialect, NULL, NULL, NULL, NULL); @@ -3211,6 +3209,10 @@ void setLogin(ClumpletWriter& dpb, bool spbFlag) const UCHAR utf8Tag = spbFlag ? isc_spb_utf8_filename : isc_dpb_utf8_filename; // username and password tags match for both SPB and DPB + // We should not use environment variables when user explicitly requested + // trusted authentication (trusted_auth), on network server (address_path) + // and when authentication block is present (auth_block). The latter + // typically happens only on network server but extra protection won't hurt. if (!(dpb.find(trusted_auth) || dpb.find(address_path) || dpb.find(auth_block))) { bool utf8 = dpb.find(utf8Tag); diff --git a/src/yvalve/why.cpp b/src/yvalve/why.cpp index ea72ab0431a..035f867327a 100644 --- a/src/yvalve/why.cpp +++ b/src/yvalve/why.cpp @@ -99,9 +99,6 @@ static ISC_STATUS openOrCreateBlob(ISC_STATUS* userStatus, isc_db_handle* dbHand //------------------------------------- -static constexpr USHORT PREPARE_BUFFER_SIZE = 32768; // size of buffer used in isc_dsql_prepare call -static constexpr USHORT DESCRIBE_BUFFER_SIZE = 1024; // size of buffer used in isc_dsql_describe_xxx call - namespace Why { class StatusVector; extern UtilInterface utilInterface;