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

Merge branch 'master' into ods14-header-page

This commit is contained in:
Dmitry Yemanov 2025-01-19 17:58:58 +03:00
commit 52e7efa305
94 changed files with 3767 additions and 3547 deletions

View File

@ -43,7 +43,7 @@ $ANDROID_HOME/platform-tools/adb -s $AndroidDeviceName shell "rm -rf $AndroidDir
$ANDROID_HOME/platform-tools/adb -s $AndroidDeviceName shell "mkdir $AndroidDir"
$ANDROID_HOME/platform-tools/adb -s $AndroidDeviceName push gen/$InitialDebugTar $AndroidDir/
$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=all && ./libEngine14_test --log_level=all)"
$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)"
$ANDROID_HOME/platform-tools/adb -s $AndroidDeviceName pull $AndroidDir/firebird/firebird.msg gen/Release/firebird/
$ANDROID_HOME/platform-tools/adb -s $AndroidDeviceName pull $AndroidDir/firebird/security6.fdb gen/Release/firebird/

View File

@ -1,6 +1,6 @@
#########################################
#
# Firebird version 5.0 configuration file
# Firebird version 6.0 configuration file
#
#########################################

View File

@ -799,7 +799,7 @@ install install-embedded silent_install package packages dist:
.PHONY: tests tests_process run_tests run_tests_process
log_level ?= all
log_level ?= error
tests:
$(MAKE) TARGET?=$(DefaultTarget) tests_process

View File

@ -111,7 +111,7 @@ GLOB_OPTIONS:=
#____________________________________________________________________________
# Global c++ flags: firebird needs no RTTI, choose build standard and c++ specific warnings level
PLUSPLUS_FLAGS:= -fno-rtti -std=c++17 -Werror=delete-incomplete
PLUSPLUS_FLAGS:= -fno-rtti -std=c++17 -Werror=delete-incomplete -Werror=return-type
# If this is defined then we use special rules useful for developers only
IsDeveloper = @DEVEL_FLG@

View File

@ -28,6 +28,7 @@
<UseFullPaths>false</UseFullPaths>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<TreatSpecificWarningsAsErrors>4715</TreatSpecificWarningsAsErrors>
</ClCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>

View File

@ -24,6 +24,7 @@
<ClCompile Include="..\..\..\gen\isql\extract.cpp" />
<ClCompile Include="..\..\..\src\common\fb_exception.cpp" />
<ClCompile Include="..\..\..\src\isql\FrontendLexer.cpp" />
<ClCompile Include="..\..\..\src\isql\FrontendParser.cpp" />
<ClCompile Include="..\..\..\src\isql\InputDevices.cpp" />
<ClCompile Include="..\..\..\gen\isql\isql.cpp" />
<ClCompile Include="..\..\..\src\isql\iutils.cpp" />
@ -40,6 +41,7 @@
<ClInclude Include="..\..\..\src\isql\Extender.h" />
<ClInclude Include="..\..\..\src\isql\extra_proto.h" />
<ClInclude Include="..\..\..\src\isql\FrontendLexer.h" />
<ClInclude Include="..\..\..\src\isql\FrontendParser.h" />
<ClInclude Include="..\..\..\src\isql\InputDevices.h" />
<ClInclude Include="..\..\..\src\isql\isql.h" />
<ClInclude Include="..\..\..\src\isql\isql_proto.h" />

View File

@ -30,6 +30,9 @@
<ClCompile Include="..\..\..\src\isql\FrontendLexer.cpp">
<Filter>ISQL files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\isql\FrontendParser.cpp">
<Filter>ISQL files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\isql\InputDevices.cpp">
<Filter>ISQL files</Filter>
</ClCompile>
@ -73,6 +76,9 @@
<ClInclude Include="..\..\..\src\isql\FrontendLexer.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\isql\FrontendParser.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\isql\InputDevices.h">
<Filter>Header files</Filter>
</ClInclude>

View File

@ -177,6 +177,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\src\isql\tests\FrontendLexerTest.cpp" />
<ClCompile Include="..\..\..\src\isql\tests\FrontendParserTest.cpp" />
<ClCompile Include="..\..\..\src\isql\tests\ISqlTest.cpp" />
</ItemGroup>
<ItemGroup>

View File

@ -10,6 +10,9 @@
<ClCompile Include="..\..\..\src\isql\tests\FrontendLexerTest.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\isql\tests\FrontendParserTest.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\isql\tests\ISqlTest.cpp">
<Filter>source</Filter>
</ClCompile>

View File

@ -5,8 +5,8 @@
@call setenvvar.bat %*
@if errorlevel 1 (goto :END)
@%FB_BIN_DIR%\common_test --log_level=all || exit /b
@%FB_BIN_DIR%\engine_test --log_level=all || exit /b
@%FB_BIN_DIR%\isql_test --log_level=all || exit /b
@%FB_BIN_DIR%\common_test --log_level=error || exit /b
@%FB_BIN_DIR%\engine_test --log_level=error || exit /b
@%FB_BIN_DIR%\isql_test --log_level=error || exit /b
:END

View File

@ -132,6 +132,11 @@
# define CDS_PROCESSOR__NAME "LOONGARCH"
# define CDS_PROCESSOR__NICK "loongarch"
# define CDS_BUILD_BITS 64
#elif defined(__riscv) && __riscv_xlen == 64
# define CDS_PROCESSOR_ARCH CDS_PROCESSOR_RISCV64
# define CDS_PROCESSOR__NAME "RISC-V64"
# define CDS_PROCESSOR__NICK "riscv64"
# define CDS_BUILD_BITS 64
#else
# if defined(CDS_USE_LIBCDS_ATOMIC)
# error "Libcds does not support atomic implementation for the processor architecture. Try to use C++11-compatible compiler and remove CDS_USE_LIBCDS_ATOMIC flag from compiler command line"

View File

@ -4204,53 +4204,85 @@ bool get_files(BurpGlobals* tdgbl)
att_type attribute;
scan_attr_t scan_next_attr;
STORE (REQUEST_HANDLE tdgbl->handles_get_files_req_handle1)
X IN RDB$FILES
X.RDB$FILE_FLAGS = 0;
BASED_ON RDB$FILES.RDB$FILE_NAME filename = "";
SSHORT flags = 0, sequence = 0, number = 0;
SLONG start = 0, length = 0;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
{
switch (attribute)
{
switch (attribute)
{
case att_file_filename:
GET_TEXT(X.RDB$FILE_NAME);
BURP_verbose (116, X.RDB$FILE_NAME);
// msg 116 restoring file %s
break;
case att_file_filename:
GET_TEXT(filename);
break;
case att_file_sequence:
X.RDB$FILE_SEQUENCE = (USHORT) get_int32(tdgbl);
break;
case att_file_sequence:
sequence = (SSHORT) get_int32(tdgbl);
break;
case att_file_start:
X.RDB$FILE_START = get_int32(tdgbl);
break;
case att_file_start:
start = get_int32(tdgbl);
break;
case att_file_length:
X.RDB$FILE_LENGTH = get_int32(tdgbl);
break;
case att_file_length:
length = get_int32(tdgbl);
break;
case att_file_flags:
X.RDB$FILE_FLAGS |= get_int32(tdgbl);
break;
case att_file_flags:
flags |= (SSHORT) get_int32(tdgbl);
break;
case att_shadow_number:
X.RDB$SHADOW_NUMBER = (USHORT) get_int32(tdgbl);
if (tdgbl->gbl_sw_kill && X.RDB$SHADOW_NUMBER)
X.RDB$FILE_FLAGS |= FILE_inactive;
break;
case att_shadow_number:
number = (SSHORT) get_int32(tdgbl);
if (tdgbl->gbl_sw_kill && number)
flags |= FILE_inactive;
break;
default:
bad_attribute(scan_next_attr, attribute, 85);
// msg 85 file
break;
}
default:
bad_attribute(scan_next_attr, attribute, 85);
// msg 85 file
break;
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
}
const bool multiFileSupport = (tdgbl->runtimeODS <= DB_VERSION_DDL13_1);
if ((multiFileSupport || !sequence) && filename[0])
{
BURP_verbose (116, filename);
// msg 116 restoring file %s
STORE (REQUEST_HANDLE tdgbl->handles_get_files_req_handle1)
X IN RDB$FILES
strncpy(X.RDB$FILE_NAME, filename, sizeof(X.RDB$FILE_NAME));
X.RDB$FILE_FLAGS = flags;
X.RDB$SHADOW_NUMBER = number;
if (multiFileSupport)
{
X.RDB$FILE_SEQUENCE.NULL = FALSE;
X.RDB$FILE_SEQUENCE = sequence;
X.RDB$FILE_START.NULL = FALSE;
X.RDB$FILE_START = start;
X.RDB$FILE_LENGTH.NULL = FALSE;
X.RDB$FILE_LENGTH = length;
}
else
{
X.RDB$FILE_SEQUENCE.NULL = TRUE;
X.RDB$FILE_START.NULL = TRUE;
X.RDB$FILE_LENGTH.NULL = TRUE;
}
END_STORE;
ON_ERROR
general_on_error ();
END_ERROR;
}
return true;
}

View File

@ -70,7 +70,7 @@ namespace
}
}
bool contains(const char* value, USHORT& outTimezoneId, int& outParsedTimezoneLength)
bool contains(const char* value, USHORT& outTimezoneId, unsigned int& outParsedTimezoneLength)
{
const TrieNode* currentNode = m_root;
FB_SIZE_T valueLength = fb_strlen(value);
@ -97,7 +97,7 @@ namespace
TrieNode* currentNode = m_root;
FB_SIZE_T valueLength = fb_strlen(value);
for (int i = 0; i < valueLength; i++)
for (unsigned int i = 0; i < valueLength; i++)
{
int index = calculateIndex(value[i]);
@ -460,7 +460,7 @@ namespace
patternStr = std::string_view(format + formatStart, offset - formatStart + 1);
bool isFound = false;
for (int j = 0; j < PatternsSize; j++)
for (unsigned int j = 0; j < PatternsSize; j++)
{
if (!strncmp(patterns[j], patternStr.data(), patternStr.length()))
{
@ -1124,6 +1124,7 @@ namespace
return twelveHours == 12 ? twelveHours : 12 + twelveHours;
cb->err(Arg::Gds(isc_incorrect_hours_period) << string(period.data(), period.length()));
return 0; // suppress compiler warning/error
}
constexpr int roundYearPatternImplementation(int parsedRRValue, int currentYear)
@ -1331,7 +1332,7 @@ namespace
bool isFound = false;
std::string_view monthShortName = getSubstringFromString(str, strLength, strOffset, 3);
for (int i = 0; i < FB_NELEM(FB_SHORT_MONTHS) - 1; i++)
for (FB_SIZE_T i = 0; i < FB_NELEM(FB_SHORT_MONTHS) - 1; i++)
{
if (std::equal(monthShortName.begin(), monthShortName.end(),
FB_SHORT_MONTHS[i], FB_SHORT_MONTHS[i] + strlen(FB_SHORT_MONTHS[i]),
@ -1352,7 +1353,7 @@ namespace
bool isFound = false;
std::string_view monthFullName = getSubstringFromString(str, strLength, strOffset);
for (int i = 0; i < FB_NELEM(FB_LONG_MONTHS_UPPER) - 1; i++)
for (FB_SIZE_T i = 0; i < FB_NELEM(FB_LONG_MONTHS_UPPER) - 1; i++)
{
if (std::equal(monthFullName.begin(), monthFullName.end(),
FB_LONG_MONTHS_UPPER[i], FB_LONG_MONTHS_UPPER[i] + strlen(FB_LONG_MONTHS_UPPER[i]),
@ -1541,7 +1542,7 @@ namespace
}
case Format::TZR:
{
int parsedTimezoneNameLength = 0;
unsigned int parsedTimezoneNameLength = 0;
const bool timezoneNameIsCorrect = timeZoneTrie().contains(str + strOffset, outTimezoneId, parsedTimezoneNameLength);
if (!timezoneNameIsCorrect)
status_exception::raise(Arg::Gds(isc_invalid_timezone_region) << string(str + strOffset, parsedTimezoneNameLength));
@ -1668,7 +1669,7 @@ ISC_TIMESTAMP_TZ CVT_format_string_to_datetime(const dsc* desc, const Firebird::
stringUpper[i] = toupper(sourceString[i]);
string formatUpper(format.length(), '\0');
for (int i = 0; i < format.length(); i++)
for (unsigned int i = 0; i < format.length(); i++)
formatUpper[i] = toupper(format[i]);
StringToDateTimeData cvtData;

View File

@ -410,7 +410,7 @@ namespace
if (!hasPatternChar() || getPatternChar() != ']')
status_exception::raise(Arg::Gds(isc_invalid_similar_pattern));
for (item.clazz = 0; item.clazz < FB_NELEM(classes); ++item.clazz)
for (item.clazz = 0; static_cast<FB_SIZE_T>(item.clazz) < FB_NELEM(classes); ++item.clazz)
{
if (fb_utils::strnicmp(patternStr + charSavePos,
classes[item.clazz].similarClass, len) == 0)
@ -419,7 +419,7 @@ namespace
}
}
if (item.clazz >= FB_NELEM(classes))
if (static_cast<FB_SIZE_T>(item.clazz) >= FB_NELEM(classes))
status_exception::raise(Arg::Gds(isc_invalid_similar_pattern));
}
else

42
src/common/StdHelper.h Normal file
View File

@ -0,0 +1,42 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2024 Adriano dos Santos Fernandes <adrianosf at gmail.com>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#ifndef FB_COMMON_STD_HELPER_H
#define FB_COMMON_STD_HELPER_H
namespace Firebird {
// To be used with std::visit
template <typename... Ts>
struct StdVisitOverloads : Ts...
{
using Ts::operator()...;
};
template <typename... Ts>
StdVisitOverloads(Ts...) -> StdVisitOverloads<Ts...>;
} // namespace Firebird
#endif // FB_COMMON_STD_HELPER_H

View File

@ -153,7 +153,7 @@ TextType::TextType(TTYPE_ID _type, texttype *_tt, USHORT _attributes, CharSet* _
{'S', CHAR_UPPER_S}
};
for (int i = 0; i < FB_NELEM(conversions); i++)
for (FB_SIZE_T i = 0; i < FB_NELEM(conversions); i++)
{
try
{

View File

@ -465,7 +465,7 @@ void callRemoteServiceManager(ISC_STATUS* status,
{
const char request[] = {isc_info_svc_get_users};
int startQuery = 0;
Auth::StackUserData uData;
Auth::UserData uData;
for (;;)
{

View File

@ -93,6 +93,30 @@ public:
int compare(const AbstractString& s) const { return compare(s.c_str(), s.length()); }
int compare(const MetaString& m) const { return memcmp(data, m.data, MAX_SQL_IDENTIFIER_SIZE); }
string toQuotedString() const
{
string s;
if (hasData())
{
s.reserve(count + 2);
s.append("\"");
for (const auto c : *this)
{
if (c == '"')
s.append("\"");
s.append(&c, 1);
}
s.append("\"");
}
return s;
}
bool operator==(const char* s) const { return compare(s) == 0; }
bool operator!=(const char* s) const { return compare(s) != 0; }
bool operator==(const AbstractString& s) const { return compare(s) == 0; }

View File

@ -330,7 +330,7 @@ void NoThrowTimeStamp::round_time(ISC_TIME &ntime, const int precision)
if (scale <= 0)
return;
fb_assert(scale < FB_NELEM(POW_10_TABLE));
fb_assert(static_cast<FB_SIZE_T>(scale) < FB_NELEM(POW_10_TABLE));
const ISC_TIME period = POW_10_TABLE[scale];

View File

@ -14,7 +14,7 @@ BOOST_AUTO_TEST_CASE(ConstructionWithStdInitializerTest)
{
Array<int> array(*getDefaultMemoryPool(), {1, 2, 3, 4});
BOOST_TEST(array.getCount() == 4);
BOOST_TEST(array.getCount() == 4u);
BOOST_TEST(array[0] == 1);
BOOST_TEST(array[3] == 4);
}
@ -23,22 +23,22 @@ BOOST_AUTO_TEST_CASE(ClearTest)
{
Array<int> array(*getDefaultMemoryPool(), {1, 2, 3, 4});
BOOST_TEST(array.getCount() == 4);
BOOST_TEST(array.getCount() == 4u);
array.clear();
BOOST_TEST(array.getCount() == 0);
BOOST_TEST(array.getCount() == 0u);
}
BOOST_AUTO_TEST_CASE(IsEmptyAndHasDataTest)
{
Array<int> array(*getDefaultMemoryPool(), {1, 2, 3, 4});
BOOST_TEST(array.getCount() > 0);
BOOST_TEST(array.getCount() > 0u);
BOOST_TEST(!array.isEmpty());
BOOST_TEST(array.hasData());
array.clear();
BOOST_TEST(array.getCount() == 0);
BOOST_TEST(array.getCount() == 0u);
BOOST_TEST(array.isEmpty());
BOOST_TEST(!array.hasData());
}
@ -46,12 +46,12 @@ BOOST_AUTO_TEST_CASE(IsEmptyAndHasDataTest)
BOOST_AUTO_TEST_CASE(CapacityAndCountTest)
{
Array<int> array1(10);
BOOST_TEST(array1.getCapacity() == 10);
BOOST_TEST(array1.getCount() == 0);
BOOST_TEST(array1.getCapacity() == 10u);
BOOST_TEST(array1.getCount() == 0u);
Array<int> array2(*getDefaultMemoryPool(), 11);
BOOST_TEST(array2.getCapacity() == 11);
BOOST_TEST(array2.getCount() == 0);
BOOST_TEST(array2.getCapacity() == 11u);
BOOST_TEST(array2.getCount() == 0u);
}
BOOST_AUTO_TEST_SUITE_END() // ArrayTests

View File

@ -17,7 +17,7 @@ BOOST_AUTO_TEST_CASE(ConstructionWithStdInitializerTest)
{
DoublyLinkedList<int> list(*getDefaultMemoryPool(), {1, 2, 3, 4});
BOOST_TEST(list.getCount() == 4);
BOOST_TEST(list.getCount() == 4u);
BOOST_TEST(list.front() == 1);
BOOST_TEST(list.back() == 4);
}
@ -26,10 +26,10 @@ BOOST_AUTO_TEST_CASE(ClearTest)
{
DoublyLinkedList<int> list(*getDefaultMemoryPool(), {1, 2, 3, 4});
BOOST_TEST(list.getCount() == 4);
BOOST_TEST(list.getCount() == 4u);
list.clear();
BOOST_TEST(list.getCount() == 0);
BOOST_TEST(list.getCount() == 0u);
}
BOOST_AUTO_TEST_CASE(SpliceTest)

View File

@ -1356,7 +1356,7 @@ static bool validate_dsc_tables();
int dsc::getStringLength() const
USHORT dsc::getStringLength() const
{
return DSC_string_length(this);
}
@ -1533,7 +1533,7 @@ bool DSC_make_descriptor(DSC* desc,
}
int DSC_string_length(const dsc* desc)
USHORT DSC_string_length(const dsc* desc)
{
/**************************************
*
@ -1561,10 +1561,10 @@ int DSC_string_length(const dsc* desc)
return desc->dsc_length - sizeof(USHORT);
default:
if (!DTYPE_IS_EXACT(desc->dsc_dtype) || desc->dsc_scale == 0)
return (int) _DSC_convert_to_text_length[desc->dsc_dtype];
return _DSC_convert_to_text_length[desc->dsc_dtype];
if (desc->dsc_scale < 0)
return (int) _DSC_convert_to_text_length[desc->dsc_dtype] + 1;
return (int) _DSC_convert_to_text_length[desc->dsc_dtype] + desc->dsc_scale;
return _DSC_convert_to_text_length[desc->dsc_dtype] + 1;
return _DSC_convert_to_text_length[desc->dsc_dtype] + desc->dsc_scale;
}
}

View File

@ -499,7 +499,7 @@ typedef struct dsc
dsc_address = address;
}
int getStringLength() const;
USHORT getStringLength() const;
operator Ods::Descriptor() const
{

View File

@ -26,7 +26,7 @@
#include "../common/dsc.h"
int DSC_string_length(const struct dsc*);
USHORT DSC_string_length(const struct dsc*);
const TEXT* DSC_dtype_tostring(UCHAR);
void DSC_get_dtype_name(const dsc*, TEXT*, USHORT);
bool DSC_make_descriptor(dsc*, USHORT, SSHORT,

View File

@ -159,7 +159,7 @@ int PRETTY_print_cdb(const UCHAR* blr, FPTR_PRINT_CALLBACK routine, void* user_a
while (parameter = BLR_BYTE)
{
const char* p;
if (parameter > FB_NELEM(cdb_table) || !(p = cdb_table[parameter]))
if (parameter > static_cast<FB_SSIZE_T>(FB_NELEM(cdb_table)) || !(p = cdb_table[parameter]))
{
return error(control, 0, "*** cdb parameter %d is undefined ***\n", parameter);
}

View File

@ -155,7 +155,7 @@ private:
typedef Firebird::Array<UCHAR> AuthenticationBlock;
class UserData :
class UserData final :
public Firebird::VersionedIface<Firebird::IUserImpl<UserData, Firebird::CheckStatusWrapper> >
{
public:
@ -233,31 +233,6 @@ public:
IntField u, g;
};
class StackUserData final : public UserData
{
public:
void* operator new(size_t, void* memory) noexcept
{
return memory;
}
};
class DynamicUserData final : public UserData
{
public:
#ifdef DEBUG_GDS_ALLOC
void* operator new(size_t size, Firebird::MemoryPool& pool, const char* fileName, int line)
{
return pool.allocate(size, fileName, line);
}
#else // DEBUG_GDS_ALLOC
void* operator new(size_t size, Firebird::MemoryPool& pool)
{
return pool.allocate(size);
}
#endif // DEBUG_GDS_ALLOC
};
class Get : public Firebird::GetPlugins<Firebird::IManagement>
{
public:

View File

@ -418,47 +418,47 @@ BOOST_AUTO_TEST_CASE(FindTest)
// 9
string b = "345";
check(a.find(b), 3);
check(a.find("45"), 4);
check(a.find('5'), 5);
check(a.find(b), 3u);
check(a.find("45"), 4u);
check(a.find('5'), 5u);
check(a.find("ZZ"), string::npos);
check(a.rfind(b), 9);
check(a.rfind("45"), 10);
check(a.rfind('5'), 11);
check(a.rfind(b), 9u);
check(a.rfind("45"), 10u);
check(a.rfind('5'), 11u);
check(a.rfind("ZZ"), string::npos);
check(a.find("45", 8), 10);
check(a.find("45", 8), 10u);
check(a.find_first_of("aub"), 6);
check(a.find_first_of(b), 3);
check(a.find_first_of("54"), 4);
check(a.find_first_of('5'), 5);
check(a.find_first_of("aub"), 6u);
check(a.find_first_of(b), 3u);
check(a.find_first_of("54"), 4u);
check(a.find_first_of('5'), 5u);
check(a.find_first_of("ZZ"), string::npos);
check(a.find_last_of("aub"), 8);
check(a.find_last_of(b), 11);
check(a.find_last_of("54"), 11);
check(a.find_last_of('5'), 11);
check(a.find_last_of("aub"), 8u);
check(a.find_last_of(b), 11u);
check(a.find_last_of("54"), 11u);
check(a.find_last_of('5'), 11u);
check(a.find_last_of("ZZ"), string::npos);
check(a.find_first_of("45", 8), 10);
check(a.find_first_of("45", 8u), 10u);
b = "010";
check(a.find_first_not_of("aub"), 0);
check(a.find_first_not_of(b), 2);
check(a.find_first_not_of("0102"), 3);
check(a.find_first_not_of('0'), 1);
check(a.find_first_not_of("aub"), 0u);
check(a.find_first_not_of(b), 2u);
check(a.find_first_not_of("0102"), 3u);
check(a.find_first_not_of('0'), 1u);
check(a.find_first_not_of(a), string::npos);
b = "878";
check(a.find_last_not_of("aub"), 14);
check(a.find_last_not_of(b), 12);
check(a.find_last_not_of("78"), 12);
check(a.find_last_not_of('8'), 13);
check(a.find_last_not_of("aub"), 14u);
check(a.find_last_not_of(b), 12u);
check(a.find_last_not_of("78"), 12u);
check(a.find_last_not_of('8'), 13u);
check(a.find_last_not_of(a), string::npos);
check(a.find_first_not_of("u345", 8), 12);
check(a.find_first_not_of("u345", 8u), 12u);
}
BOOST_AUTO_TEST_CASE(SubstrTest)
@ -466,13 +466,13 @@ BOOST_AUTO_TEST_CASE(SubstrTest)
string a = lbl;
string b;
b = a.substr(3, 4);
b = a.substr(3u, 4u);
validate(b, "3456");
b = a.substr(5, 20);
b = a.substr(5u, 20u);
validate(b, "56789");
b = a.substr(50, 20);
b = a.substr(50u, 20u);
validate(b, "");
}

View File

@ -2176,16 +2176,20 @@ BoolExprNode* RseBoolNode::convertNeqAllToNotAny(thread_db* tdbb, CompilerScratc
andNode->arg1 = missNode;
RseNode* newInnerRse1 = innerRse->clone(csb->csb_pool);
newInnerRse1->flags |= RseNode::FLAG_SUB_QUERY;
RseBoolNode* rseBoolNode = FB_NEW_POOL(csb->csb_pool) RseBoolNode(csb->csb_pool, blr_any);
rseBoolNode->rse = innerRse;
rseBoolNode->rse = newInnerRse1;
rseBoolNode->ownSavepoint = this->ownSavepoint;
andNode->arg2 = rseBoolNode;
RseNode* newInnerRse = innerRse->clone(csb->csb_pool);
RseNode* newInnerRse2 = innerRse->clone(csb->csb_pool);
newInnerRse2->flags |= RseNode::FLAG_SUB_QUERY;
rseBoolNode = FB_NEW_POOL(csb->csb_pool) RseBoolNode(csb->csb_pool, blr_any);
rseBoolNode->rse = newInnerRse;
rseBoolNode->rse = newInnerRse2;
rseBoolNode->ownSavepoint = this->ownSavepoint;
orNode->arg2 = rseBoolNode;
@ -2201,16 +2205,16 @@ BoolExprNode* RseBoolNode::convertNeqAllToNotAny(thread_db* tdbb, CompilerScratc
outerRseNeq->blrOp = blr_eql;
// If there was a boolean on the stream, append (AND) the new one
if (newInnerRse->rse_boolean)
if (newInnerRse2->rse_boolean)
{
andNode = FB_NEW_POOL(csb->csb_pool) BinaryBoolNode(csb->csb_pool, blr_and);
andNode->arg1 = newInnerRse->rse_boolean;
andNode->arg1 = newInnerRse2->rse_boolean;
andNode->arg2 = boolean;
boolean = andNode;
}
newInnerRse->rse_boolean = boolean;
newInnerRse2->rse_boolean = boolean;
SubExprNodeCopier copier(csb->csb_pool, csb);
return copier.copy(tdbb, static_cast<BoolExprNode*>(newNode));

View File

@ -80,9 +80,6 @@ static void defineComputed(DsqlCompilerScratch* dsqlScratch, RelationSourceNode*
dsql_fld* field, ValueSourceClause* clause, string& source, BlrDebugWriter::BlrData& value);
static void deleteKeyConstraint(thread_db* tdbb, jrd_tra* transaction,
const MetaName& relationName, const MetaName& constraintName, const MetaName& indexName);
static void defineFile(thread_db* tdbb, jrd_tra* transaction, SLONG shadowNumber, bool manualShadow,
bool conditionalShadow, SLONG& dbAlloc,
const PathName& name, SLONG start, SLONG length);
static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const MetaName& relationName,
const MetaName& fieldName);
static bool isItSqlRole(thread_db* tdbb, jrd_tra* transaction, const MetaName& inputName,
@ -490,46 +487,6 @@ static void deleteKeyConstraint(thread_db* tdbb, jrd_tra* transaction,
}
}
// Define a database or shadow file.
static void defineFile(thread_db* tdbb, jrd_tra* transaction, SLONG shadowNumber, bool manualShadow,
bool conditionalShadow, SLONG& dbAlloc, const PathName& name, SLONG start, SLONG length)
{
PathName expandedName = name;
if (!ISC_expand_filename(expandedName, false))
status_exception::raise(Arg::PrivateDyn(231)); // File name is invalid.
if (tdbb->getDatabase()->dbb_filename == expandedName)
status_exception::raise(Arg::PrivateDyn(166));
AutoCacheRequest request(tdbb, drq_l_files, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
FIRST 1 X IN RDB$FILES
WITH X.RDB$FILE_NAME EQ expandedName.c_str()
{
status_exception::raise(Arg::PrivateDyn(166));
}
END_FOR
request.reset(tdbb, drq_s_files, DYN_REQUESTS);
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
X IN RDB$FILES
{
expandedName.copyTo(X.RDB$FILE_NAME, sizeof(X.RDB$FILE_NAME));
X.RDB$SHADOW_NUMBER = shadowNumber;
X.RDB$FILE_FLAGS = (manualShadow ? FILE_manual : 0) |
(conditionalShadow ? FILE_conditional : 0);
dbAlloc = MAX(dbAlloc, start);
X.RDB$FILE_START = dbAlloc;
X.RDB$FILE_LENGTH = length;
dbAlloc += length;
}
END_STORE
}
// Checks to see if the given field already exists in a relation.
static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const MetaName& relationName,
const MetaName& fieldName)
@ -10462,7 +10419,7 @@ string CreateShadowNode::internalPrint(NodePrinter& printer) const
NODE_PRINT(printer, number);
NODE_PRINT(printer, manual);
NODE_PRINT(printer, conditional);
NODE_PRINT(printer, files);
NODE_PRINT(printer, fileName);
return "CreateShadowNode";
}
@ -10486,7 +10443,7 @@ void CreateShadowNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScrat
// run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction);
// If a shadow set identified by the shadow number already exists return error.
// If a shadow set identified by the shadow number already exists return error
AutoCacheRequest request(tdbb, drq_l_shadow, DYN_REQUESTS);
@ -10502,25 +10459,34 @@ void CreateShadowNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScrat
}
END_FOR
SLONG start = 0;
PathName expandedName = fileName.ToPathName();
for (NestConst<DbFileClause>* i = files.begin(); i != files.end(); ++i)
if (!ISC_expand_filename(expandedName, false))
status_exception::raise(Arg::PrivateDyn(231)); // File name is invalid
if (tdbb->getDatabase()->dbb_filename == expandedName)
status_exception::raise(Arg::PrivateDyn(166));
request.reset(tdbb, drq_l_files, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
FIRST 1 X IN RDB$FILES
WITH X.RDB$FILE_NAME EQ expandedName.c_str()
{
bool first = i == files.begin();
DbFileClause* file = *i;
if (!first && i[-1]->length == 0 && file->start == 0)
{
// Preceding file did not specify length, so %s must include starting page number
status_exception::raise(
Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
Arg::Gds(isc_dsql_command_err) <<
Arg::Gds(isc_dsql_file_length_err) << file->name);
}
defineFile(tdbb, transaction, number, manual && first, conditional && first,
start, file->name.c_str(), file->start, file->length);
status_exception::raise(Arg::PrivateDyn(166));
}
END_FOR
request.reset(tdbb, drq_s_files, DYN_REQUESTS);
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
X IN RDB$FILES
{
expandedName.copyTo(X.RDB$FILE_NAME, sizeof(X.RDB$FILE_NAME));
X.RDB$SHADOW_NUMBER = number;
X.RDB$FILE_FLAGS = (manual ? FILE_manual : 0) | (conditional ? FILE_conditional : 0);
}
END_STORE
savePoint.release(); // everything is ok
}
@ -11352,7 +11318,7 @@ void CreateAlterUserNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
// run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction);
Auth::DynamicUserData* userData = FB_NEW_POOL(*transaction->tra_pool) Auth::DynamicUserData;
Auth::UserData* userData = FB_NEW_POOL(*transaction->tra_pool) Auth::UserData;
MetaName text(name);
if (text.isEmpty() && mode == USER_MOD)
@ -11469,7 +11435,7 @@ void DropUserNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jr
// run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction);
Auth::DynamicUserData* userData = FB_NEW_POOL(*transaction->tra_pool) Auth::DynamicUserData;
Auth::UserData* userData = FB_NEW_POOL(*transaction->tra_pool) Auth::UserData;
string text = name.c_str();
@ -12742,13 +12708,11 @@ string AlterDatabaseNode::internalPrint(NodePrinter& printer) const
DdlNode::internalPrint(printer);
NODE_PRINT(printer, create);
NODE_PRINT(printer, createLength);
NODE_PRINT(printer, linger);
NODE_PRINT(printer, clauses);
NODE_PRINT(printer, differenceFile);
NODE_PRINT(printer, setDefaultCharSet);
NODE_PRINT(printer, setDefaultCollation);
NODE_PRINT(printer, files);
NODE_PRINT(printer, cryptPlugin);
NODE_PRINT(printer, keyName);
@ -12924,18 +12888,6 @@ void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
}
}
SLONG dbAlloc = PageSpace::maxAlloc(tdbb->getDatabase());
SLONG start = create ? createLength + 1 : 0;
for (NestConst<DbFileClause>* i = files.begin(); i != files.end(); ++i)
{
DbFileClause* file = *i;
start = MAX(start, file->start);
defineFile(tdbb, transaction, 0, false, false, dbAlloc,
file->name.c_str(), start, file->length);
start += file->length;
}
if (differenceFile.hasData())
defineDifference(tdbb, transaction, differenceFile.c_str());
@ -13064,7 +13016,6 @@ void AlterDatabaseNode::changeBackupMode(thread_db* tdbb, jrd_tra* transaction,
X IN RDB$FILES
{
X.RDB$FILE_FLAGS = FILE_difference | FILE_backing_up;
X.RDB$FILE_START = 0;
}
END_STORE
@ -13116,7 +13067,6 @@ void AlterDatabaseNode::defineDifference(thread_db* tdbb, jrd_tra* transaction,
strcpy(FIL.RDB$FILE_NAME, file.c_str());
FIL.RDB$FILE_FLAGS = FILE_difference;
FIL.RDB$FILE_START = 0;
}
END_STORE
}

View File

@ -101,40 +101,6 @@ public:
};
class DbFileClause : public Printable
{
public:
DbFileClause(MemoryPool& p, const DbFileClause& o)
: name(p, o.name),
start(o.start),
length(o.length)
{
}
explicit DbFileClause(MemoryPool& p, const Firebird::string& aName)
: name(p, aName),
start(0),
length(0)
{
}
public:
virtual Firebird::string internalPrint(NodePrinter& printer) const
{
NODE_PRINT(printer, name);
NODE_PRINT(printer, start);
NODE_PRINT(printer, length);
return "DbFileClause";
}
public:
Firebird::string name; // File name
SLONG start; // Starting page
SLONG length; // File length in pages
};
class ExternalClause : public Printable
{
public:
@ -1967,12 +1933,13 @@ public:
class CreateShadowNode : public DdlNode
{
public:
CreateShadowNode(MemoryPool& p, const SSHORT aNumber)
CreateShadowNode(MemoryPool& p, SSHORT aNumber, bool aManual, bool aConditional,
const Firebird::string& aFileName)
: DdlNode(p),
number(aNumber),
manual(false),
conditional(false),
files(p)
manual(aManual),
conditional(aConditional),
fileName(p, aFileName)
{
}
@ -1996,7 +1963,7 @@ public:
SSHORT number;
bool manual;
bool conditional;
Firebird::Array<NestConst<DbFileClause> > files;
Firebird::string fileName;
bool createIfNotExistsOnly = false;
};
@ -2425,14 +2392,9 @@ public:
public:
AlterDatabaseNode(MemoryPool& p)
: DdlNode(p),
create(false),
createLength(0),
linger(-1),
clauses(0),
differenceFile(p),
setDefaultCharSet(p),
setDefaultCollation(p),
files(p),
cryptPlugin(p),
keyName(p),
pubTables(p)
@ -2468,13 +2430,12 @@ private:
void checkClauses(thread_db* tdbb);
public:
bool create; // Is the node created with a CREATE DATABASE command?
SLONG createLength, linger;
unsigned clauses;
bool create = false; // Is the node created with a CREATE DATABASE command?
SLONG linger = -1;
unsigned clauses = 0;
Firebird::string differenceFile;
MetaName setDefaultCharSet;
MetaName setDefaultCollation;
Firebird::Array<NestConst<DbFileClause> > files;
MetaName cryptPlugin;
MetaName keyName;
Firebird::TriState ssDefiner;

View File

@ -56,17 +56,15 @@ void DsqlStatement::rethrowDdlException(status_exception& ex, bool metadataUpdat
status_exception::raise(newVector);
}
int DsqlStatement::release()
void DsqlStatement::release()
{
fb_assert(refCounter.value() > 0);
int refCnt = --refCounter;
if (!refCnt)
if (!--refCounter)
{
if (cacheKey)
{
dsqlAttachment->dbb_statement_cache->statementGoingInactive(cacheKey);
refCnt = refCounter;
}
else
{
@ -74,8 +72,6 @@ int DsqlStatement::release()
dsqlAttachment->deletePool(&getPool());
}
}
return refCnt;
}
void DsqlStatement::doRelease()

View File

@ -83,12 +83,12 @@ protected:
virtual ~DsqlStatement() = default;
public:
int addRef()
void addRef()
{
return ++refCounter;
++refCounter;
}
int release();
void release();
bool isCursorBased() const
{

View File

@ -767,8 +767,6 @@ using namespace Firebird;
Firebird::string* stringPtr;
Jrd::IntlString* intlStringPtr;
Jrd::Lim64String* lim64ptr;
Jrd::DbFileClause* dbFileClause;
Firebird::Array<NestConst<Jrd::DbFileClause> >* dbFilesClause;
Jrd::ExternalClause* externalClause;
Firebird::NonPooledPair<Jrd::MetaName*, Jrd::ValueExprNode*>* namedArgument;
Firebird::NonPooledPair<Firebird::ObjectsArray<Jrd::MetaName>*, Jrd::ValueListNode*>* namedArguments;
@ -1807,16 +1805,8 @@ index_condition_opt
// CREATE SHADOW
%type <createShadowNode> shadow_clause
shadow_clause
: pos_short_integer manual_auto conditional utf_string first_file_length
{
$$ = newNode<CreateShadowNode>($1);
$$->manual = $2;
$$->conditional = $3;
$$->files.add(newNode<DbFileClause>(*$4));
$$->files.front()->length = $5;
}
sec_shadow_files(NOTRIAL(&$6->files))
{ $$ = $6; }
: pos_short_integer manual_auto conditional utf_string
{ $$ = newNode<CreateShadowNode>($1, $2, $3, *$4); }
;
%type <boolVal> manual_auto
@ -1832,24 +1822,6 @@ conditional
| CONDITIONAL { $$ = true; }
;
%type <int32Val> first_file_length
first_file_length
: /* nothing */ { $$ = 0; }
| LENGTH equals long_integer page_noise { $$ = $3; }
;
%type sec_shadow_files(<dbFilesClause>)
sec_shadow_files($dbFilesClause)
: // nothing
| db_file_list($dbFilesClause)
;
%type db_file_list(<dbFilesClause>)
db_file_list($dbFilesClause)
: db_file { $dbFilesClause->add($1); }
| db_file_list db_file { $dbFilesClause->add($2); }
;
// CREATE DOMAIN
@ -2279,8 +2251,6 @@ db_initial_option($alterDatabaseNode)
| ROLE utf_string
| PASSWORD utf_string
| SET NAMES utf_string
| LENGTH equals long_integer page_noise
{ $alterDatabaseNode->createLength = $3; }
;
%type db_rem_desc1(<alterDatabaseNode>)
@ -2297,9 +2267,7 @@ db_rem_desc($alterDatabaseNode)
%type db_rem_option(<alterDatabaseNode>)
db_rem_option($alterDatabaseNode)
: db_file
{ $alterDatabaseNode->files.add($1); }
| DEFAULT CHARACTER SET symbol_character_set_name
: DEFAULT CHARACTER SET symbol_character_set_name
{ $alterDatabaseNode->setDefaultCharSet = *$4; }
| DEFAULT CHARACTER SET symbol_character_set_name COLLATION symbol_collation_name
{
@ -2310,49 +2278,6 @@ db_rem_option($alterDatabaseNode)
{ $alterDatabaseNode->differenceFile = *$3; }
;
%type <dbFileClause> db_file
db_file
: FILE utf_string
{
DbFileClause* clause = newNode<DbFileClause>(*$2);
$$ = clause;
}
file_desc1($3)
{ $$ = $3; }
;
%type file_desc1(<dbFileClause>)
file_desc1($dbFileClause)
: // nothing
| file_desc($dbFileClause)
;
%type file_desc(<dbFileClause>)
file_desc($dbFileClause)
: file_clause($dbFileClause)
| file_desc file_clause($dbFileClause)
;
%type file_clause(<dbFileClause>)
file_clause($dbFileClause)
: STARTING file_clause_noise long_integer
{ $dbFileClause->start = $3; }
| LENGTH equals long_integer page_noise
{ $dbFileClause->length = $3; }
;
file_clause_noise
: // nothing
| AT
| AT PAGE
;
page_noise
: // nothing
| PAGE
| PAGES
;
// CREATE TABLE
@ -4770,8 +4695,7 @@ alter_db($alterDatabaseNode)
%type db_alter_clause(<alterDatabaseNode>)
db_alter_clause($alterDatabaseNode)
: ADD db_file_list(NOTRIAL(&$alterDatabaseNode->files))
| ADD DIFFERENCE FILE utf_string
: ADD DIFFERENCE FILE utf_string
{ $alterDatabaseNode->differenceFile = *$4; }
| DROP DIFFERENCE FILE
{ $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_DROP_DIFFERENCE; }

View File

@ -38,7 +38,7 @@ static int hash(const SCHAR*);
static bool scompare(const SCHAR*, const SCHAR*);
static bool scompare2(const SCHAR*, const SCHAR*);
const int HASH_SIZE = 211;
const FB_SIZE_T HASH_SIZE = 211;
static gpre_sym* hash_table[HASH_SIZE];
static gpre_sym* key_symbols;
@ -80,7 +80,7 @@ void HSH_init()
{
//const char *string;
int i = 0;
FB_SIZE_T i = 0;
for (gpre_sym** ptr = hash_table; i < HASH_SIZE; i++)
*ptr++ = NULL;

View File

@ -2293,7 +2293,10 @@ static void gen_for( const act* action, int column)
const gpre_req* request = action->act_request;
if (action->act_error || (action->act_flags & ACT_sql))
success(column, true, global_status_name, " {");
{
printa(column, "if (%s && !(%s->getState() & Firebird::IStatus::STATE_ERRORS)) {",
request->req_handle, global_status_name);
}
printa(column, "while (1)");
column += INDENT;
@ -3075,11 +3078,10 @@ static void gen_s_start( const act* action, int column)
if (action->act_error || (action->act_flags & ACT_sql))
{
make_ok_test(action, request, column);
printa(column, "{");
column += INDENT;
}
gen_start(action, port, column, false);
if (action->act_error || (action->act_flags & ACT_sql))
column -= INDENT;
const TEXT* pattern1 = "if (%V1->getErrors()[1] == isc_bad_req_handle) { %RH->release(); %RH = NULL; }";
PAT args;
@ -3088,6 +3090,12 @@ static void gen_s_start( const act* action, int column)
PATTERN_expand((USHORT) column, pattern1, &args);
printa(column, "else break;");
if (action->act_error || (action->act_flags & ACT_sql))
{
column -= INDENT;
printa(column, "}");
}
if (action->act_type == ACT_open)
{
endp(column);

View File

@ -135,9 +135,9 @@ typedef int (*lock_ast_t)(void*);
// Number of elements in an array
template <typename T, std::size_t N>
constexpr int FB_NELEM(const T (&)[N])
constexpr FB_SIZE_T FB_NELEM(const T (&)[N])
{
return N;
return static_cast<FB_SIZE_T>(N);
}
// Intl types

View File

@ -28,9 +28,7 @@
#include <cctype>
static std::string trim(std::string_view str);
static std::string trim(std::string_view str)
std::string FrontendLexer::trim(std::string_view str)
{
auto finish = str.end();
auto start = str.begin();
@ -142,7 +140,7 @@ std::variant<FrontendLexer::SingleStatement, FrontendLexer::IncompleteTokenError
while (pos < end)
{
if (end - pos >= term.length() && std::equal(term.begin(), term.end(), pos))
if (std::size_t(end - pos) >= term.length() && std::equal(term.begin(), term.end(), pos))
{
const auto initialStatement = std::string(buffer.cbegin(), pos);
pos += term.length();
@ -189,22 +187,8 @@ FrontendLexer::Token FrontendLexer::getToken()
switch (toupper(*pos))
{
case '(':
token.type = Token::TYPE_OPEN_PAREN;
token.processedText = *pos++;
break;
case ')':
token.type = Token::TYPE_CLOSE_PAREN;
token.processedText = *pos++;
break;
case ',':
token.type = Token::TYPE_COMMA;
token.processedText = *pos++;
break;
case ';':
case '.':
token.type = Token::TYPE_OTHER;
token.processedText = *pos++;
break;
@ -224,13 +208,83 @@ FrontendLexer::Token FrontendLexer::getToken()
return token;
}
std::optional<FrontendLexer::Token> FrontendLexer::getStringToken()
FrontendLexer::Token FrontendLexer::getNameToken()
{
skipSpacesAndComments();
Token token;
if (pos >= end)
{
token.type = Token::TYPE_EOF;
return token;
}
if (const auto optStringToken = getStringToken(); optStringToken.has_value())
return optStringToken.value();
/*** Revert to strict parsing with schemas support branch.
const auto start = pos;
bool first = true;
while (pos < end)
{
const auto c = *pos++;
if (!((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
c == '{' ||
c == '}' ||
(!first && c >= '0' && c <= '9') ||
(!first && c == '$') ||
(!first && c == '_')))
{
if (!first)
--pos;
break;
}
first = false;
}
token.processedText = token.rawText = std::string(start, pos);
std::transform(token.processedText.begin(), token.processedText.end(),
token.processedText.begin(), toupper);
return token;
***/
const auto start = pos;
switch (toupper(*pos))
{
case ';':
token.type = Token::TYPE_OTHER;
token.processedText = *pos++;
break;
default:
while (pos != end && !fb_utils::isspace(*pos) && *pos != '.')
++pos;
token.processedText = std::string(start, pos);
std::transform(token.processedText.begin(), token.processedText.end(),
token.processedText.begin(), toupper);
break;
}
token.rawText = std::string(start, pos);
return token;
}
std::optional<FrontendLexer::Token> FrontendLexer::getStringToken()
{
if (pos >= end)
return std::nullopt;
Token token;
const auto start = pos;
switch (toupper(*pos))

View File

@ -39,15 +39,18 @@ public:
TYPE_EOF,
TYPE_STRING,
TYPE_META_STRING,
TYPE_OPEN_PAREN,
TYPE_CLOSE_PAREN,
TYPE_COMMA,
TYPE_OTHER
};
Type type = TYPE_OTHER;
std::string rawText;
std::string processedText;
const std::string& getProcessedString() const
{
return type == FrontendLexer::Token::TYPE_STRING || type == FrontendLexer::Token::TYPE_META_STRING ?
processedText : rawText;
}
};
struct SingleStatement
@ -74,6 +77,7 @@ public:
FrontendLexer& operator=(const FrontendLexer&) = delete;
public:
static std::string trim(std::string_view str);
static std::string stripComments(std::string_view statement);
public:
@ -87,6 +91,11 @@ public:
return pos;
}
void setPos(std::string::const_iterator newPos)
{
pos = newPos;
}
void rewind()
{
deletePos = buffer.begin();
@ -97,7 +106,9 @@ public:
void appendBuffer(std::string_view newBuffer);
void reset();
std::variant<SingleStatement, FrontendLexer::IncompleteTokenError> getSingleStatement(std::string_view term);
Token getToken();
Token getNameToken();
private:
std::optional<Token> getStringToken();

732
src/isql/FrontendParser.cpp Normal file
View File

@ -0,0 +1,732 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2024 Adriano dos Santos Fernandes <adrianosf at gmail.com>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#include "firebird.h"
#include "../isql/FrontendParser.h"
#include <cctype>
FrontendParser::AnyNode FrontendParser::internalParse()
{
static constexpr std::string_view TOKEN_ADD("ADD");
static constexpr std::string_view TOKEN_BLOBDUMP("BLOBDUMP");
static constexpr std::string_view TOKEN_BLOBVIEW("BLOBVIEW");
static constexpr std::string_view TOKEN_CONNECT("CONNECT");
static constexpr std::string_view TOKEN_COPY("COPY");
static constexpr std::string_view TOKEN_CREATE("CREATE");
static constexpr std::string_view TOKEN_DROP("DROP");
static constexpr std::string_view TOKEN_EDIT("EDIT");
static constexpr std::string_view TOKEN_EXIT("EXIT");
static constexpr std::string_view TOKEN_EXPLAIN("EXPLAIN");
static constexpr std::string_view TOKEN_HELP("HELP");
static constexpr std::string_view TOKEN_INPUT("INPUT");
static constexpr std::string_view TOKEN_OUTPUT("OUTPUT");
static constexpr std::string_view TOKEN_QUIT("QUIT");
static constexpr std::string_view TOKEN_SET("SET");
static constexpr std::string_view TOKEN_SHELL("SHELL");
static constexpr std::string_view TOKEN_SHOW("SHOW");
const auto commandToken = lexer.getToken();
if (commandToken.type != Token::TYPE_OTHER)
return InvalidNode();
const auto& command = commandToken.processedText;
if (command == TOKEN_ADD)
{
if (auto tableName = parseName())
{
AddNode node;
node.tableName = std::move(tableName.value());
if (parseEof())
return node;
}
}
else if (command == TOKEN_BLOBDUMP || command == TOKEN_BLOBVIEW)
{
if (const auto blobId = lexer.getToken(); blobId.type != Token::TYPE_EOF)
{
BlobDumpViewNode node;
// Find the high and low values of the blob id
if (blobId.processedText.empty())
return InvalidNode();
sscanf(blobId.processedText.c_str(), "%" xLONGFORMAT":%" xLONGFORMAT,
&node.blobId.gds_quad_high, &node.blobId.gds_quad_low);
if (command == TOKEN_BLOBDUMP)
{
if (auto file = parseFileName())
{
node.file = std::move(file.value());
if (parseEof())
return node;
}
}
else
{
if (parseEof())
return node;
}
}
}
else if (command == TOKEN_CONNECT)
{
ConnectNode node;
do
{
auto token = lexer.getToken();
if (token.type == Token::TYPE_EOF)
{
if (node.args.empty())
break;
else
return node;
}
else if (token.type != Token::TYPE_OTHER &&
token.type != Token::TYPE_STRING &&
token.type != Token::TYPE_META_STRING)
{
return InvalidNode();
}
node.args.push_back(std::move(token));
} while(true);
}
else if (command == TOKEN_COPY)
{
CopyNode node;
if (auto source = parseName())
node.source = std::move(source.value());
else
return InvalidNode();
if (auto destination = parseName())
node.destination = std::move(destination.value());
else
return InvalidNode();
if (auto database = parseFileName())
node.database = std::move(database.value());
else
return InvalidNode();
if (parseEof())
return node;
}
else if (command == TOKEN_CREATE)
{
if (const auto createWhat = lexer.getToken();
createWhat.type == Token::TYPE_OTHER &&
(createWhat.processedText == "DATABASE" ||
(options.schemaAsDatabase && createWhat.processedText == "SCHEMA")))
{
CreateDatabaseNode node;
do
{
auto token = lexer.getToken();
if (token.type == Token::TYPE_EOF)
{
if (node.args.empty())
break;
else
return node;
}
else if (token.type != Token::TYPE_OTHER &&
token.type != Token::TYPE_STRING &&
token.type != Token::TYPE_META_STRING)
{
return InvalidNode();
}
node.args.push_back(std::move(token));
} while(true);
}
}
else if (command == TOKEN_DROP)
{
if (const auto dropWhat = lexer.getToken();
dropWhat.type == Token::TYPE_OTHER &&
(dropWhat.processedText == "DATABASE" ||
(options.schemaAsDatabase && dropWhat.processedText == "SCHEMA")))
{
if (parseEof())
return DropDatabaseNode();
}
}
else if (command == TOKEN_EDIT)
{
EditNode node;
node.file = parseFileName();
if (parseEof())
return node;
}
else if (command == TOKEN_EXIT)
{
if (parseEof())
return ExitNode();
}
else if (command == TOKEN_EXPLAIN)
{
ExplainNode node;
if (auto query = parseUtilEof())
{
node.query = std::move(query.value());
return node;
}
}
else if (command == TOKEN_HELP || command == "?")
{
HelpNode node;
if (const auto token = lexer.getToken(); token.type == Token::TYPE_EOF)
return node;
else if (token.type == Token::TYPE_OTHER)
{
node.command = token.processedText;
if (parseEof())
return node;
}
}
else if (command.length() >= 2 && TOKEN_INPUT.find(command) == 0)
{
if (auto file = parseFileName())
{
InputNode node;
node.file = std::move(file.value());
if (parseEof())
return node;
}
}
else if (command.length() >= 3 && TOKEN_OUTPUT.find(command) == 0)
{
OutputNode node;
node.file = parseFileName();
if (parseEof())
return node;
}
else if (command == TOKEN_QUIT)
{
if (parseEof())
return QuitNode();
}
else if (command == TOKEN_SET)
{
if (const auto setNode = parseSet(); !std::holds_alternative<InvalidNode>(setNode))
return setNode;
}
else if (command == TOKEN_SHELL)
{
ShellNode node;
node.command = parseUtilEof();
return node;
}
else if (command == TOKEN_SHOW)
{
if (const auto showNode = parseShow(); !std::holds_alternative<InvalidNode>(showNode))
return showNode;
}
return InvalidNode();
}
FrontendParser::AnySetNode FrontendParser::parseSet()
{
static constexpr std::string_view TOKEN_AUTODDL("AUTODDL");
static constexpr std::string_view TOKEN_AUTOTERM("AUTOTERM");
static constexpr std::string_view TOKEN_BAIL("BAIL");
static constexpr std::string_view TOKEN_BLOBDISPLAY("BLOBDISPLAY");
static constexpr std::string_view TOKEN_BULK_INSERT("BULK_INSERT");
static constexpr std::string_view TOKEN_COUNT("COUNT");
static constexpr std::string_view TOKEN_ECHO("ECHO");
static constexpr std::string_view TOKEN_EXEC_PATH_DISPLAY("EXEC_PATH_DISPLAY");
static constexpr std::string_view TOKEN_EXPLAIN("EXPLAIN");
static constexpr std::string_view TOKEN_HEADING("HEADING");
static constexpr std::string_view TOKEN_KEEP_TRAN_PARAMS("KEEP_TRAN_PARAMS");
static constexpr std::string_view TOKEN_LIST("LIST");
static constexpr std::string_view TOKEN_LOCAL_TIMEOUT("LOCAL_TIMEOUT");
static constexpr std::string_view TOKEN_MAXROWS("MAXROWS");
static constexpr std::string_view TOKEN_NAMES("NAMES");
static constexpr std::string_view TOKEN_PER_TABLE_STATS("PER_TABLE_STATS");
static constexpr std::string_view TOKEN_PLAN("PLAN");
static constexpr std::string_view TOKEN_PLANONLY("PLANONLY");
static constexpr std::string_view TOKEN_ROWCOUNT("ROWCOUNT");
static constexpr std::string_view TOKEN_SQL("SQL");
static constexpr std::string_view TOKEN_SQLDA_DISPLAY("SQLDA_DISPLAY");
static constexpr std::string_view TOKEN_STATS("STATS");
static constexpr std::string_view TOKEN_TERMINATOR("TERMINATOR");
static constexpr std::string_view TOKEN_TIME("TIME");
static constexpr std::string_view TOKEN_TRANSACTION("TRANSACTION");
static constexpr std::string_view TOKEN_WARNINGS("WARNINGS");
static constexpr std::string_view TOKEN_WIDTH("WIDTH");
static constexpr std::string_view TOKEN_WNG("WNG");
static constexpr std::string_view TOKEN_WIRE_STATS("WIRE_STATS");
switch (const auto setCommandToken = lexer.getToken(); setCommandToken.type)
{
case Token::TYPE_EOF:
return SetNode();
case Token::TYPE_OTHER:
{
const auto& text = setCommandToken.processedText;
if (const auto parsed = parseSet<SetAutoDdlNode>(text, TOKEN_AUTODDL, 4))
return parsed.value();
else if (const auto parsed = parseSet<SetAutoTermNode>(text, TOKEN_AUTOTERM))
return parsed.value();
else if (const auto parsed = parseSet<SetBailNode>(text, TOKEN_BAIL))
return parsed.value();
else if (const auto parsed = parseSet<SetBlobDisplayNode>(text, TOKEN_BLOBDISPLAY, 4))
return parsed.value();
else if (text == TOKEN_BULK_INSERT)
{
SetBulkInsertNode node;
if (const auto statement = parseUtilEof())
{
node.statement = statement.value();
return node;
}
}
else if (const auto parsed = parseSet<SetCountNode>(text, TOKEN_COUNT))
return parsed.value();
else if (const auto parsed = parseSet<SetEchoNode>(text, TOKEN_ECHO))
return parsed.value();
else if (const auto parsed = parseSet<SetExecPathDisplayNode>(text, TOKEN_EXEC_PATH_DISPLAY))
return parsed.value();
else if (const auto parsed = parseSet<SetExplainNode>(text, TOKEN_EXPLAIN))
return parsed.value();
else if (const auto parsed = parseSet<SetHeadingNode>(text, TOKEN_HEADING))
return parsed.value();
else if (const auto parsed = parseSet<SetKeepTranParamsNode>(text, TOKEN_KEEP_TRAN_PARAMS, 9))
return parsed.value();
else if (const auto parsed = parseSet<SetListNode>(text, TOKEN_LIST))
return parsed.value();
else if (const auto parsed = parseSet<SetLocalTimeoutNode>(text, TOKEN_LOCAL_TIMEOUT))
return parsed.value();
else if (const auto parsed = parseSet<SetMaxRowsNode>(text, TOKEN_MAXROWS))
return parsed.value();
else if (text == TOKEN_NAMES)
{
SetNamesNode node;
node.name = parseName();
if (parseEof())
return node;
}
else if (const auto parsed = parseSet<SetPerTableStatsNode>(text, TOKEN_PER_TABLE_STATS, 7))
return parsed.value();
else if (const auto parsed = parseSet<SetPlanNode>(text, TOKEN_PLAN))
return parsed.value();
else if (const auto parsed = parseSet<SetPlanOnlyNode>(text, TOKEN_PLANONLY))
return parsed.value();
else if (const auto parsed = parseSet<SetMaxRowsNode>(text, TOKEN_ROWCOUNT))
return parsed.value();
else if (text == TOKEN_SQL)
{
SetSqlDialectNode node;
if (const auto dialectToken = lexer.getToken();
dialectToken.type == Token::TYPE_OTHER && dialectToken.processedText == "DIALECT")
{
if (const auto arg = lexer.getToken(); arg.type != Token::TYPE_EOF)
{
node.arg = arg.processedText;
if (parseEof())
return node;
}
}
}
else if (const auto parsed = parseSet<SetSqldaDisplayNode>(text, TOKEN_SQLDA_DISPLAY))
return parsed.value();
else if (const auto parsed = parseSet<SetStatsNode>(text, TOKEN_STATS, 4))
return parsed.value();
else if (const auto parsed = parseSet<SetTermNode>(text, TOKEN_TERMINATOR, 4, false))
return parsed.value();
else if (const auto parsed = parseSet<SetTimeNode>(text, TOKEN_TIME))
{
if (const auto setTimeNode = std::get_if<SetTimeNode>(&parsed.value());
setTimeNode && setTimeNode->arg == "ZONE")
{
return InvalidNode();
}
return parsed.value();
}
else if (text.length() >= 5 && TOKEN_TRANSACTION.find(text) == 0)
{
SetTransactionNode node;
node.statement = lexer.getBuffer();
return node;
}
else if (const auto parsed = parseSet<SetWarningsNode>(text, TOKEN_WARNINGS, 7))
return parsed.value();
else if (const auto parsed = parseSet<SetWarningsNode>(text, TOKEN_WNG))
return parsed.value();
else if (text == TOKEN_WIDTH)
{
SetWidthNode node;
if (const auto column = lexer.getToken(); column.type != Token::TYPE_EOF)
{
node.column = column.processedText;
if (const auto width = lexer.getToken(); width.type != Token::TYPE_EOF)
{
node.width = width.processedText;
if (!parseEof())
return InvalidNode();
}
return node;
}
}
else if (const auto parsed = parseSet<SetWireStatsNode>(text, TOKEN_WIRE_STATS, 4))
return parsed.value();
break;
}
}
return InvalidNode();
}
template <typename Node>
std::optional<FrontendParser::AnySetNode> FrontendParser::parseSet(std::string_view setCommand,
std::string_view testCommand, unsigned testCommandMinLen, bool useProcessedText)
{
if (setCommand == testCommand ||
(testCommandMinLen && setCommand.length() >= testCommandMinLen &&
testCommand.find(setCommand) == 0))
{
Node node;
if (const auto arg = lexer.getToken(); arg.type != Token::TYPE_EOF)
{
node.arg = useProcessedText ? arg.processedText : arg.rawText;
if (!parseEof())
return InvalidNode();
}
return node;
}
return std::nullopt;
}
FrontendParser::AnyShowNode FrontendParser::parseShow()
{
static constexpr std::string_view TOKEN_CHECKS("CHECKS");
static constexpr std::string_view TOKEN_COLLATES("COLLATES");
static constexpr std::string_view TOKEN_COLLATIONS("COLLATIONS");
static constexpr std::string_view TOKEN_COMMENTS("COMMENTS");
static constexpr std::string_view TOKEN_DATABASE("DATABASE");
static constexpr std::string_view TOKEN_DEPENDENCIES("DEPENDENCIES");
static constexpr std::string_view TOKEN_DEPENDENCY("DEPENDENCY");
static constexpr std::string_view TOKEN_DOMAINS("DOMAINS");
static constexpr std::string_view TOKEN_EXCEPTIONS("EXCEPTIONS");
static constexpr std::string_view TOKEN_FILTERS("FILTERS");
static constexpr std::string_view TOKEN_FUNCTIONS("FUNCTIONS");
static constexpr std::string_view TOKEN_INDEXES("INDEXES");
static constexpr std::string_view TOKEN_INDICES("INDICES");
static constexpr std::string_view TOKEN_GENERATORS("GENERATORS");
static constexpr std::string_view TOKEN_GRANTS("GRANTS");
static constexpr std::string_view TOKEN_MAPPINGS("MAPPINGS");
static constexpr std::string_view TOKEN_PACKAGES("PACKAGES");
static constexpr std::string_view TOKEN_PROCEDURES("PROCEDURES");
static constexpr std::string_view TOKEN_PUBLICATIONS("PUBLICATIONS");
static constexpr std::string_view TOKEN_ROLES("ROLES");
static constexpr std::string_view TOKEN_SECCLASSES("SECCLASSES");
static constexpr std::string_view TOKEN_SEQUENCES("SEQUENCES");
static constexpr std::string_view TOKEN_SQL("SQL");
static constexpr std::string_view TOKEN_SYSTEM("SYSTEM");
static constexpr std::string_view TOKEN_TABLES("TABLES");
static constexpr std::string_view TOKEN_TRIGGERS("TRIGGERS");
static constexpr std::string_view TOKEN_USERS("USERS");
static constexpr std::string_view TOKEN_VER("VER");
static constexpr std::string_view TOKEN_VERSION("VERSION");
static constexpr std::string_view TOKEN_VIEWS("VIEWS");
static constexpr std::string_view TOKEN_WIRE_STATISTICS("WIRE_STATISTICS");
static constexpr std::string_view TOKEN_WIRE_STATS("WIRE_STATS");
switch (const auto showCommandToken = lexer.getToken(); showCommandToken.type)
{
case Token::TYPE_EOF:
return ShowNode();
case Token::TYPE_OTHER:
{
const auto& text = showCommandToken.processedText;
if (const auto parsed = parseShowOptName<ShowChecksNode>(text, TOKEN_CHECKS, 5))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowCollationsNode>(text, TOKEN_COLLATES, 7))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowCollationsNode>(text, TOKEN_COLLATIONS, 9))
return parsed.value();
else if (text.length() >= 7 && TOKEN_COMMENTS.find(text) == 0)
{
if (parseEof())
return ShowCommentsNode();
}
else if (text == TOKEN_DATABASE)
{
if (parseEof())
return ShowDatabaseNode();
}
else if (const auto parsed = parseShowOptName<ShowDependenciesNode>(text, TOKEN_DEPENDENCIES, 5))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowDependenciesNode>(text, TOKEN_DEPENDENCY, 5))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowDomainsNode>(text, TOKEN_DOMAINS, 6))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowExceptionsNode>(text, TOKEN_EXCEPTIONS, 5))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowFiltersNode>(text, TOKEN_FILTERS, 6))
return parsed.value();
else if (text.length() >= 4 && TOKEN_FUNCTIONS.find(text) == 0)
{
ShowFunctionsNode node;
node.name = parseName();
if (node.name)
{
if (const auto token = lexer.getToken();
token.type == Token::TYPE_OTHER && token.rawText == ".")
{
node.package = node.name;
node.name = parseName();
if (parseEof())
return node;
}
else if (token.type == Token::TYPE_EOF)
{
return node;
}
}
else
return node;
}
else if (const auto parsed = parseShowOptName<ShowIndexesNode>(text, TOKEN_INDEXES, 3))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowIndexesNode>(text, TOKEN_INDICES, 0))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowGeneratorsNode>(text, TOKEN_GENERATORS, 3))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowGrantsNode>(text, TOKEN_GRANTS, 5))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowMappingsNode>(text, TOKEN_MAPPINGS, 3))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowPackagesNode>(text, TOKEN_PACKAGES, 4))
return parsed.value();
else if (text.length() >= 4 && TOKEN_PROCEDURES.find(text) == 0)
{
ShowProceduresNode node;
node.name = parseName();
if (node.name)
{
if (const auto token = lexer.getToken();
token.type == Token::TYPE_OTHER && token.rawText == ".")
{
node.package = node.name;
node.name = parseName();
if (parseEof())
return node;
}
else if (token.type == Token::TYPE_EOF)
{
return node;
}
}
else
return node;
}
else if (const auto parsed = parseShowOptName<ShowPublicationsNode>(text, TOKEN_PUBLICATIONS, 3))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowRolesNode>(text, TOKEN_ROLES, 4))
return parsed.value();
else if (text.length() >= 6 && TOKEN_SECCLASSES.find(text) == 0)
{
const auto lexerPos = lexer.getPos();
const auto token = lexer.getNameToken();
ShowSecClassesNode node;
if (!(token.type == Token::TYPE_OTHER && token.rawText == "*"))
{
lexer.setPos(lexerPos);
node.name = parseName();
if (!node.name)
return InvalidNode();
}
const auto optDetail = parseName();
node.detail = optDetail == "DET" || optDetail == "DETAIL";
if (!node.detail && optDetail)
return InvalidNode();
if (parseEof())
return node;
}
else if (const auto parsed = parseShowOptName<ShowGeneratorsNode>(text, TOKEN_SEQUENCES, 3))
return parsed.value();
else if (text == TOKEN_SQL)
{
if (const auto dialectToken = lexer.getToken();
dialectToken.type == Token::TYPE_OTHER && dialectToken.processedText == "DIALECT")
{
if (parseEof())
return ShowSqlDialectNode();
}
}
else if (text.length() >= 3 && TOKEN_SYSTEM.find(text) == 0)
{
ShowSystemNode node;
if (const auto objectType = parseName())
{
const auto objectTypeText = std::string(objectType->c_str());
if ((objectTypeText.length() >= 7 && TOKEN_COLLATES.find(objectTypeText) == 0) ||
(objectTypeText.length() >= 9 && TOKEN_COLLATIONS.find(objectTypeText) == 0))
{
node.objType = obj_collation;
}
else if (objectTypeText.length() >= 4 && TOKEN_FUNCTIONS.find(objectTypeText) == 0)
node.objType = obj_udf;
else if (objectTypeText.length() >= 5 && TOKEN_TABLES.find(objectTypeText) == 0)
node.objType = obj_relation;
else if (objectTypeText.length() >= 4 && TOKEN_ROLES.find(objectTypeText) == 0)
node.objType = obj_sql_role;
else if (objectTypeText.length() >= 4 && TOKEN_PROCEDURES.find(objectTypeText) == 0)
node.objType = obj_procedure;
else if (objectTypeText.length() >= 4 && TOKEN_PACKAGES.find(objectTypeText) == 0)
node.objType = obj_package_header;
else if (objectTypeText.length() >= 3 && TOKEN_PUBLICATIONS.find(objectTypeText) == 0)
node.objType = obj_publication;
else
return InvalidNode();
if (!parseEof())
return InvalidNode();
}
return node;
}
else if (const auto parsed = parseShowOptName<ShowTablesNode>(text, TOKEN_TABLES, 5))
return parsed.value();
else if (const auto parsed = parseShowOptName<ShowTriggersNode>(text, TOKEN_TRIGGERS, 4))
return parsed.value();
else if (text == TOKEN_USERS)
{
if (parseEof())
return ShowUsersNode();
}
else if (text == TOKEN_VER || text == TOKEN_VERSION)
{
if (parseEof())
return ShowVersionNode();
}
else if (const auto parsed = parseShowOptName<ShowViewsNode>(text, TOKEN_VIEWS, 4))
return parsed.value();
else if (text.length() >= 9 && TOKEN_WIRE_STATISTICS.find(text) == 0 ||
text == TOKEN_WIRE_STATS)
{
if (parseEof())
return ShowWireStatsNode();
}
break;
}
}
return InvalidNode();
}
template <typename Node>
std::optional<FrontendParser::AnyShowNode> FrontendParser::parseShowOptName(std::string_view showCommand,
std::string_view testCommand, unsigned testCommandMinLen)
{
if (showCommand == testCommand ||
(testCommandMinLen && showCommand.length() >= testCommandMinLen &&
testCommand.find(showCommand) == 0))
{
Node node;
node.name = parseName();
if (!parseEof())
return InvalidNode();
return node;
}
return std::nullopt;
}
std::optional<std::string> FrontendParser::parseUtilEof()
{
const auto startIt = lexer.getPos();
auto lastPosIt = startIt;
bool first = true;
do
{
const auto token = lexer.getToken();
if (token.type == Token::TYPE_EOF)
{
if (first)
return std::nullopt;
return FrontendLexer::trim(std::string(startIt, lastPosIt));
}
lastPosIt = lexer.getPos();
first = false;
} while (true);
return std::nullopt;
}

286
src/isql/FrontendParser.h Normal file
View File

@ -0,0 +1,286 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2024 Adriano dos Santos Fernandes <adrianosf at gmail.com>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#ifndef FB_ISQL_FRONTEND_PARSER_H
#define FB_ISQL_FRONTEND_PARSER_H
#include "../isql/FrontendLexer.h"
#include "../jrd/obj.h"
#include "../common/classes/MetaString.h"
#include <optional>
#include <string>
#include <string_view>
#include <variant>
#include <vector>
class FrontendParser
{
private:
using Token = FrontendLexer::Token;
public:
struct Options
{
bool schemaAsDatabase = false;
};
struct InvalidNode {};
struct AddNode { Firebird::MetaString tableName; };
struct BlobDumpViewNode { ISC_QUAD blobId; std::optional<std::string> file; };
struct ConnectNode { std::vector<Token> args; };
struct CopyNode { Firebird::MetaString source; Firebird::MetaString destination; std::string database; };
struct CreateDatabaseNode { std::vector<Token> args; };
struct DropDatabaseNode {};
struct EditNode { std::optional<std::string> file; };
struct ExitNode {};
struct ExplainNode { std::string query; };
struct HelpNode { std::optional<std::string> command; };
struct InputNode { std::string file; };
struct OutputNode { std::optional<std::string> file; };
struct QuitNode {};
struct ShellNode { std::optional<std::string> command; };
struct SetNode {};
struct SetAutoDdlNode { std::string arg; };
struct SetAutoTermNode { std::string arg; };
struct SetBailNode { std::string arg; };
struct SetBlobDisplayNode { std::string arg; };
struct SetBulkInsertNode { std::string statement; };
struct SetCountNode { std::string arg; };
struct SetEchoNode { std::string arg; };
struct SetExecPathDisplayNode { std::string arg; };
struct SetExplainNode { std::string arg; };
struct SetHeadingNode { std::string arg; };
struct SetKeepTranParamsNode { std::string arg; };
struct SetListNode { std::string arg; };
struct SetLocalTimeoutNode { std::string arg; };
struct SetMaxRowsNode { std::string arg; };
struct SetNamesNode { std::optional<Firebird::MetaString> name; };
struct SetPerTableStatsNode { std::string arg; };
struct SetPlanNode { std::string arg; };
struct SetPlanOnlyNode { std::string arg; };
struct SetSqldaDisplayNode { std::string arg; };
struct SetSqlDialectNode { std::string arg; };
struct SetStatsNode { std::string arg; };
struct SetTermNode { std::string arg; };
struct SetTimeNode { std::string arg; };
struct SetTransactionNode { std::string statement; };
struct SetWarningsNode { std::string arg; };
struct SetWidthNode { std::string column; std::string width; };
struct SetWireStatsNode { std::string arg; };
struct ShowNode {};
struct ShowChecksNode { std::optional<Firebird::MetaString> name; };
struct ShowCollationsNode { std::optional<Firebird::MetaString> name; };
struct ShowCommentsNode {};
struct ShowDatabaseNode {};
struct ShowDomainsNode { std::optional<Firebird::MetaString> name; };
struct ShowDependenciesNode { std::optional<Firebird::MetaString> name; };
struct ShowExceptionsNode { std::optional<Firebird::MetaString> name; };
struct ShowFiltersNode { std::optional<Firebird::MetaString> name; };
struct ShowFunctionsNode { std::optional<Firebird::MetaString> name; std::optional<Firebird::MetaString> package; };
struct ShowGeneratorsNode { std::optional<Firebird::MetaString> name; };
struct ShowGrantsNode { std::optional<Firebird::MetaString> name; };
struct ShowIndexesNode { std::optional<Firebird::MetaString> name; };
struct ShowMappingsNode { std::optional<Firebird::MetaString> name; };
struct ShowPackagesNode { std::optional<Firebird::MetaString> name; };
struct ShowProceduresNode { std::optional<Firebird::MetaString> name; std::optional<Firebird::MetaString> package; };
struct ShowPublicationsNode { std::optional<Firebird::MetaString> name; };
struct ShowRolesNode { std::optional<Firebird::MetaString> name; };
struct ShowSecClassesNode { std::optional<Firebird::MetaString> name; bool detail = false; };
struct ShowSqlDialectNode {};
struct ShowSystemNode { std::optional<ObjectType> objType; };
struct ShowTablesNode { std::optional<Firebird::MetaString> name; };
struct ShowTriggersNode { std::optional<Firebird::MetaString> name; };
struct ShowUsersNode {};
struct ShowVersionNode {};
struct ShowViewsNode { std::optional<Firebird::MetaString> name; };
struct ShowWireStatsNode {};
using AnySetNode = std::variant<
SetNode,
SetAutoDdlNode,
SetAutoTermNode,
SetBailNode,
SetBlobDisplayNode,
SetBulkInsertNode,
SetCountNode,
SetEchoNode,
SetExecPathDisplayNode,
SetExplainNode,
SetHeadingNode,
SetKeepTranParamsNode,
SetListNode,
SetLocalTimeoutNode,
SetMaxRowsNode,
SetNamesNode,
SetPerTableStatsNode,
SetPlanNode,
SetPlanOnlyNode,
SetSqldaDisplayNode,
SetSqlDialectNode,
SetStatsNode,
SetTermNode,
SetTimeNode,
SetTransactionNode,
SetWarningsNode,
SetWidthNode,
SetWireStatsNode,
InvalidNode
>;
using AnyShowNode = std::variant<
ShowNode,
ShowChecksNode,
ShowCollationsNode,
ShowCommentsNode,
ShowDatabaseNode,
ShowDomainsNode,
ShowDependenciesNode,
ShowExceptionsNode,
ShowFiltersNode,
ShowFunctionsNode,
ShowGeneratorsNode,
ShowGrantsNode,
ShowIndexesNode,
ShowMappingsNode,
ShowPackagesNode,
ShowProceduresNode,
ShowPublicationsNode,
ShowRolesNode,
ShowSecClassesNode,
ShowSqlDialectNode,
ShowSystemNode,
ShowTablesNode,
ShowTriggersNode,
ShowUsersNode,
ShowVersionNode,
ShowViewsNode,
ShowWireStatsNode,
InvalidNode
>;
using AnyNode = std::variant<
AddNode,
BlobDumpViewNode,
ConnectNode,
CopyNode,
CreateDatabaseNode,
DropDatabaseNode,
EditNode,
ExitNode,
ExplainNode,
HelpNode,
InputNode,
OutputNode,
QuitNode,
ShellNode,
AnySetNode,
AnyShowNode,
InvalidNode
>;
template <typename>
static inline constexpr bool AlwaysFalseV = false;
private:
FrontendParser(std::string_view statement, const Options& aOptions)
: lexer(statement),
options(aOptions)
{
}
public:
FrontendParser(const FrontendParser&) = delete;
FrontendParser& operator=(const FrontendParser&) = delete;
public:
static AnyNode parse(std::string_view statement, const Options& options)
{
try
{
FrontendParser parser(statement, options);
return parser.internalParse();
}
catch (const FrontendLexer::IncompleteTokenError&)
{
return InvalidNode();
}
}
private:
AnyNode internalParse();
AnySetNode parseSet();
template <typename Node>
std::optional<AnySetNode> parseSet(std::string_view setCommand,
std::string_view testCommand, unsigned testCommandMinLen = 0, bool useProcessedText = true);
AnyShowNode parseShow();
template <typename Node>
std::optional<AnyShowNode> parseShowOptName(std::string_view showCommand,
std::string_view testCommand, unsigned testCommandMinLen = 0);
bool parseEof()
{
return lexer.getToken().type == Token::TYPE_EOF;
}
std::optional<Firebird::MetaString> parseName()
{
const auto token = lexer.getNameToken();
if (token.type != Token::TYPE_EOF)
return Firebird::MetaString(token.processedText.c_str());
return std::nullopt;
}
std::optional<std::string> parseFileName()
{
const auto token = lexer.getToken();
if (token.type == Token::TYPE_STRING || token.type == Token::TYPE_META_STRING)
return token.processedText;
else if (token.type != Token::TYPE_EOF)
return token.rawText;
return std::nullopt;
}
std::optional<std::string> parseUtilEof();
private:
FrontendLexer lexer;
const Options options;
};
#endif // FB_ISQL_FRONTEND_PARSER_H

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,7 @@
#include "../common/utils_proto.h"
#include <stdarg.h>
using namespace Firebird;
using MsgFormat::SafeArg;
@ -148,6 +149,16 @@ void IUTILS_msg_get(USHORT number, USHORT size, TEXT* msg, const SafeArg& args)
fb_msg_format(NULL, ISQL_MSG_FAC, number, size, msg, args);
}
string IUTILS_name_to_string(const MetaString& name)
{
if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
return name.toQuotedString();
else
return name.c_str();
}
void IUTILS_printf(FILE* fp, const char* buffer)
{
/**************************************

View File

@ -24,6 +24,7 @@
#ifndef ISQL_IUTILS_PROTO_H
#define ISQL_IUTILS_PROTO_H
#include "../common/classes/MetaString.h"
#include "../common/classes/SafeArg.h"
#include <stdio.h>
@ -33,6 +34,7 @@ void IUTILS_msg_get(USHORT number, TEXT* msg,
const MsgFormat::SafeArg& args = MsgFormat::SafeArg());
void IUTILS_msg_get(USHORT number, USHORT size, TEXT* msg,
const MsgFormat::SafeArg& args = MsgFormat::SafeArg());
Firebird::string IUTILS_name_to_string(const Firebird::MetaString& name);
void IUTILS_printf(FILE*, const char*);
void IUTILS_printf2(FILE*, const char*, ...);
void IUTILS_put_errmsg(USHORT number, const MsgFormat::SafeArg& args);

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,7 @@
#include "../common/classes/fb_string.h"
#include <firebird/Interface.h>
#include "../isql/FrontendParser.h"
#include "../jrd/obj.h"
void SHOW_comments(bool force);
@ -36,7 +37,7 @@ void SHOW_grant_roles (const SCHAR*, bool*);
void SHOW_grant_roles2 (const SCHAR*, bool*, const TEXT*, bool);
void SHOW_print_metadata_text_blob(FILE*, ISC_QUAD*, bool escape_squote = false,
bool avoid_end_in_single_line_comment = false);
processing_state SHOW_metadata(const SCHAR* const*, SCHAR**);
processing_state SHOW_metadata(const FrontendParser::AnyShowNode& node);
void SHOW_read_owner();
const Firebird::string SHOW_trigger_action(SINT64);
processing_state SHOW_maps(bool extract, const SCHAR* map_name);

View File

@ -0,0 +1,621 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2024 Adriano dos Santos Fernandes <adrianosf at gmail.com>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#include "firebird.h"
#include "boost/test/unit_test.hpp"
#include "../FrontendParser.h"
#include <variant>
using namespace Firebird;
BOOST_AUTO_TEST_SUITE(ISqlSuite)
BOOST_AUTO_TEST_SUITE(FrontendParserSuite)
BOOST_AUTO_TEST_SUITE(FrontendParserTests)
BOOST_AUTO_TEST_CASE(ParseCommandTest)
{
const FrontendParser::Options parserOptions;
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"add", parserOptions)));
BOOST_TEST((std::get<FrontendParser::AddNode>(FrontendParser::parse(
"add table1", parserOptions)).tableName == "TABLE1"));
BOOST_TEST((std::get<FrontendParser::AddNode>(FrontendParser::parse(
"add \"table2\"", parserOptions)).tableName == "table2"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"blobdump", parserOptions)));
{
const auto blobDump1 = std::get<FrontendParser::BlobDumpViewNode>(FrontendParser::parse(
"blobdump 1:2 /tmp/blob.txt", parserOptions));
BOOST_TEST(blobDump1.blobId.gds_quad_high == 1);
BOOST_TEST(blobDump1.blobId.gds_quad_low == 2u);
BOOST_TEST(blobDump1.file.value() == "/tmp/blob.txt");
const auto blobDump2 = std::get<FrontendParser::BlobDumpViewNode>(FrontendParser::parse(
"blobdump 1:2 'C:\\A dir\\blob.txt'", parserOptions));
BOOST_TEST((blobDump2.file.value() == "C:\\A dir\\blob.txt"));
}
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"blobview", parserOptions)));
{
const auto blobView1 = std::get<FrontendParser::BlobDumpViewNode>(FrontendParser::parse(
"blobview 1:2", parserOptions));
BOOST_TEST(blobView1.blobId.gds_quad_high == 1);
BOOST_TEST(blobView1.blobId.gds_quad_low == 2u);
BOOST_TEST(!blobView1.file);
}
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"connect", parserOptions)));
{
const auto connect1 = std::get<FrontendParser::ConnectNode>(FrontendParser::parse(
"connect 'test.fdb'", parserOptions));
BOOST_TEST(connect1.args[0].getProcessedString() == "test.fdb");
const auto connect2 = std::get<FrontendParser::ConnectNode>(FrontendParser::parse(
"connect 'test.fdb' user user", parserOptions));
BOOST_TEST(connect2.args.size() == 3u);
}
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"copy", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"copy source destination", parserOptions)));
{
const auto copy1 = std::get<FrontendParser::CopyNode>(FrontendParser::parse(
"copy source \"destination\" localhost:/tmp/database.fdb", parserOptions));
BOOST_TEST((copy1.source == "SOURCE"));
BOOST_TEST((copy1.destination == "destination"));
BOOST_TEST(copy1.database == "localhost:/tmp/database.fdb");
}
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"create", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"create database", parserOptions)));
{
const auto createDatabase1 = std::get<FrontendParser::CreateDatabaseNode>(FrontendParser::parse(
"create database 'test.fdb'", parserOptions));
BOOST_TEST(createDatabase1.args[0].getProcessedString() == "test.fdb");
const auto createDatabase2 = std::get<FrontendParser::CreateDatabaseNode>(FrontendParser::parse(
"create database 'test.fdb' user user", parserOptions));
BOOST_TEST(createDatabase2.args.size() == 3u);
}
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"drop database x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::DropDatabaseNode>(FrontendParser::parse(
"drop database", parserOptions)));
BOOST_TEST(!std::get<FrontendParser::EditNode>(FrontendParser::parse(
"edit", parserOptions)).file);
BOOST_TEST(std::get<FrontendParser::EditNode>(FrontendParser::parse(
"edit /tmp/file.sql", parserOptions)).file.value() == "/tmp/file.sql");
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"exit x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::ExitNode>(FrontendParser::parse(
"exit", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"explain", parserOptions)));
BOOST_TEST(std::get<FrontendParser::ExplainNode>(FrontendParser::parse(
"explain select 1 from rdb$database", parserOptions)).query == "select 1 from rdb$database");
BOOST_TEST(!std::get<FrontendParser::HelpNode>(FrontendParser::parse(
"help", parserOptions)).command.has_value());
BOOST_TEST(std::get<FrontendParser::HelpNode>(FrontendParser::parse(
"help set", parserOptions)).command.value() == "SET");
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"help set x", parserOptions)));
BOOST_TEST(!std::get<FrontendParser::HelpNode>(FrontendParser::parse(
"?", parserOptions)).command.has_value());
BOOST_TEST(std::get<FrontendParser::HelpNode>(FrontendParser::parse(
"? set", parserOptions)).command.value() == "SET");
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"? set x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"input", parserOptions)));
BOOST_TEST(std::get<FrontendParser::InputNode>(FrontendParser::parse(
"input /tmp/file.sql", parserOptions)).file == "/tmp/file.sql");
BOOST_TEST(!std::get<FrontendParser::OutputNode>(FrontendParser::parse(
"output", parserOptions)).file);
BOOST_TEST(std::get<FrontendParser::OutputNode>(FrontendParser::parse(
"output /tmp/file.txt", parserOptions)).file.value() == "/tmp/file.txt");
BOOST_TEST(std::holds_alternative<FrontendParser::QuitNode>(FrontendParser::parse(
"quit", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"quit x", parserOptions)));
BOOST_TEST(!std::get<FrontendParser::ShellNode>(FrontendParser::parse(
"shell", parserOptions)).command);
BOOST_TEST(std::get<FrontendParser::ShellNode>(FrontendParser::parse(
"shell ls -l /tmp", parserOptions)).command.value() == "ls -l /tmp");
}
BOOST_AUTO_TEST_CASE(ParseSetTest)
{
const FrontendParser::Options parserOptions;
const auto parseSet = [&](const std::string_view text) {
return std::get<FrontendParser::AnySetNode>(FrontendParser::parse(text, parserOptions));
};
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"\"set\"", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::SetNode>(parseSet("set")));
BOOST_TEST(std::get<FrontendParser::SetAutoDdlNode>(parseSet(
"set auto")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetAutoDdlNode>(parseSet(
"set auto on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set auto off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetAutoDdlNode>(parseSet(
"set autoddl")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetAutoDdlNode>(parseSet(
"set autoddl on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set autoddl off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetAutoTermNode>(parseSet(
"set autoterm")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetAutoTermNode>(parseSet(
"set autoterm on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set autoterm off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetBailNode>(parseSet(
"set bail")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetBailNode>(parseSet(
"set bail on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set bail off x", parserOptions)));
BOOST_TEST((std::get<FrontendParser::SetBulkInsertNode>(parseSet(
"set bulk_insert insert into mytable (a, b) values (1, ?)")).statement ==
"insert into mytable (a, b) values (1, ?)"));
BOOST_TEST(std::get<FrontendParser::SetBlobDisplayNode>(parseSet(
"set blob")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetBlobDisplayNode>(parseSet(
"set blob on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set blob off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetBlobDisplayNode>(parseSet(
"set blobdisplay")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetBlobDisplayNode>(parseSet(
"set blobdisplay on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set blobdisplay off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetCountNode>(parseSet(
"set count")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetCountNode>(parseSet(
"set count on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set count off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetEchoNode>(parseSet(
"set echo")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetEchoNode>(parseSet(
"set echo on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set echo off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetExecPathDisplayNode>(parseSet(
"set exec_path_display")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetExecPathDisplayNode>(parseSet(
"set exec_path_display blr")).arg == "BLR"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set exec_path_display off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetExplainNode>(parseSet(
"set explain")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetExplainNode>(parseSet(
"set explain on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set explain off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetHeadingNode>(parseSet(
"set heading")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetHeadingNode>(parseSet(
"set heading on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set heading off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetKeepTranParamsNode>(parseSet(
"set keep_tran")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetKeepTranParamsNode>(parseSet(
"set keep_tran on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set keep_tran off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetKeepTranParamsNode>(parseSet(
"set keep_tran_params")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetKeepTranParamsNode>(parseSet(
"set keep_tran_params on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set keep_tran_params off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetListNode>(parseSet(
"set list")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetListNode>(parseSet(
"set list on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set list off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetLocalTimeoutNode>(parseSet(
"set local_timeout")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetLocalTimeoutNode>(parseSet(
"set local_timeout 80")).arg == "80"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set local_timeout 90 x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetMaxRowsNode>(parseSet(
"set maxrows")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetMaxRowsNode>(parseSet(
"set maxrows 80")).arg == "80"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set maxrows 90 x", parserOptions)));
BOOST_TEST(!std::get<FrontendParser::SetNamesNode>(parseSet(
"set names")).name.has_value());
BOOST_TEST((std::get<FrontendParser::SetNamesNode>(parseSet(
"set names utf8")).name == "UTF8"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set names utf8 x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetPerTableStatsNode>(parseSet(
"set per_tab")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetPerTableStatsNode>(parseSet(
"set per_tab on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set per_tab off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetPerTableStatsNode>(parseSet(
"set per_table_stats")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetPerTableStatsNode>(parseSet(
"set per_table_stats on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set per_table_stats off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetPlanNode>(parseSet(
"set plan")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetPlanNode>(parseSet(
"set plan on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set plan off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetPlanOnlyNode>(parseSet(
"set planonly")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetPlanOnlyNode>(parseSet(
"set planonly on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set planonly off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetMaxRowsNode>(parseSet(
"set rowcount")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetMaxRowsNode>(parseSet(
"set rowcount 80")).arg == "80"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set rowcount 90 x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set sql", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set sql dialect", parserOptions)));
BOOST_TEST((std::get<FrontendParser::SetSqlDialectNode>(parseSet(
"set sql dialect 3")).arg == "3"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set sql dialect 3 x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetSqldaDisplayNode>(parseSet(
"set sqlda_display")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetSqldaDisplayNode>(parseSet(
"set sqlda_display on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set sqlda_display off x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set sta", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set sta on", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetStatsNode>(parseSet(
"set stat")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetStatsNode>(parseSet(
"set stat on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set stat off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetStatsNode>(parseSet(
"set stats")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetStatsNode>(parseSet(
"set stats on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set stats off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetTermNode>(parseSet(
"set term")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetTermNode>(parseSet(
"set term !")).arg == "!"));
BOOST_TEST((std::get<FrontendParser::SetTermNode>(parseSet(
"set term Go")).arg == "Go"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set term a b", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetTermNode>(parseSet(
"set terminator")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetTermNode>(parseSet(
"set terminator !")).arg == "!"));
BOOST_TEST((std::get<FrontendParser::SetTermNode>(parseSet(
"set terminator Go")).arg == "Go"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set terminator a b", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetTimeNode>(parseSet(
"set time")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetTimeNode>(parseSet(
"set time on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set time off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetTransactionNode>(parseSet(
"set transaction")).statement == "set transaction");
BOOST_TEST(std::get<FrontendParser::SetTransactionNode>(parseSet(
"set transaction read committed")).statement == "set transaction read committed");
BOOST_TEST(std::get<FrontendParser::SetWarningsNode>(parseSet(
"set warning")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetWarningsNode>(parseSet(
"set warning on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set warning off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetWarningsNode>(parseSet(
"set warnings")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetWarningsNode>(parseSet(
"set warnings on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set warnings off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetWarningsNode>(parseSet(
"set wng")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetWarningsNode>(parseSet(
"set wng on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set wng off x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set width", parserOptions)));
BOOST_TEST((std::get<FrontendParser::SetWidthNode>(parseSet(
"set width x")).column == "X"));
BOOST_TEST(std::get<FrontendParser::SetWidthNode>(parseSet(
"set width x")).width.empty());
BOOST_TEST((std::get<FrontendParser::SetWidthNode>(parseSet(
"set width x 80")).column == "X"));
BOOST_TEST((std::get<FrontendParser::SetWidthNode>(parseSet(
"set width x 90")).width == "90"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set width x 90 y", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetWireStatsNode>(parseSet(
"set wire")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetWireStatsNode>(parseSet(
"set wire on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set wire off x", parserOptions)));
BOOST_TEST(std::get<FrontendParser::SetWireStatsNode>(parseSet(
"set wire_stats")).arg.empty());
BOOST_TEST((std::get<FrontendParser::SetWireStatsNode>(parseSet(
"set wire_stats on")).arg == "ON"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set wire_stats off x", parserOptions)));
// Engine commands.
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set decfloat", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set decfloat x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set generator", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set generator x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set role", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set role x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set statistics", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set statistics x", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set time zone", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set trusted", parserOptions)));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"set trusted x", parserOptions)));
}
BOOST_AUTO_TEST_CASE(ParseShowTest)
{
const FrontendParser::Options parserOptions;
const auto parseShow = [&](const std::string_view text) {
return std::get<FrontendParser::AnyShowNode>(FrontendParser::parse(text, parserOptions));
};
BOOST_TEST((std::holds_alternative<FrontendParser::ShowNode>(parseShow("show"))));
BOOST_TEST(!std::get<FrontendParser::ShowChecksNode>(parseShow(
"show check")).name);
BOOST_TEST((std::get<FrontendParser::ShowChecksNode>(parseShow(
"show check name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowCollationsNode>(parseShow(
"show collate")).name);
BOOST_TEST((std::get<FrontendParser::ShowCollationsNode>(parseShow(
"show collate name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowCollationsNode>(parseShow(
"show collation")).name);
BOOST_TEST((std::get<FrontendParser::ShowCollationsNode>(parseShow(
"show collation name")).name == "NAME"));
BOOST_TEST(std::holds_alternative<FrontendParser::ShowCommentsNode>(parseShow(
"show comments")));
BOOST_TEST(!std::get<FrontendParser::ShowDependenciesNode>(parseShow(
"show depen")).name);
BOOST_TEST((std::get<FrontendParser::ShowDependenciesNode>(parseShow(
"show depen name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowDomainsNode>(parseShow(
"show domain")).name);
BOOST_TEST((std::get<FrontendParser::ShowDomainsNode>(parseShow(
"show domain name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowExceptionsNode>(parseShow(
"show excep")).name);
BOOST_TEST((std::get<FrontendParser::ShowExceptionsNode>(parseShow(
"show excep name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowFiltersNode>(parseShow(
"show filter")).name);
BOOST_TEST((std::get<FrontendParser::ShowFiltersNode>(parseShow(
"show filter name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowFunctionsNode>(parseShow(
"show func")).name);
BOOST_TEST((std::get<FrontendParser::ShowFunctionsNode>(parseShow(
"show func name")).name == "NAME"));
BOOST_TEST((std::get<FrontendParser::ShowFunctionsNode>(parseShow(
"show func package.name")).package == "PACKAGE"));
BOOST_TEST((std::get<FrontendParser::ShowFunctionsNode>(parseShow(
"show func package.name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowIndexesNode>(parseShow(
"show ind")).name);
BOOST_TEST((std::get<FrontendParser::ShowIndexesNode>(parseShow(
"show index name")).name == "NAME"));
BOOST_TEST((std::get<FrontendParser::ShowIndexesNode>(parseShow(
"show indices name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowGeneratorsNode>(parseShow(
"show gen")).name);
BOOST_TEST((std::get<FrontendParser::ShowGeneratorsNode>(parseShow(
"show generator name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowMappingsNode>(parseShow(
"show map")).name);
BOOST_TEST((std::get<FrontendParser::ShowMappingsNode>(parseShow(
"show mapping name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowPackagesNode>(parseShow(
"show pack")).name);
BOOST_TEST((std::get<FrontendParser::ShowPackagesNode>(parseShow(
"show package name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowProceduresNode>(parseShow(
"show proc")).name);
BOOST_TEST((std::get<FrontendParser::ShowProceduresNode>(parseShow(
"show proc name")).name == "NAME"));
BOOST_TEST((std::get<FrontendParser::ShowProceduresNode>(parseShow(
"show proc package.name")).package == "PACKAGE"));
BOOST_TEST((std::get<FrontendParser::ShowProceduresNode>(parseShow(
"show proc package.name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowPublicationsNode>(parseShow(
"show pub")).name);
BOOST_TEST((std::get<FrontendParser::ShowPublicationsNode>(parseShow(
"show publication name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowRolesNode>(parseShow(
"show role")).name);
BOOST_TEST((std::get<FrontendParser::ShowRolesNode>(parseShow(
"show roles name")).name == "NAME"));
BOOST_TEST(std::holds_alternative<FrontendParser::InvalidNode>(FrontendParser::parse(
"show seccla", parserOptions)));
BOOST_TEST(!std::get<FrontendParser::ShowSecClassesNode>(parseShow(
"show seccla *")).detail);
BOOST_TEST(std::get<FrontendParser::ShowSecClassesNode>(parseShow(
"show seccla * detail")).detail);
BOOST_TEST(!std::get<FrontendParser::ShowSecClassesNode>(parseShow(
"show seccla * detail")).name);
BOOST_TEST((std::get<FrontendParser::ShowSecClassesNode>(parseShow(
"show secclasses name")).name == "NAME"));
BOOST_TEST((!std::get<FrontendParser::ShowSystemNode>(parseShow(
"show system")).objType.has_value()));
BOOST_TEST((!std::get<FrontendParser::ShowSystemNode>(parseShow(
"show system table")).objType == obj_relation));
BOOST_TEST((std::get<FrontendParser::ShowTablesNode>(parseShow(
"show table \"test\"")).name == "test"));
BOOST_TEST((std::get<FrontendParser::ShowTablesNode>(parseShow(
"show table \"te\"\"st\"")).name == "te\"st"));
BOOST_TEST(!std::get<FrontendParser::ShowTablesNode>(parseShow(
"show table")).name);
BOOST_TEST((std::get<FrontendParser::ShowTablesNode>(parseShow(
"show tables name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowTriggersNode>(parseShow(
"show trig")).name);
BOOST_TEST((std::get<FrontendParser::ShowTriggersNode>(parseShow(
"show triggers name")).name == "NAME"));
BOOST_TEST(!std::get<FrontendParser::ShowViewsNode>(parseShow(
"show view")).name);
BOOST_TEST((std::get<FrontendParser::ShowViewsNode>(parseShow(
"show views name")).name == "NAME"));
BOOST_TEST(std::holds_alternative<FrontendParser::ShowWireStatsNode>(parseShow(
"show wire_stat")));
BOOST_TEST(std::holds_alternative<FrontendParser::ShowWireStatsNode>(parseShow(
"show wire_statistics")));
}
BOOST_AUTO_TEST_SUITE_END() // FrontendParserTests
BOOST_AUTO_TEST_SUITE_END() // FrontendParserSuite
BOOST_AUTO_TEST_SUITE_END() // ISqlSuite

View File

@ -4,16 +4,3 @@
#define BOOST_TEST_MODULE ISqlTest
#include "boost/test/included/unit_test.hpp"
// TODO: Remove.
BOOST_AUTO_TEST_SUITE(IsqlSuite)
BOOST_AUTO_TEST_SUITE(DummySuite)
BOOST_AUTO_TEST_CASE(DummyTest)
{
}
BOOST_AUTO_TEST_SUITE_END() // DummySuite
BOOST_AUTO_TEST_SUITE_END() // IsqlSuite

View File

@ -898,7 +898,7 @@ private:
if (*control == *(CharType*) obj->getCanonicalChar(CHAR_GDML_SUBSTITUTE))
{
// Note: don't allow substitution characters larger than vector
CharType** const end_vector = vector + (((int) c < FB_NELEM(vector)) ? c : 0);
CharType** const end_vector = vector + ((static_cast<FB_SSIZE_T>(c) < static_cast<FB_SSIZE_T>(FB_NELEM(vector))) ? c : 0);
while (v <= end_vector)
*v++ = 0;
*end_vector = t;

View File

@ -367,7 +367,7 @@ namespace Jrd {
return;
fb_assert(tdbb);
lockAndReadHeader(tdbb, CRYPT_HDR_NOWAIT);
lockAndReadHeader(tdbb, CRYPT_HDR_NOWAIT | CRYPT_RELOAD_PLUGIN);
}
void CryptoManager::lockAndReadHeader(thread_db* tdbb, unsigned flags)
@ -407,9 +407,15 @@ namespace Jrd {
crypt = hdr->hdr_flags & Ods::hdr_encrypted;
process = hdr->hdr_flags & Ods::hdr_crypt_process;
if (flags & CRYPT_RELOAD_PLUGIN && cryptPlugin)
{
PluginManagerInterfacePtr()->releasePlugin(cryptPlugin);
cryptPlugin = NULL;
}
// tdbb w/o attachment comes when database is shutting down in the end of detachDatabase()
// the only needed here page is header, i.e. we can live w/o cryptPlugin
if ((crypt || process) && tdbb->getAttachment())
if ((crypt || process) && !cryptPlugin && tdbb->getAttachment())
{
ClumpletWriter hc(ClumpletWriter::UnTagged, hdr->hdr_page_size);
hdr.getClumplets(hc);
@ -418,56 +424,18 @@ namespace Jrd {
else
keyName = "";
if (!cryptPlugin)
loadPlugin(tdbb, hdr->hdr_crypt_plugin);
pluginName = hdr->hdr_crypt_plugin;
string valid;
calcValidation(valid, cryptPlugin);
if (hc.find(Ods::HDR_crypt_hash))
{
loadPlugin(tdbb, hdr->hdr_crypt_plugin);
pluginName = hdr->hdr_crypt_plugin;
string valid;
calcValidation(valid, cryptPlugin);
if (hc.find(Ods::HDR_crypt_hash))
{
hc.getString(hash);
if (hash != valid)
(Arg::Gds(isc_bad_crypt_key) << keyName).raise();
}
else
hash = valid;
hc.getString(hash);
if (hash != valid)
(Arg::Gds(isc_bad_crypt_key) << keyName).raise();
}
else
{
for (GetPlugins<IKeyHolderPlugin> keyControl(IPluginManager::TYPE_KEY_HOLDER, dbb.dbb_config);
keyControl.hasData(); keyControl.next())
{
// check does keyHolder want to provide a key for us
IKeyHolderPlugin* keyHolder = keyControl.plugin();
FbLocalStatus st;
int keyCallbackRc = keyHolder->keyCallback(&st, tdbb->getAttachment()->att_crypt_callback);
st.check();
if (!keyCallbackRc)
continue;
// validate a key
AutoPlugin<IDbCryptPlugin> crypt(checkFactory->makeInstance());
setDbInfo(crypt);
crypt->setKey(&st, 1, &keyHolder, keyName.c_str());
string valid;
calcValidation(valid, crypt);
if (hc.find(Ods::HDR_crypt_hash))
{
hc.getString(hash);
if (hash == valid)
{
// unload old plugin and set new one
PluginManagerInterfacePtr()->releasePlugin(cryptPlugin);
cryptPlugin = NULL;
cryptPlugin = crypt.release();
}
}
}
}
hash = valid;
}
if (cryptPlugin && (flags & CRYPT_HDR_INIT))

View File

@ -364,6 +364,7 @@ private:
void lockAndReadHeader(thread_db* tdbb, unsigned flags = 0);
static const unsigned CRYPT_HDR_INIT = 0x01;
static const unsigned CRYPT_HDR_NOWAIT = 0x02;
static const unsigned CRYPT_RELOAD_PLUGIN = 0x04;
void addClumplet(Firebird::string& value, Firebird::ClumpletReader& block, UCHAR tag);
void calcDigitalSignature(thread_db* tdbb, Firebird::string& signature, const class Header& hdr);

View File

@ -62,6 +62,7 @@
#include "../common/classes/FpeControl.h"
#include "../jrd/extds/ExtDS.h"
#include "../jrd/align.h"
#include "firebird/impl/types_pub.h"
#include <functional>
#include <cmath>
@ -2625,7 +2626,7 @@ dsc* evlCharToUuid(thread_db* tdbb, const SysFunction* function, const NestValue
Arg::Str(function->name));
}
for (int i = 0; i < Uuid::STR_LEN; ++i)
for (unsigned int i = 0; i < Uuid::STR_LEN; ++i)
{
if (i == 8 || i == 13 || i == 18 || i == 23)
{
@ -2709,7 +2710,7 @@ const char* extractParts[] =
const char* getPartName(int n)
{
if (n < 0 || n >= FB_NELEM(extractParts) || !extractParts[n])
if (n < 0 || static_cast<FB_SIZE_T>(n) >= FB_NELEM(extractParts) || !extractParts[n])
return "Unknown";
return extractParts[n];

View File

@ -314,7 +314,7 @@ void UserManagement::commit()
}
}
USHORT UserManagement::put(Auth::DynamicUserData* userData)
USHORT UserManagement::put(Auth::UserData* userData)
{
const FB_SIZE_T ret = commands.getCount();
if (ret > MAX_USHORT)
@ -379,7 +379,7 @@ void UserManagement::execute(USHORT id)
if (command->attr.entered() || command->op == Auth::ADDMOD_OPER)
{
Auth::StackUserData cmd;
Auth::UserData cmd;
cmd.op = Auth::DIS_OPER;
cmd.user.set(&statusWrapper, command->userName()->get());
check(&statusWrapper);
@ -614,7 +614,7 @@ RecordBuffer* UserManagement::getList(thread_db* tdbb, jrd_rel* relation)
for (FillSnapshot fillSnapshot(this); fillSnapshot.pos < managers.getCount(); ++fillSnapshot.pos)
{
Auth::StackUserData u;
Auth::UserData u;
u.op = Auth::DIS_OPER;
*ec = managers[fillSnapshot.pos].second->execute(currentWrapper, &u, &fillSnapshot);

View File

@ -59,7 +59,7 @@ public:
~UserManagement();
// store userData for DFW-time processing
USHORT put(Auth::DynamicUserData* userData);
USHORT put(Auth::UserData* userData);
// execute command with ID
void execute(USHORT id);
// commit transaction in security database
@ -71,7 +71,7 @@ public:
private:
thread_db* threadDbb;
Firebird::HalfStaticArray<Auth::DynamicUserData*, 8> commands;
Firebird::HalfStaticArray<Auth::UserData*, 8> commands;
typedef Firebird::Pair<Firebird::NonPooled<MetaName, Firebird::IManagement*> > Manager;
Firebird::ObjectsArray<Manager> managers;
Firebird::NoCaseString plugins;

View File

@ -49,8 +49,10 @@ const unsigned WORKER_IDLE_TIMEOUT = 60; // 1 minute
/// class WorkerStableAttachment
WorkerStableAttachment::WorkerStableAttachment(FbStatusVector* status, Jrd::Attachment* attachment) :
SysStableAttachment(attachment)
WorkerStableAttachment::WorkerStableAttachment(FbStatusVector* status, Jrd::Attachment* attachment,
WorkerAttachment* workers) :
SysStableAttachment(attachment),
m_workers(workers)
{
UserId user;
user.setUserName("<Worker>");
@ -69,6 +71,7 @@ WorkerStableAttachment::WorkerStableAttachment(FbStatusVector* status, Jrd::Atta
Monitoring::publishAttachment(tdbb);
initDone();
m_workers->incWorkers();
}
WorkerStableAttachment::~WorkerStableAttachment()
@ -76,16 +79,17 @@ WorkerStableAttachment::~WorkerStableAttachment()
fini();
}
WorkerStableAttachment* WorkerStableAttachment::create(FbStatusVector* status, Jrd::Database* dbb)
WorkerStableAttachment* WorkerStableAttachment::create(FbStatusVector* status, Database* dbb,
JProvider* provider, WorkerAttachment* workers)
{
Attachment* attachment = NULL;
try
{
attachment = Attachment::create(dbb, NULL);
attachment = Attachment::create(dbb, provider);
attachment->att_filename = dbb->dbb_filename;
attachment->att_flags |= ATT_worker;
WorkerStableAttachment* sAtt = FB_NEW WorkerStableAttachment(status, attachment);
WorkerStableAttachment* sAtt = FB_NEW WorkerStableAttachment(status, attachment, workers);
return sAtt;
}
catch (const Exception& ex)
@ -120,6 +124,8 @@ void WorkerStableAttachment::fini()
BackgroundContextHolder tdbb(dbb, attachment, &status_vector, FB_FUNCTION);
Monitoring::cleanupAttachment(tdbb);
dbb->dbb_extManager->closeAttachment(tdbb, attachment);
attachment->releaseLocks(tdbb);
LCK_fini(tdbb, LCK_OWNER_attachment);
@ -127,6 +133,8 @@ void WorkerStableAttachment::fini()
}
destroy(attachment);
m_workers->decWorkers();
}
/// class WorkerAttachment
@ -137,8 +145,7 @@ bool WorkerAttachment::m_shutdown = false;
WorkerAttachment::WorkerAttachment() :
m_idleAtts(*getDefaultMemoryPool()),
m_activeAtts(*getDefaultMemoryPool()),
m_cntUserAtts(0)
m_activeAtts(*getDefaultMemoryPool())
{
}
@ -175,6 +182,30 @@ void WorkerAttachment::decUserAtts(const PathName& dbname)
}
}
void WorkerAttachment::incWorkers()
{
fb_assert(Config::getServerMode() == MODE_SUPER);
MutexLockGuard guard(m_mutex, FB_FUNCTION);
++m_cntWorkers;
}
void WorkerAttachment::decWorkers()
{
fb_assert(Config::getServerMode() == MODE_SUPER);
MutexLockGuard guard(m_mutex, FB_FUNCTION);
if (--m_cntWorkers == 0)
m_noWorkers.notifyAll();
}
void WorkerAttachment::waitForWorkers()
{
MutexLockGuard guard(m_mutex, FB_FUNCTION);
while (m_cntWorkers != 0)
m_noWorkers.wait(m_mutex);
}
WorkerAttachment* WorkerAttachment::getByName(const PathName& dbname)
{
if (m_shutdown)
@ -228,13 +259,17 @@ void WorkerAttachment::shutdownDbb(Database* dbb)
if (Config::getServerMode() != MODE_SUPER)
return;
MutexLockGuard guard(m_mapMutex, FB_FUNCTION);
WorkerAttachment* item = NULL;
if (!m_map->get(dbb->dbb_filename, item))
return;
{
MutexLockGuard guard(m_mapMutex, FB_FUNCTION);
if (!m_map->get(dbb->dbb_filename, item))
return;
}
item->clear(false);
item->waitForWorkers();
}
StableAttachmentPart* WorkerAttachment::getAttachment(FbStatusVector* status, Database* dbb)
@ -299,7 +334,7 @@ StableAttachmentPart* WorkerAttachment::getAttachment(FbStatusVector* status, Da
MutexUnlockGuard unlock(item->m_mutex, FB_FUNCTION);
status->init();
sAtt = doAttach(status, dbb);
sAtt = item->doAttach(status, dbb);
if (!sAtt)
{
// log error ?
@ -433,18 +468,17 @@ StableAttachmentPart* WorkerAttachment::doAttach(FbStatusVector* status, Databas
{
StableAttachmentPart* sAtt = NULL;
AutoPlugin<JProvider> jInstance(JProvider::getInstance());
//jInstance->setDbCryptCallback(&status, tdbb->getAttachment()->att_crypt_callback);
if (Config::getServerMode() == MODE_SUPER)
sAtt = WorkerStableAttachment::create(status, dbb);
sAtt = WorkerStableAttachment::create(status, dbb, jInstance, this);
else
{
ClumpletWriter dpb(ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
dpb.insertString(isc_dpb_trusted_auth, DBA_USER_NAME);
dpb.insertInt(isc_dpb_worker_attach, 1);
AutoPlugin<JProvider> jInstance(JProvider::getInstance());
//jInstance->setDbCryptCallback(&status, tdbb->getAttachment()->att_crypt_callback);
JAttachment* jAtt = jInstance->attachDatabase(status, dbb->dbb_filename.c_str(),
dpb.getBufferLength(), dpb.getBuffer());
@ -456,6 +490,7 @@ StableAttachmentPart* WorkerAttachment::doAttach(FbStatusVector* status, Databas
{
sAtt->addRef(); // !!
sAtt->getHandle()->setIdleTimeout(WORKER_IDLE_TIMEOUT);
jInstance->addRef();
}
return sAtt;
@ -465,6 +500,15 @@ void WorkerAttachment::doDetach(FbStatusVector* status, StableAttachmentPart* sA
{
status->init();
AutoPlugin<JProvider> provider;
{
AttSyncLockGuard guard(*sAtt->getSync(), FB_FUNCTION);
Attachment* attachment = sAtt->getHandle();
if (attachment)
provider.reset(attachment->getProvider());
}
// if (att->att_flags & ATT_system)
if (Config::getServerMode() == MODE_SUPER)
{

View File

@ -31,6 +31,7 @@
#include "firebird.h"
#include "../common/classes/alloc.h"
#include "../common/classes/array.h"
#include "../common/classes/condition.h"
#include "../common/classes/fb_string.h"
#include "../common/classes/GenericMap.h"
#include "../common/classes/init.h"
@ -43,10 +44,13 @@
namespace Jrd
{
class WorkerAttachment;
class WorkerStableAttachment : public SysStableAttachment
{
public:
static WorkerStableAttachment* create(FbStatusVector* status, Jrd::Database* dbb);
static WorkerStableAttachment* create(FbStatusVector* status, Database* dbb, JProvider* provider,
WorkerAttachment* workers);
void fini();
@ -54,8 +58,10 @@ protected:
virtual void doOnIdleTimer(Firebird::TimerImpl* timer);
private:
explicit WorkerStableAttachment(FbStatusVector* status, Jrd::Attachment* att);
explicit WorkerStableAttachment(FbStatusVector* status, Jrd::Attachment* att, WorkerAttachment* workers);
virtual ~WorkerStableAttachment();
WorkerAttachment* m_workers;
};
@ -77,6 +83,8 @@ private:
class WorkerAttachment
{
friend class WorkerStableAttachment;
public:
explicit WorkerAttachment();
@ -93,10 +101,14 @@ public:
private:
static WorkerAttachment* getByName(const Firebird::PathName& dbname);
static Jrd::StableAttachmentPart* doAttach(FbStatusVector* status, Jrd::Database* dbb);
Jrd::StableAttachmentPart* doAttach(FbStatusVector* status, Jrd::Database* dbb);
static void doDetach(FbStatusVector* status, Jrd::StableAttachmentPart* sAtt);
void clear(bool checkRefs);
void incWorkers();
void decWorkers();
void waitForWorkers();
typedef Firebird::GenericMap<Firebird::Pair<Firebird::Left<Firebird::PathName, WorkerAttachment*> > >
MapDbIdToWorkAtts;
@ -109,7 +121,15 @@ private:
Firebird::HalfStaticArray<Jrd::StableAttachmentPart*, 8> m_idleAtts;
Firebird::SortedArray<Jrd::StableAttachmentPart*,
Firebird::InlineStorage<Jrd::StableAttachmentPart*, 8> > m_activeAtts;
int m_cntUserAtts;
// count of regular user attachments, used with non-shared Database
int m_cntUserAtts = 0;
// count of internal worker attachments, used with shared Database
int m_cntWorkers = 0;
// used to wait for "no internal workers" condition
Firebird::Condition m_noWorkers;
};
} // namespace Jrd

View File

@ -239,7 +239,7 @@ BlobFilter* BLF_lookup_internal_filter(thread_db* tdbb, SSHORT from, SSHORT to)
// Check for system defined filter
if (to == isc_blob_text && from >= 0 && from < FB_NELEM(filters))
if (to == isc_blob_text && from >= 0 && static_cast<FB_SIZE_T>(from) < FB_NELEM(filters))
{
BlobFilter* result = FB_NEW_POOL(*dbb->dbb_permanent) BlobFilter(*dbb->dbb_permanent);
result->blf_next = NULL;

View File

@ -3,16 +3,16 @@
*** DO NOT EDIT ***
TO CHANGE ANY INFORMATION IN HERE PLEASE
EDIT src/misc/writeBuildNum.sh
FORMAL BUILD NUMBER:553
FORMAL BUILD NUMBER:587
*/
#define PRODUCT_VER_STRING "6.0.0.553"
#define FILE_VER_STRING "WI-T6.0.0.553"
#define LICENSE_VER_STRING "WI-T6.0.0.553"
#define FILE_VER_NUMBER 6, 0, 0, 553
#define PRODUCT_VER_STRING "6.0.0.587"
#define FILE_VER_STRING "WI-T6.0.0.587"
#define LICENSE_VER_STRING "WI-T6.0.0.587"
#define FILE_VER_NUMBER 6, 0, 0, 587
#define FB_MAJOR_VER "6"
#define FB_MINOR_VER "0"
#define FB_REV_NO "0"
#define FB_BUILD_NO "553"
#define FB_BUILD_NO "587"
#define FB_BUILD_TYPE "T"
#define FB_BUILD_SUFFIX "Firebird 6.0 Initial"

View File

@ -2488,15 +2488,6 @@ bool CCH_write_all_shadows(thread_db* tdbb, Shadow* shadow, BufferDesc* bdb, Ods
PAG_add_header_entry(tdbb, header, HDR_root_file_name,
(USHORT) strlen((const char*) q), q);
jrd_file* next_file = shadow_file->fil_next;
if (next_file)
{
q = (UCHAR *) next_file->fil_string;
const SLONG last = next_file->fil_min_page - 1;
PAG_add_header_entry(tdbb, header, HDR_file, (USHORT) strlen((const char*) q), q);
PAG_add_header_entry(tdbb, header, HDR_last_page, sizeof(last), (const UCHAR*) &last);
}
header->hdr_flags |= hdr_active_shadow;
header->hdr_header.pag_pageno = bdb->bdb_page.getPageNum();
}

View File

@ -56,7 +56,7 @@
* BUGCHECK(291) took place. To avoid that issue, it was decided not to modify data
* in system transaction. An exception is RDB$FORMATS relation, which is always modified
* by transaction zero. Also an aspect of 'dirty' access from system transaction was
* taken into an account in add_file(), make_version() and create_index().
* taken into an account in make_version() and create_index().
*
*/
@ -449,7 +449,6 @@ private:
*
*==================================================================
*/
static bool add_file(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool add_shadow(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool delete_shadow(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool compute_security(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
@ -1272,7 +1271,6 @@ namespace
static const deferred_task task_table[] =
{
{ dfw_add_file, add_file },
{ dfw_add_shadow, add_shadow },
{ dfw_delete_index, modify_index },
{ dfw_delete_rfr, delete_rfr },
@ -1876,133 +1874,6 @@ void DFW_update_index(const TEXT* name, USHORT id, const SelectivityList& select
}
static bool add_file(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction)
{
/**************************************
*
* a d d _ f i l e
*
**************************************
*
* Functional description
* Add a file to a database.
* This file could be a regular database
* file or a shadow file. Either way we
* require exclusive access to the database.
*
**************************************/
USHORT section, shadow_number;
SLONG start, min_start;
SET_TDBB(tdbb);
Database* const dbb = tdbb->getDatabase();
switch (phase)
{
case 0:
CCH_release_exclusive(tdbb);
return false;
case 1:
case 2:
return true;
case 3:
if (!CCH_exclusive(tdbb, LCK_EX, WAIT_PERIOD, NULL))
raiseDatabaseInUseError(true);
return true;
case 4:
CCH_flush(tdbb, FLUSH_FINI, 0);
start = PageSpace::maxAlloc(dbb) + 1;
AutoRequest handle;
AutoRequest handle2;
// Check the file name for node name. This has already
// been done for shadows in add_shadow()
if (work->dfw_type != dfw_add_shadow) {
check_filename(work->dfw_name, true);
}
// User transaction may be safely used instead of system, cause
// we requested and got exclusive database access. AP-2008.
// get any files to extend into
FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) X IN RDB$FILES
WITH X.RDB$FILE_NAME EQ work->dfw_name.c_str()
// First expand the file name This has already been done
// for shadows in add_shadow ())
if (work->dfw_type != dfw_add_shadow)
{
MODIFY X USING
ISC_expand_filename(X.RDB$FILE_NAME, 0,
X.RDB$FILE_NAME, sizeof(X.RDB$FILE_NAME), false);
END_MODIFY
}
// Check the previous file length
FOR(REQUEST_HANDLE handle2 TRANSACTION_HANDLE transaction)
FIRST 1 Y IN RDB$FILES
WITH Y.RDB$SHADOW_NUMBER EQ X.RDB$SHADOW_NUMBER
AND Y.RDB$FILE_SEQUENCE NOT MISSING
SORTED BY DESCENDING Y.RDB$FILE_SEQUENCE
{
if (!Y.RDB$FILE_START.NULL && !Y.RDB$FILE_LENGTH.NULL)
{
min_start = Y.RDB$FILE_START + (Y.RDB$FILE_LENGTH ? Y.RDB$FILE_LENGTH : 1);
start = MAX(min_start, start);
}
}
END_FOR
// If there is no starting position specified, or if it is
// too low a value, raise the error.
if (X.RDB$FILE_START < start)
{
ERR_post(Arg::Gds(isc_file_starting_page_err) <<
Arg::Str(X.RDB$FILE_NAME) << Arg::Num(start));
}
start = X.RDB$FILE_START;
shadow_number = X.RDB$SHADOW_NUMBER;
if ((shadow_number &&
(section = SDW_add_file(tdbb, X.RDB$FILE_NAME, start, shadow_number))) ||
(section = PAG_add_file(tdbb, X.RDB$FILE_NAME, start)))
{
MODIFY X USING
X.RDB$FILE_SEQUENCE = section;
X.RDB$FILE_START = start;
END_MODIFY
}
END_FOR
if (section)
{
handle.reset();
section--;
FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) X IN RDB$FILES
WITH X.RDB$FILE_SEQUENCE EQ section
AND X.RDB$SHADOW_NUMBER EQ shadow_number
{
MODIFY X USING
X.RDB$FILE_LENGTH = start - X.RDB$FILE_START;
END_MODIFY
}
END_FOR
}
CCH_release_exclusive(tdbb);
break;
}
return false;
}
static bool add_shadow(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction)
{
/**************************************
@ -2053,11 +1924,11 @@ static bool add_shadow(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr
finished = false;
handle.reset();
FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction)
F IN RDB$FILES
WITH F.RDB$FILE_NAME EQ work->dfw_name.c_str()
F IN RDB$FILES WITH F.RDB$FILE_NAME EQ work->dfw_name.c_str()
{
expanded_fname = F.RDB$FILE_NAME;
ISC_expand_filename(expanded_fname, false);
MODIFY F USING
expanded_fname.copyTo(F.RDB$FILE_NAME, sizeof(F.RDB$FILE_NAME));
END_MODIFY
@ -2066,94 +1937,34 @@ static bool add_shadow(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr
{
if ((F.RDB$SHADOW_NUMBER == shadow->sdw_number) && !(shadow->sdw_flags & SDW_IGNORE))
{
if (F.RDB$FILE_FLAGS & FILE_shadow)
{
// This is the case of a bogus duplicate posted
// work when we added a multi-file shadow
finished = true;
}
else if (shadow->sdw_flags & (SDW_dumped))
{
/* Case of adding a file to a currently active
* shadow set.
* Note: as of 1995-January-31 there is
* no SQL syntax that supports this, but there
* may be GDML
*/
add_file(tdbb, 3, work, transaction);
add_file(tdbb, 4, work, transaction);
finished = true;
}
else
if (!(F.RDB$FILE_FLAGS & FILE_shadow))
{
// We cannot add a file to a shadow that is still
// in the process of being created.
raiseDatabaseInUseError(false);
}
// This is the case of a bogus duplicate posted
// work when we added a multi-file shadow
finished = true;
break;
}
}
}
END_FOR
if (finished)
return false;
// this file is part of a new shadow, so get all files for the shadow
// in order of the starting page for the file
// Note that for a multi-file shadow, we have several pieces of
// work posted (one dfw_add_shadow for each file). Rather than
// trying to cancel the other pieces of work we ignore them
// when they arrive in this routine.
sequence = 0;
min_page = 0;
shadow = NULL;
handle.reset();
FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction)
X IN RDB$FILES CROSS
Y IN RDB$FILES
OVER RDB$SHADOW_NUMBER
WITH X.RDB$FILE_NAME EQ expanded_fname.c_str()
SORTED BY Y.RDB$FILE_START
F IN RDB$FILES WITH F.RDB$FILE_NAME EQ expanded_fname.c_str()
{
// for the first file, create a brand new shadow; for secondary
// files that have a starting page specified, add a file
if (!sequence)
SDW_add(tdbb, Y.RDB$FILE_NAME, Y.RDB$SHADOW_NUMBER, Y.RDB$FILE_FLAGS);
else if (Y.RDB$FILE_START)
{
if (!shadow)
{
for (shadow = dbb->dbb_shadow; shadow; shadow = shadow->sdw_next)
{
if ((Y.RDB$SHADOW_NUMBER == shadow->sdw_number) &&
!(shadow->sdw_flags & SDW_IGNORE))
{
break;
}
}
}
SDW_add(tdbb, F.RDB$FILE_NAME, F.RDB$SHADOW_NUMBER, F.RDB$FILE_FLAGS);
if (!shadow)
BUGCHECK(203); // msg 203 shadow block not found for extend file
min_page = MAX((min_page + 1), (ULONG) Y.RDB$FILE_START);
add_sequence = SDW_add_file(tdbb, Y.RDB$FILE_NAME, min_page, Y.RDB$SHADOW_NUMBER);
}
// update the sequence number and bless the file entry as being good
if (!sequence || (Y.RDB$FILE_START && add_sequence))
{
MODIFY Y
Y.RDB$FILE_FLAGS |= FILE_shadow;
Y.RDB$FILE_SEQUENCE = sequence;
Y.RDB$FILE_START = min_page;
END_MODIFY
sequence++;
}
MODIFY F
F.RDB$FILE_FLAGS |= FILE_shadow;
END_MODIFY
}
END_FOR

View File

@ -171,7 +171,7 @@ void InternalConnection::attach(thread_db* tdbb)
memset(m_features, false, sizeof(m_features));
static const info_features features[] = ENGINE_FEATURES;
for (int i = 0; i < FB_NELEM(features); i++)
for (FB_SIZE_T i = 0; i < FB_NELEM(features); i++)
setFeature(features[i]);
}

View File

@ -811,7 +811,7 @@ ISC_STATUS filter_transliterate_text(USHORT action, BlobControl* control)
{
case isc_blob_filter_open:
case isc_blob_filter_create:
for (SSHORT i = 0; i < FB_NELEM(control->ctl_data); i++)
for (FB_SIZE_T i = 0; i < FB_NELEM(control->ctl_data); i++)
control->ctl_data[i] = 0;
aux = NULL;

View File

@ -633,6 +633,8 @@ void INF_database_info(thread_db* tdbb,
}
{
StrArray names;
SyncLockGuard sync(&dbb->dbb_sync, SYNC_SHARED, "INF_database_info");
for (const Jrd::Attachment* att = dbb->dbb_attachments; att; att = att->att_next)
@ -643,6 +645,13 @@ void INF_database_info(thread_db* tdbb,
{
const char* userName = user->getUserName().hasData() ?
user->getUserName().c_str() : "(Firebird Worker Thread)";
FB_SIZE_T pos;
if (names.find(userName, pos))
continue;
names.insert(pos, userName);
p = buffer;
const ULONG len = MIN(strlen(userName), MAX_UCHAR);
*p++ = static_cast<UCHAR>(len);

View File

@ -1619,7 +1619,7 @@ static void store_indices(thread_db* tdbb, USHORT odsVersion)
AutoRequest handle1, handle2, handle3;
for (int n = 0; n < SYSTEM_INDEX_COUNT; n++)
for (FB_SIZE_T n = 0; n < SYSTEM_INDEX_COUNT; n++)
{
const ini_idx_t* index = &indices[n];
const auto relation = MET_relation(tdbb, index->ini_idx_relid);

View File

@ -1301,7 +1301,7 @@ private:
static void check_database(thread_db* tdbb, bool async = false);
static void commit(thread_db*, jrd_tra*, const bool);
static bool drop_files(const jrd_file*);
static bool drop_file(Database*, const jrd_file*);
static void find_intl_charset(thread_db*, Jrd::Attachment*, const DatabaseOptions*);
static void init_database_lock(thread_db*);
static void run_commit_triggers(thread_db* tdbb, jrd_tra* transaction);
@ -1831,7 +1831,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
dbb->dbb_crypto_manager = FB_NEW_POOL(*dbb->dbb_permanent) CryptoManager(tdbb);
dbb->dbb_monitoring_data = FB_NEW_POOL(*dbb->dbb_permanent) MonitoringData(dbb);
PAG_init2(tdbb, 0);
PAG_init2(tdbb);
PAG_header(tdbb, false, newForceWrite);
dbb->dbb_page_manager.initTempPageSpace(tdbb);
dbb->dbb_crypto_manager->attach(tdbb, attachment);
@ -3552,11 +3552,9 @@ void JAttachment::internalDropDatabase(CheckStatusWrapper* user_status)
// This point on database is useless
// drop the files here
bool err = drop_files(file);
bool err = drop_file(dbb, file);
for (; shadow; shadow = shadow->sdw_next)
{
err = drop_files(shadow->sdw_file) || err;
}
err = drop_file(dbb, shadow->sdw_file) || err;
tdbb->setDatabase(NULL);
Database::destroy(dbb);
@ -6798,31 +6796,28 @@ static void commit(thread_db* tdbb, jrd_tra* transaction, const bool retaining_f
}
static bool drop_files(const jrd_file* file)
static bool drop_file(Database* dbb, const jrd_file* file)
{
/**************************************
*
* d r o p _ f i l e s
* d r o p _ f i l e
*
**************************************
*
* Functional description
* drop a linked list of files
* Drop a file.
*
**************************************/
FbLocalStatus status;
for (; file; file = file->fil_next)
if (unlink(file->fil_string))
{
if (unlink(file->fil_string))
{
ERR_build_status(&status, Arg::Gds(isc_io_error) << Arg::Str("unlink") <<
Arg::Str(file->fil_string) <<
Arg::Gds(isc_io_delete_err) << SYS_ERR(errno));
Database* dbb = GET_DBB();
PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
iscDbLogStatus(pageSpace->file->fil_string, &status);
}
ERR_build_status(&status, Arg::Gds(isc_io_error) << Arg::Str("unlink") <<
Arg::Str(file->fil_string) <<
Arg::Gds(isc_io_delete_err) << SYS_ERR(errno));
PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
iscDbLogStatus(pageSpace->file->fil_string, &status);
}
return status->getState() & IStatus::STATE_ERRORS ? true : false;

View File

@ -1782,7 +1782,6 @@ void MET_get_shadow_files(thread_db* tdbb, bool delete_files)
FOR(REQUEST_HANDLE handle) X IN RDB$FILES
WITH X.RDB$SHADOW_NUMBER NOT MISSING
AND X.RDB$SHADOW_NUMBER NE 0
AND X.RDB$FILE_SEQUENCE EQ 0
{
if ((X.RDB$FILE_FLAGS & FILE_shadow) && !(X.RDB$FILE_FLAGS & FILE_inactive))
{

View File

@ -24,6 +24,8 @@
#ifndef JRD_OBJ_H
#define JRD_OBJ_H
#include "../common/gdsassert.h"
// Object types used in RDB$DEPENDENCIES and RDB$USER_PRIVILEGES and stored in backup.
// Note: some values are hard coded in grant.gdl
// Keep existing constants unchanged.
@ -76,10 +78,11 @@ const ObjectType obj_index_condition = 37;
const ObjectType obj_type_MAX = 38;
// used in the parser only / no relation with obj_type_MAX (should be greater)
// not used in metadata / no relation with obj_type_MAX (should be greater)
const ObjectType obj_user_or_role= 100;
const ObjectType obj_parameter = 101;
const ObjectType obj_column = 102;
const ObjectType obj_publication = 103;
const ObjectType obj_any = 255;

View File

@ -530,8 +530,8 @@ static_assert(offsetof(struct header_page, hdr_data) == 136, "hdr_data offset mi
inline constexpr UCHAR HDR_end = 0;
inline constexpr UCHAR HDR_root_file_name = 1; // Original name of root file
inline constexpr UCHAR HDR_file = 2; // Secondary file
inline constexpr UCHAR HDR_last_page = 3; // Last logical page number of file
//inline constexpr UCHAR HDR_file = 2; // Secondary file
//inline constexpr UCHAR HDR_last_page = 3; // Last logical page number of file
inline constexpr UCHAR HDR_sweep_interval = 4; // Transactions between sweeps
inline constexpr UCHAR HDR_crypt_checksum = 5; // Checksum of critical crypt parameters
inline constexpr UCHAR HDR_difference_file = 6; // Delta file that is used during backup lock

View File

@ -922,7 +922,7 @@ public:
RecordSource* generate();
private:
RecordSource* process(const JoinType joinType);
RecordSource* process(StreamList* outerStreams = nullptr);
thread_db* const tdbb;
Optimizer* const optimizer;

View File

@ -94,15 +94,25 @@ OuterJoin::OuterJoin(thread_db* aTdbb, Optimizer* opt,
RecordSource* OuterJoin::generate()
{
const auto outerJoinRsb = process(OUTER_JOIN);
if (!optimizer->isFullJoin())
return outerJoinRsb;
{
fb_assert(optimizer->isLeftJoin());
return process();
}
// A FULL JOIN B is currently implemented similar to (A LEFT JOIN B) UNION ALL (B ANTI-JOIN A).
StreamList outerStreams;
const auto outerJoinRsb = process(&outerStreams);
// A FULL JOIN B is currently implemented similar to:
//
// (A LEFT JOIN B)
// UNION ALL
// (B LEFT JOIN A WHERE A.* IS NULL)
//
// See also FullOuterJoin class implementation.
//
// At this point we already have the first part -- (A LEFT JOIN B) -- ready,
// so just swap the sides and make an anti-join.
// so just swap the sides and make the second (inverted) join.
auto& outerStream = joinStreams[0];
auto& innerStream = joinStreams[1];
@ -131,15 +141,15 @@ RecordSource* OuterJoin::generate()
iter.reset(CMP_clone_node_opt(tdbb, csb, iter));
}
const auto antiJoinRsb = process(ANTI_JOIN);
const auto antiJoinRsb = process();
// Allocate and return the final join record source
return FB_NEW_POOL(getPool()) FullOuterJoin(csb, outerJoinRsb, antiJoinRsb);
return FB_NEW_POOL(getPool()) FullOuterJoin(csb, outerJoinRsb, antiJoinRsb, outerStreams);
}
RecordSource* OuterJoin::process(const JoinType joinType)
RecordSource* OuterJoin::process(StreamList* outerStreams)
{
BoolExprNode* boolean = nullptr;
@ -153,8 +163,7 @@ RecordSource* OuterJoin::process(const JoinType joinType)
{
fb_assert(!outerStream.rsb);
outerStream.rsb = optimizer->generateRetrieval(outerStream.number,
optimizer->isFullJoin() ? nullptr : sortPtr,
true, false, &boolean);
optimizer->isFullJoin() ? nullptr : sortPtr, true, false, &boolean);
}
else
{
@ -173,13 +182,15 @@ RecordSource* OuterJoin::process(const JoinType joinType)
boolean = optimizer->composeBoolean();
}
if (outerStreams)
outerStream.rsb->findUsedStreams(*outerStreams);
if (innerStream.number != INVALID_STREAM)
{
fb_assert(!innerStream.rsb);
// AB: the sort clause for the inner stream of an OUTER JOIN
// should never be used for the index retrieval
innerStream.rsb = optimizer->generateRetrieval(innerStream.number, nullptr,
false, (joinType == OUTER_JOIN) ? true : false);
innerStream.rsb = optimizer->generateRetrieval(innerStream.number, nullptr, false, true);
}
// Generate a parent filter record source for any remaining booleans that
@ -189,8 +200,7 @@ RecordSource* OuterJoin::process(const JoinType joinType)
// Allocate and return the join record source
return FB_NEW_POOL(getPool())
NestedLoopJoin(csb, outerStream.rsb, innerRsb, boolean, joinType);
return FB_NEW_POOL(getPool()) NestedLoopJoin(csb, outerStream.rsb, innerRsb, boolean);
};

View File

@ -1414,17 +1414,37 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
for (auto inversion : inversions)
{
const auto indexScratch = inversion->scratch;
// If the explicit plan doesn't mention this index, fake it as used
// thus excluding it from the cost-based algorithm. Otherwise,
// given this index is suitable for navigation, also mark it as used.
if ((indexScratch &&
(indexScratch->index->idx_runtime_flags & idx_plan_dont_use)) ||
(!customPlan && inversion == navigationCandidate))
if (const auto indexScratch = inversion->scratch)
{
inversion->used = true;
const auto idx = indexScratch->index;
// If the explicit plan doesn't mention this index, fake it as used
// thus excluding it from the cost-based algorithm. Otherwise,
// given this index is suitable for navigation, also mark it as used.
if (((idx->idx_runtime_flags & idx_plan_dont_use)) ||
(!customPlan && inversion == navigationCandidate))
{
inversion->used = true;
}
// If the index is conditional and its condition is also present in
// some other inversion as a boolean (it represents the OR operation),
// fake these other inversions as used, so that the full index scan would
// be preferred to multiple range scans. The cost-based algorithm below
// cannot handle it currently.
if (idx->idx_flags & idx_condition)
{
for (auto otherInversion : inversions)
{
if (otherInversion->boolean &&
idx->idx_condition->sameAs(otherInversion->boolean, true))
{
otherInversion->used = true;
}
}
}
}
}
@ -1460,11 +1480,9 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
if (!invCandidate)
invCandidate = FB_NEW_POOL(getPool()) InversionCandidate(getPool());
if (!currentInv->inversion && currentInv->scratch)
invCandidate->inversion = makeIndexScanNode(currentInv->scratch);
else
invCandidate->inversion = currentInv->inversion;
const auto inversionNode = (!currentInv->inversion && currentInv->scratch) ?
makeIndexScanNode(currentInv->scratch) : currentInv->inversion;
invCandidate->inversion = inversionNode;
invCandidate->dbkeyRanges.assign(currentInv->dbkeyRanges);
invCandidate->unique = currentInv->unique;
invCandidate->selectivity = currentInv->selectivity;
@ -1473,44 +1491,32 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
invCandidate->nonFullMatchedSegments = 0;
invCandidate->matchedSegments = currentInv->matchedSegments;
invCandidate->dependencies = currentInv->dependencies;
matches.clear();
for (const auto currentMatch : currentInv->matches)
{
if (!matches.exist(currentMatch))
matches.add(currentMatch);
if (!invCandidate->matches.exist(currentMatch))
invCandidate->matches.add(currentMatch);
}
if (currentInv->boolean)
if (const auto currentMatch = currentInv->boolean)
{
if (!matches.exist(currentInv->boolean))
matches.add(currentInv->boolean);
if (!invCandidate->matches.exist(currentMatch))
invCandidate->matches.add(currentMatch);
}
invCandidate->matches.join(matches);
matches.assign(invCandidate->matches);
if (customPlan)
continue;
return invCandidate;
}
// Look if a match is already used by previous matches.
bool anyMatchAlreadyUsed = false, matchUsedByNavigation = false;
if (currentInv->boolean)
if (!customPlan)
{
if (matches.exist(currentInv->boolean))
{
anyMatchAlreadyUsed = true;
// Look if a match is already used by previous matches
bool anyMatchAlreadyUsed = false, matchUsedByNavigation = false;
if (navigationCandidate &&
navigationCandidate->matches.exist(currentInv->boolean))
{
matchUsedByNavigation = true;
}
}
}
else
{
for (const auto currentMatch : currentInv->matches)
{
if (matches.exist(currentMatch))
@ -1526,29 +1532,49 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
break;
}
}
}
if (currentInv->boolean && matches.exist(currentInv->boolean))
anyMatchAlreadyUsed = true;
if (anyMatchAlreadyUsed && !customPlan)
{
currentInv->used = true;
if (matchUsedByNavigation)
continue;
// If a match on this index was already used by another
// index, add also the other matches from this index.
for (const auto currentMatch : currentInv->matches)
if (const auto currentMatch = currentInv->boolean)
{
if (!matches.exist(currentMatch))
matches.add(currentMatch);
if (matches.exist(currentMatch))
{
anyMatchAlreadyUsed = true;
if (navigationCandidate &&
navigationCandidate->matches.exist(currentMatch))
{
matchUsedByNavigation = true;
}
}
else if (matchUsedByNavigation)
anyMatchAlreadyUsed = false;
}
// Restart loop, because other indexes could also be excluded now.
restartLoop = true;
break;
// If some match was already used by another index, skip this index
if (anyMatchAlreadyUsed)
{
if (!matchUsedByNavigation)
{
// Add the other matches from this index
for (const auto currentMatch : currentInv->matches)
{
if (!matches.exist(currentMatch))
matches.add(currentMatch);
}
if (const auto currentMatch = currentInv->boolean)
{
if (!matches.exist(currentMatch))
matches.add(currentMatch);
}
}
// Restart loop, because other indexes could also be excluded now
currentInv->used = true;
restartLoop = true;
break;
}
}
if (!bestCandidate)
@ -1645,12 +1671,9 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
if (!invCandidate)
{
invCandidate = FB_NEW_POOL(getPool()) InversionCandidate(getPool());
if (!bestCandidate->inversion && bestCandidate->scratch) {
invCandidate->inversion = makeIndexScanNode(bestCandidate->scratch);
}
else {
invCandidate->inversion = bestCandidate->inversion;
}
const auto inversionNode = (!bestCandidate->inversion && bestCandidate->scratch) ?
makeIndexScanNode(bestCandidate->scratch) : bestCandidate->inversion;
invCandidate->inversion = inversionNode;
invCandidate->dbkeyRanges.assign(bestCandidate->dbkeyRanges);
invCandidate->unique = bestCandidate->unique;
invCandidate->selectivity = bestCandidate->selectivity;
@ -1661,30 +1684,26 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
invCandidate->dependencies = bestCandidate->dependencies;
invCandidate->condition = bestCandidate->condition;
for (FB_SIZE_T j = 0; j < bestCandidate->matches.getCount(); j++)
for (const auto bestMatch : bestCandidate->matches)
{
if (!matches.exist(bestCandidate->matches[j]))
matches.add(bestCandidate->matches[j]);
if (!invCandidate->matches.exist(bestMatch))
invCandidate->matches.add(bestMatch);
}
if (bestCandidate->boolean)
if (const auto bestMatch = bestCandidate->boolean)
{
if (!matches.exist(bestCandidate->boolean))
matches.add(bestCandidate->boolean);
if (!invCandidate->matches.exist(bestMatch))
invCandidate->matches.add(bestMatch);
}
matches.join(invCandidate->matches);
}
else if (!bestCandidate->condition)
{
if (!bestCandidate->inversion && bestCandidate->scratch)
{
invCandidate->inversion = composeInversion(invCandidate->inversion,
makeIndexScanNode(bestCandidate->scratch), InversionNode::TYPE_AND);
}
else
{
invCandidate->inversion = composeInversion(invCandidate->inversion,
bestCandidate->inversion, InversionNode::TYPE_AND);
}
const auto inversionNode = (!bestCandidate->inversion && bestCandidate->scratch) ?
makeIndexScanNode(bestCandidate->scratch) : bestCandidate->inversion;
invCandidate->inversion = composeInversion(invCandidate->inversion,
inversionNode, InversionNode::TYPE_AND);
invCandidate->dbkeyRanges.join(bestCandidate->dbkeyRanges);
invCandidate->unique = (invCandidate->unique || bestCandidate->unique);
invCandidate->selectivity = totalSelectivity;
@ -1697,15 +1716,17 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
for (const auto bestMatch : bestCandidate->matches)
{
if (!matches.exist(bestMatch))
matches.add(bestMatch);
if (!invCandidate->matches.exist(bestMatch))
invCandidate->matches.add(bestMatch);
}
if (bestCandidate->boolean)
if (const auto bestMatch = bestCandidate->boolean)
{
if (!matches.exist(bestCandidate->boolean))
matches.add(bestCandidate->boolean);
if (!invCandidate->matches.exist(bestMatch))
invCandidate->matches.add(bestMatch);
}
matches.join(invCandidate->matches);
}
if (invCandidate->unique)
@ -1739,10 +1760,13 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
invCandidate->cost += navigationCandidate->cost;
++invCandidate->indexes;
invCandidate->navigated = true;
}
if (invCandidate)
invCandidate->matches.join(matches);
for (const auto navMatch : navigationCandidate->matches)
{
if (!invCandidate->matches.exist(navMatch))
invCandidate->matches.add(navMatch);
}
}
return invCandidate;
}
@ -1754,6 +1778,16 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
if (boolean->nodFlags & ExprNode::FLAG_DEOPTIMIZE)
return false;
const auto idx = indexScratch->index;
if (idx->idx_flags & idx_condition)
{
// If index condition matches the boolean, this should not be
// considered a match. Full index scan will be used instead.
if (idx->idx_condition->sameAs(boolean, true))
return false;
}
const auto cmpNode = nodeAs<ComparativeBoolNode>(boolean);
const auto missingNode = nodeAs<MissingBoolNode>(boolean);
const auto listNode = nodeAs<InListBoolNode>(boolean);
@ -1788,16 +1822,6 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
ValueExprNode* value2 = (cmpNode && cmpNode->blrOp == blr_between) ?
cmpNode->arg3 : nullptr;
const auto idx = indexScratch->index;
if (idx->idx_flags & idx_condition)
{
// If index condition matches the boolean, this should not be
// considered a match. Full index scan will be used instead.
if (idx->idx_condition->sameAs(boolean, true))
return false;
}
if (idx->idx_flags & idx_expression)
{
// see if one side or the other is matchable to the index expression

View File

@ -41,11 +41,6 @@ namespace Jrd {
class jrd_file : public pool_alloc_rpt<SCHAR, type_fil>
{
public:
jrd_file* fil_next; // Next file in database
ULONG fil_min_page; // Minimum page number in file
ULONG fil_max_page; // Maximum page number in file
USHORT fil_sequence; // Sequence number of file
USHORT fil_fudge; // Fudge factor for page relocation
int fil_desc;
Firebird::Mutex fil_mutex;
USHORT fil_flags;
@ -69,11 +64,6 @@ public:
delete fil_ext_lock;
}
jrd_file* fil_next; // Next file in database
ULONG fil_min_page; // Minimum page number in file
ULONG fil_max_page; // Maximum page number in file
USHORT fil_sequence; // Sequence number of file
USHORT fil_fudge; // Fudge factor for page relocation
HANDLE fil_desc; // File descriptor
Firebird::RWLock* fil_ext_lock; // file extend lock
USHORT fil_flags;

View File

@ -36,7 +36,6 @@ namespace Ods {
struct pag;
}
int PIO_add_file(Jrd::thread_db*, Jrd::jrd_file*, const Firebird::PathName&, SLONG);
void PIO_close(Jrd::jrd_file*);
Jrd::jrd_file* PIO_create(Jrd::thread_db*, const Firebird::PathName&,
const bool, const bool);

View File

@ -132,7 +132,7 @@ using namespace Firebird;
static const mode_t MASK = 0660;
static jrd_file* seek_file(jrd_file*, BufferDesc*, FB_UINT64*, FbStatusVector*);
static bool seek_file(jrd_file*, BufferDesc*, FB_UINT64*, FbStatusVector*);
static jrd_file* setup_file(Database*, const PathName&, int, USHORT);
static void lockDatabaseFile(int& desc, const bool shareMode, const bool temporary,
const char* fileName, ISC_STATUS operation);
@ -149,42 +149,8 @@ static int raw_devices_unlink_database (const PathName&);
static int openFile(const Firebird::PathName&, const bool, const bool, const bool);
static void maybeCloseFile(int&);
int PIO_add_file(thread_db* tdbb, jrd_file* main_file, const PathName& file_name, SLONG start)
{
/**************************************
*
* P I O _ a d d _ f i l e
*
**************************************
*
* Functional description
* Add a file to an existing database. Return the sequence
* number of the new file. If anything goes wrong, return a
* sequence of 0.
* NOTE: This routine does not lock any mutexes on
* its own behalf. It is assumed that mutexes will
* have been locked before entry.
*
**************************************/
jrd_file* new_file = PIO_create(tdbb, file_name, false, false);
if (!new_file)
return 0;
new_file->fil_min_page = start;
USHORT sequence = 1;
jrd_file* file;
for (file = main_file; file->fil_next; file = file->fil_next)
++sequence;
file->fil_max_page = start - 1;
file->fil_next = new_file;
return sequence;
}
void PIO_close(jrd_file* main_file)
void PIO_close(jrd_file* file)
{
/**************************************
*
@ -199,13 +165,10 @@ void PIO_close(jrd_file* main_file)
*
**************************************/
for (jrd_file* file = main_file; file; file = file->fil_next)
if (file->fil_desc && file->fil_desc != -1)
{
if (file->fil_desc && file->fil_desc != -1)
{
close(file->fil_desc);
file->fil_desc = -1;
}
close(file->fil_desc);
file->fil_desc = -1;
}
}
@ -336,7 +299,7 @@ bool PIO_expand(const TEXT* file_name, USHORT file_length, TEXT* expanded_name,
}
void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, const USHORT pageSize)
void PIO_extend(thread_db* tdbb, jrd_file* file, const ULONG extPages, const USHORT pageSize)
{
/**************************************
*
@ -348,56 +311,46 @@ void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, cons
* Extend file by extPages pages of pageSize size.
*
**************************************/
fb_assert(extPages);
#if defined(HAVE_LINUX_FALLOC_H) && defined(HAVE_FALLOCATE)
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
ULONG leftPages = extPages;
for (jrd_file* file = main_file; file && leftPages; file = file->fil_next)
if (file->fil_flags & FIL_no_fast_extend)
return;
const ULONG filePages = PIO_get_number_of_pages(file, pageSize);
const ULONG extendBy = MIN(MAX_ULONG - filePages, extPages);
int r;
for (r = 0; r < IO_RETRY; r++)
{
const ULONG filePages = PIO_get_number_of_pages(file, pageSize);
const ULONG fileMaxPages = (file->fil_max_page == MAX_ULONG) ?
MAX_ULONG : file->fil_max_page - file->fil_min_page + 1;
if (filePages < fileMaxPages)
{
if (file->fil_flags & FIL_no_fast_extend)
return;
int err = fallocate(file->fil_desc, 0, filePages * pageSize, extendBy * pageSize);
if (err == 0)
break;
const ULONG extendBy = MIN(fileMaxPages - filePages + file->fil_fudge, leftPages);
err = errno;
if (SYSCALL_INTERRUPTED(err))
continue;
int r;
for (r = 0; r < IO_RETRY; r++)
{
int err = fallocate(file->fil_desc, 0, filePages * pageSize, extendBy * pageSize);
if (err == 0)
break;
if (err != EOPNOTSUPP && err != ENOSYS)
unix_error("fallocate", file, isc_io_write_err);
err = errno;
if (SYSCALL_INTERRUPTED(err))
continue;
file->fil_flags |= FIL_no_fast_extend;
return;
}
if (err != EOPNOTSUPP && err != ENOSYS)
unix_error("fallocate", file, isc_io_write_err);
file->fil_flags |= FIL_no_fast_extend;
return;
}
if (r == IO_RETRY)
{
if (r == IO_RETRY)
{
#ifdef DEV_BUILD
fprintf(stderr, "PIO_extend: retry count exceeded\n");
fflush(stderr);
fprintf(stderr, "PIO_extend: retry count exceeded\n");
fflush(stderr);
#endif
unix_error("fallocate_retry", file, isc_io_write_err);
}
leftPages -= extendBy;
}
unix_error("fallocate_retry", file, isc_io_write_err);
}
#else
main_file->fil_flags |= FIL_no_fast_extend;
file->fil_flags |= FIL_no_fast_extend;
#endif // fallocate present
// not implemented
@ -405,7 +358,7 @@ void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, cons
}
void PIO_flush(thread_db* tdbb, jrd_file* main_file)
void PIO_flush(thread_db* tdbb, jrd_file* file)
{
/**************************************
*
@ -422,15 +375,12 @@ void PIO_flush(thread_db* tdbb, jrd_file* main_file)
#ifndef SUPERSERVER_V2
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
MutexLockGuard guard(main_file->fil_mutex, FB_FUNCTION);
MutexLockGuard guard(file->fil_mutex, FB_FUNCTION);
for (jrd_file* file = main_file; file; file = file->fil_next)
if (file->fil_desc != -1)
{
if (file->fil_desc != -1)
{
// This really should be an error
fsync(file->fil_desc);
}
// This really should be an error
fsync(file->fil_desc);
}
#endif
}
@ -615,7 +565,7 @@ void PIO_header(thread_db* tdbb, UCHAR* address, int length)
static Firebird::InitInstance<ZeroBuffer> zeros;
USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* status_vector,
USHORT PIO_init_data(thread_db* tdbb, jrd_file* file, FbStatusVector* status_vector,
ULONG startPage, USHORT initPages)
{
/**************************************
@ -642,16 +592,14 @@ USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* statu
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
jrd_file* file = seek_file(main_file, &bdb, &offset, status_vector);
if (!file)
if (!seek_file(file, &bdb, &offset, status_vector))
return 0;
if (file->fil_min_page + 8 > startPage)
if (startPage < 8)
return 0;
USHORT leftPages = initPages;
const ULONG initBy = MIN(file->fil_max_page - startPage, leftPages);
const ULONG initBy = MIN(MAX_ULONG - startPage, leftPages);
if (initBy < leftPages)
leftPages = initBy;
@ -667,15 +615,16 @@ USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* statu
for (int r = 0; r < IO_RETRY; r++)
{
if (!(file = seek_file(file, &bdb, &offset, status_vector)))
return false;
if (!seek_file(file, &bdb, &offset, status_vector))
return 0;
if ((written = os_utils::pwrite(file->fil_desc, zero_buff, to_write, LSEEK_OFFSET_CAST offset)) == to_write)
break;
if (written < 0 && !SYSCALL_INTERRUPTED(errno))
return unix_error("write", file, isc_io_write_err, status_vector);
}
leftPages -= write_pages;
i += write_pages;
}
@ -812,7 +761,7 @@ bool PIO_read(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
for (i = 0; i < IO_RETRY; i++)
{
if (!(file = seek_file(file, bdb, &offset, status_vector)))
if (!seek_file(file, bdb, &offset, status_vector))
return false;
if ((bytes = os_utils::pread(file->fil_desc, page, size, LSEEK_OFFSET_CAST offset)) == size)
@ -864,7 +813,7 @@ bool PIO_write(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
for (i = 0; i < IO_RETRY; i++)
{
if (!(file = seek_file(file, bdb, &offset, status_vector)))
if (!seek_file(file, bdb, &offset, status_vector))
return false;
if ((bytes = os_utils::pwrite(file->fil_desc, page, size, LSEEK_OFFSET_CAST offset)) == size)
@ -881,8 +830,8 @@ bool PIO_write(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
}
static jrd_file* seek_file(jrd_file* file, BufferDesc* bdb, FB_UINT64* offset,
FbStatusVector* status_vector)
static bool seek_file(jrd_file* file, BufferDesc* bdb, FB_UINT64* offset,
FbStatusVector* status_vector)
{
/**************************************
*
@ -891,43 +840,29 @@ static jrd_file* seek_file(jrd_file* file, BufferDesc* bdb, FB_UINT64* offset,
**************************************
*
* Functional description
* Given a buffer descriptor block, find the appropriate
* file block and seek to the proper page in that file.
* Given a buffer descriptor block, seek to the proper page in that file.
*
**************************************/
BufferControl* bcb = bdb->bdb_bcb;
Database* dbb = bcb->bcb_database;
ULONG page = bdb->bdb_page.getPageNum();
for (;; file = file->fil_next)
{
if (!file) {
CORRUPT(158); // msg 158 database file not available
}
else if (page >= file->fil_min_page && page <= file->fil_max_page)
break;
}
BufferControl* const bcb = bdb->bdb_bcb;
const ULONG page = bdb->bdb_page.getPageNum();
if (file->fil_desc == -1)
{
unix_error("lseek", file, isc_io_access_err, status_vector);
return 0;
return false;
}
page -= file->fil_min_page - file->fil_fudge;
FB_UINT64 lseek_offset = page;
lseek_offset *= dbb->dbb_page_size;
lseek_offset *= bcb->bcb_page_size;
if (lseek_offset != (FB_UINT64) LSEEK_OFFSET_CAST lseek_offset)
{
unix_error("lseek", file, isc_io_32bit_exceeded_err, status_vector);
return 0;
return false;
}
*offset = lseek_offset;
return file;
return true;
}
@ -999,7 +934,6 @@ static jrd_file* setup_file(Database* dbb, const PathName& file_name, int desc,
{
file = FB_NEW_RPT(*dbb->dbb_permanent, file_name.length() + 1) jrd_file();
file->fil_desc = desc;
file->fil_max_page = MAX_ULONG;
file->fil_flags = flags;
strcpy(file->fil_string, file_name.c_str());
}

View File

@ -106,7 +106,7 @@ using namespace Firebird;
#define TEXT SCHAR
static bool maybeCloseFile(HANDLE&);
static jrd_file* seek_file(jrd_file*, BufferDesc*, OVERLAPPED*);
static bool seek_file(jrd_file*, BufferDesc*, OVERLAPPED*);
static jrd_file* setup_file(Database*, const Firebird::PathName&, HANDLE, USHORT);
static bool nt_error(const TEXT*, const jrd_file*, ISC_STATUS, FbStatusVector* const);
@ -121,39 +121,7 @@ static const DWORD g_dwExtraTempFlags = FILE_ATTRIBUTE_TEMPORARY |
FILE_FLAG_DELETE_ON_CLOSE;
int PIO_add_file(thread_db* tdbb, jrd_file* main_file, const Firebird::PathName& file_name, SLONG start)
{
/**************************************
*
* P I O _ a d d _ f i l e
*
**************************************
*
* Functional description
* Add a file to an existing database. Return the sequence
* number of the new file. If anything goes wrong, return a
* sequence of 0.
*
**************************************/
jrd_file* const new_file = PIO_create(tdbb, file_name, false, false);
if (!new_file)
return 0;
new_file->fil_min_page = start;
USHORT sequence = 1;
jrd_file* file;
for (file = main_file; file->fil_next; file = file->fil_next)
++sequence;
file->fil_max_page = start - 1;
file->fil_next = new_file;
return sequence;
}
void PIO_close(jrd_file* main_file)
void PIO_close(jrd_file* file)
{
/**************************************
*
@ -164,10 +132,7 @@ void PIO_close(jrd_file* main_file)
* Functional description
*
**************************************/
for (jrd_file* file = main_file; file; file = file->fil_next)
{
maybeCloseFile(file->fil_desc);
}
maybeCloseFile(file->fil_desc);
}
@ -251,7 +216,7 @@ bool PIO_expand(const TEXT* file_name, USHORT file_length, TEXT* expanded_name,
}
void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, const USHORT pageSize)
void PIO_extend(thread_db* tdbb, jrd_file* file, const ULONG extPages, const USHORT pageSize)
{
/**************************************
*
@ -263,6 +228,8 @@ void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, cons
* Extend file by extPages pages of pageSize size.
*
**************************************/
fb_assert(extPages);
// hvlad: prevent other reading\writing threads from changing file pointer.
// As we open file without FILE_FLAG_OVERLAPPED, ReadFile\WriteFile calls
// will change file pointer we set here and file truncation instead of file
@ -271,42 +238,30 @@ void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, cons
// and read\write activity performed simultaneously)
// if file have no extend lock it is better to not extend file than corrupt it
if (!main_file->fil_ext_lock)
if (!file->fil_ext_lock)
return;
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
FileExtendLockGuard extLock(main_file->fil_ext_lock, true);
FileExtendLockGuard extLock(file->fil_ext_lock, true);
ULONG leftPages = extPages;
for (jrd_file* file = main_file; file && leftPages; file = file->fil_next)
{
const ULONG filePages = PIO_get_number_of_pages(file, pageSize);
const ULONG fileMaxPages = (file->fil_max_page == MAX_ULONG) ?
MAX_ULONG : file->fil_max_page - file->fil_min_page + 1;
if (filePages < fileMaxPages)
{
const ULONG extendBy = MIN(fileMaxPages - filePages + file->fil_fudge, leftPages);
const ULONG filePages = PIO_get_number_of_pages(file, pageSize);
const ULONG extendBy = MIN(MAX_ULONG - filePages, extPages);
HANDLE hFile = file->fil_desc;
const HANDLE hFile = file->fil_desc;
LARGE_INTEGER newSize;
newSize.QuadPart = ((ULONGLONG) filePages + extendBy) * pageSize;
LARGE_INTEGER newSize;
newSize.QuadPart = ((ULONGLONG) filePages + extendBy) * pageSize;
const DWORD ret = SetFilePointer(hFile, newSize.LowPart, &newSize.HighPart, FILE_BEGIN);
if (ret == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
nt_error("SetFilePointer", file, isc_io_write_err, NULL);
}
if (!SetEndOfFile(hFile)) {
nt_error("SetEndOfFile", file, isc_io_write_err, NULL);
}
const DWORD ret = SetFilePointer(hFile, newSize.LowPart, &newSize.HighPart, FILE_BEGIN);
if (ret == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
nt_error("SetFilePointer", file, isc_io_write_err, NULL);
leftPages -= extendBy;
}
}
if (!SetEndOfFile(hFile))
nt_error("SetEndOfFile", file, isc_io_write_err, NULL);
}
void PIO_flush(thread_db* tdbb, jrd_file* main_file)
void PIO_flush(thread_db* tdbb, jrd_file* file)
{
/**************************************
*
@ -320,7 +275,7 @@ void PIO_flush(thread_db* tdbb, jrd_file* main_file)
**************************************/
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
for (jrd_file* file = main_file; file; file = file->fil_next)
if (file->fil_desc != INVALID_HANDLE_VALUE)
FlushFileBuffers(file->fil_desc);
}
@ -417,7 +372,7 @@ void PIO_header(thread_db* tdbb, UCHAR* address, int length)
static Firebird::InitInstance<ZeroBuffer> zeros;
USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* status_vector,
USHORT PIO_init_data(thread_db* tdbb, jrd_file* file, FbStatusVector* status_vector,
ULONG startPage, USHORT initPages)
{
/**************************************
@ -436,7 +391,7 @@ USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* statu
Database* const dbb = tdbb->getDatabase();
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
FileExtendLockGuard extLock(main_file->fil_ext_lock, false);
FileExtendLockGuard extLock(file->fil_ext_lock, false);
// Fake buffer, used in seek_file. Page space ID doesn't matter there
// as we already know file to work with
@ -444,16 +399,14 @@ USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* statu
bdb.bdb_page = PageNumber(0, startPage);
OVERLAPPED overlapped;
jrd_file* file = seek_file(main_file, &bdb, &overlapped);
if (!file)
if (!seek_file(file, &bdb, &overlapped))
return 0;
if (file->fil_min_page + 8 > startPage)
if (startPage < 8)
return 0;
USHORT leftPages = initPages;
const ULONG initBy = MIN(file->fil_max_page - startPage, leftPages);
const ULONG initBy = MIN(MAX_ULONG - startPage, leftPages);
if (initBy < leftPages)
leftPages = initBy;
@ -464,8 +417,8 @@ USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* statu
if (write_pages > leftPages)
write_pages = leftPages;
jrd_file* file1 = seek_file(main_file, &bdb, &overlapped);
fb_assert(file1 == file);
if (!seek_file(file, &bdb, &overlapped))
return 0;
const DWORD to_write = (DWORD) write_pages * dbb->dbb_page_size;
DWORD written;
@ -590,7 +543,7 @@ bool PIO_read(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
FileExtendLockGuard extLock(file->fil_ext_lock, false);
OVERLAPPED overlapped;
if (!(file = seek_file(file, bdb, &overlapped)))
if (!seek_file(file, bdb, &overlapped))
return false;
HANDLE desc = file->fil_desc;
@ -625,14 +578,12 @@ bool PIO_read_ahead(thread_db* tdbb,
**************************************
*
* Functional description
* Read a contiguous set of pages. The only
* tricky part is to segment the I/O when crossing
* file boundaries.
* Read a contiguous set of pages.
*
**************************************/
OVERLAPPED overlapped, *overlapped_ptr;
Database* const dbb = tdbb->getDatabase();
const auto dbb = tdbb->getDatabase();
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
@ -647,60 +598,45 @@ bool PIO_read_ahead(thread_db* tdbb,
piob->piob_flags = 0;
}
// Setup up a dummy buffer descriptor block for seeking file
BufferDesc bdb;
while (pages)
bdb.bdb_dbb = dbb;
bdb.bdb_page = start_page;
const jrd_file* const file = dbb->dbb_file;
if (!seek_file(file, &bdb, status_vector, overlapped_ptr, &overlapped_ptr))
return false;
const HANDLE desc = file->fil_desc;
const DWORD length = pages * dbb->dbb_page_size;
DWORD actual_length;
if (ReadFile(desc, buffer, length, &actual_length, overlapped_ptr) &&
actual_length == length)
{
// Setup up a dummy buffer descriptor block for seeking file.
bdb.bdb_dbb = dbb;
bdb.bdb_page = start_page;
jrd_file* file = seek_file(dbb->dbb_file, &bdb, status_vector, overlapped_ptr, &overlapped_ptr);
if (!file)
return false;
// Check that every page within the set resides in the same database
// file. If not read what you can and loop back for the rest.
DWORD segmented_length = 0;
while (pages && start_page >= file->fil_min_page && start_page <= file->fil_max_page)
{
segmented_length += dbb->dbb_page_size;
++start_page;
--pages;
}
HANDLE desc = file->fil_desc;
DWORD actual_length;
if (ReadFile(desc, buffer, segmented_length, &actual_length, overlapped_ptr) &&
actual_length == segmented_length)
{
if (piob && !pages)
piob->piob_flags = PIOB_success;
}
else if (piob && !pages)
{
piob->piob_flags = PIOB_pending;
piob->piob_desc = reinterpret_cast<SLONG>(desc);
piob->piob_file = file;
piob->piob_io_length = segmented_length;
}
else if (!GetOverlappedResult(desc, overlapped_ptr, &actual_length, TRUE) ||
actual_length != segmented_length)
{
if (piob)
piob->piob_flags = PIOB_error;
release_io_event(file, overlapped_ptr);
return nt_error("GetOverlappedResult", file, isc_io_read_err, status_vector);
}
if (!piob || (piob->piob_flags & (PIOB_success | PIOB_error)))
release_io_event(file, overlapped_ptr);
buffer += segmented_length;
if (piob)
piob->piob_flags = PIOB_success;
}
else if (piob)
{
piob->piob_flags = PIOB_pending;
piob->piob_desc = reinterpret_cast<SLONG>(desc);
piob->piob_file = file;
piob->piob_io_length = segmented_length;
}
else if (!GetOverlappedResult(desc, overlapped_ptr, &actual_length, TRUE) ||
actual_length != length)
{
if (piob)
piob->piob_flags = PIOB_error;
release_io_event(file, overlapped_ptr);
return nt_error("GetOverlappedResult", file, isc_io_read_err, status_vector);
}
if (!piob || (piob->piob_flags & (PIOB_success | PIOB_error)))
release_io_event(file, overlapped_ptr);
return true;
}
@ -767,8 +703,7 @@ bool PIO_write(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
FileExtendLockGuard extLock(file->fil_ext_lock, false);
OVERLAPPED overlapped;
file = seek_file(file, bdb, &overlapped);
if (!file)
if (!seek_file(file, bdb, &overlapped))
return false;
HANDLE desc = file->fil_desc;
@ -813,9 +748,7 @@ ULONG PIO_get_number_of_pages(const jrd_file* file, const USHORT pagesize)
}
static jrd_file* seek_file(jrd_file* file,
BufferDesc* bdb,
OVERLAPPED* overlapped)
static bool seek_file(jrd_file* file, BufferDesc* bdb, OVERLAPPED* overlapped)
{
/**************************************
*
@ -824,24 +757,11 @@ static jrd_file* seek_file(jrd_file* file,
**************************************
*
* Functional description
* Given a buffer descriptor block, find the appropriate
* file block and seek to the proper page in that file.
* Given a buffer descriptor block, seek to the proper page in that file.
*
**************************************/
BufferControl *bcb = bdb->bdb_bcb;
ULONG page = bdb->bdb_page.getPageNum();
for (;; file = file->fil_next)
{
if (!file) {
CORRUPT(158); // msg 158 database file not available
}
else if (page >= file->fil_min_page && page <= file->fil_max_page) {
break;
}
}
page -= file->fil_min_page - file->fil_fudge;
BufferControl* const bcb = bdb->bdb_bcb;
const ULONG page = bdb->bdb_page.getPageNum();
LARGE_INTEGER liOffset;
liOffset.QuadPart = UInt32x32To64((DWORD) page, (DWORD) bcb->bcb_page_size);
@ -854,7 +774,7 @@ static jrd_file* seek_file(jrd_file* file,
ThreadSync* thd = ThreadSync::getThread(FB_FUNCTION);
overlapped->hEvent = thd->getIOEvent();
return file;
return true;
}
@ -876,7 +796,6 @@ static jrd_file* setup_file(Database* dbb, const Firebird::PathName& file_name,
{
file = FB_NEW_RPT(*dbb->dbb_permanent, file_name.length() + 1) jrd_file();
file->fil_desc = desc;
file->fil_max_page = MAX_ULONG;
file->fil_flags = flags;
strcpy(file->fil_string, file_name.c_str());

View File

@ -364,115 +364,6 @@ namespace
} // namespace
USHORT PAG_add_file(thread_db* tdbb, const TEXT* file_name, SLONG start)
{
/**************************************
*
* P A G _ a d d _ f i l e
*
**************************************
*
* Functional description
* Add a file to the current database. Return the sequence number for the new file.
*
**************************************/
SET_TDBB(tdbb);
ensureDbWritable(tdbb);
const auto dbb = tdbb->getDatabase();
// Find current last file
PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
jrd_file* file = pageSpace->file;
while (file->fil_next) {
file = file->fil_next;
}
// Verify database file path against DatabaseAccess entry of firebird.conf
if (!JRD_verify_database_access(file_name))
{
string fileName(file_name);
ISC_systemToUtf8(fileName);
ERR_post(Arg::Gds(isc_conf_access_denied) << Arg::Str("additional database file") <<
Arg::Str(fileName));
}
// Create the file. If the sequence number comes back zero, it didn't work, so punt
const USHORT sequence = PIO_add_file(tdbb, pageSpace->file, file_name, start);
if (!sequence)
return 0;
// Create header page for new file
jrd_file* next = file->fil_next;
WIN window(DB_PAGE_SPACE, next->fil_min_page);
header_page* header = (header_page*) CCH_fake(tdbb, &window, 1);
header->hdr_header.pag_type = pag_header;
header->hdr_sequence = sequence;
header->hdr_page_size = dbb->dbb_page_size;
header->hdr_data[0] = HDR_end;
header->hdr_end = HDR_SIZE;
next->fil_sequence = sequence;
#ifdef SUPPORT_RAW_DEVICES
// The following lines (taken from PAG_format_header) are needed to identify
// this file in raw_devices_validate_database as a valid database attachment.
*(ISC_TIMESTAMP*) header->hdr_creation_date = TimeZoneUtil::getCurrentGmtTimeStamp().utc_timestamp;
// should we include milliseconds or not?
//TimeStamp::round_time(header->hdr_creation_date->timestamp_time, 0);
header->hdr_ods_version = ODS_VERSION | ODS_FIREBIRD_FLAG;
DbImplementation::current.store(header);
header->hdr_ods_minor = ODS_CURRENT;
if (dbb->dbb_flags & DBB_DB_SQL_dialect_3)
header->hdr_flags |= hdr_SQL_dialect_3;
#endif
header->hdr_header.pag_pageno = window.win_page.getPageNum();
// It's header, never encrypted
PIO_write(tdbb, pageSpace->file, window.win_bdb, window.win_buffer, tdbb->tdbb_status_vector);
CCH_RELEASE(tdbb, &window);
next->fil_fudge = 1;
// Update the previous header page to point to new file
file->fil_fudge = 0;
window.win_page = file->fil_min_page;
header = (header_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_header);
if (!file->fil_min_page)
CCH_MARK_MUST_WRITE(tdbb, &window);
else
CCH_MARK(tdbb, &window);
--start;
if (file->fil_min_page)
{
PAG_add_header_entry(tdbb, header, HDR_file, static_cast<USHORT>(strlen(file_name)),
reinterpret_cast<const UCHAR*>(file_name));
PAG_add_header_entry(tdbb, header, HDR_last_page, sizeof(SLONG), (UCHAR*) &start);
}
else
{
storeClump(tdbb, HDR_file, static_cast<USHORT>(strlen(file_name)),
reinterpret_cast<const UCHAR*>(file_name));
storeClump(tdbb, HDR_last_page, sizeof(SLONG), (UCHAR*) &start);
}
header->hdr_header.pag_pageno = window.win_page.getPageNum();
// It's header, never encrypted
PIO_write(tdbb, pageSpace->file, window.win_bdb, window.win_buffer, tdbb->tdbb_status_vector);
CCH_RELEASE(tdbb, &window);
if (file->fil_min_page)
file->fil_fudge = 1;
return sequence;
}
void PAG_add_header_entry(thread_db* tdbb, header_page* header,
USHORT type, USHORT len, const UCHAR* entry)
{
@ -1134,8 +1025,7 @@ void PAG_header(thread_db* tdbb, bool info, const TriState newForceWrite)
// Ensure the file-level FW mode matches the actual FW mode in the database
const auto pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
for (jrd_file* file = pageSpace->file; file; file = file->fil_next)
PIO_force_write(file, forceWrite && !readOnly);
PIO_force_write(pageSpace->file, forceWrite && !readOnly);
if (dbb->dbb_backup_manager->getState() != Ods::hdr_nbak_normal)
dbb->dbb_backup_manager->setForcedWrites(forceWrite);
@ -1310,7 +1200,7 @@ void PAG_init(thread_db* tdbb)
}
void PAG_init2(thread_db* tdbb, USHORT shadow_number)
void PAG_init2(thread_db* tdbb)
{
/**************************************
*
@ -1319,128 +1209,40 @@ void PAG_init2(thread_db* tdbb, USHORT shadow_number)
**************************************
*
* Functional description
* Perform second phase of page initialization -- the eternal
* search for additional files.
* Read and apply the database header options.
*
**************************************/
SET_TDBB(tdbb);
const auto dbb = tdbb->getDatabase();
FbStatusVector* status = tdbb->tdbb_status_vector;
WIN window(HEADER_PAGE_NUMBER);
const auto header = (header_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_header);
// allocate a spare buffer which is large enough,
// and set up to release it in case of error. Align
// the temporary page buffer for raw disk access.
Array<UCHAR> temp;
UCHAR* const temp_page = temp.getAlignedBuffer(dbb->dbb_page_size, dbb->getIOBlockSize());
PageSpace* const pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
jrd_file* file = pageSpace->file;
if (shadow_number)
for (const UCHAR* p = header->hdr_data; *p != HDR_end; p += 2 + p[1])
{
Shadow* shadow = dbb->dbb_shadow;
for (; shadow; shadow = shadow->sdw_next)
switch (*p)
{
if (shadow->sdw_number == shadow_number)
{
file = shadow->sdw_file;
break;
}
}
if (!shadow)
BUGCHECK(161); // msg 161 shadow block not found
}
USHORT sequence = 1;
WIN window(DB_PAGE_SPACE, -1);
// Loop thru files and header pages until everything is open
while (true)
{
window.win_page = file->fil_min_page;
ULONG last_page = 0;
BufferDesc temp_bdb(dbb->dbb_bcb);
// note that we do not have to get a read lock on
// the header page (except for header page 0) because
// the only time it will be modified is when adding a file,
// which must be done with an exclusive lock on the database --
// if this changes, this policy will have to be reevaluated;
// at any rate there is a problem with getting a read lock
// because the corresponding page in the main database file may not exist
if (!file->fil_min_page)
CCH_FETCH(tdbb, &window, LCK_read, pag_header);
header_page* header = (header_page*) temp_page;
temp_bdb.bdb_buffer = (pag*) header;
temp_bdb.bdb_page = window.win_page;
// Read the required page into the local buffer
// It's header, never encrypted
PIO_read(tdbb, file, &temp_bdb, (PAG) header, status);
if (shadow_number && !file->fil_min_page)
CCH_RELEASE(tdbb, &window);
PathName nextFileName;
for (const UCHAR* p = header->hdr_data; *p != HDR_end; p += 2 + p[1])
{
switch (*p)
{
case HDR_file:
nextFileName.assign(p + 2, p[1]);
break;
case HDR_last_page:
fb_assert(p[1] == sizeof(last_page));
memcpy(&last_page, p + 2, sizeof(last_page));
break;
case HDR_sweep_interval:
fb_assert(p[1] == sizeof(SLONG));
memcpy(&dbb->dbb_sweep_interval, p + 2, sizeof(SLONG));
break;
case HDR_db_guid:
fb_assert(p[1] == Guid::SIZE);
dbb->dbb_guid = Guid(p + 2);
break;
case HDR_repl_seq:
fb_assert(p[1] == sizeof(FB_UINT64));
memcpy(&dbb->dbb_repl_sequence, p + 2, sizeof(FB_UINT64));
break;
}
}
if (!shadow_number && !file->fil_min_page)
CCH_RELEASE(tdbb, &window);
if (file->fil_min_page)
file->fil_fudge = 1;
if (nextFileName.isEmpty())
case HDR_sweep_interval:
fb_assert(p[1] == sizeof(SLONG));
memcpy(&dbb->dbb_sweep_interval, p + 2, sizeof(SLONG));
break;
// Verify database file path against DatabaseAccess entry of firebird.conf
if (!JRD_verify_database_access(nextFileName))
{
ISC_systemToUtf8(nextFileName);
ERR_post(Arg::Gds(isc_conf_access_denied) << Arg::Str("additional database file") <<
Arg::Str(nextFileName));
case HDR_db_guid:
fb_assert(p[1] == Guid::SIZE);
dbb->dbb_guid = Guid(p + 2);
break;
case HDR_repl_seq:
fb_assert(p[1] == sizeof(FB_UINT64));
memcpy(&dbb->dbb_repl_sequence, p + 2, sizeof(FB_UINT64));
break;
default:
break;
}
file->fil_next = PIO_open(tdbb, nextFileName, nextFileName);
file->fil_max_page = last_page;
file = file->fil_next;
file->fil_min_page = last_page + 1;
file->fil_sequence = sequence++;
}
CCH_RELEASE(tdbb, &window);
}
@ -1627,14 +1429,10 @@ void PAG_set_force_write(thread_db* tdbb, bool flag)
CCH_RELEASE(tdbb, &window);
PageSpace* const pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
for (jrd_file* file = pageSpace->file; file; file = file->fil_next)
PIO_force_write(file, flag);
PIO_force_write(pageSpace->file, flag);
for (Shadow* shadow = dbb->dbb_shadow; shadow; shadow = shadow->sdw_next)
{
for (jrd_file* file = shadow->sdw_file; file; file = file->fil_next)
PIO_force_write(file, flag);
}
PIO_force_write(shadow->sdw_file, flag);
if (dbb->dbb_backup_manager->getState() != Ods::hdr_nbak_normal)
dbb->dbb_backup_manager->setForcedWrites(flag);
@ -1898,13 +1696,7 @@ PageSpace::~PageSpace()
if (file)
{
PIO_close(file);
while (file)
{
jrd_file* next = file->fil_next;
delete file;
file = next;
}
delete file;
}
}
@ -1917,15 +1709,7 @@ ULONG PageSpace::actAlloc()
*
**************************************/
// Traverse the linked list of files and add up the
// number of pages in each file
const USHORT pageSize = dbb->dbb_page_size;
ULONG tot_pages = 0;
for (const jrd_file* f = file; f != NULL; f = f->fil_next) {
tot_pages += PIO_get_number_of_pages(f, pageSize);
}
return tot_pages;
return PIO_get_number_of_pages(file, dbb->dbb_page_size);
}
ULONG PageSpace::actAlloc(const Database* dbb)
@ -1942,17 +1726,7 @@ ULONG PageSpace::maxAlloc()
* Compute last physically allocated page of database.
*
**************************************/
const USHORT pageSize = dbb->dbb_page_size;
const jrd_file* f = file;
ULONG nPages = PIO_get_number_of_pages(f, pageSize);
while (f->fil_next && nPages == f->fil_max_page - f->fil_min_page + 1 + f->fil_fudge)
{
f = f->fil_next;
nPages = PIO_get_number_of_pages(f, pageSize);
}
nPages += f->fil_min_page - f->fil_fudge;
const ULONG nPages = PIO_get_number_of_pages(file, dbb->dbb_page_size);
if (maxPageNumber < nPages)
maxPageNumber = nPages;
@ -1968,15 +1742,7 @@ ULONG PageSpace::maxAlloc(const Database* dbb)
bool PageSpace::onRawDevice() const
{
#ifdef SUPPORT_RAW_DEVICES
for (const jrd_file* f = file; f != NULL; f = f->fil_next)
{
if (f->fil_flags & FIL_raw_device)
return true;
}
#endif
return false;
return (file->fil_flags & FIL_raw_device) != 0;
}
ULONG PageSpace::lastUsedPage()

View File

@ -37,7 +37,6 @@ namespace Ods {
struct header_page;
}
USHORT PAG_add_file(Jrd::thread_db* tdbb, const TEXT*, SLONG);
void PAG_add_header_entry(Jrd::thread_db* tdbb, Ods::header_page*, USHORT, USHORT, const UCHAR*);
bool PAG_replace_entry_first(Jrd::thread_db* tdbb, Ods::header_page*, USHORT, USHORT, const UCHAR*);
Ods::pag* PAG_allocate_pages(Jrd::thread_db* tdbb, Jrd::win* window, unsigned cntAlloc, bool aligned);
@ -49,7 +48,7 @@ bool PAG_get_clump(Jrd::thread_db*, USHORT, USHORT*, UCHAR*);
void PAG_header(Jrd::thread_db*, bool, const Firebird::TriState newForceWrite = Firebird::TriState());
void PAG_header_init(Jrd::thread_db*);
void PAG_init(Jrd::thread_db*);
void PAG_init2(Jrd::thread_db*, USHORT);
void PAG_init2(Jrd::thread_db*);
SLONG PAG_last_page(Jrd::thread_db* tdbb);
void PAG_release_page(Jrd::thread_db* tdbb, const Jrd::PageNumber&, const Jrd::PageNumber&);
void PAG_release_pages(Jrd::thread_db* tdbb, USHORT pageSpaceID, int cntRelease,

View File

@ -1519,7 +1519,7 @@ DmlNode* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb)
const ULONG blrOffset = csb->csb_blr_reader.getOffset();
const SSHORT blrOperator = csb->csb_blr_reader.getByte();
if (blrOperator < 0 || blrOperator >= FB_NELEM(blr_parsers))
if (blrOperator < 0 || static_cast<FB_SIZE_T>(blrOperator) >= FB_NELEM(blr_parsers))
{
// NS: This error string is correct, please do not mangle it again and again.
// The whole error message is "BLR syntax error: expected %s at offset %d, encountered %d"

View File

@ -37,10 +37,13 @@ using namespace Jrd;
// Data access: full outer join
// ----------------------------
FullOuterJoin::FullOuterJoin(CompilerScratch* csb, RecordSource* arg1, RecordSource* arg2)
FullOuterJoin::FullOuterJoin(CompilerScratch* csb,
RecordSource* arg1, RecordSource* arg2,
const StreamList& checkStreams)
: RecordSource(csb),
m_arg1(arg1),
m_arg2(arg2)
m_arg2(arg2),
m_checkStreams(csb->csb_pool, checkStreams)
{
fb_assert(m_arg1 && m_arg2);
@ -97,7 +100,27 @@ bool FullOuterJoin::internalGetRecord(thread_db* tdbb) const
m_arg2->open(tdbb);
}
return m_arg2->getRecord(tdbb);
// We should exclude matching records from the right-joined (second) record source,
// as they're already returned from the left-joined (first) record source
while (m_arg2->getRecord(tdbb))
{
bool matched = false;
for (const auto stream : m_checkStreams)
{
if (request->req_rpb[stream].rpb_number.isValid())
{
matched = true;
break;
}
}
if (!matched)
return true;
}
return false;
}
bool FullOuterJoin::refetchRecord(thread_db* /*tdbb*/) const

View File

@ -53,10 +53,11 @@ NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb, FB_SIZE_T count, RecordSour
}
}
NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb, RecordSource* outer, RecordSource* inner,
BoolExprNode* boolean, JoinType joinType)
NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb,
RecordSource* outer, RecordSource* inner,
BoolExprNode* boolean)
: RecordSource(csb),
m_joinType(joinType),
m_joinType(OUTER_JOIN),
m_args(csb->csb_pool),
m_boolean(boolean)
{

View File

@ -1137,7 +1137,7 @@ namespace Jrd
public:
NestedLoopJoin(CompilerScratch* csb, FB_SIZE_T count, RecordSource* const* args);
NestedLoopJoin(CompilerScratch* csb, RecordSource* outer, RecordSource* inner,
BoolExprNode* boolean, JoinType joinType);
BoolExprNode* boolean);
void close(thread_db* tdbb) const override;
@ -1168,7 +1168,8 @@ namespace Jrd
class FullOuterJoin : public RecordSource
{
public:
FullOuterJoin(CompilerScratch* csb, RecordSource* arg1, RecordSource* arg2);
FullOuterJoin(CompilerScratch* csb, RecordSource* arg1, RecordSource* arg2,
const StreamList& checkStreams);
void close(thread_db* tdbb) const override;
@ -1191,6 +1192,7 @@ namespace Jrd
private:
NestConst<RecordSource> m_arg1;
NestConst<RecordSource> m_arg2;
const StreamList m_checkStreams;
};
class HashJoin : public RecordSource

View File

@ -64,7 +64,6 @@ static bool check_for_file(thread_db* tdbb, const SCHAR*, USHORT);
#ifdef NOT_USED_OR_REPLACED
static void check_if_got_ast(thread_db* tdbb, jrd_file*);
#endif
static void copy_header(thread_db* tdbb);
static void update_dbb_to_sdw(Database*);
@ -112,147 +111,6 @@ void SDW_add(thread_db* tdbb, const TEXT* file_name, USHORT shadow_number, USHOR
}
int SDW_add_file(thread_db* tdbb, const TEXT* file_name, SLONG start, USHORT shadow_number)
{
/**************************************
*
* S D W _ a d d _ f i l e
*
**************************************
*
* Functional description
* Add a file to a shadow set.
* Return the sequence number for the new file.
*
**************************************/
SET_TDBB(tdbb);
Database* dbb = tdbb->getDatabase();
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_add_file");
// Find the file to be extended
jrd_file* shadow_file = 0;
Shadow* shadow;
for (shadow = dbb->dbb_shadow; shadow; shadow = shadow->sdw_next)
{
if ((shadow->sdw_number == shadow_number) &&
!(shadow->sdw_flags & (SDW_IGNORE | SDW_rollover)))
{
shadow_file = shadow->sdw_file;
break;
}
}
if (!shadow) {
return 0;
}
// find the last file in the list, open the new file
jrd_file* file = shadow_file;
while (file->fil_next) {
file = file->fil_next;
}
// Verify shadow file path against DatabaseAccess entry of firebird.conf
if (!JRD_verify_database_access(file_name))
{
ERR_post(Arg::Gds(isc_conf_access_denied) << Arg::Str("database shadow") <<
Arg::Str(file_name));
}
const SLONG sequence = PIO_add_file(tdbb, shadow_file, file_name, start);
if (!sequence)
return 0;
jrd_file* next = file->fil_next;
// Always write the header page, even for a conditional
// shadow that hasn't been activated.
// allocate a spare buffer which is large enough,
// and set up to release it in case of error. Align
// the spare page buffer for raw disk access.
Array<UCHAR> temp;
UCHAR* const spare_page = temp.getAlignedBuffer(dbb->dbb_page_size, dbb->getIOBlockSize());
// create the header using the spare_buffer
header_page* header = (header_page*) spare_page;
header->hdr_header.pag_type = pag_header;
header->hdr_sequence = sequence;
header->hdr_page_size = dbb->dbb_page_size;
header->hdr_data[0] = HDR_end;
header->hdr_end = HDR_SIZE;
// fool PIO_write into writing the scratch page into the correct place
BufferDesc temp_bdb(dbb->dbb_bcb);
temp_bdb.bdb_page = next->fil_min_page;
temp_bdb.bdb_buffer = (PAG) header;
header->hdr_header.pag_pageno = temp_bdb.bdb_page.getPageNum();
// It's header, never encrypted
if (!PIO_write(tdbb, shadow_file, &temp_bdb, reinterpret_cast<Ods::pag*>(header), 0))
return 0;
next->fil_fudge = 1;
// Update the previous header page to point to new file --
// we can use the same header page, suitably modified,
// because they all look pretty much the same at this point
/*******************
Fix for bug 7925. drop_gdb wan not dropping secondary file in
multi-shadow files. The structure was not being filled with the
info. Commented some code so that the structure will always be filled.
-Sudesh 07/06/95
The original code :
===
if (shadow_file == file)
copy_header(tdbb);
else
===
************************/
// Temporarly reverting the change ------- Sudesh 07/07/95 *******
if (shadow_file == file)
{
copy_header(tdbb);
}
else
{
--start;
header->hdr_data[0] = HDR_end;
header->hdr_end = HDR_SIZE;
PAG_add_header_entry(tdbb, header, HDR_file, static_cast<USHORT>(strlen(file_name)),
reinterpret_cast<const UCHAR*>(file_name));
PAG_add_header_entry(tdbb, header, HDR_last_page, sizeof(start),
reinterpret_cast<const UCHAR*>(&start));
file->fil_fudge = 0;
temp_bdb.bdb_page = file->fil_min_page;
header->hdr_header.pag_pageno = temp_bdb.bdb_page.getPageNum();
// It's header, never encrypted
if (!PIO_write(tdbb, shadow_file, &temp_bdb, reinterpret_cast<Ods::pag*>(header), 0))
return 0;
if (file->fil_min_page) {
file->fil_fudge = 1;
}
}
if (file->fil_min_page) {
file->fil_fudge = 1;
}
return sequence;
}
void SDW_check(thread_db* tdbb)
{
/**************************************
@ -814,12 +672,7 @@ bool SDW_rollover_to_shadow(thread_db* tdbb, jrd_file* file, const bool inAst)
// close the main database file if possible and release all file blocks
PIO_close(pageSpace->file);
while ( (file = pageSpace->file) )
{
pageSpace->file = file->fil_next;
delete file;
}
delete pageSpace->file;
/* point the main database file at the file of the first shadow
in the list and mark that shadow as rolled over to
@ -894,13 +747,7 @@ static void shutdown_shadow(Shadow* shadow)
// close the shadow files and free up the associated memory
PIO_close(shadow->sdw_file);
jrd_file* file;
jrd_file* free = shadow->sdw_file;
for (; (file = free->fil_next); free = file)
delete free;
delete free;
delete shadow->sdw_file;
delete shadow;
}
@ -1003,12 +850,6 @@ void SDW_start(thread_db* tdbb, const TEXT* file_name,
const header_page* shadow_header = (header_page*) spare_page;
// NOTE ! NOTE! NOTE!
// Starting V4.0, header pages can have overflow pages. For the shadow,
// we are making an assumption that the shadow header page will not
// overflow, as the only things written on a shadow header is the
// HDR_root_file_name, HDR_file, and HDR_last_page
const UCHAR* p = shadow_header->hdr_data;
while (*p != HDR_end && *p != HDR_root_file_name) {
p += 2 + p[1];
@ -1046,10 +887,6 @@ void SDW_start(thread_db* tdbb, const TEXT* file_name,
shadow->sdw_flags |= SDW_dumped;
}
// get the ancillary files and reset the error environment
PAG_init2(tdbb, shadow_number);
} // try
catch (const Firebird::Exception& ex)
{
@ -1257,35 +1094,6 @@ static void check_if_got_ast(thread_db* tdbb, jrd_file* file)
}
#endif
static void copy_header(thread_db* tdbb)
{
/**************************************
*
* c o p y _ h e a d e r
*
**************************************
*
* Functional description
* Fetch the header page from the database
* and write it to the shadow file. This is
* done so that if this shadow is extended,
* the header page will be there for writing
* the name of the extend file.
*
**************************************/
SET_TDBB(tdbb);
Database* dbb = tdbb->getDatabase();
CHECK_DBB(dbb);
// get the database header page and write it out --
// CCH will take care of modifying it
WIN window(HEADER_PAGE_NUMBER);
CCH_FETCH(tdbb, &window, LCK_write, pag_header);
CCH_MARK_MUST_WRITE(tdbb, &window);
CCH_RELEASE(tdbb, &window);
}
static void update_dbb_to_sdw(Database* dbb)
{
@ -1319,13 +1127,7 @@ static void update_dbb_to_sdw(Database* dbb)
// hvlad: need sync for this code
PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
PIO_close(pageSpace->file);
jrd_file* file;
while ( (file = pageSpace->file) )
{
pageSpace->file = file->fil_next;
delete file;
}
delete pageSpace->file;
pageSpace->file = shadow->sdw_file;
shadow->sdw_flags |= SDW_rollover;

View File

@ -29,7 +29,6 @@ namespace Jrd {
}
void SDW_add(Jrd::thread_db* tdbb, const TEXT*, USHORT, USHORT);
int SDW_add_file(Jrd::thread_db* tdbb, const TEXT*, SLONG, USHORT);
void SDW_check(Jrd::thread_db* tdbb);
bool SDW_check_conditional(Jrd::thread_db* tdbb);
void SDW_close();

View File

@ -1525,7 +1525,7 @@ void Sort::mergeRuns(USHORT n)
// and there n < RUN_GROUP * MAX_MERGE_LEVEL
merge_control blks[RUN_GROUP * MAX_MERGE_LEVEL];
fb_assert((n - 1) <= FB_NELEM(blks)); // stack var big enough?
fb_assert(static_cast<FB_SIZE_T>(n - 1) <= FB_NELEM(blks)); // stack var big enough?
m_longs -= SIZEOF_SR_BCKPTR_IN_LONGS;

View File

@ -478,7 +478,6 @@ enum dfw_t {
dfw_create_index,
dfw_delete_index,
dfw_compute_security,
dfw_add_file,
dfw_add_shadow,
dfw_delete_shadow,
dfw_delete_shadow_nodelete,

View File

@ -2240,27 +2240,32 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
case rel_files:
protect_system_table_delupd(tdbb, relation, "DELETE");
{
const bool name_defined = EVL_field(0, rpb->rpb_record, f_file_name, &desc);
const USHORT file_flags = EVL_field(0, rpb->rpb_record, f_file_flags, &desc2) ?
const bool nameDefined = EVL_field(0, rpb->rpb_record, f_file_name, &desc);
const auto shadowNumber = EVL_field(0, rpb->rpb_record, f_file_shad_num, &desc2) ?
MOV_get_long(tdbb, &desc2, 0) : 0;
if (file_flags & FILE_difference)
const auto fileFlags = EVL_field(0, rpb->rpb_record, f_file_flags, &desc2) ?
MOV_get_long(tdbb, &desc2, 0) : 0;
if (shadowNumber)
{
if (file_flags & FILE_backing_up)
DFW_post_work(transaction, dfw_end_backup, &desc, 0);
if (name_defined)
DFW_post_work(transaction, dfw_delete_difference, &desc, 0);
}
else if (EVL_field(0, rpb->rpb_record, f_file_shad_num, &desc2) &&
(id = MOV_get_long(tdbb, &desc2, 0)))
{
if (!(file_flags & FILE_inactive))
if (!(fileFlags & FILE_inactive))
{
if (file_flags & FILE_nodelete)
DFW_post_work(transaction, dfw_delete_shadow_nodelete, &desc, id);
else
DFW_post_work(transaction, dfw_delete_shadow, &desc, id);
const auto work = (fileFlags & FILE_nodelete) ?
dfw_delete_shadow_nodelete : dfw_delete_shadow;
DFW_post_work(transaction, work, &desc, shadowNumber);
}
}
else if (fileFlags & FILE_difference)
{
if (fileFlags & FILE_backing_up)
DFW_post_work(transaction, dfw_end_backup, &desc, 0);
if (nameDefined)
DFW_post_work(transaction, dfw_delete_difference, &desc, 0);
}
}
break;
@ -3617,18 +3622,24 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
case rel_files:
protect_system_table_delupd(tdbb, relation, "UPDATE");
{
SSHORT new_rel_flags, old_rel_flags;
EVL_field(0, new_rpb->rpb_record, f_file_name, &desc1);
if (EVL_field(0, new_rpb->rpb_record, f_file_flags, &desc2) &&
((new_rel_flags = MOV_get_long(tdbb, &desc2, 0)) & FILE_difference) &&
EVL_field(0, org_rpb->rpb_record, f_file_flags, &desc2) &&
((old_rel_flags = MOV_get_long(tdbb, &desc2, 0)) != new_rel_flags))
const auto orgFileFlags = EVL_field(0, org_rpb->rpb_record, f_file_flags, &desc2) ?
MOV_get_long(tdbb, &desc2, 0) : 0;
const auto newFileFlags = EVL_field(0, new_rpb->rpb_record, f_file_flags, &desc2) ?
MOV_get_long(tdbb, &desc2, 0) : 0;
if ((newFileFlags & FILE_difference) && orgFileFlags != newFileFlags)
{
DFW_post_work(transaction,
(new_rel_flags & FILE_backing_up ? dfw_begin_backup : dfw_end_backup),
(newFileFlags & FILE_backing_up) ? dfw_begin_backup : dfw_end_backup,
&desc1, 0);
}
}
// Nullify the unsupported fields
new_rpb->rpb_record->setNull(f_file_seq);
new_rpb->rpb_record->setNull(f_file_start);
new_rpb->rpb_record->setNull(f_file_length);
break;
case rel_charsets:
@ -4175,34 +4186,32 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
case rel_files:
protect_system_table_insert(tdbb, request, relation);
{
const bool name_defined = EVL_field(0, rpb->rpb_record, f_file_name, &desc);
if (EVL_field(0, rpb->rpb_record, f_file_shad_num, &desc2) &&
MOV_get_long(tdbb, &desc2, 0))
const bool nameDefined = EVL_field(0, rpb->rpb_record, f_file_name, &desc);
const auto shadowNumber = EVL_field(0, rpb->rpb_record, f_file_shad_num, &desc2) ?
MOV_get_long(tdbb, &desc2, 0) : 0;
const auto fileFlags = EVL_field(0, rpb->rpb_record, f_file_flags, &desc2) ?
MOV_get_long(tdbb, &desc2, 0) : 0;
if (shadowNumber)
{
EVL_field(0, rpb->rpb_record, f_file_flags, &desc2);
if (!(MOV_get_long(tdbb, &desc2, 0) & FILE_inactive)) {
if (!(fileFlags & FILE_inactive))
DFW_post_work(transaction, dfw_add_shadow, &desc, 0);
}
}
else
else if (fileFlags & FILE_difference)
{
USHORT rel_flags;
if (EVL_field(0, rpb->rpb_record, f_file_flags, &desc2) &&
((rel_flags = MOV_get_long(tdbb, &desc2, 0)) & FILE_difference))
{
if (name_defined) {
DFW_post_work(transaction, dfw_add_difference, &desc, 0);
}
if (rel_flags & FILE_backing_up)
{
DFW_post_work(transaction, dfw_begin_backup, &desc, 0);
}
}
else {
DFW_post_work(transaction, dfw_add_file, &desc, 0);
}
if (nameDefined)
DFW_post_work(transaction, dfw_add_difference, &desc, 0);
if (fileFlags & FILE_backing_up)
DFW_post_work(transaction, dfw_begin_backup, &desc, 0);
}
}
// Nullify the unsupported fields
rpb->rpb_record->setNull(f_file_seq);
rpb->rpb_record->setNull(f_file_start);
rpb->rpb_record->setNull(f_file_length);
break;
case rel_triggers:

View File

@ -9,7 +9,7 @@ BuildType=T
MajorVer=6
MinorVer=0
RevNo=0
BuildNum=553
BuildNum=587
NowAt=`pwd`
cd `dirname $0`

View File

@ -308,7 +308,7 @@ namespace {
public Firebird::AutoIface<Firebird::IListUsersImpl<Callback, Firebird::CheckStatusWrapper> >
{
public:
explicit Callback(StackUserData* pu)
explicit Callback(UserData* pu)
: u(pu)
{ }
@ -329,7 +329,7 @@ namespace {
}
private:
StackUserData* u;
UserData* u;
};
} // anonymous namespace
@ -356,7 +356,7 @@ int gsec(Firebird::UtilSvc* uSvc)
tsec* tdsec = &tsecInstance;
tsec::putSpecific(tdsec);
StackUserData u;
UserData u;
tdsec->tsec_user_data = &u;
Firebird::LocalStatus lsManager;
@ -549,7 +549,7 @@ int gsec(Firebird::UtilSvc* uSvc)
if (user_data->operation() == MOD_OPER && user_data->userName()->entered() &&
(fieldSet(&user_data->u) || fieldSet(&user_data->g) || fieldSet(&user_data->group)))
{
StackUserData u;
UserData u;
u.op = DIS_OPER;
u.user.set(&statusWrapper, user_data->userName()->get());
check(&statusWrapper);

View File

@ -164,10 +164,6 @@ struct dba_rel
struct dba_fil
{
dba_fil* fil_next; // Next file in database
ULONG fil_min_page; // Minimum page number in file
ULONG fil_max_page; // Maximum page number in file
USHORT fil_fudge; // Fudge factor for page relocation
#ifdef WIN_NT
void *fil_desc;
#else
@ -216,16 +212,6 @@ static void print_help();
#include "../utilities/gstat/dba_proto.h"
struct open_files
{
#ifdef WIN_NT
void* desc;
#else
int desc;
#endif
open_files* open_files_next;
};
struct dba_mem
{
char* memory;
@ -241,7 +227,7 @@ public:
: ThreadData(tddDBA), uSvc(us)
{
//dba_throw = false;
files = 0;
file = 0;
relations = 0;
page_size = 0;
dp_per_pp = 0;
@ -252,14 +238,13 @@ public:
global_buffer = 0;
exit_code = 0;
head_of_mem_list = 0;
head_of_files_list = 0;
memset(dba_status_vector, 0, sizeof (dba_status_vector));
dba_status = dba_status_vector;
}
//bool dba_throw;
Firebird::UtilSvc* uSvc;
dba_fil* files;
dba_fil* file;
dba_rel* relations;
USHORT page_size;
USHORT dp_per_pp;
@ -270,7 +255,6 @@ public:
pag* global_buffer;
int exit_code;
dba_mem *head_of_mem_list;
open_files *head_of_files_list;
ISC_STATUS *dba_status;
ISC_STATUS_ARRAY dba_status_vector;
@ -613,7 +597,7 @@ int gstat(Firebird::UtilSvc* uSvc)
expandDatabaseName(fileName, tempStr, NULL);
fileName = tempStr;
dba_fil* current = db_open(fileName.c_str(), fileName.length());
dba_fil* file = 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);
@ -661,38 +645,6 @@ int gstat(Firebird::UtilSvc* uSvc)
if (sw_header)
dba_exit(FINI_OK, tddba);
// gather continuation files
while (true)
{
if (page != HEADER_PAGE)
{
current = db_open(file_name, static_cast<USHORT>(strlen(file_name)));
header = (const header_page*) db_read(page);
}
if (current != tddba->files)
current->fil_fudge = 1; // ignore header page once read it
PathName nextFileName;
const UCHAR* vp = header->hdr_data;
for (const auto vend = reinterpret_cast<const UCHAR*>(header) + header->hdr_page_size;
vp < vend && *vp != HDR_end; vp += 2 + vp[1])
{
if (*vp == HDR_file)
nextFileName.assign(vp + 2, vp[1]);
if (*vp == HDR_last_page)
memcpy(&current->fil_max_page, vp + 2, sizeof(current->fil_max_page));
}
if (nextFileName.isEmpty())
break;
page = current->fil_max_page + 1; // first page of next file
}
if (sw_enc)
{
class Statist
@ -724,6 +676,7 @@ int gstat(Firebird::UtilSvc* uSvc)
private:
ULONG enc, non;
};
Statist data, index, blob, generator, other;
ULONG last = lastUsedPage(header->hdr_page_size);
@ -766,18 +719,6 @@ int gstat(Firebird::UtilSvc* uSvc)
dba_exit(FINI_OK, tddba);
}
// print continuation file sequence
dba_print(false, 7);
// msg 7: \n\nDatabase file sequence:
for (current = tddba->files; current->fil_next; current = current->fil_next)
{
dba_print(false, 8, SafeArg() << current->fil_string << current->fil_next->fil_string);
// msg 8: File %s continues as file %s
}
dba_print(false, 9, SafeArg() << current->fil_string << ((current == tddba->files) ? "only" : "last"));
// msg 9: File %s is the %s file\n
// Check to make sure that the user accessing the database is either
// SYSDBA or owner of the database
@ -1192,22 +1133,11 @@ int gstat(Firebird::UtilSvc* uSvc)
alloced = alloced->mem_next;
}
// close files
open_files* open_file = tddba->head_of_files_list;
while (open_file)
{
db_close(open_file->desc);
open_file = open_file->open_files_next;
}
// close file
if (tddba->file)
db_close(tddba->file->fil_desc);
// free linked lists
while (tddba->head_of_files_list != 0)
{
open_files* tmp1 = tddba->head_of_files_list;
tddba->head_of_files_list = tddba->head_of_files_list->open_files_next;
delete tmp1;
}
while (tddba->head_of_mem_list != 0)
{
dba_mem* tmp2 = tddba->head_of_mem_list;
@ -1865,29 +1795,12 @@ static dba_fil* db_open(const char* file_name, USHORT file_length)
**************************************/
tdba* tddba = tdba::getSpecific();
dba_fil* fil;
const auto file = (dba_fil*) alloc(sizeof(dba_fil) + file_length + 1);
if (tddba->files)
{
for (fil = tddba->files; fil->fil_next; fil = fil->fil_next);
fil->fil_next = (dba_fil*) alloc(sizeof(dba_fil) + file_length + 1);
fil->fil_next->fil_min_page = fil->fil_max_page + 1;
fil = fil->fil_next;
}
else
{
// empty list
fil = tddba->files = (dba_fil*) alloc(sizeof(dba_fil) + file_length + 1);
fil->fil_min_page = 0L;
}
strcpy(file->fil_string, file_name);
file->fil_length = file_length;
fil->fil_next = NULL;
strcpy(fil->fil_string, file_name);
fil->fil_length = file_length;
fil->fil_fudge = 0;
fil->fil_max_page = 0L;
fil->fil_desc = CreateFile( file_name,
file->fil_desc = CreateFile(file_name,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
@ -1895,31 +1808,15 @@ static dba_fil* db_open(const char* file_name, USHORT file_length)
FILE_ATTRIBUTE_NORMAL,
0);
if (fil->fil_desc == INVALID_HANDLE_VALUE)
if (file->fil_desc == INVALID_HANDLE_VALUE)
{
tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 29, SafeArg() << file_name);
// msg 29: Can't open database file %s
db_error(GetLastError());
}
open_files* file_list = FB_NEW_POOL(*getDefaultMemoryPool()) open_files;
if (!file_list)
{
// NOMEM: return error
dba_error(31);
}
file_list->desc = fil->fil_desc;
file_list->open_files_next = 0;
if (tddba->head_of_files_list == 0)
tddba->head_of_files_list = file_list;
else
{
file_list->open_files_next = tddba->head_of_files_list;
tddba->head_of_files_list = file_list;
}
return fil;
tddba->file = file;
return file;
}
@ -1945,17 +1842,9 @@ static const pag* db_read( SLONG page_number, bool ok_enc)
tddba->page_number = page_number;
dba_fil* fil;
for (fil = tddba->files; page_number > (SLONG) fil->fil_max_page && fil->fil_next;)
{
fil = fil->fil_next;
}
page_number -= fil->fil_min_page - fil->fil_fudge;
LARGE_INTEGER liOffset;
liOffset.QuadPart = UInt32x32To64((DWORD) page_number, (DWORD) tddba->page_size);
if (SetFilePointer(fil->fil_desc, (LONG) liOffset.LowPart, &liOffset.HighPart, FILE_BEGIN) ==
if (SetFilePointer(tddba->file->fil_desc, (LONG) liOffset.LowPart, &liOffset.HighPart, FILE_BEGIN) ==
(DWORD) -1)
{
int lastError = GetLastError();
@ -1968,7 +1857,7 @@ static const pag* db_read( SLONG page_number, bool ok_enc)
}
SLONG actual_length;
if (!ReadFile( fil->fil_desc,
if (!ReadFile( tddba->file->fil_desc,
tddba->global_buffer,
tddba->page_size,
reinterpret_cast<LPDWORD>(&actual_length),
@ -2057,54 +1946,20 @@ static dba_fil* db_open(const char* file_name, USHORT file_length)
**************************************/
tdba* tddba = tdba::getSpecific();
dba_fil* fil;
if (tddba->files)
{
for (fil = tddba->files; fil->fil_next; fil = fil->fil_next)
;
fil->fil_next = (dba_fil*) alloc(sizeof(dba_fil) + file_length + 1);
fil->fil_next->fil_min_page = fil->fil_max_page + 1;
fil = fil->fil_next;
}
else
{
// empty list
const auto file = (dba_fil*) alloc(sizeof(dba_fil) + file_length + 1);
fil = tddba->files = (dba_fil*) alloc(sizeof(dba_fil) + file_length + 1);
fil->fil_min_page = 0L;
}
strcpy(file->fil_string, file_name);
file->fil_length = file_length;
fil->fil_next = NULL;
strcpy(fil->fil_string, file_name);
fil->fil_length = file_length;
fil->fil_fudge = 0;
fil->fil_max_page = 0L;
if ((fil->fil_desc = os_utils::open(file_name, O_RDONLY)) == -1)
if ((file->fil_desc = os_utils::open(file_name, O_RDONLY)) == -1)
{
tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 29, SafeArg() << file_name);
// msg 29: Can't open database file %s
db_error(errno);
}
open_files* file_list = FB_NEW_POOL(*getDefaultMemoryPool()) open_files;
if (!file_list)
{
// NOMEM: return error
dba_error(31);
}
file_list->desc = fil->fil_desc;
file_list->open_files_next = 0;
if (tddba->head_of_files_list == 0)
tddba->head_of_files_list = file_list;
else
{
file_list->open_files_next = tddba->head_of_files_list;
tddba->head_of_files_list = file_list;
}
return fil;
tddba->file = file;
return file;
}
@ -2127,15 +1982,8 @@ static const pag* db_read( SLONG page_number, bool ok_enc)
tddba->page_number = page_number;
dba_fil* fil;
for (fil = tddba->files; page_number > (SLONG) fil->fil_max_page && fil->fil_next;)
{
fil = fil->fil_next;
}
page_number -= fil->fil_min_page - fil->fil_fudge;
const FB_UINT64 offset = ((FB_UINT64) page_number) * ((FB_UINT64) tddba->page_size);
if (os_utils::lseek (fil->fil_desc, offset, 0) == -1)
if (os_utils::lseek (tddba->file->fil_desc, offset, 0) == -1)
{
tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg());
// msg 30: Can't read a database page
@ -2145,7 +1993,7 @@ static const pag* db_read( SLONG page_number, bool ok_enc)
USHORT length = tddba->page_size;
for (SCHAR* p = (SCHAR *) tddba->global_buffer; length > 0;)
{
const int l = read(fil->fil_desc, p, length);
const int l = read(tddba->file->fil_desc, p, length);
if (l < 0)
{
tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg());

View File

@ -233,17 +233,6 @@ void PPG_print_header(const header_page* header, bool nocreation, Firebird::Util
uSvc->printf(false, "\tRoot file name:\t\t%s\n", temp);
break;
case HDR_file:
memcpy(temp, p + 2, p[1]);
temp[p[1]] = '\0';
uSvc->printf(false, "\tContinuation file:\t\t%s\n", temp);
break;
case HDR_last_page:
memcpy(&number, p + 2, sizeof(number));
uSvc->printf(false, "\tLast logical page:\t\t%ld\n", number);
break;
case HDR_sweep_interval:
memcpy(&number, p + 2, sizeof(number));
uSvc->printf(false, "\tSweep interval:\t\t%ld\n", number);

View File

@ -1818,7 +1818,7 @@ void TracePluginImpl::register_sql_statement(ITraceSQLStatement* statement)
stmt_data.description = FB_NEW_POOL(*getDefaultMemoryPool()) string(*getDefaultMemoryPool());
if (stmt_data.id) {
stmt_data.description->printf(NEWLINE "Statement %d:", stmt_data.id);
stmt_data.description->printf(NEWLINE "Statement %" SQUADFORMAT":", stmt_data.id);
}
string temp(*getDefaultMemoryPool());

View File

@ -63,7 +63,6 @@ static void format_index_root(index_root_page*, int, SSHORT, SSHORT);
static void format_pointer(pointer_page*, int, SSHORT, SSHORT, bool, SSHORT, const SLONG*);
static void format_pip(page_inv_page*, int, int);
static void format_tip(tx_inv_page*, int, SLONG);
static void get_next_file(rbdb*, header_page*);
static void get_range(TEXT***, const TEXT* const* const, ULONG*, ULONG*);
static void get_switch(TEXT**, swc*);
static header_page* open_database(rbdb*, ULONG);
@ -197,8 +196,7 @@ int main( int argc, char *argv[])
rbdb = (rbdb*) RBDB_alloc((SLONG) (sizeof(struct rbdb) + strlen(db_in)));
strcpy(rbdb->rbdb_file.fil_name, db_in);
rbdb->rbdb_file.fil_length = strlen(db_in);
if (header = open_database(rbdb, pg_size))
get_next_file(rbdb, header);
header = open_database(rbdb, pg_size);
// some systems don't care for this write sharing stuff...
if (rbdb && (sw_dump_tips || sw_dump_pages))
@ -210,7 +208,6 @@ int main( int argc, char *argv[])
}
}
gdbb = &tdbb_struct;
gdbb->tdbb_database = &dbb_struct;
gdbb->tdbb_transaction = &dull;
@ -252,17 +249,15 @@ int main( int argc, char *argv[])
fclose(dbg_file);
if (rbdb)
{
RBDB_close(rbdb);
while (rbdb)
{
rbdb* const next_db = rbdb->rbdb_next;
if (rbdb->rbdb_buffer1)
gds__free(rbdb->rbdb_buffer1);
if (rbdb->rbdb_buffer2)
gds__free(rbdb->rbdb_buffer2);
gds__free(rbdb);
rbdb = next_db;
}
return 0;
@ -332,8 +327,7 @@ void RBDB_close( rbdb* rbdb)
* Functional description
*
**************************************/
for (; rbdb; rbdb = rbdb->rbdb_next)
close(rbdb->rbdb_file.fil_file);
close(rbdb->rbdb_file.fil_file);
}
@ -732,36 +726,6 @@ static void format_tip( tx_inv_page* page, int page_size, SLONG next_page)
}
static void get_next_file( rbdb* rbdb, header_page* header)
{
/**************************************
*
* g e t _ n e x t _ f i l e
*
**************************************
*
* Functional description
* If there's another file as part of
* this database, get it now.
*
**************************************/
rbdb** next = &rbdb->rbdb_next;
const UCHAR* p = header->hdr_data;
for (const UCHAR* const end = p + header->hdr_page_size; p < end && *p != HDR_end; p += 2 + p[1])
{
if (*p == HDR_file)
{
rbdb* next_rbdb = (rbdb*) RBDB_alloc(sizeof(struct rbdb) + (SSHORT) p[1]);
next_rbdb->rbdb_file.fil_length = (SSHORT) p[1];
strncpy(next_rbdb->rbdb_file.fil_name, p + 2, (SSHORT) p[1]);
*next = next_rbdb;
next = &next_rbdb->rbdb_next;
break;
}
}
}
static void get_range(TEXT*** argv, const TEXT* const* const end, ULONG* lower, ULONG* upper)
{
/**************************************

View File

@ -250,7 +250,7 @@ ISC_STATUS API_ROUTINE_VARARG gds__start_transaction(ISC_STATUS* status_vector,
teb_t tebs[16];
teb_t* teb = tebs;
if (count > FB_NELEM(tebs))
if (static_cast<FB_SIZE_T>(count) > FB_NELEM(tebs))
teb = (teb_t*) gds__alloc(((SLONG) sizeof(teb_t) * count));
// FREE: later in this module
@ -862,7 +862,7 @@ ISC_STATUS API_ROUTINE isc_add_user(ISC_STATUS* status, const USER_SEC_DATA* inp
* Return > 0 if any error occurs.
*
**************************************/
Auth::StackUserData userInfo;
Auth::UserData userInfo;
userInfo.op = Auth::ADD_OPER;
Firebird::LocalStatus s;
Firebird::CheckStatusWrapper statusWrapper(&s);
@ -925,7 +925,7 @@ ISC_STATUS API_ROUTINE isc_delete_user(ISC_STATUS* status, const USER_SEC_DATA*
* Return > 0 if any error occurs.
*
**************************************/
Auth::StackUserData userInfo;
Auth::UserData userInfo;
userInfo.op = Auth::DEL_OPER;
Firebird::LocalStatus s;
Firebird::CheckStatusWrapper statusWrapper(&s);
@ -970,7 +970,7 @@ ISC_STATUS API_ROUTINE isc_modify_user(ISC_STATUS* status, const USER_SEC_DATA*
* Return > 0 if any error occurs.
*
**************************************/
Auth::StackUserData userInfo;
Auth::UserData userInfo;
userInfo.op = Auth::MOD_OPER;
Firebird::LocalStatus s;
Firebird::CheckStatusWrapper statusWrapper(&s);

View File

@ -975,7 +975,7 @@ static SLONG safe_interpret(char* const s, const FB_SIZE_T bufsize,
}
if (!found) {
sprintf(s, "unknown ISC error %ld", (SLONG) code); // TXNN
sprintf(s, "unknown ISC error %" SLONGFORMAT, (SLONG) code); // TXNN
}
}
}
@ -1000,11 +1000,11 @@ static SLONG safe_interpret(char* const s, const FB_SIZE_T bufsize,
break;
case isc_arg_dos:
sprintf(s, "unknown dos error %ld", (SLONG) code); // TXNN
sprintf(s, "unknown dos error %" SLONGFORMAT, (SLONG) code); // TXNN
break;
case isc_arg_next_mach:
sprintf(s, "next/mach error %ld", (SLONG) code); // AP
sprintf(s, "next/mach error %" SLONGFORMAT, (SLONG) code); // AP
break;
case isc_arg_win32:
@ -1016,7 +1016,7 @@ static SLONG safe_interpret(char* const s, const FB_SIZE_T bufsize,
s, bufsize, NULL))
#endif
{
sprintf(s, "unknown Win32 error %ld", (SLONG) code); // TXNN
sprintf(s, "unknown Win32 error %" SLONGFORMAT, (SLONG) code); // TXNN
}
break;
@ -4025,7 +4025,7 @@ static void blr_print_verb(gds_ctl* control, SSHORT level)
case blr_invoke_function_type:
n = control->ctl_blr_reader.getByte();
if (n == 0 || n >= FB_NELEM(typeSubCodes))
if (n == 0 || n >= static_cast<FB_SSIZE_T>(FB_NELEM(typeSubCodes)))
blr_error(control, "*** invalid blr_invoke_function_type sub code ***");
blr_format(control, "blr_invoke_function_type_%s,", typeSubCodes[n]);
@ -4123,7 +4123,7 @@ static void blr_print_verb(gds_ctl* control, SSHORT level)
case blr_invsel_procedure_type:
n = control->ctl_blr_reader.getByte();
if (n == 0 || n >= FB_NELEM(typeSubCodes))
if (n == 0 || n >= static_cast<FB_SSIZE_T>(FB_NELEM(typeSubCodes)))
blr_error(control, "*** invalid blr_invsel_procedure_type sub code ***");
blr_format(control, "blr_invsel_procedure_type_%s,", typeSubCodes[n]);

View File

@ -831,11 +831,11 @@ private:
explicit CtrlCHandler(MemoryPool& p)
: ShutdownInit(p)
{
shutdownSemaphore = &semaphore;
Thread::start(shutdownThread, 0, 0, &handle);
procInt = ISC_signal(SIGINT, handlerInt, 0);
procTerm = ISC_signal(SIGTERM, handlerTerm, 0);
shutdownSemaphore = &semaphore;
}
~CtrlCHandler()