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

Merged with v4.0-release

This commit is contained in:
AlexPeshkoff 2023-11-22 17:27:30 +03:00
parent 3dba22bda0
commit 10c2e8ec01
28 changed files with 485 additions and 294 deletions

View File

@ -1,3 +1,79 @@
# v4.0.4
## Improvements
* [#7818](https://github.com/FirebirdSQL/firebird/issues/7818): Extend `RDB$GET_CONTEXT('SYSTEM', '***')` with other info from `MON$ATTACHMENTS`
Contributor(s): Vlad Khorsun
* [#7755](https://github.com/FirebirdSQL/firebird/issues/7755): Update Windows distribution with new _zlib_ version 1.3 (released 2023-08-18)
Contributor(s): Vlad Khorsun
## Bugfixes
* [#7817](https://github.com/FirebirdSQL/firebird/issues/7817): Memory leak is possible for UDF array arguments
Contributor(s): Dmitry Yemanov
* [#7812](https://github.com/FirebirdSQL/firebird/issues/7812): Service backup does not work in multiple engines configuration
Contributor(s): Alexander Peshkov
* [#7779](https://github.com/FirebirdSQL/firebird/issues/7779): Firebird 4.0.3 is constantly crashing with the same symptoms (fbclient.dll)
Contributor(s): Vlad Khorsun
* [#7772](https://github.com/FirebirdSQL/firebird/issues/7772): Blob corruption in FB4.0.3 (embedded)
Contributor(s): Vlad Khorsun
* [#7770](https://github.com/FirebirdSQL/firebird/issues/7770): Restore takes 25% more time vs 4.0.0
Contributor(s): Vlad Khorsun
* [#7766](https://github.com/FirebirdSQL/firebird/issues/7766): Firebird 4 Windows Installer omits DLLs during custom installation mode
Contributor(s): Paul Reeves
* [#7762](https://github.com/FirebirdSQL/firebird/issues/7762): Crash on "Operating system call pthread_mutex_destroy failed. Error code 16" in log
Contributor(s): Alexander Peshkov
* [#7761](https://github.com/FirebirdSQL/firebird/issues/7761): Regression when displaying line number of errors in _ISQL_ scripts
Contributor(s): Adriano dos Santos Fernandes
* [#7759](https://github.com/FirebirdSQL/firebird/issues/7759): Routine calling overhead increased by factor 6 vs Firebird 4.0.0
Contributor(s): Adriano dos Santos Fernandes
* [#7747](https://github.com/FirebirdSQL/firebird/pull/7747): Fix an issue where the garbage collection in indexes and blobs is not performed in _VIO_backout_
Contributor(s): Ilya Eremin
* [#7745](https://github.com/FirebirdSQL/firebird/issues/7745): Error restoring database which has system domains in user table with BLOBs using embedded connection
Contributor(s): Alexander Peshkov
* [#7738](https://github.com/FirebirdSQL/firebird/issues/7738): Crash on multiple connections/disconnections
Contributor(s): Alexander Peshkov
* [#7737](https://github.com/FirebirdSQL/firebird/pull/7737): Fix cases where the precedence relationship between a record page and a blob page is not set
Contributor(s): Ilya Eremin
* [#7731](https://github.com/FirebirdSQL/firebird/issues/7731): Display length of `TIMESTAMP WITH TIME ZONE` is wrong in dialect 1
Contributor(s): Alexander Peshkov
* [#7730](https://github.com/FirebirdSQL/firebird/issues/7730): Server ignores the size of `VARCHAR` when performing `SET BIND ... TO VARCHAR(N)`
Contributor(s): Alexander Peshkov
* [#7729](https://github.com/FirebirdSQL/firebird/issues/7729): `SET BIND OF TS WITH TZ TO VARCHAR(128)` uses the date format of dialect 1
Contributor(s): Alexander Peshkov
* [#7727](https://github.com/FirebirdSQL/firebird/issues/7727): Index for integer column cannot be used when `INT128/DECFLOAT` value is being searched
Contributor(s): Dmitry Yemanov
* [#7723](https://github.com/FirebirdSQL/firebird/issues/7723): Wrong error message on login if the user doesn't exist and _WireCrypt_ is disabled
Contributor(s): Alexander Peshkov
* [#7713](https://github.com/FirebirdSQL/firebird/issues/7713): `FOR SELECT` statement can not see any changes made inside the `DO` block
Contributor(s): Vlad Khorsun
* [#7691](https://github.com/FirebirdSQL/firebird/issues/7691): `WITH CALLER PRIVILEGES` has no effect in triggers
Contributor(s): Alexander Peshkov
* [#7480](https://github.com/FirebirdSQL/firebird/issues/7480): Firebird server stops accepting new connections after some time
Contributor(s): Alexander Peshkov
# v4.0.3
## Improvements

View File

@ -612,10 +612,14 @@ program Setup;
// Some global variables are also in FirebirdInstallEnvironmentChecks.inc
// This is not ideal, but then this scripting environment is not ideal, either.
// The basic point of the include files is to isolate chunks of code that are
// a) Form a module or have common functionality
// a) From a module or have common functionality
// b) Debugged.
// This hopefully keeps the main script simpler to follow.
const
UNDEFINED = -1;
Var
InstallRootDir: String;
FirebirdConfSaved: String;
@ -631,6 +635,8 @@ Var
SYSDBAPassword: String; // SYSDBA password
init_secdb: integer; // Is set to UNDEFINED by default in InitializeSetup
#ifdef setuplogging
// Not yet implemented - leave log in %TEMP%
// OkToCopyLog : Boolean; // Set when installation is complete.
@ -681,7 +687,7 @@ begin
// or
// (pos('/?',Uppercase(CommandLine)) > 0) or // InnoSetup displays its own help if these switches are passed.
// (pos('/H',Uppercase(CommandLine)) > 0) ) // Note also that our help scren only appears after the Choose Language dialogue :-(
then begin
then begin
ShowHelpDlg;
result := False;
Exit;
@ -713,7 +719,7 @@ begin
exit;
end;
//By default we want to install and confugure,
//By default we want to install and configure,
//unless subsequent analysis suggests otherwise.
InstallAndConfigure := Install + Configure;
@ -722,6 +728,7 @@ begin
InitExistingInstallRecords;
AnalyzeEnvironment;
result := AnalysisAssessment;
init_secdb := UNDEFINED;
end;
@ -851,26 +858,25 @@ begin
end;
function InitSecurityDB: Boolean;
var
AStringList: TStringList;
TempDir: String;
ResultCode: Integer;
CmdStr: string;
ResultCode: Integer;
CmdStr: string;
begin
TempDir := ExpandConstant( '{tmp}' );
CmdStr := ExpandConstant( '{app}\isql.exe' );
AStringList := TStringList.create;
with AStringList do begin
Add( 'create user ' + GetAdminUserName + ' password ''' + GetAdminUserPassword + ''' using plugin Srp;' );
Add( 'commit;' ); //Technically exit implies a commit so this not necessary. OTOH, explicitly committing makes for more readable code.
Add( 'exit;' );
SaveToFile( Tempdir +'\temp.sql' );
end;
Result := Exec( CmdStr , ' -m -m2 -user SYSDBA -i ' + TempDir + '\temp.sql -o ' + TempDir + '\temp.sql.txt employee ' , TempDir, SW_HIDE, ewWaitUntilTerminated, ResultCode );
DeleteFile( TempDir + +'\temp.sql ');
TempDir := ExpandConstant( '{tmp}' );
CmdStr := ExpandConstant( '{app}\isql.exe' );
AStringList := TStringList.create;
with AStringList do begin
Add( 'create user ' + GetAdminUserName + ' password ''' + GetAdminUserPassword + ''' using plugin Srp;' );
Add( 'commit;' ); //Technically exit implies a commit so this not necessary. OTOH, explicitly committing makes for more readable code.
Add( 'exit;' );
SaveToFile( Tempdir +'\temp.sql' );
end;
Result := Exec( CmdStr , ' -m -m2 -user SYSDBA -i ' + TempDir + '\temp.sql -o ' + TempDir + '\temp.sql.txt employee ' , TempDir, SW_HIDE, ewWaitUntilTerminated, ResultCode );
DeleteFile( TempDir + '\temp.sql');
DeleteFile( TempDir + '\temp.sql.txt');
end;
@ -954,16 +960,16 @@ begin
// These attempts to modify firebird.conf may not survice repeated installs.
if WizardIsTaskSelected('UseClassicServerTask') then
ReplaceLine(GetAppPath+'\firebird.conf','ServerMode = ','ServerMode = Classic','#');
if WizardIsTaskSelected('UseClassicServerTask') then
ReplaceLine(GetAppPath+'\firebird.conf','ServerMode = ','ServerMode = Classic','#');
if WizardIsTaskSelected('UseSuperClassicTask') then
ReplaceLine(GetAppPath+'\firebird.conf','ServerMode = ','ServerMode = SuperClassic','#');
ReplaceLine(GetAppPath+'\firebird.conf','ServerMode = ','ServerMode = SuperClassic','#');
if WizardIsTaskSelected('UseSuperServerTask') then
ReplaceLine(GetAppPath+'\firebird.conf','ServerMode = ','ServerMode = Super','#');
if WizardIsTaskSelected('UseSuperServerTask') then
ReplaceLine(GetAppPath+'\firebird.conf','ServerMode = ','ServerMode = Super','#');
end;
end;
end;
end;
@ -986,16 +992,16 @@ var
begin
//Do resize only once!
if wizardform.height = initWizardHeight then begin
AHeight := HEIGHT_INCREASE;
AWidth := WIDTH_INCREASE;
AHeight := HEIGHT_INCREASE;
AWidth := WIDTH_INCREASE;
if not Increase then begin
AHeight := (AHeight * (-1));
AWidth := (AWidth * (-1));
end;
if not Increase then begin
AHeight := (AHeight * (-1));
AWidth := (AWidth * (-1));
end;
SetupWizardFormComponentsArrays;
ResizeWizardFormHeight(AHeight);
SetupWizardFormComponentsArrays;
ResizeWizardFormHeight(AHeight);
// ResizeWizardFormWidth(AWidth);
end;
end;
@ -1019,9 +1025,8 @@ var
AppStr: String;
ReadMeFileStr: String;
begin
case CurStep of
case CurStep of
ssInstall: begin
// RenamePreFB3RC1Files;
SetupSharedFilesArray;
GetSharedLibCountBeforeCopy;
end;
@ -1035,7 +1040,8 @@ begin
IncrementSharedCount(Is64BitInstallMode, GetAppPath+'\security4.fdb', false);
IncrementSharedCount(Is64BitInstallMode, GetAppPath+'\replication.conf', false);
InitSecurityDB;
if init_secdb = 1 then
InitSecurityDB;
//Fix up conf file
UpdateFirebirdConf;
@ -1080,7 +1086,7 @@ end;
// # FIXME - we can probably remove this function
function ChooseUninstallIcon(Default: String): String;
begin
result := GetAppPath+'\firebird.exe';
result := GetAppPath+'\firebird.exe';
end;
//InnoSetup has a Check Parameter that allows installation if the function returns true.
@ -1203,12 +1209,12 @@ end;
function NextButtonClick(CurPageID: Integer): Boolean;
var
i: integer;
i: integer;
begin
Result := True;
case CurPageID of
AdminUserPage.ID : begin
{ check user has entered new sysdba password correctly. }
{ check user has entered new sysdba password correctly. }
i := CompareStr(AdminUserPage.Values[0],AdminUserPage.Values[1]);
If not (i = 0) then begin
Result := False;
@ -1222,3 +1228,5 @@ end;
begin
end.
; kate: replace-tabs on; indent-width 2; tab-width 2; replace-tabs-save on; syntax Pascal;

View File

@ -387,11 +387,9 @@ var
product: Integer;
gds32VersionString: String;
VerInt: Array of Integer;
// BoolOne, BoolTwo, BoolEval: Boolean;
// EvalOne, EvalTwo: Integer;
dbg_ProductPath, dbg_BinPath, dbg_ClientVersion, dbg_GBAKVersion, dbg_Server: String;
dbg_InstallType : Integer;
// eval_bool: boolean;
begin
@ -1181,32 +1179,28 @@ begin
end;
{ procedure RenamePreFB3RC1Files;
//The method of specifying the architecture used changed after Beta 2
//Detect this old config and rename it.
var
FirebirdConfStr: AnsiString;
begin
if FileExists(GetAppPath+'\firebird.conf') then begin
LoadStringFromFile( GetAppPath+'\firebird.conf', FirebirdConfStr );
if pos('SharedDatabase', FirebirdConfStr) > 0 then begin
RenameFile(GetAppPath+'\firebird.conf', GetAppPath+'\firebird.conf.preRC1');
RenameFile(GetAppPath+'\security4.fdb', GetAppPath+'\security4.fdb.preRC1');
end
end
end;
}
function ConfigureAuthentication: boolean;
// This function should only be called once - when the innosetup installer tries to
// install the secdb. If it is called a second time it will always find the secdb
// exists, even if it hasn't been configured. The only real way to test whether we
// should configure authentication is to actually _open_ a database and read the
// sec$users table. Except we cannot do that as we need this information before we
// install the files needed to read the database.
begin
if IsNotServerInstall then
Result := false
else
if FileExists(WizardDirValue + '\security4.fdb') then
Result := false
else
Result := true;
// if it is the first time we are called test for existence of the security db
if init_secdb = UNDEFINED then begin
if FileExists(WizardDirValue + '\security4.fdb') then
Result := false
else
Result := true
end
else
// else the result is the current setting of init_secdb
Result := Boolean(init_secdb);
// Whatever the result, cast it to an integer and update init_secdb
init_secdb := Integer(Result);
end;
@ -1231,3 +1225,5 @@ begin
result := NOT HasWI30;
end;
// kate: replace-tabs on; indent-width 2; tab-width 2; replace-tabs-save on; syntax Pascal;

View File

@ -30,8 +30,7 @@ framework:
mkdir -p $(FB_FW)/Versions/A/Libraries
cp $(ICU_LOC)*.dylib ../gen/$(TARGET)/firebird/lib/
ln -s Versions/Current/Firebird $(FB_FW)/Firebird
ln -s Versions/Current/Libraries/libfbclient.dylib $(FB_FW)/Firebird
ln -s Versions/Current/Headers $(FB_FW)/Headers
ln -s Versions/Current/Resources $(FB_FW)/Resources
ln -s Versions/Current/Libraries $(FB_FW)/Libraries

View File

@ -1055,7 +1055,7 @@ AC_CHECK_FUNCS(sem_init)
if test "$ac_cv_func_sem_init" = "yes"; then
AC_MSG_CHECKING(for working sem_init())
AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <semaphore.h>
main () {
int main () {
sem_t s;
return sem_init(&s,0,0);
}
@ -1096,7 +1096,7 @@ AC_SYS_LARGEFILE
if test "$ac_cv_sys_file_offset_bits" = "no"; then
AC_MSG_CHECKING(for native large file support)
AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <unistd.h>
main () {
int main () {
return !(sizeof(off_t) == 8);
}]])],[ac_cv_sys_file_offset_bits=64; AC_DEFINE(_FILE_OFFSET_BITS,64)
AC_MSG_RESULT(yes)],[AC_MSG_RESULT(no)],[])
@ -1143,7 +1143,7 @@ dnl EKU: try to determine the alignment of long and double
dnl replaces FB_ALIGNMENT and FB_DOUBLE_ALIGN in src/jrd/common.h
AC_MSG_CHECKING(alignment of long)
AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <semaphore.h>
main () {
int main () {
struct s {
char a;
union { long long x; sem_t y; } b;
@ -1154,7 +1154,7 @@ AC_MSG_RESULT($ac_cv_c_alignment)
AC_DEFINE_UNQUOTED(FB_ALIGNMENT, $ac_cv_c_alignment, [Alignment of long])
AC_MSG_CHECKING(alignment of double)
AC_RUN_IFELSE([AC_LANG_SOURCE([[main () {
AC_RUN_IFELSE([AC_LANG_SOURCE([[int main () {
struct s {
char a;
double b;

View File

@ -115,6 +115,10 @@ In the Beta 1 release, any physical copying method can be used:
* nbackup -l + file-level copy + nbackup -n
* nbackup -b 0
If _nbackup_ was used, restore or fixup operation should be performed to complete the replica creation. Note that if you're recreating a priorly working replica, then `-seq[uence]` option of _nbackup_ must be used during restore/fixup to preserve the replication sequence counter inside the database, so that replication could continue from the moment when the primary database was copied:
* nbackup -f &lt;database&gt; -seq
Then the replica mode must be activated for the database copy. Two options are possible:
* gfix -replica read\_only &lt;database&gt; -- set up database as read-only replica

View File

@ -70,10 +70,14 @@ Usage:
CLIENT_HOST | The wire protocol host name of remote client. Value is
| returned for all supported protocols.
|
CLIENT_OS_USER | Remote OS user name
|
CLIENT_PID | Process ID of remote client application
|
CLIENT_PROCESS | Process name of remote client application
|
CLIENT_VERSION | Version of the client library used by client application
|
DB_NAME | Canonical name of current database. It is either alias
| name if connectivity via file names is not allowed or
| fully expanded database file name otherwise.

View File

@ -4,7 +4,7 @@ architectures.
The source code of zlib library was downloaded from
http://zlib.net/zlib1213.zip
https://www.zlib.net/zlib13.zip
It was built with MSVC17 compilers using commands specified at win32/Makefile.msc:

BIN
extern/zlib/zlib.exe vendored

Binary file not shown.

View File

@ -965,6 +965,7 @@ void put_array( burp_fld* field, burp_rel* relation, ISC_QUAD* blob_id)
case blr_long:
case blr_quad:
case blr_int64:
case blr_int128:
add_byte(blr, field->fld_scale);
break;
case blr_text:

View File

@ -570,8 +570,6 @@ int gbak(Firebird::UtilSvc* uSvc)
if (switches.exists(IN_SW_BURP_SE, argv.begin(), 1, argc))
return svc_api_gbak(uSvc, switches);
uSvc->started();
if (argc <= 1)
{
burp_usage(switches);
@ -1375,12 +1373,11 @@ int gbak(Firebird::UtilSvc* uSvc)
tdgbl->action->act_action = ACT_unknown;
action = open_files(file1, &file2, sw_replace, dpb);
MVOL_init(tdgbl->io_buffer_size);
uSvc->started();
int result;
tdgbl->uSvc->started();
switch (action)
{
case RESTORE:

View File

@ -733,8 +733,7 @@ enum fld_flags_vals {
FLD_update_missing = 8,
FLD_null_flag = 16,
FLD_charset_flag = 32, // column has global charset
FLD_collate_flag = 64, // local column has specific collation
FLD_system_domain = 128 // field uses a system domain (on restore)
FLD_collate_flag = 64 // local column has specific collation
};
// relation definition - holds useful relation type stuff
@ -957,6 +956,7 @@ public:
: ThreadData(ThreadData::tddGBL),
GblPool(us->isService()),
defaultCollations(getPool()),
systemFields(getPool()),
uSvc(us),
verboseInterval(10000),
flag_on_line(true),
@ -1184,6 +1184,7 @@ public:
Firebird::Array<Firebird::Pair<Firebird::NonPooled<Firebird::MetaString, Firebird::MetaString> > >
defaultCollations;
Firebird::SortedArray<Firebird::MetaString> systemFields;
Firebird::UtilSvc* uSvc;
ULONG verboseInterval; // How many records should be backed up or restored before we show this message
bool flag_on_line; // indicates whether we will bring the database on-line

View File

@ -1783,6 +1783,7 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
case blr_long:
case blr_quad:
case blr_int64:
case blr_int128:
add_byte(blr, field->fld_type);
add_byte(blr, field->fld_scale);
break;
@ -2017,6 +2018,7 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
case blr_long:
case blr_quad:
case blr_int64:
case blr_int128:
add_byte(blr, field->fld_type);
add_byte(blr, field->fld_scale);
break;
@ -2979,6 +2981,12 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
if (tdgbl->gbl_network_protocol == 0)
{
// If user relation uses system field there is a chance that definition of such
// system field was changed in target database. Old, BLR-based code, didn't
// coerce data types thus error could happen. To avoid it, let use SQL-based
// approach, while it is a bit slower in embedded mode.
// Here we are mostly interested in legacy UNICODE_FSS fields - see #7611.
bool sysDomFlag = false;
for (field = relation->rel_fields; field && !sysDomFlag; field = field->fld_next)
@ -2986,27 +2994,7 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
if (field->fld_flags & FLD_computed)
continue;
const char* dom = field->fld_source;
if (strncmp(dom, "RDB$", 4) == 0)
{
for (dom += 4; *dom; ++dom)
{
#ifdef HAVE_CTYPE_H
if (!isdigit(*dom))
#else
if (*dom < '0' || *dom > '9')
#endif
{
sysDomFlag = true;
break;
}
}
}
// Not all system domains starts with RDB$
// There is also SEC$ fields. Here we are mostly interested in legacy UNICODE_FSS fields - see #7611.
if (field->fld_flags & FLD_system_domain)
if (tdgbl->systemFields.exist(field->fld_source))
{
sysDomFlag = true;
break;
@ -4455,7 +4443,6 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation)
case att_field_system_flag:
X.RDB$SYSTEM_FLAG = (USHORT) get_int32(tdgbl);
X.RDB$SYSTEM_FLAG.NULL = FALSE;
field->fld_flags |= FLD_system_domain;
break;
case att_view_context:
@ -4660,7 +4647,6 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation)
case att_field_system_flag:
X.RDB$SYSTEM_FLAG = (USHORT) get_int32(tdgbl);
X.RDB$SYSTEM_FLAG.NULL = FALSE;
field->fld_flags |= FLD_system_domain;
break;
case att_view_context:
@ -5401,7 +5387,10 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments)
break;
case att_functionarg_field_precision:
get_int32(tdgbl);
if (tdgbl->RESTORE_format >= 6)
get_int32(tdgbl);
else
bad_attribute(scan_next_attr, attribute, 90);
break;
case att_functionarg_package_name:
@ -8095,8 +8084,6 @@ bool get_publication(BurpGlobals* tdgbl)
*
**************************************/
att_type attribute;
TEXT temp[GDS_NAME_LEN];
SSHORT len;
scan_attr_t scan_next_attr;
if (tdgbl->runtimeODS >= DB_VERSION_DDL13)
@ -8194,8 +8181,6 @@ bool get_pub_table(BurpGlobals* tdgbl)
*
**************************************/
att_type attribute;
TEXT temp[GDS_NAME_LEN];
SSHORT len;
scan_attr_t scan_next_attr;
if (tdgbl->runtimeODS >= DB_VERSION_DDL13)
@ -10979,6 +10964,28 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file
Firebird::IRequest* req_handle4 = nullptr;
Firebird::IRequest* req_handle5 = nullptr;
// Collect system fields
{
Firebird::IRequest* req_handle = nullptr;
tdgbl->systemFields.setSortMode(Firebird::FB_ARRAY_SORT_MANUAL);
FOR(REQUEST_HANDLE req_handle)
X IN RDB$FIELDS WITH
X.RDB$SYSTEM_FLAG EQ 1
const auto len = MISC_symbol_length(X.RDB$FIELD_NAME, sizeof(X.RDB$FIELD_NAME));
Firebird::MetaString name(X.RDB$FIELD_NAME, len);
tdgbl->systemFields.add(name);
END_FOR;
ON_ERROR
general_on_error();
END_ERROR;
MISC_release_request_silent(req_handle);
tdgbl->systemFields.sort();
}
while (get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)

View File

@ -45,10 +45,20 @@ namespace
public:
TimeZoneDesc(MemoryPool& pool)
: asciiName(pool),
unicodeName(pool)
unicodeName(pool),
icuCachedCalendar(nullptr)
{
}
~TimeZoneDesc()
{
if (const auto calendar = icuCachedCalendar.exchange(nullptr))
{
auto& icuLib = Jrd::UnicodeUtil::getConversionICU();
icuLib.ucalClose(calendar);
}
}
public:
void setName(const char* name)
{
@ -70,9 +80,21 @@ namespace
return unicodeName.begin();
}
IcuCalendarWrapper getCalendar(const Jrd::UnicodeUtil::ConversionICU& icuLib, UErrorCode* err = nullptr) const
{
auto calendar = icuCachedCalendar.exchange(nullptr);
UErrorCode internalErr = U_ZERO_ERROR;
if (!calendar)
calendar = icuLib.ucalOpen(getUnicodeName(), -1, nullptr, UCAL_GREGORIAN, (err ? err : &internalErr));
return IcuCalendarWrapper(calendar, &icuCachedCalendar);
}
private:
string asciiName;
Array<UChar> unicodeName;
mutable std::atomic<UCalendar*> icuCachedCalendar;
};
}
@ -588,8 +610,7 @@ void TimeZoneUtil::extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, SSHORT* of
Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU();
UCalendar* icuCalendar = icuLib.ucalOpen(
getDesc(timeStampTz.time_zone)->getUnicodeName(), -1, NULL, UCAL_GREGORIAN, &icuErrorCode);
auto icuCalendar = getDesc(timeStampTz.time_zone)->getCalendar(icuLib, &icuErrorCode);
if (!icuCalendar)
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_open.");
@ -597,21 +618,13 @@ void TimeZoneUtil::extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, SSHORT* of
icuLib.ucalSetMillis(icuCalendar, timeStampToIcuDate(timeStampTz.utc_timestamp), &icuErrorCode);
if (U_FAILURE(icuErrorCode))
{
icuLib.ucalClose(icuCalendar);
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_setMillis.");
}
displacement = (icuLib.ucalGet(icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) +
icuLib.ucalGet(icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE;
if (U_FAILURE(icuErrorCode))
{
icuLib.ucalClose(icuCalendar);
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_get.");
}
icuLib.ucalClose(icuCalendar);
}
*offset = displacement;
@ -683,8 +696,7 @@ void TimeZoneUtil::localTimeStampToUtc(ISC_TIMESTAMP_TZ& timeStampTz)
Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU();
UCalendar* icuCalendar = icuLib.ucalOpen(
getDesc(timeStampTz.time_zone)->getUnicodeName(), -1, NULL, UCAL_GREGORIAN, &icuErrorCode);
auto icuCalendar = getDesc(timeStampTz.time_zone)->getCalendar(icuLib, &icuErrorCode);
if (!icuCalendar)
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_open.");
@ -696,21 +708,13 @@ void TimeZoneUtil::localTimeStampToUtc(ISC_TIMESTAMP_TZ& timeStampTz)
times.tm_hour, times.tm_min, times.tm_sec, &icuErrorCode);
if (U_FAILURE(icuErrorCode))
{
icuLib.ucalClose(icuCalendar);
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_setDateTime.");
}
displacement = (icuLib.ucalGet(icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) +
icuLib.ucalGet(icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE;
if (U_FAILURE(icuErrorCode))
{
icuLib.ucalClose(icuCalendar);
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_get.");
}
icuLib.ucalClose(icuCalendar);
}
const auto ticks = TimeStamp::timeStampToTicks(timeStampTz.utc_timestamp) -
@ -752,8 +756,7 @@ bool TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, bool gmt
#endif
Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU();
UCalendar* icuCalendar = icuLib.ucalOpen(
getDesc(timeStampTz.time_zone)->getUnicodeName(), -1, NULL, UCAL_GREGORIAN, &icuErrorCode);
auto icuCalendar = getDesc(timeStampTz.time_zone)->getCalendar(icuLib, &icuErrorCode);
if (!icuCalendar)
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_open.");
@ -761,21 +764,13 @@ bool TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, bool gmt
icuLib.ucalSetMillis(icuCalendar, timeStampToIcuDate(timeStampTz.utc_timestamp), &icuErrorCode);
if (U_FAILURE(icuErrorCode))
{
icuLib.ucalClose(icuCalendar);
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_setMillis.");
}
displacement = (icuLib.ucalGet(icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) +
icuLib.ucalGet(icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE;
if (U_FAILURE(icuErrorCode))
{
icuLib.ucalClose(icuCalendar);
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_get.");
}
icuLib.ucalClose(icuCalendar);
}
catch (const Exception&)
{
@ -1044,12 +1039,11 @@ ISC_TIMESTAMP_TZ TimeZoneUtil::dateToTimeStampTz(const ISC_DATE& date, Callbacks
TimeZoneRuleIterator::TimeZoneRuleIterator(USHORT aId, const ISC_TIMESTAMP_TZ& aFrom, const ISC_TIMESTAMP_TZ& aTo)
: id(aId),
icuLib(Jrd::UnicodeUtil::getConversionICU()),
toTicks(TimeStamp::timeStampToTicks(aTo.utc_timestamp))
toTicks(TimeStamp::timeStampToTicks(aTo.utc_timestamp)),
icuCalendar(getDesc(aId)->getCalendar(icuLib))
{
UErrorCode icuErrorCode = U_ZERO_ERROR;
icuCalendar = icuLib.ucalOpen(getDesc(id)->getUnicodeName(), -1, NULL, UCAL_GREGORIAN, &icuErrorCode);
if (!icuCalendar)
status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_open.");
@ -1086,11 +1080,6 @@ TimeZoneRuleIterator::TimeZoneRuleIterator(USHORT aId, const ISC_TIMESTAMP_TZ& a
startTicks = TimeStamp::timeStampToTicks(TimeZoneUtil::icuDateToTimeStamp(icuDate));
}
TimeZoneRuleIterator::~TimeZoneRuleIterator()
{
icuLib.ucalClose(icuCalendar);
}
bool TimeZoneRuleIterator::next()
{
if (startTicks > toTicks)

View File

@ -27,6 +27,7 @@
#ifndef COMMON_TIME_ZONE_UTIL_H
#define COMMON_TIME_ZONE_UTIL_H
#include <atomic>
#include <functional>
#include "../common/classes/fb_string.h"
#include "../common/classes/timestamp.h"
@ -133,11 +134,63 @@ public:
static ISC_TIMESTAMP_TZ dateToTimeStampTz(const ISC_DATE& date, Callbacks* cb);
};
class IcuCalendarWrapper
{
public:
IcuCalendarWrapper(UCalendar* aWrapped, std::atomic<UCalendar*>* aCachePtr)
: wrapped(aWrapped),
cachePtr(aCachePtr)
{}
IcuCalendarWrapper(IcuCalendarWrapper&& o)
: wrapped(o.wrapped),
cachePtr(o.cachePtr)
{
o.wrapped = nullptr;
}
~IcuCalendarWrapper()
{
if (wrapped)
{
auto newCached = cachePtr->exchange(wrapped);
if (newCached)
{
auto& icuLib = Jrd::UnicodeUtil::getConversionICU();
icuLib.ucalClose(newCached);
}
}
}
IcuCalendarWrapper(const IcuCalendarWrapper&) = delete;
IcuCalendarWrapper& operator=(const IcuCalendarWrapper&) = delete;
public:
UCalendar* operator->()
{
return wrapped;
}
operator UCalendar*()
{
return wrapped;
}
bool operator!() const
{
return !wrapped;
}
private:
UCalendar* wrapped;
std::atomic<UCalendar*>* cachePtr;
};
class TimeZoneRuleIterator
{
public:
TimeZoneRuleIterator(USHORT aId, const ISC_TIMESTAMP_TZ& aFrom, const ISC_TIMESTAMP_TZ& aTo);
~TimeZoneRuleIterator();
public:
bool next();
@ -153,7 +206,7 @@ private:
Jrd::UnicodeUtil::ConversionICU& icuLib;
SINT64 startTicks;
SINT64 toTicks;
UCalendar* icuCalendar;
IcuCalendarWrapper icuCalendar;
UDate icuDate;
};

View File

@ -656,7 +656,9 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
desc[0] = EVL_expr(tdbb, request, arg1);
const ULONG flags = request->req_flags;
// arg1 IS NULL
const bool null1 = (request->req_flags & req_null);
request->req_flags &= ~req_null;
bool force_equal = (request->req_flags & req_same_tx_upd) != 0;
@ -721,19 +723,22 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
else
desc[1] = EVL_expr(tdbb, request, arg2);
// arg2 IS NULL
const bool null2 = (request->req_flags & req_null);
// An equivalence operator evaluates to true when both operands
// are NULL and behaves like an equality operator otherwise.
// Note that this operator never sets req_null flag
if (blrOp == blr_equiv)
{
if ((flags & req_null) && (request->req_flags & req_null))
if (null1 && null2)
{
request->req_flags &= ~req_null;
return true;
}
if ((flags & req_null) || (request->req_flags & req_null))
if (null1 || null2)
{
request->req_flags &= ~req_null;
return false;
@ -741,13 +746,15 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
}
// If either of expressions above returned NULL set req_null flag
// and return false
// and return false. The exception is BETWEEN operator that could
// return FALSE even when arg2 IS NULL, for example:
// 1 BETWEEN NULL AND 0
if (flags & req_null)
if (null1 || (null2 && (blrOp != blr_between)))
{
request->req_flags |= req_null;
if (request->req_flags & req_null)
return false;
}
force_equal |= (request->req_flags & req_same_tx_upd) != 0;
int comparison; // while the two switch() below are in sync, no need to initialize
@ -761,8 +768,19 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
case blr_lss:
case blr_leq:
case blr_neq:
case blr_between:
comparison = MOV_compare(tdbb, desc[0], desc[1]);
break;
case blr_between:
if (!null2)
{
comparison = MOV_compare(tdbb, desc[0], desc[1]);
if (comparison < 0)
return false;
}
else
comparison = -1;
break;
}
// If we are checking equality of record_version
@ -799,8 +817,22 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
case blr_between:
desc[1] = EVL_expr(tdbb, request, arg3);
if (request->req_flags & req_null)
{
if (!null2 && comparison < 0)
request->req_flags &= ~req_null;
return false;
return comparison >= 0 && MOV_compare(tdbb, desc[0], desc[1]) <= 0;
}
{
// arg1 <= arg3
const bool cmp1_3 = (MOV_compare(tdbb, desc[0], desc[1]) <= 0);
if (null2)
{
if (cmp1_3)
request->req_flags |= req_null;
return false;
}
return cmp1_3;
}
case blr_containing:
case blr_starting:

View File

@ -637,7 +637,7 @@ private:
}
}
blob->BLB_put_segment(tdbb, flow.data, dataSize);
blob->BLB_put_data(tdbb, flow.data, dataSize);
flow.move(dataSize);
}
}
@ -687,6 +687,7 @@ private:
while (remains >= m_messageSize)
{
const bool start = startRequest;
if (startRequest)
{
EXE_unwind(tdbb, req);
@ -727,7 +728,8 @@ private:
}
// map message to internal engine format
m_request->mapInOut(tdbb, false, message, m_meta, NULL, data);
// pass m_meta one time only to avoid parsing its metadata for every message
m_request->mapInOut(tdbb, false, message, start ? m_meta : nullptr, NULL, data);
data += m_messageSize;
remains -= m_messageSize;

View File

@ -8518,35 +8518,10 @@ ValueExprNode* DerivedFieldNode::dsqlFieldRemapper(FieldRemapper& visitor)
void DerivedFieldNode::setParameterName(dsql_par* parameter) const
{
const dsql_ctx* context = NULL;
const FieldNode* fieldNode = NULL;
const RecordKeyNode* dbKeyNode = NULL;
const DerivedFieldNode* drvField = nodeAs<DerivedFieldNode>(value);
while (drvField)
{
if ((fieldNode = nodeAs<FieldNode>(drvField->value)))
break;
if ((dbKeyNode = nodeAs<RecordKeyNode>(drvField->value)))
break;
drvField = nodeAs<DerivedFieldNode>(drvField->value);
}
if (fieldNode || (fieldNode = nodeAs<FieldNode>(value)))
{
parameter->par_name = fieldNode->dsqlField->fld_name.c_str();
context = fieldNode->dsqlContext;
}
else if (dbKeyNode || (dbKeyNode = nodeAs<RecordKeyNode>(value)))
dbKeyNode->setParameterName(parameter);
value->setParameterName(parameter);
parameter->par_alias = name;
setParameterInfo(parameter, context);
parameter->par_rel_alias = this->context->ctx_alias;
parameter->par_rel_alias = context->ctx_alias;
}
void DerivedFieldNode::genBlr(DsqlCompilerScratch* dsqlScratch)

View File

@ -737,39 +737,52 @@ dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat
else
{
DSC d;
d.dsc_dtype = (F.RDB$FIELD_TYPE != blr_blob) ?
gds_cvt_blr_dtype[F.RDB$FIELD_TYPE] : dtype_blob;
// dimitr: adjust the UDF arguments for CSTRING
if (d.dsc_dtype == dtype_cstring) {
d.dsc_dtype = dtype_text;
}
d.dsc_scale = F.RDB$FIELD_SCALE;
if (!F.RDB$FIELD_SUB_TYPE.NULL) {
d.dsc_sub_type = F.RDB$FIELD_SUB_TYPE;
}
else {
if (X.RDB$MECHANISM == FUN_scalar_array)
{
d.dsc_dtype = dtype_array;
d.dsc_scale = 0;
d.dsc_sub_type = 0;
}
d.dsc_length = F.RDB$FIELD_LENGTH;
if (d.dsc_dtype == dtype_varying) {
d.dsc_length += sizeof(USHORT);
}
d.dsc_address = NULL;
if (!F.RDB$CHARACTER_SET_ID.NULL)
{
if (d.dsc_dtype != dtype_blob) {
d.dsc_ttype() = F.RDB$CHARACTER_SET_ID;
}
else {
d.dsc_scale = F.RDB$CHARACTER_SET_ID;
}
}
if (X.RDB$MECHANISM != FUN_value && X.RDB$MECHANISM != FUN_reference)
{
d.dsc_length = sizeof(ISC_QUAD);
d.dsc_flags = DSC_nullable;
}
else
{
d.dsc_dtype = (F.RDB$FIELD_TYPE != blr_blob) ?
gds_cvt_blr_dtype[F.RDB$FIELD_TYPE] : dtype_blob;
// dimitr: adjust the UDF arguments for CSTRING
if (d.dsc_dtype == dtype_cstring) {
d.dsc_dtype = dtype_text;
}
d.dsc_scale = F.RDB$FIELD_SCALE;
if (!F.RDB$FIELD_SUB_TYPE.NULL) {
d.dsc_sub_type = F.RDB$FIELD_SUB_TYPE;
}
else {
d.dsc_sub_type = 0;
}
d.dsc_length = F.RDB$FIELD_LENGTH;
if (d.dsc_dtype == dtype_varying) {
d.dsc_length += sizeof(USHORT);
}
if (!F.RDB$CHARACTER_SET_ID.NULL)
{
if (d.dsc_dtype != dtype_blob) {
d.dsc_ttype() = F.RDB$CHARACTER_SET_ID;
}
else {
d.dsc_scale = F.RDB$CHARACTER_SET_ID;
}
}
if (X.RDB$MECHANISM != FUN_value && X.RDB$MECHANISM != FUN_reference)
{
d.dsc_flags = DSC_nullable;
}
}
d.dsc_address = NULL;
if (!X.RDB$DEFAULT_VALUE.NULL ||
(fb_utils::implicit_domain(F.RDB$FIELD_NAME) && !F.RDB$DEFAULT_VALUE.NULL))
@ -810,39 +823,52 @@ dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat
else
{
DSC d;
d.dsc_dtype = (X.RDB$FIELD_TYPE != blr_blob) ?
gds_cvt_blr_dtype[X.RDB$FIELD_TYPE] : dtype_blob;
// dimitr: adjust the UDF arguments for CSTRING
if (d.dsc_dtype == dtype_cstring) {
d.dsc_dtype = dtype_text;
}
d.dsc_scale = X.RDB$FIELD_SCALE;
if (!X.RDB$FIELD_SUB_TYPE.NULL) {
d.dsc_sub_type = X.RDB$FIELD_SUB_TYPE;
}
else {
if (X.RDB$MECHANISM == FUN_scalar_array)
{
d.dsc_dtype = dtype_array;
d.dsc_scale = 0;
d.dsc_sub_type = 0;
}
d.dsc_length = X.RDB$FIELD_LENGTH;
if (d.dsc_dtype == dtype_varying) {
d.dsc_length += sizeof(USHORT);
}
d.dsc_address = NULL;
if (!X.RDB$CHARACTER_SET_ID.NULL)
{
if (d.dsc_dtype != dtype_blob) {
d.dsc_ttype() = X.RDB$CHARACTER_SET_ID;
}
else {
d.dsc_scale = X.RDB$CHARACTER_SET_ID;
}
}
if (X.RDB$MECHANISM != FUN_value && X.RDB$MECHANISM != FUN_reference)
{
d.dsc_length = sizeof(ISC_QUAD);
d.dsc_flags = DSC_nullable;
}
else
{
d.dsc_dtype = (X.RDB$FIELD_TYPE != blr_blob) ?
gds_cvt_blr_dtype[X.RDB$FIELD_TYPE] : dtype_blob;
// dimitr: adjust the UDF arguments for CSTRING
if (d.dsc_dtype == dtype_cstring) {
d.dsc_dtype = dtype_text;
}
d.dsc_scale = X.RDB$FIELD_SCALE;
if (!X.RDB$FIELD_SUB_TYPE.NULL) {
d.dsc_sub_type = X.RDB$FIELD_SUB_TYPE;
}
else {
d.dsc_sub_type = 0;
}
d.dsc_length = X.RDB$FIELD_LENGTH;
if (d.dsc_dtype == dtype_varying) {
d.dsc_length += sizeof(USHORT);
}
if (!X.RDB$CHARACTER_SET_ID.NULL)
{
if (d.dsc_dtype != dtype_blob) {
d.dsc_ttype() = X.RDB$CHARACTER_SET_ID;
}
else {
d.dsc_scale = X.RDB$CHARACTER_SET_ID;
}
}
if (X.RDB$MECHANISM != FUN_value && X.RDB$MECHANISM != FUN_reference)
{
d.dsc_flags = DSC_nullable;
}
}
d.dsc_address = NULL;
if (!X.RDB$DEFAULT_VALUE.NULL)
{

View File

@ -95,7 +95,7 @@ bool ColList::remove(const char* name)
if (pold)
pold->next = p->next;
else
m_head = NULL;
m_head = p->next;
delete p;
--m_count;

View File

@ -379,8 +379,10 @@ const char
WIRE_CRYPT_PLUGIN_NAME[] = "WIRE_CRYPT_PLUGIN",
CLIENT_ADDRESS_NAME[] = "CLIENT_ADDRESS",
CLIENT_HOST_NAME[] = "CLIENT_HOST",
CLIENT_OS_USER_NAME[] = "CLIENT_OS_USER",
CLIENT_PID_NAME[] = "CLIENT_PID",
CLIENT_PROCESS_NAME[] = "CLIENT_PROCESS",
CLIENT_VERSION_NAME[] = "CLIENT_VERSION",
CURRENT_USER_NAME[] = "CURRENT_USER",
CURRENT_ROLE_NAME[] = "CURRENT_ROLE",
SESSION_IDLE_TIMEOUT[] = "SESSION_IDLE_TIMEOUT",
@ -4564,6 +4566,13 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar
resultStr = attachment->att_remote_host;
}
else if (nameStr == CLIENT_OS_USER_NAME)
{
if (attachment->att_remote_os_user.isEmpty())
return NULL;
resultStr = attachment->att_remote_os_user;
}
else if (nameStr == CLIENT_PID_NAME)
{
if (!attachment->att_remote_pid)
@ -4578,6 +4587,13 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar
resultStr = attachment->att_remote_process.ToString();
}
else if (nameStr == CLIENT_VERSION_NAME)
{
if (attachment->att_client_version.isEmpty())
return NULL;
resultStr = attachment->att_client_version;
}
else if (nameStr == CURRENT_USER_NAME)
{
const MetaString& user = attachment->getUserName();

View File

@ -3,16 +3,16 @@
*** DO NOT EDIT ***
TO CHANGE ANY INFORMATION IN HERE PLEASE
EDIT src/misc/writeBuildNum.sh
FORMAL BUILD NUMBER:2998
FORMAL BUILD NUMBER:3025
*/
#define PRODUCT_VER_STRING "4.0.4.2998-Fix7809"
#define FILE_VER_STRING "WI-V4.0.4.2998"
#define LICENSE_VER_STRING "WI-V4.0.4.2998"
#define FILE_VER_NUMBER 4, 0, 4, 2998
#define PRODUCT_VER_STRING "4.0.5.3025"
#define FILE_VER_STRING "WI-V4.0.5.3025"
#define LICENSE_VER_STRING "WI-V4.0.5.3025"
#define FILE_VER_NUMBER 4, 0, 5, 3025
#define FB_MAJOR_VER "4"
#define FB_MINOR_VER "0"
#define FB_REV_NO "4"
#define FB_BUILD_NO "2998"
#define FB_REV_NO "5"
#define FB_BUILD_NO "3025"
#define FB_BUILD_TYPE "V"
#define FB_BUILD_SUFFIX "Firebird 4.0 Fix7809"
#define FB_BUILD_SUFFIX "Firebird 4.0"

View File

@ -113,6 +113,12 @@ void IscConnection::attach(thread_db* tdbb)
validatePassword(tdbb, m_dbName, newDpb);
newDpb.insertInt(isc_dpb_ext_call_depth, attachment->att_ext_call_depth + 1);
if (newDpb.getBufferLength() > MAX_USHORT)
{
ERR_post(Arg::Gds(isc_imp_exc) <<
Arg::Gds(isc_random) << Arg::Str("DPB size greater than 64KB"));
}
FbLocalStatus status;
{
EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);

View File

@ -292,7 +292,8 @@ enum UdfError
static SSHORT blob_get_segment(blb*, UCHAR*, USHORT, USHORT*);
static void blob_put_segment(blb*, const UCHAR*, USHORT);
static SLONG blob_lseek(blb*, USHORT, SLONG);
static SLONG get_scalar_array(const Parameter*, DSC*, scalar_array_desc*, UCharStack&);
static ULONG get_scalar_array(thread_db* tdbb, const Parameter*, DSC*,
scalar_array_desc*, UCharStack&);
static void invoke(thread_db* tdbb,
const Function* function,
const Parameter* return_ptr,
@ -436,8 +437,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra
temp_desc = parameter->prm_desc;
temp_desc.dsc_address = temp_ptr;
// CVC: There's a theoretical possibility of overflowing "length" here.
USHORT length = FB_ALIGN(temp_desc.dsc_length, FB_DOUBLE_ALIGN);
ULONG length = FB_ALIGN(temp_desc.dsc_length, FB_DOUBLE_ALIGN);
// If we've got a null argument, just pass zeros (got any better ideas?)
@ -446,7 +446,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra
if (parameter->prm_fun_mechanism == FUN_value)
{
UCHAR* p = (UCHAR *) arg_ptr;
MOVE_CLEAR(p, (SLONG) length);
MOVE_CLEAR(p, length);
p += length;
arg_ptr = reinterpret_cast<UDF_ARG*>(p);
continue;
@ -458,7 +458,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra
}
if (parameter->prm_fun_mechanism != FUN_ref_with_null)
MOVE_CLEAR(temp_ptr, (SLONG) length);
MOVE_CLEAR(temp_ptr, length);
else
{
// Probably for arrays and blobs it's better to preserve the
@ -468,7 +468,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra
case dtype_quad:
case dtype_array:
case dtype_blob:
MOVE_CLEAR(temp_ptr, (SLONG) length);
MOVE_CLEAR(temp_ptr, length);
break;
default: // FUN_ref_with_null, non-blob, non-array: we send null pointer.
*arg_ptr++ = 0;
@ -478,7 +478,8 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra
}
else if (parameter->prm_fun_mechanism == FUN_scalar_array)
{
length = get_scalar_array(parameter, input, (scalar_array_desc*)temp_ptr, array_stack);
length = get_scalar_array(tdbb, parameter, input, (scalar_array_desc*) temp_ptr,
array_stack);
}
else
{
@ -975,10 +976,11 @@ static SSHORT blob_get_segment(blb* blob, UCHAR* buffer, USHORT length, USHORT*
}
static SLONG get_scalar_array(const Parameter* arg,
DSC* value,
scalar_array_desc* scalar_desc,
UCharStack& stack)
static ULONG get_scalar_array(thread_db* tdbb,
const Parameter* arg,
DSC* value,
scalar_array_desc* scalar_desc,
UCharStack& stack)
{
/**************************************
*
@ -992,17 +994,16 @@ static SLONG get_scalar_array(const Parameter* arg,
* Return length of array desc.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
MemoryPool& pool = *tdbb->getDefaultPool();
// Get first the array descriptor, then the array
SLONG stuff[IAD_LEN(16) / 4];
Ods::InternalArrayDesc* array_desc = (Ods::InternalArrayDesc*) stuff;
blb* blob = blb::get_array(tdbb, tdbb->getRequest()->req_transaction, (bid*)value->dsc_address,
array_desc);
blb* blob = blb::get_array(tdbb, tdbb->getRequest()->req_transaction,
(bid*) value->dsc_address, array_desc);
fb_assert(array_desc->iad_total_length >= 0); // check before upcasting to size_t
UCHAR* data = FB_NEW_POOL(*getDefaultMemoryPool()) UCHAR[static_cast<size_t>(array_desc->iad_total_length)];
AutoPtr<UCHAR, ArrayDelete> data(FB_NEW_POOL(pool) UCHAR[array_desc->iad_total_length]);
blob->BLB_get_data(tdbb, data, array_desc->iad_total_length);
const USHORT dimensions = array_desc->iad_dimensions;
@ -1012,39 +1013,29 @@ static SLONG get_scalar_array(const Parameter* arg,
dsc from = array_desc->iad_rpt[0].iad_desc;
if (to.dsc_dtype != from.dsc_dtype ||
to.dsc_scale != from.dsc_scale || to.dsc_length != from.dsc_length)
to.dsc_scale != from.dsc_scale ||
to.dsc_length != from.dsc_length)
{
SLONG n = array_desc->iad_count;
UCHAR* const temp = FB_NEW_POOL(*getDefaultMemoryPool()) UCHAR[static_cast<size_t>(to.dsc_length * n)];
ULONG n = array_desc->iad_count;
AutoPtr<UCHAR, ArrayDelete> temp(FB_NEW_POOL(pool) UCHAR[to.dsc_length * n]);
to.dsc_address = temp;
from.dsc_address = data;
// This loop may call ERR_post indirectly.
try
for (; n; --n, to.dsc_address += to.dsc_length,
from.dsc_address += array_desc->iad_element_length)
{
for (; n; --n, to.dsc_address += to.dsc_length,
from.dsc_address += array_desc->iad_element_length)
{
MOV_move(tdbb, &from, &to);
}
}
catch (const Exception&)
{
delete[] data;
delete[] temp;
throw;
MOV_move(tdbb, &from, &to);
}
delete[] data;
data = temp;
data = temp.release();
}
// Fill out the scalar array descriptor
stack.push(data);
scalar_desc->sad_desc = arg->prm_desc;
scalar_desc->sad_desc.dsc_address = data;
scalar_desc->sad_dimensions = dimensions;
stack.push(data.release());
const Ods::InternalArrayDesc::iad_repeat* tail1 = array_desc->iad_rpt;
scalar_array_desc::sad_repeat* tail2 = scalar_desc->sad_rpt;
@ -1055,7 +1046,8 @@ static SLONG get_scalar_array(const Parameter* arg,
tail2->sad_lower = tail1->iad_lower;
}
return static_cast<SLONG>(sizeof(scalar_array_desc) + (dimensions - 1u) * sizeof(scalar_array_desc::sad_repeat));
return static_cast<ULONG>(sizeof(scalar_array_desc) +
(dimensions - 1u) * sizeof(scalar_array_desc::sad_repeat));
}

View File

@ -2054,6 +2054,13 @@ static void delete_version_chain(thread_db* tdbb, record_param* rpb, bool delete
rpb->rpb_f_page, rpb->rpb_f_line);
#endif
// It's possible to get rpb_page == 0 from VIO_intermediate_gc via
// staying_chain_rpb. This case happens there when the staying record
// stack has 1 item at the moment this rpb is created. So return to
// avoid an error on DPM_fetch below.
if (!rpb->rpb_page)
return;
ULONG prior_page = 0;
// Note that the page number of the oldest version in the chain should

View File

@ -8,9 +8,8 @@ BuildVersion="$Id: writeBuildNum.sh,v 1.28732 2010/05/29 13:12:08 fsg Exp $"
BuildType=V
MajorVer=4
MinorVer=0
RevNo=4
BuildNum=2998
SPECIAL_BUILD_SUFFIX=Fix7809
RevNo=5
BuildNum=3025
NowAt=`pwd`
cd `dirname $0`

View File

@ -7152,6 +7152,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
int inet_af = AF_UNSPEC;
cBlock.loadClnt(pb, &parSet);
pb.deleteWithTag(parSet.auth_block);
authenticateStep0(cBlock);
bool needFile = !(flags & ANALYZE_EMP_NAME);

View File

@ -1593,7 +1593,7 @@ ISC_STATUS API_ROUTINE isc_attach_database(ISC_STATUS* userStatus, SSHORT fileLe
return status[1];
YAttachment* attachment = dispatcher->attachDatabase(&statusWrapper, pathName.c_str(),
dpbLength, reinterpret_cast<const UCHAR*>(dpb));
static_cast<USHORT>(dpbLength), reinterpret_cast<const UCHAR*>(dpb));
if (status.getState() & IStatus::STATE_ERRORS)
return status[1];