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

Merges changes from master

This commit is contained in:
AlexPeshkoff 2017-04-02 19:12:18 +03:00
commit f995ed4408
116 changed files with 2891 additions and 826 deletions

View File

@ -11,24 +11,24 @@ branches:
- master - master
install: install:
- wget --no-check-certificate https://www.cmake.org/files/v3.2/cmake-3.2.3-Linux-x86_64.sh # wget --no-check-certificate https://www.cmake.org/files/v3.2/cmake-3.2.3-Linux-x86_64.sh
- sudo sh cmake-3.2.3-Linux-x86_64.sh --skip-license --prefix=/usr # sudo sh cmake-3.2.3-Linux-x86_64.sh --skip-license --prefix=/usr
- sudo apt-get update - sudo apt-get update
- sudo apt-get install -y libtommath0 libtommath-dev - sudo apt-get install -y libtommath0 libtommath-dev
- sudo python -m pip install Mako fdb # sudo python -m pip install Mako fdb
- svn co http://svn.code.sf.net/p/firebird/code/qa/fbtest/trunk/ fbtest # svn co http://svn.code.sf.net/p/firebird/code/qa/fbtest/trunk/ fbtest
- svn co http://svn.code.sf.net/p/firebird/code/qa/fbt-repository/trunk/ fbtest/fbt # svn co http://svn.code.sf.net/p/firebird/code/qa/fbt-repository/trunk/ fbtest/fbt
script: script:
- ./autogen.sh - ./autogen.sh --enable-binreloc --prefix=/opt/firebird
- make -j2 - make -j4
- sudo echo `pwd`/gen/Release/firebird/lib | sudo tee --append /etc/ld.so.conf - make dist
- sudo ldconfig - tar xzvf gen/Firebird-[0-9]*.tar.gz
- sudo ./gen/Release/firebird/bin/gsec -add sysdba -pw masterkey - (cd Firebird-[0-9]*; sudo ./install.sh -silent)
- chmod 777 travis.sh - sudo usermod -a -G firebird travis
- sudo ./travis.sh start_server & # sg firebird -c "/opt/firebird/bin/gsec -user sysdba -add sysdba -pw masterkey"
- ./travis.sh dummy_output & # ./travis.sh dummy_output &
- ./travis.sh skip_tests # ./travis.sh skip_tests
- sleep 3 # sleep 3
- cd fbtest/fbt # cd fbtest/fbt
- python ../fbtest.py -d `pwd`/tmp -b `pwd`/../../gen/Release/firebird/bin -v -x -k ../../skip.txt # sg firebird -c "python ../fbtest.py -d `pwd`/tmp -b /opt/firebird/bin -v -x -k ../../skip.txt"

View File

@ -1,3 +1,5 @@
[![Build Status](https://travis-ci.org/FirebirdSQL/firebird.svg?branch=master)](https://travis-ci.org/FirebirdSQL/firebird)
# Firebird README # Firebird README
Firebird is a relational database offering many ANSI SQL standard features that runs on Linux, Windows, MacOS and a variety of Unix platforms. Firebird offers excellent concurrency, high performance, and powerful language support for stored procedures and triggers. It has been used in production systems, under a variety of names, since 1981. Firebird is a relational database offering many ANSI SQL standard features that runs on Linux, Windows, MacOS and a variety of Unix platforms. Firebird offers excellent concurrency, high performance, and powerful language support for stored procedures and triggers. It has been used in production systems, under a variety of names, since 1981.

View File

@ -5,6 +5,7 @@ Conflicts=firebird-superserver.service
[Socket] [Socket]
ListenStream=3050 ListenStream=3050
Accept=true Accept=true
MaxConnections=2048
[Install] [Install]
WantedBy=sockets.target WantedBy=sockets.target

View File

@ -483,8 +483,8 @@
# database feature for encrypted database. In that case special care should be # database feature for encrypted database. In that case special care should be
# taken to encrypt that key before passing it to server using callback. Make # taken to encrypt that key before passing it to server using callback. Make
# sure your keys are well encrypted before enabling this parameter. Take into # sure your keys are well encrypted before enabling this parameter. Take into
# account that with CryptSecurityDatabase=TRUE unencrypted by firebird protocol # account that with AllowEncryptedSecurityDatabase=TRUE unencrypted by firebird
# key transfer may take place even with not encrypted security database. # protocol key transfer may take place even with not encrypted security database.
# This feature is not supported by legacy authentication plugin - if you care # This feature is not supported by legacy authentication plugin - if you care
# about security please never use legacy authentication. # about security please never use legacy authentication.
# #
@ -496,7 +496,7 @@
# Please understand what are you doing before enabling this feature !!! # # Please understand what are you doing before enabling this feature !!! #
######################################################################### #########################################################################
# #
#CryptSecurityDatabase = false #AllowEncryptedSecurityDatabase = false
# ---------------------------- # ----------------------------
# #
@ -526,6 +526,30 @@
#DeadlockTimeout = 10 #DeadlockTimeout = 10
# ----------------------------
#
# Set number of seconds after which statement execution will be automatically
# cancelled by the engine. Zero means no timeout is set.
#
# Per-database configurable.
#
# Type: integer
#
#StatementTimeout = 0
# ----------------------------
#
# Set number of minutes after which idle attachment will be disconnected by the
# engine. Zero means no timeout is set.
#
# Per-database configurable.
#
# Type: integer
#
#ConnectionIdleTimeout = 0
# ---------------------------- # ----------------------------
# #
# How often the pages are flushed on disk # How often the pages are flushed on disk

View File

@ -1,4 +1,4 @@
config.guess config.guess
config.h.in config.h.in*
config.sub config.sub
ltmain.sh ltmain.sh

View File

@ -347,6 +347,7 @@ fb_get_database_handle
fb_get_transaction_handle fb_get_transaction_handle
fb_database_crypt_callback fb_database_crypt_callback
fb_dsql_set_timeout
# Other misc functions # Other misc functions

View File

@ -222,6 +222,7 @@ EXPORTS
isc_dsql_release @199 isc_dsql_release @199
isc_dsql_set_cursor_name @200 isc_dsql_set_cursor_name @200
isc_dsql_sql_info @201 isc_dsql_sql_info @201
fb_dsql_set_timeout
; ESQL functions ; ESQL functions

View File

@ -0,0 +1,113 @@
Timeouts for idle database sessions.
Author:
Vlad Khorsun <hvlad@users.sf.net>
Description:
The feature allows to automatically close user connection after period of inactivity.
It could be used by database administrators to forcibly close old inactive connections
and free resources it occupies. Application and tools developers also could find it as
easy replacement of self-made control for the connection life time.
It is recommended (but not required) to set idle timeout to reasonable big value, such
as few hours. By default it is not enabled.
The feature works as below
- when user API call leaves engine, special idle timer assotiated with current connection
is started
- when user API call enters engine, idle timer is stopped
- when idle time is fired engine immediately closes the connection in the same way as
with asyncronous connection cancellation:
- all active statements and cursors are closed
- all active transactions are rolled back
- network connection is not closed at this moment. It allows client application to get
exact error code on next API call. Network connection will be closed by the server
side after error is reported or due to network timeout if client side disconnects.
- idle session timeout could be set:
- at database level, by setting value in firebird.conf (or databases.conf) by database
administrator
scope - all user connections, except of system connections (garbage collector, cache
writer, etc)
units - minutes
- at connection level, using API and\or new SQL statement (see below)
scope - given connection
units - up to seconds
- effective value of idle timeout is evaluated every time user API call leaves the engine
as:
- if not set at connection level, look at database level
- in any case can't be greater than value set at database level
i.e. value of idle timeout could be overriden by application developer at given
connection but it can't relax limit set by DBA (in config)
- zero timeout means no timeout, i.e. idle timer will not start
- while idle timeout is set in seconds at API level, we can't promise absolute precision.
With high load it could be less precise. The only guarantee is that timeout will not
fire before specified moment.
- if connection was cancelled, next user API call returns error isc_att_shutdown with
secondary error code specifying exact reason:
isc_att_shut_killed: Killed by database administrator
isc_att_shut_idle: Idle timeout expired
isc_att_shut_db_down: Database is shutdown
isc_att_shut_engine: Engine is shutdown
Support at configuration level (firebird.conf and\or databases.conf)
New setting "ConnectionIdleTimeout": set number of minutes after which idle connection
will be disconnected by the engine. Zero means no timeout is set.
Per-database configurable. Type: integer. Default value is 0.
Support at API level
- get\set idle connection timeout, seconds
interface Attachment
uint getIdleTimeout(Status status);
void setIdleTimeout(Status status, uint timeOut);
- get idle connection timeout at config and\or connection level is possible
using isc_database_info() API with new info tags:
- fb_info_ses_idle_timeout_db value set at config level
- fb_info_ses_idle_timeout_att value set at given connection level
- fb_info_ses_idle_timeout_run actual timeout value for given connection
evaluated considering values set at config and
connection levels, see "effective value of idle
timeout" above
Remote client implementation notes:
- Attachment::setIdleTimeout() issued "SET SESSION IDLE TIMEOUT" SQL statement
- Attachment::getIdleTimeout() calls isc_database_info() with
fb_info_ses_idle_timeout_att tag
If remote server doesn't support idle connection timeouts (protocol version less than 16):
- Attachment::setIdleTimeout() will return isc_wish_list error
- Attachment::getIdleTimeout() will return zero and set isc_wish_list error
- isc_database_info() will return isc_info_error tag in info buffer (as usual).
Support in SQL
- New SQL statement allows to set idle connection timeout at connection level:
SET SESSION IDLE TIMEOUT <value> [HOUR | MINUTE | SECOND]
if timepart is not set, default is MINUTE.
This statement could run outside of transaction control and immediately effective.
- Context variables
Context 'SYSTEM' have new variable: 'SESSION_IDLE_TIMEOUT'. It contains current value
of idle connection timeout that was set at connection level, or zero, if timeout was not
set.
- Monitoring tables
MON$ATTACHMENTS
MON$IDLE_TIMEOUT Connection level idle timeout
MON$IDLE_TIMER Idle timer expiration time
MON$IDLE_TIMEOUT contains timeout value set at connection level, in seconds. Zero, if
timeout is not set.
MON$IDLE_TIMER contains NULL value if idle timeout was not set or if timer is not
running.

View File

@ -0,0 +1,159 @@
Timeouts for running SQL statements.
Author:
Vlad Khorsun <hvlad@users.sf.net>
Description:
The feature allows to set timeout for SQL statement, i.e. it allows to automatically
stop execution of SQL statement when it running longer than given timeout value.
The feature could be useful for:
- database administrators get instrument to limit heavy queries from consuming too
much resources
- application developers could use statement timeout when creating\debugging complex
queries with unknown in advance execution time
- testers could use statement timeout to detect long running queries and ensure finite
run time of the test suites
- and so on
From the end user point of view feature have following details:
- when statement starts execution (or cursor is opened), engine starts special timer
- fetch doesn't reset timer
- timer is stopped when statement execution finished (or last record is fetched)
- when timer is fired
- if statement execution is active, it stops at closest possible moment
- if statement is not active currently (between fetches, for example), it is marked
as cancelled and next fetch will actually break execution and returns with error
- timeout value could be set:
- at database level, by setting value in firebird.conf (or databases.conf) by database
administrator
scope - all statements in all connections
units - seconds
- at connection level, using API and\or new SQL statement (see below)
scope - all statements at given connection
units - up to milliseconds
- at statement level, using API
scope - given statement
units - milliseconds
- effective value of timeout is evaluated every time statement starts execution
(or cursor is opened) as:
- if not set at statement level, look at connection level
- if not set at connection level, look at database level
- in any case can't be greater than value set at database level
i.e. value of statement timeout could be overriden by application developer at lower
scope but it can't relax limit set by DBA (in config)
- zero timeout means no timeout, i.e. timer will not start
- while statement timeout is set in milliseconds at API level, we can't promise
absolute precision. With big load it could be less precise. The only guarantee
is that timeout will not fire before specified moment.
- if statement execution is cancelled due to timeout, then API call returns error
isc_cancelled with secondary error code specifying exact reason:
- isc_cfg_stmt_timeout: Config level timeout expired
- isc_att_stmt_timeout: Attachment level timeout expired
- isc_req_stmt_timeout: Statement level timeout expired
- statement timeout is ignored for all internal queries issued by engine itself
- statement timeout is ignored for DDL statements
- client application could wait more time than set by timeout value if engine
need to undo many actions due to statement cancellation
- when engine run EXECUTE STATEMENT statement, it pass rest of currently active timeout
to the new statement. If external (remote) engine doesn't support statement timeouts,
local engine silently ignores corresponding error
- when engine acquires some lock of lock manager, it could lower value of lock timeout
using rest of the currently active statement timeout, if possible. Due to lock manager
internals rest of statement timeout will be rounded up to the whole seconds.
Support at configuration level (firebird.conf and\or databases.conf)
New setting "StatementTimeout": set number of seconds after which statement execution
will be automatically cancelled by the engine. Zero means no timeout is set.
Per-database configurable. Type: integer. Default value is 0.
Support at API level
- get\set statement execution timeout at connection level, milliseconds:
interface Attachment
uint getStatementTimeout(Status status);
void setStatementTimeout(Status status, uint timeOut);
- get\set statement execution timeout at statement level, milliseconds:
interface Statement
uint getTimeout(Status status);
void setTimeout(Status status, uint timeOut);
- set statement execution timeout at statement level using ISC API, milliseconds:
ISC_STATUS ISC_EXPORT fb_dsql_set_timeout(ISC_STATUS*, isc_stmt_handle*, ISC_ULONG);
- get statement execution timeout at config and\or connection level is possible
using isc_database_info() API with new info tags:
- fb_info_statement_timeout_db
- fb_info_statement_timeout_att
- get statement execution timeout at statement level is possible using isc_dsql_info()
API with new info tags:
- isc_info_sql_stmt_timeout_user timeout value of given statement
- isc_info_sql_stmt_timeout_run actual timeout value of given statement
evaluated considering values set at config, connection and statement levels, see
"effective value of timeout" above. Valid only when timeout timer is running, i.e.
for currently executed statements.
Remote client implementation notes:
- Attachment::setStatementTimeout() issued "SET STATEMENT TIMEOUT" SQL statement
- Attachment::getStatementTimeout() calls isc_database_info() with
fb_info_statement_timeout_att tag
- Statement::setTimeout() save timeout value given and pass it with op_execute
and op_execute2 packets
- Statement::getTimeout() returns saved timeout value
- fb_dsql_set_timeout() is a wrapper over Statement::setTimeout()
If remote server doesn't support statement timeouts (protocol version less than 16):
- "set" functions will return isc_wish_list error
- "get" functions will return zero and set isc_wish_list error
- "info" functions will return isc_info_error tag in info buffer (as usual).
Support in SQL
- New SQL statement allows to set set statement execution timeout at connection level:
SET STATEMENT TIMEOUT <value> [HOUR | MINUTE | SECOND | MILLISECOND]
if timepart is not set, default is SECOND.
This statement could run outside of transaction control and immediately effective.
- Context variables
Context 'SYSTEM' have new variable: 'STATEMENT_TIMEOUT'. It contains current value of
statement execution timeout that was set at connection level, or zero, if timeout was
not set.
- Monitoring tables
MON$ATTACHMENTS
MON$STATEMENT_TIMEOUT Connection level statement timeout
MON$STATEMENTS
MON$STATEMENT_TIMEOUT Statement level statement timeout
MON$STATEMENT_TIMER Timeout timer expiration time
MON$STATEMENT_TIMEOUT contains timeout values set at connection\statement level,
in milliseconds. Zero, if timeout is not set.
MON$STATEMENT_TIMER contains NULL value if timeout was not set or if timer is not
running.
Support in ISQL tool
New ISQL command is introduced:
SET LOCAL_TIMEOUT <int>
It allows to set statement execution timeout (in milliseconds) for the next statement.
After statement execution it automatically reset to zero.

View File

@ -11,16 +11,20 @@ Description:
Syntax: Syntax:
<column definition> ::= <column definition> ::=
<name> <type> GENERATED BY DEFAULT AS IDENTITY [ ( <identity column option>... ) ] <constraints> <name> <type> GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( <identity column option>... ) ] <constraints>
<identity column option> ::= <identity column option> ::=
START WITH <value> | START WITH <value> |
INCREMENT [ BY ] <value> INCREMENT [ BY ] <value>
<alter column definition> ::= <alter column definition> ::=
<name> <set identity column generation clause> [ <alter identity column option>... ] |
<name> <alter identity column option>... | <name> <alter identity column option>... |
<name> DROP IDENTITY <name> DROP IDENTITY
<set identity column generation clause> ::=
SET GENERATED { ALWAYS | BY DEFAULT }
<alter identity column option> ::= <alter identity column option> ::=
RESTART [ WITH <value> ] | RESTART [ WITH <value> ] |
SET INCREMENT [ BY ] <value> SET INCREMENT [ BY ] <value>
@ -39,10 +43,8 @@ Notes:
Implementation: Implementation:
Two columns have been inserted in RDB$RELATION_FIELDS: RDB$GENERATOR_NAME and RDB$IDENTITY_TYPE. Two columns have been inserted in RDB$RELATION_FIELDS: RDB$GENERATOR_NAME and RDB$IDENTITY_TYPE.
RDB$GENERATOR_NAME stores the automatically created generator for the column. In RDB$GENERATORS, RDB$GENERATOR_NAME stores the automatically created generator for the column. In RDB$GENERATORS,
the value of RDB$SYSTEM_FLAG of that generator will be 6. RDB$IDENTITY_TYPE will currently the value of RDB$SYSTEM_FLAG of that generator will be 6. RDB$IDENTITY_TYPE stores the value
always store the value 1 (by default) for identity columns and NULL for non-identity columns. 0 for GENERATED ALWAYS, 1 for GENERATED BY DEFAULT, and NULL for non-identity columns.
In the future this column will store the value 0, too (for ALWAYS) when Firebird support this type
of identity column.
Example: Example:
@ -84,3 +86,21 @@ alter table objects
alter table objects alter table objects
alter id drop identity; alter id drop identity;
---------------
Override Clause
---------------
BY DEFAULT identity columns can be overriden in INSERT statements (INSERT, UPDATE OR INSERT, MERGE ... WHEN NOT MATCHED)
just specifying the value in the values list. However, for ALWAYS identity columns that is not allowed.
To use the value passed in the INSERT statement for an ALWAYS column, you should pass OVERRIDING SYSTEM VALUE as
following:
insert into objects (id, name) overriding system value values (11, 'Laptop');
OVERRIDING also supports a subclause to be used with BY DEFAULT columns, to ignore the value passed in INSERT and use
the defined sequence:
insert into objects (id, name) overriding user value values (12, 'Laptop'); -- 12 is not used

View File

@ -236,10 +236,8 @@ void DbCrypt::setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolder
return; return;
if (callback && callback->callback(0, NULL, 1, &key) == 1) if (callback && callback->callback(0, NULL, 1, &key) == 1)
{
return; return;
} }
}
key = 0; key = 0;
noKeyError(status); noKeyError(status);

View File

@ -1664,8 +1664,30 @@ C --
PARAMETER (GDS__dsql_window_duplicate = 335545125) PARAMETER (GDS__dsql_window_duplicate = 335545125)
INTEGER*4 GDS__sql_too_long INTEGER*4 GDS__sql_too_long
PARAMETER (GDS__sql_too_long = 335545126) PARAMETER (GDS__sql_too_long = 335545126)
INTEGER*4 GDS__cfg_stmt_timeout
PARAMETER (GDS__cfg_stmt_timeout = 335545127)
INTEGER*4 GDS__att_stmt_timeout
PARAMETER (GDS__att_stmt_timeout = 335545128)
INTEGER*4 GDS__req_stmt_timeout
PARAMETER (GDS__req_stmt_timeout = 335545129)
INTEGER*4 GDS__att_shut_killed
PARAMETER (GDS__att_shut_killed = 335545130)
INTEGER*4 GDS__att_shut_idle
PARAMETER (GDS__att_shut_idle = 335545131)
INTEGER*4 GDS__att_shut_db_down
PARAMETER (GDS__att_shut_db_down = 335545132)
INTEGER*4 GDS__att_shut_engine
PARAMETER (GDS__att_shut_engine = 335545133)
INTEGER*4 GDS__overriding_without_identity
PARAMETER (GDS__overriding_without_identity = 335545134)
INTEGER*4 GDS__overriding_system_invalid
PARAMETER (GDS__overriding_system_invalid = 335545135)
INTEGER*4 GDS__overriding_user_invalid
PARAMETER (GDS__overriding_user_invalid = 335545136)
INTEGER*4 GDS__overriding_system_missing
PARAMETER (GDS__overriding_system_missing = 335545137)
INTEGER*4 GDS__decprecision_err INTEGER*4 GDS__decprecision_err
PARAMETER (GDS__decprecision_err = 335545127) PARAMETER (GDS__decprecision_err = 335545138)
INTEGER*4 GDS__gfix_db_name INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929) PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw INTEGER*4 GDS__gfix_invalid_sw

View File

@ -1659,8 +1659,30 @@ const
gds_dsql_window_duplicate = 335545125; gds_dsql_window_duplicate = 335545125;
isc_sql_too_long = 335545126; isc_sql_too_long = 335545126;
gds_sql_too_long = 335545126; gds_sql_too_long = 335545126;
isc_decprecision_err = 335545127; isc_cfg_stmt_timeout = 335545127;
gds_decprecision_err = 335545127; gds_cfg_stmt_timeout = 335545127;
isc_att_stmt_timeout = 335545128;
gds_att_stmt_timeout = 335545128;
isc_req_stmt_timeout = 335545129;
gds_req_stmt_timeout = 335545129;
isc_att_shut_killed = 335545130;
gds_att_shut_killed = 335545130;
isc_att_shut_idle = 335545131;
gds_att_shut_idle = 335545131;
isc_att_shut_db_down = 335545132;
gds_att_shut_db_down = 335545132;
isc_att_shut_engine = 335545133;
gds_att_shut_engine = 335545133;
isc_overriding_without_identity = 335545134;
gds_overriding_without_identity = 335545134;
isc_overriding_system_invalid = 335545135;
gds_overriding_system_invalid = 335545135;
isc_overriding_user_invalid = 335545136;
gds_overriding_user_invalid = 335545136;
isc_overriding_system_missing = 335545137;
gds_overriding_system_missing = 335545137;
isc_decprecision_err = 335545138;
gds_decprecision_err = 335545138;
isc_gfix_db_name = 335740929; isc_gfix_db_name = 335740929;
gds_gfix_db_name = 335740929; gds_gfix_db_name = 335740929;
isc_gfix_invalid_sw = 335740930; isc_gfix_invalid_sw = 335740930;

View File

@ -539,12 +539,13 @@ public:
case Firebird::IUser::OP_USER_DISPLAY: case Firebird::IUser::OP_USER_DISPLAY:
{ {
Firebird::string disp = "SELECT PLG$USER_NAME, PLG$FIRST, PLG$MIDDLE, PLG$LAST, PLG$COMMENT, PLG$ATTRIBUTES, " Firebird::string disp =
" CASE WHEN RDB$RELATION_NAME IS NULL THEN FALSE ELSE TRUE END, PLG$ACTIVE " "WITH ADMINS AS (SELECT RDB$USER FROM RDB$USER_PRIVILEGES "
"FROM PLG$SRP_VIEW LEFT JOIN RDB$USER_PRIVILEGES " " WHERE RDB$RELATION_NAME = 'RDB$ADMIN' AND RDB$PRIVILEGE = 'M' GROUP BY RDB$USER) "
" ON PLG$SRP_VIEW.PLG$USER_NAME = RDB$USER_PRIVILEGES.RDB$USER " "SELECT PLG$USER_NAME, PLG$FIRST, PLG$MIDDLE, PLG$LAST, PLG$COMMENT, PLG$ATTRIBUTES, "
" AND RDB$RELATION_NAME = '" ADMIN_ROLE "' " " CASE WHEN RDB$USER IS NULL THEN FALSE ELSE TRUE END, PLG$ACTIVE "
" AND RDB$PRIVILEGE = 'M' "; "FROM PLG$SRP_VIEW LEFT JOIN ADMINS "
" ON PLG$SRP_VIEW.PLG$USER_NAME = ADMINS.RDB$USER ";
if (user->userName()->entered()) if (user->userName()->entered())
{ {
disp += " WHERE PLG$USER_NAME = ?"; disp += " WHERE PLG$USER_NAME = ?";

View File

@ -353,6 +353,7 @@ int SecurityDatabase::verify(IWriter* authBlock, IServerBlock* sBlock)
pw1[MAX_LEGACY_PASSWORD_LENGTH] = 0; pw1[MAX_LEGACY_PASSWORD_LENGTH] = 0;
string storedHash(pw1, MAX_LEGACY_PASSWORD_LENGTH); string storedHash(pw1, MAX_LEGACY_PASSWORD_LENGTH);
storedHash.rtrim(); storedHash.rtrim();
storedHash.recalculate_length();
string newHash; string newHash;
LegacyHash::hash(newHash, login, passwordEnc, storedHash); LegacyHash::hash(newHash, login, passwordEnc, storedHash);

View File

@ -359,9 +359,9 @@ int MsgPrintErr(const char* format, const SafeArg& arg, bool userFormatting)
int fb_msg_format(void* handle, USHORT facility, USHORT number, unsigned int bsize, TEXT* buffer, int fb_msg_format(void* handle, USHORT facility, USHORT number, unsigned int bsize, TEXT* buffer,
const MsgFormat::SafeArg& arg) const MsgFormat::SafeArg& arg)
{ {
// The field MESSAGES.TEXT is 118 bytes long. // The field MESSAGES.TEXT is 138 bytes long.
int total_msg = 0; int total_msg = 0;
char msg[120] = ""; char msg[138 + 2] = "";
const int n = gds__msg_lookup(handle, facility, number, sizeof(msg), msg, NULL); const int n = gds__msg_lookup(handle, facility, number, sizeof(msg), msg, NULL);
if (n > 0 && unsigned(n) < sizeof(msg)) if (n > 0 && unsigned(n) < sizeof(msg))

View File

@ -35,7 +35,7 @@ class NullableClear
public: public:
static void clear(T& v) static void clear(T& v)
{ {
v = 0; v = T();
} }
}; };
@ -70,6 +70,11 @@ public:
return (!specified && !o.specified) || (specified == o.specified && value == o.value); return (!specified && !o.specified) || (specified == o.specified && value == o.value);
} }
bool operator ==(const T& o) const
{
return specified && value == o;
}
void operator =(const T& v) void operator =(const T& v)
{ {
this->value = v; this->value = v;
@ -84,26 +89,6 @@ public:
// NullableClear specializations. // NullableClear specializations.
template <>
class NullableClear<Firebird::string> // string especialization for NullableClear
{
public:
static void clear(Firebird::string& v)
{
v = "";
}
};
template <>
class NullableClear<Firebird::MetaName> // MetaName especialization for NullableClear
{
public:
static void clear(Firebird::MetaName& v)
{
v = "";
}
};
template <typename T> template <typename T>
class NullableClear<BaseNullable<T> > class NullableClear<BaseNullable<T> >
{ {

View File

@ -108,7 +108,7 @@ namespace
{ {
fprintf(stderr, "dladdr: %s\n", dlerror()); fprintf(stderr, "dladdr: %s\n", dlerror());
} }
#elif defined(WIN_32) #elif defined(WIN_NT)
HMODULE hmod = 0; HMODULE hmod = 0;
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCTSTR) &allClean, (LPCTSTR) &allClean,

View File

@ -39,124 +39,6 @@ namespace Firebird {
#if defined(WIN_NT) #if defined(WIN_NT)
// Win9X support
#ifdef WIN9X_SUPPORT
// NS: This code is adapted from from KernelEx project, with the explicit
// permission from the author. KernelEx project aims to provide Windows XP
// compatibility layer for Windows 98 and Windows ME. For further information
// please refer to http://www.sourceforge.net/projects/kernelex/
static const K32OBJ_CRITICAL_SECTION = 4;
static const TDBX_WIN98 = 0x50;
static const TDBX_WINME = 0x80;
typedef struct _CRIT_SECT // Size = 0x20
{
BYTE Type; // 00 = 4: K32_OBJECT_CRITICAL_SECTION
int RecursionCount; // 04 initially 0, incremented on lock
void* OwningThread; // 08 pointer to TDBX
DWORD un3; // 0C
int LockCount; // 10 initially 1, decremented on lock
struct _CRIT_SECT* Next; // 14
void* PLst; // 18 list of processes using it?
struct _WIN_CRITICAL_SECTION* UserCS; // 1C pointer to user defined CRITICAL_SECTION
} CRIT_SECT, *PCRIT_SECT;
typedef struct _WIN_CRITICAL_SECTION
{
BYTE Type; //= 4: K32_OBJECT_CRITICAL_SECTION
PCRIT_SECT crit;
DWORD un1;
DWORD un2;
DWORD un3;
DWORD un4;
} WIN_CRITICAL_SECTION, *PWIN_CRITICAL_SECTION;
static DWORD tdbx_offset;
__declspec(naked) BOOL WINAPI TryEnterCrst(CRIT_SECT* crit)
{
__asm {
mov edx, [esp+4]
xor eax, eax
inc eax
xor ecx, ecx
cmpxchg [edx+10h], ecx ;if (OP1==eax) { OP1=OP2; ZF=1; } else { eax=OP1; ZF=0 }
;mov ecx, ppTDBXCur
mov ecx, fs:[18h]
add ecx, [tdbx_offset]
mov ecx, [ecx] ;ecx will contain TDBX now
cmp eax, 1
jnz L1
;critical section was unowned => successful lock
mov [edx+8], ecx
inc dword ptr [edx+4]
ret 4
L1:
cmp [edx+8], ecx
jnz L2
;critical section owned by this thread
dec dword ptr [edx+10h]
inc dword ptr [edx+4]
xor eax, eax
inc eax
ret 4
L2:
;critical section owned by other thread - do nothing
xor eax, eax
ret 4
}
}
BOOL WINAPI TryEnterCriticalSection_Win9X(CRITICAL_SECTION* cs)
{
WIN_CRITICAL_SECTION* mycs = (WIN_CRITICAL_SECTION*) cs;
if (mycs->Type != K32OBJ_CRITICAL_SECTION)
RaiseException(STATUS_ACCESS_VIOLATION, 0, 0, NULL);
return TryEnterCrst(mycs->crit);
}
#endif
// On Win 98 and Win ME TryEnterCriticalSection is defined, but not implemented
// So direct linking to it won't hurt and will signal our incompatibility with Win 95
TryEnterCS::tTryEnterCriticalSection TryEnterCS::m_funct =
reinterpret_cast<TryEnterCS::tTryEnterCriticalSection>(TryEnterCriticalSection);
static TryEnterCS tryEnterCS;
TryEnterCS::TryEnterCS()
{
// Win9X support
#ifdef WIN9X_SUPPORT
OSVERSIONINFO OsVersionInfo;
OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (GetVersionEx((LPOSVERSIONINFO) &OsVersionInfo))
{
if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
OsVersionInfo.dwMajorVersion == 4)
{
// Windows 98
if (OsVersionInfo.dwMinorVersion == 10)
{
tdbx_offset = TDBX_WIN98;
m_funct = TryEnterCriticalSection_Win9X;
}
// Windows ME
if (OsVersionInfo.dwMinorVersion == 90)
{
tdbx_offset = TDBX_WINME;
m_funct = TryEnterCriticalSection_Win9X;
}
}
}
#endif
}
void Spinlock::init() void Spinlock::init()
{ {
SetCriticalSectionSpinCount(&spinlock, 4000); SetCriticalSectionSpinCount(&spinlock, 4000);

View File

@ -55,22 +55,6 @@ class Exception; // Needed for catch
// Windows version of the class // Windows version of the class
class TryEnterCS
{
public:
TryEnterCS();
static bool tryEnter(LPCRITICAL_SECTION lpCS)
{
return ((m_funct) (lpCS) == TRUE);
}
private:
typedef BOOL (WINAPI *tTryEnterCriticalSection)(LPCRITICAL_SECTION lpCriticalSection);
static tTryEnterCriticalSection m_funct;
};
class Mutex : public Reasons class Mutex : public Reasons
{ {
protected: protected:
@ -97,7 +81,7 @@ public:
~Mutex() ~Mutex()
{ {
#if defined DEV_BUILD && !defined WIN9X_SUPPORT #if defined DEV_BUILD
if (spinlock.OwningThread != 0) if (spinlock.OwningThread != 0)
DebugBreak(); DebugBreak();
fb_assert(lockCount == 0); fb_assert(lockCount == 0);
@ -116,7 +100,7 @@ public:
bool tryEnter(const char* aReason) bool tryEnter(const char* aReason)
{ {
const bool ret = TryEnterCS::tryEnter(&spinlock); const bool ret = (TryEnterCriticalSection(&spinlock) == TRUE);
if (ret) if (ret)
{ {
reason(aReason); reason(aReason);
@ -129,7 +113,7 @@ public:
void leave() void leave()
{ {
#if defined DEV_BUILD && !defined WIN9X_SUPPORT #if defined DEV_BUILD
// NS: This check is based on internal structure on CRITICAL_SECTION // NS: This check is based on internal structure on CRITICAL_SECTION
// On 9X it works differently, and future OS versions may break this check as well // On 9X it works differently, and future OS versions may break this check as well
if ((U_IPTR) spinlock.OwningThread != GetCurrentThreadId()) if ((U_IPTR) spinlock.OwningThread != GetCurrentThreadId())

View File

@ -551,11 +551,6 @@ extern "C" int remove(const char* path);
#define INET_ERRNO WSAGetLastError() #define INET_ERRNO WSAGetLastError()
#define H_ERRNO WSAGetLastError() #define H_ERRNO WSAGetLastError()
// For Visual Studio 2003 and earlier enable Windows 9X support
#if defined _MSC_VER && (_MSC_VER < 1400)
#define WIN9X_SUPPORT
#endif
#endif /* WIN_NT */ #endif /* WIN_NT */

View File

@ -69,13 +69,15 @@ public:
} }
} }
/* It was a kind of getting ready for changing config remotely... /***
It was a kind of getting ready for changing config remotely...
void changeDefaultConfig(Config* newConfig) void changeDefaultConfig(Config* newConfig)
{ {
defaultConfig = newConfig; defaultConfig = newConfig;
} }
*/ ***/
Firebird::RefPtr<const Config>& getDefaultConfig() Firebird::RefPtr<const Config>& getDefaultConfig()
{ {
return defaultConfig; return defaultConfig;
@ -197,7 +199,9 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] =
{TYPE_BOOLEAN, "WireCompression", (ConfigValue) false}, {TYPE_BOOLEAN, "WireCompression", (ConfigValue) false},
{TYPE_INTEGER, "MaxIdentifierByteLength", (ConfigValue) -1}, {TYPE_INTEGER, "MaxIdentifierByteLength", (ConfigValue) -1},
{TYPE_INTEGER, "MaxIdentifierCharLength", (ConfigValue) -1}, {TYPE_INTEGER, "MaxIdentifierCharLength", (ConfigValue) -1},
{TYPE_BOOLEAN, "CryptSecurityDatabase", (ConfigValue) false} {TYPE_BOOLEAN, "AllowEncryptedSecurityDatabase", (ConfigValue) false},
{TYPE_INTEGER, "StatementTimeout", (ConfigValue) 0},
{TYPE_INTEGER, "ConnectionIdleTimeout", (ConfigValue) 0}
}; };
/****************************************************************************** /******************************************************************************
@ -818,3 +822,13 @@ bool Config::getCryptSecurityDatabase() const
{ {
return get<bool>(KEY_ENCRYPT_SECURITY_DATABASE); return get<bool>(KEY_ENCRYPT_SECURITY_DATABASE);
} }
unsigned int Config::getStatementTimeout() const
{
return get<unsigned int>(KEY_STMT_TIMEOUT);
}
unsigned int Config::getConnIdleTimeout() const
{
return get<unsigned int>(KEY_CONN_IDLE_TIMEOUT);
}

View File

@ -143,6 +143,8 @@ public:
KEY_MAX_IDENTIFIER_BYTE_LENGTH, KEY_MAX_IDENTIFIER_BYTE_LENGTH,
KEY_MAX_IDENTIFIER_CHAR_LENGTH, KEY_MAX_IDENTIFIER_CHAR_LENGTH,
KEY_ENCRYPT_SECURITY_DATABASE, KEY_ENCRYPT_SECURITY_DATABASE,
KEY_STMT_TIMEOUT,
KEY_CONN_IDLE_TIMEOUT,
MAX_CONFIG_KEY // keep it last MAX_CONFIG_KEY // keep it last
}; };
@ -352,6 +354,11 @@ public:
int getMaxIdentifierCharLength() const; int getMaxIdentifierCharLength() const;
bool getCryptSecurityDatabase() const; bool getCryptSecurityDatabase() const;
// set in seconds
unsigned int getStatementTimeout() const;
// set in minutes
unsigned int getConnIdleTimeout() const;
}; };
// Implementation of interface to access master configuration file // Implementation of interface to access master configuration file

View File

@ -32,10 +32,13 @@
#ifndef COMMON_FILE_PARAMS_H #ifndef COMMON_FILE_PARAMS_H
#define COMMON_FILE_PARAMS_H #define COMMON_FILE_PARAMS_H
#define COMMON_FILE_PREFIX "13"
static const char* const EVENT_FILE = "fb_event_%s"; static const char* const EVENT_FILE = "fb_event_%s";
static const char* const LOCK_FILE = "fb_lock_%s"; static const char* const LOCK_FILE = "fb_lock_%s";
static const char* const MONITOR_FILE = "fb_monitor_%s"; static const char* const MONITOR_FILE = "fb_monitor_%s";
static const char* const TRACE_FILE = "fb13_trace"; static const char* const TRACE_FILE = "fb" COMMON_FILE_PREFIX "_trace";
static const char* const USER_MAP_FILE = "fb" COMMON_FILE_PREFIX "_user_mapping";
#ifdef UNIX #ifdef UNIX
static const char* const INIT_FILE = "fb_init"; static const char* const INIT_FILE = "fb_init";

View File

@ -505,40 +505,6 @@ SLONG ISC_set_prefix(const TEXT* sw, const TEXT* path)
} }
#ifdef WIN9X_SUPPORT
static DWORD os_type = 0;
// Returns the type of OS: true for NT,
// false for the 16-bit based ones (9x/ME, ...).
//
bool ISC_is_WinNT()
{
// NS: this is thread safe.
// In the worst case initialization will be called more than once
if (!os_type)
{
// The first time this routine is called we use the Windows API
// call GetVersion to determine whether Windows NT or 9X
// is running.
OSVERSIONINFO OsVersionInfo;
OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (GetVersionEx((LPOSVERSIONINFO) &OsVersionInfo))
{
os_type = OsVersionInfo.dwPlatformId;
fb_assert(os_type);
}
else {
os_type = VER_PLATFORM_WIN32_NT; // Default to NT
}
}
return os_type >= VER_PLATFORM_WIN32_NT; // Windows NT, CE and future platforms
}
#endif
#ifdef WIN_NT #ifdef WIN_NT
LPSECURITY_ATTRIBUTES ISC_get_security_desc() LPSECURITY_ATTRIBUTES ISC_get_security_desc()
{ {

View File

@ -228,25 +228,27 @@ bool ISC_analyze_nfs(tstring& expanded_filename, tstring& node_name)
// If we are ignoring NFS remote mounts then do not bother checking here // If we are ignoring NFS remote mounts then do not bother checking here
// and pretend it's only local. MOD 16-Nov-2002 // and pretend it's only local. MOD 16-Nov-2002
if (Config::getRemoteFileOpenAbility()) { if (Config::getRemoteFileOpenAbility())
return false; return false;
}
#ifdef LINUX #ifdef LINUX
// In order to avoid analyzing mtab in most cases check for non-device mounts first // In order to avoid analyzing mtab in most cases check for non-device mounts first
struct stat fileStat; struct stat fileStat;
unsigned m = 1; // use something that is known to be not non-device major unsigned m = 1; // use something that is known to be not non-device major
if (os_utils::stat(expanded_filename.c_str(), &fileStat) == 0) {
if (os_utils::stat(expanded_filename.c_str(), &fileStat) == 0)
m = major(fileStat.st_dev); m = major(fileStat.st_dev);
} else // stat error - let's try with path component
else { // stat error - let's try with path component {
tstring path, name; tstring path, name;
PathUtils::splitLastComponent(path, name, expanded_filename); PathUtils::splitLastComponent(path, name, expanded_filename);
if (path.hasData() && os_utils::stat(path.c_str(), &fileStat) == 0) if (path.hasData() && os_utils::stat(path.c_str(), &fileStat) == 0)
m = major(fileStat.st_dev); m = major(fileStat.st_dev);
} }
if (m != 0 && m != 144 && m != 145 && m != 146) { if (m != 0 && m != 144 && m != 145 && m != 146)
{
// device mount or stat for file/path is impossible - definitely not NFS // device mount or stat for file/path is impossible - definitely not NFS
return false; return false;
} }

View File

@ -39,10 +39,6 @@ void iscLogStatus(const TEXT* text, const ISC_STATUS* status_vector);
void iscLogStatus(const TEXT* text, const Firebird::IStatus* status); void iscLogStatus(const TEXT* text, const Firebird::IStatus* status);
void iscLogException(const TEXT* text, const Firebird::Exception& e); void iscLogException(const TEXT* text, const Firebird::Exception& e);
#ifdef WIN9X_SUPPORT
bool ISC_is_WinNT();
#endif
#ifdef WIN_NT #ifdef WIN_NT
struct _SECURITY_ATTRIBUTES* ISC_get_security_desc(); struct _SECURITY_ATTRIBUTES* ISC_get_security_desc();
#endif #endif

View File

@ -143,4 +143,3 @@ void* DlfcnModule::findSymbol(const Firebird::string& symName)
return result; return result;
} }

View File

@ -5991,7 +5991,7 @@ void RelationNode::FieldDefinition::store(thread_db* tdbb, jrd_tra* transaction)
strcpy(RFR.RDB$GENERATOR_NAME, identitySequence.c_str()); strcpy(RFR.RDB$GENERATOR_NAME, identitySequence.c_str());
RFR.RDB$IDENTITY_TYPE.NULL = FALSE; RFR.RDB$IDENTITY_TYPE.NULL = FALSE;
RFR.RDB$IDENTITY_TYPE = IDENT_TYPE_BY_DEFAULT; RFR.RDB$IDENTITY_TYPE = identityType.value;
} }
if (notNullFlag.specified) if (notNullFlag.specified)
@ -6336,6 +6336,7 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
} }
DYN_UTIL_generate_generator_name(tdbb, fieldDefinition.identitySequence); DYN_UTIL_generate_generator_name(tdbb, fieldDefinition.identitySequence);
fieldDefinition.identityType = clause->identityOptions->type;
CreateAlterSequenceNode::store(tdbb, transaction, fieldDefinition.identitySequence, CreateAlterSequenceNode::store(tdbb, transaction, fieldDefinition.identitySequence,
fb_sysflag_identity_generator, fb_sysflag_identity_generator,
@ -7898,6 +7899,13 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc
transaction->getGenIdCache()->put(id, val); transaction->getGenIdCache()->put(id, val);
} }
if (clause->identityOptions->type.specified)
{
MODIFY RFR
RFR.RDB$IDENTITY_TYPE = clause->identityOptions->type.value;
END_MODIFY
}
if (clause->identityOptions->increment.specified) if (clause->identityOptions->increment.specified)
{ {
if (clause->identityOptions->increment.value == 0) if (clause->identityOptions->increment.value == 0)

View File

@ -1140,6 +1140,7 @@ public:
Firebird::MetaName relationName; Firebird::MetaName relationName;
Firebird::MetaName fieldSource; Firebird::MetaName fieldSource;
Firebird::MetaName identitySequence; Firebird::MetaName identitySequence;
Nullable<IdentityType> identityType;
Nullable<USHORT> collationId; Nullable<USHORT> collationId;
Nullable<bool> notNullFlag; // true = NOT NULL / false = NULL Nullable<bool> notNullFlag; // true = NOT NULL / false = NULL
Nullable<USHORT> position; Nullable<USHORT> position;
@ -1306,11 +1307,18 @@ public:
struct IdentityOptions struct IdentityOptions
{ {
IdentityOptions(MemoryPool&, IdentityType aType)
: type(aType),
restart(false)
{
}
IdentityOptions(MemoryPool&) IdentityOptions(MemoryPool&)
: restart(false) : restart(false)
{ {
} }
Nullable<IdentityType> type;
Nullable<SINT64> startValue; Nullable<SINT64> startValue;
Nullable<SLONG> increment; Nullable<SLONG> increment;
bool restart; // used in ALTER bool restart; // used in ALTER

View File

@ -10519,17 +10519,6 @@ void SubstringNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
desc->dsc_flags |= DSC_null; desc->dsc_flags |= DSC_null;
else else
{ {
if (offsetNode->is<LiteralNode>() && desc1.dsc_dtype == dtype_long)
{
SLONG offset = MOV_get_long(tdbb, &desc1, 0);
if (decrementNode && decrementNode->is<LiteralNode>() && desc3.dsc_dtype == dtype_long)
offset -= MOV_get_long(tdbb, &desc3, 0);
if (offset < 0)
ERR_post(Arg::Gds(isc_bad_substring_offset) << Arg::Num(offset + 1));
}
if (length->is<LiteralNode>() && desc2.dsc_dtype == dtype_long) if (length->is<LiteralNode>() && desc2.dsc_dtype == dtype_long)
{ {
const SLONG len = MOV_get_long(tdbb, &desc2, 0); const SLONG len = MOV_get_long(tdbb, &desc2, 0);
@ -10586,20 +10575,24 @@ dsc* SubstringNode::execute(thread_db* tdbb, jrd_req* request) const
dsc* SubstringNode::perform(thread_db* tdbb, impure_value* impure, const dsc* valueDsc, dsc* SubstringNode::perform(thread_db* tdbb, impure_value* impure, const dsc* valueDsc,
const dsc* startDsc, const dsc* lengthDsc) const dsc* startDsc, const dsc* lengthDsc)
{ {
const SLONG sStart = MOV_get_long(tdbb, startDsc, 0); SINT64 sStart = MOV_get_long(tdbb, startDsc, 0);
const SLONG sLength = MOV_get_long(tdbb, lengthDsc, 0); SINT64 sLength = MOV_get_long(tdbb, lengthDsc, 0);
if (sLength < 0)
status_exception::raise(Arg::Gds(isc_bad_substring_length) << Arg::Num(sLength));
if (sStart < 0) if (sStart < 0)
status_exception::raise(Arg::Gds(isc_bad_substring_offset) << Arg::Num(sStart + 1)); {
else if (sLength < 0) sLength = MAX(sLength + sStart, 0);
status_exception::raise(Arg::Gds(isc_bad_substring_length) << Arg::Num(sLength)); sStart = 0;
}
FB_UINT64 start = FB_UINT64(sStart);
FB_UINT64 length = FB_UINT64(sLength);
dsc desc; dsc desc;
DataTypeUtil(tdbb).makeSubstr(&desc, valueDsc, startDsc, lengthDsc); DataTypeUtil(tdbb).makeSubstr(&desc, valueDsc, startDsc, lengthDsc);
ULONG start = (ULONG) sStart;
ULONG length = (ULONG) sLength;
if (desc.isText() && length > MAX_STR_SIZE) if (desc.isText() && length > MAX_STR_SIZE)
length = MAX_STR_SIZE; length = MAX_STR_SIZE;
@ -10621,8 +10614,8 @@ dsc* SubstringNode::perform(thread_db* tdbb, impure_value* impure, const dsc* va
HalfStaticArray<UCHAR, BUFFER_LARGE> buffer; HalfStaticArray<UCHAR, BUFFER_LARGE> buffer;
CharSet* charSet = INTL_charset_lookup(tdbb, valueDsc->getCharSet()); CharSet* charSet = INTL_charset_lookup(tdbb, valueDsc->getCharSet());
const FB_UINT64 byte_offset = FB_UINT64(start) * charSet->maxBytesPerChar(); const FB_UINT64 byte_offset = start * charSet->maxBytesPerChar();
const FB_UINT64 byte_length = FB_UINT64(length) * charSet->maxBytesPerChar(); const FB_UINT64 byte_length = length * charSet->maxBytesPerChar();
if (charSet->isMultiByte()) if (charSet->isMultiByte())
{ {
@ -11520,7 +11513,8 @@ UdfCallNode::UdfCallNode(MemoryPool& pool, const QualifiedName& aName, ValueList
name(pool, aName), name(pool, aName),
args(aArgs), args(aArgs),
function(NULL), function(NULL),
dsqlFunction(NULL) dsqlFunction(NULL),
isSubRoutine(false)
{ {
addChildNode(args, args); addChildNode(args, args);
} }
@ -11583,6 +11577,8 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*
PAR_error(csb, Arg::Gds(isc_funnotdef) << Arg::Str(name.toString())); PAR_error(csb, Arg::Gds(isc_funnotdef) << Arg::Str(name.toString()));
} }
node->isSubRoutine = function->isSubRoutine();
const UCHAR argCount = csb->csb_blr_reader.getByte(); const UCHAR argCount = csb->csb_blr_reader.getByte();
// Check to see if the argument count matches. // Check to see if the argument count matches.
@ -11675,7 +11671,7 @@ ValueExprNode* UdfCallNode::copy(thread_db* tdbb, NodeCopier& copier) const
{ {
UdfCallNode* node = FB_NEW_POOL(*tdbb->getDefaultPool()) UdfCallNode(*tdbb->getDefaultPool(), name); UdfCallNode* node = FB_NEW_POOL(*tdbb->getDefaultPool()) UdfCallNode(*tdbb->getDefaultPool(), name);
node->args = copier.copy(tdbb, args); node->args = copier.copy(tdbb, args);
node->function = function; node->function = isSubRoutine ? function : Function::lookup(tdbb, name, false);
return node; return node;
} }

View File

@ -1750,6 +1750,7 @@ public:
private: private:
dsql_udf* dsqlFunction; dsql_udf* dsqlFunction;
bool isSubRoutine;
}; };

View File

@ -94,6 +94,8 @@ static void postTriggerAccess(CompilerScratch* csb, jrd_rel* ownerRelation,
ExternalAccess::exa_act operation, jrd_rel* view); ExternalAccess::exa_act operation, jrd_rel* view);
static void preModifyEraseTriggers(thread_db* tdbb, TrigVector** trigs, static void preModifyEraseTriggers(thread_db* tdbb, TrigVector** trigs,
StmtNode::WhichTrigger whichTrig, record_param* rpb, record_param* rec, TriggerAction op); StmtNode::WhichTrigger whichTrig, record_param* rpb, record_param* rec, TriggerAction op);
static void preprocessAssignments(thread_db* tdbb, CompilerScratch* csb,
StreamType stream, CompoundStmtNode* compoundNode, const Nullable<OverrideClause>* insertOverride);
static void validateExpressions(thread_db* tdbb, const Array<ValidateInfo>& validations); static void validateExpressions(thread_db* tdbb, const Array<ValidateInfo>& validations);
} // namespace Jrd } // namespace Jrd
@ -3448,6 +3450,10 @@ const StmtNode* ExecStatementNode::execute(thread_db* tdbb, jrd_req* request, Ex
const MetaName* const* inpNames = inputNames ? inputNames->begin() : NULL; const MetaName* const* inpNames = inputNames ? inputNames->begin() : NULL;
stmt->prepare(tdbb, tran, sSql, inputNames != NULL); stmt->prepare(tdbb, tran, sSql, inputNames != NULL);
const TimeoutTimer* timer = tdbb->getTimeoutTimer();
if (timer)
stmt->setTimeout(tdbb, timer->timeToExpire());
if (stmt->isSelectable()) if (stmt->isSelectable())
stmt->open(tdbb, tran, inpNames, inputs, !innerStmt); stmt->open(tdbb, tran, inpNames, inputs, !innerStmt);
else else
@ -5336,6 +5342,7 @@ StmtNode* MergeNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
store->dsqlRelation = relation; store->dsqlRelation = relation;
store->dsqlFields = notMatched->fields; store->dsqlFields = notMatched->fields;
store->dsqlValues = notMatched->values; store->dsqlValues = notMatched->values;
store->overrideClause = notMatched->overrideClause;
bool needSavePoint; // unused bool needSavePoint; // unused
thisIf->trueAction = store = store->internalDsqlPass(dsqlScratch, false, needSavePoint)->as<StoreNode>(); thisIf->trueAction = store = store->internalDsqlPass(dsqlScratch, false, needSavePoint)->as<StoreNode>();
@ -5877,50 +5884,7 @@ void ModifyNode::genBlr(DsqlCompilerScratch* dsqlScratch)
ModifyNode* ModifyNode::pass1(thread_db* tdbb, CompilerScratch* csb) ModifyNode* ModifyNode::pass1(thread_db* tdbb, CompilerScratch* csb)
{ {
CompoundStmtNode* compoundNode = statement->as<CompoundStmtNode>(); preprocessAssignments(tdbb, csb, newStream, statement->as<CompoundStmtNode>(), NULL);
// Remove assignments of DEFAULT to computed fields.
if (compoundNode)
{
for (size_t i = compoundNode->statements.getCount(); i--; )
{
const AssignmentNode* assign = compoundNode->statements[i]->as<AssignmentNode>();
fb_assert(assign);
if (!assign)
continue;
const ExprNode* assignFrom = assign->asgnFrom;
const FieldNode* assignToField = assign->asgnTo->as<FieldNode>();
if (assignToField && assignFrom->is<DefaultNode>())
{
jrd_rel* relation = csb->csb_rpt[newStream].csb_relation;
int fieldId = assignToField->fieldId;
while (true)
{
jrd_fld* fld;
if (assignToField->fieldStream == newStream &&
relation &&
relation->rel_fields &&
(fld = (*relation->rel_fields)[fieldId]))
{
if (fld->fld_computation)
compoundNode->statements.remove(i);
else if (relation->rel_view_rse && fld->fld_source_rel_field.first.hasData())
{
relation = MET_lookup_relation(tdbb, fld->fld_source_rel_field.first);
if ((fieldId = MET_lookup_field(tdbb, relation, fld->fld_source_rel_field.second)) >= 0)
continue;
}
}
break;
}
}
}
}
pass1Modify(tdbb, csb, this); pass1Modify(tdbb, csb, this);
@ -6459,6 +6423,7 @@ const StmtNode* ReceiveNode::execute(thread_db* /*tdbb*/, jrd_req* request, ExeS
static RegisterNode<StoreNode> regStoreNode(blr_store); static RegisterNode<StoreNode> regStoreNode(blr_store);
static RegisterNode<StoreNode> regStoreNode2(blr_store2); static RegisterNode<StoreNode> regStoreNode2(blr_store2);
static RegisterNode<StoreNode> regStoreNode3(blr_store3);
// Parse a store statement. // Parse a store statement.
DmlNode* StoreNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp) DmlNode* StoreNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp)
@ -6467,6 +6432,21 @@ DmlNode* StoreNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* cs
AutoSetRestore<StmtNode*> autoCurrentDMLNode(&csb->csb_currentDMLNode, node); AutoSetRestore<StmtNode*> autoCurrentDMLNode(&csb->csb_currentDMLNode, node);
if (blrOp == blr_store3)
{
node->overrideClause = static_cast<OverrideClause>(csb->csb_blr_reader.getByte());
switch (node->overrideClause.value)
{
case OverrideClause::USER_VALUE:
case OverrideClause::SYSTEM_VALUE:
break;
default:
PAR_syntax_error(csb, "invalid blr_store3 override clause");
}
}
const UCHAR* blrPos = csb->csb_blr_reader.getPos(); const UCHAR* blrPos = csb->csb_blr_reader.getPos();
node->relationSource = PAR_parseRecordSource(tdbb, csb)->as<RelationSourceNode>(); node->relationSource = PAR_parseRecordSource(tdbb, csb)->as<RelationSourceNode>();
@ -6481,6 +6461,13 @@ DmlNode* StoreNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* cs
if (blrOp == blr_store2) if (blrOp == blr_store2)
node->statement2 = PAR_parse_stmt(tdbb, csb); node->statement2 = PAR_parse_stmt(tdbb, csb);
else if (blrOp == blr_store3)
{
if (csb->csb_blr_reader.peekByte() == blr_null)
csb->csb_blr_reader.getByte();
else
node->statement2 = PAR_parse_stmt(tdbb, csb);
}
return node; return node;
} }
@ -6494,6 +6481,7 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch,
dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_INSERT); dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_INSERT);
StoreNode* node = FB_NEW_POOL(getPool()) StoreNode(getPool()); StoreNode* node = FB_NEW_POOL(getPool()) StoreNode(getPool());
node->overrideClause = overrideClause;
// Process SELECT expression, if present // Process SELECT expression, if present
@ -6602,7 +6590,21 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch,
NestConst<ValueExprNode>* ptr2 = values->items.begin(); NestConst<ValueExprNode>* ptr2 = values->items.begin();
for (const NestConst<ValueExprNode>* end = fields.end(); ptr != end; ++ptr, ++ptr2) for (const NestConst<ValueExprNode>* end = fields.end(); ptr != end; ++ptr, ++ptr2)
{ {
if (*ptr2) // it's NULL for DEFAULT // *ptr2 is NULL for DEFAULT
if (!*ptr2)
{
const FieldNode* field = (*ptr)->as<FieldNode>();
if (field && field->dsqlField)
{
*ptr2 = FB_NEW_POOL(getPool()) DefaultNode(getPool(),
relation->rel_name, field->dsqlField->fld_name);
*ptr2 = doDsqlPass(dsqlScratch, *ptr2, false);
}
}
if (*ptr2)
{ {
AssignmentNode* temp = FB_NEW_POOL(getPool()) AssignmentNode(getPool()); AssignmentNode* temp = FB_NEW_POOL(getPool()) AssignmentNode(getPool());
temp->asgnFrom = *ptr2; temp->asgnFrom = *ptr2;
@ -6687,12 +6689,19 @@ void StoreNode::genBlr(DsqlCompilerScratch* dsqlScratch)
{ {
const dsql_msg* message = dsqlGenDmlHeader(dsqlScratch, dsqlRse->as<RseNode>()); const dsql_msg* message = dsqlGenDmlHeader(dsqlScratch, dsqlRse->as<RseNode>());
dsqlScratch->appendUChar(statement2 ? blr_store2 : blr_store); dsqlScratch->appendUChar(overrideClause.specified ? blr_store3 : (statement2 ? blr_store2 : blr_store));
if (overrideClause.specified)
dsqlScratch->appendUChar(UCHAR(overrideClause.value));
GEN_expr(dsqlScratch, dsqlRelation); GEN_expr(dsqlScratch, dsqlRelation);
statement->genBlr(dsqlScratch); statement->genBlr(dsqlScratch);
if (statement2) if (statement2)
statement2->genBlr(dsqlScratch); statement2->genBlr(dsqlScratch);
else if (overrideClause.specified)
dsqlScratch->appendUChar(blr_null);
if (message) if (message)
dsqlScratch->appendUChar(blr_end); dsqlScratch->appendUChar(blr_end);
@ -6700,6 +6709,8 @@ void StoreNode::genBlr(DsqlCompilerScratch* dsqlScratch)
StoreNode* StoreNode::pass1(thread_db* tdbb, CompilerScratch* csb) StoreNode* StoreNode::pass1(thread_db* tdbb, CompilerScratch* csb)
{ {
preprocessAssignments(tdbb, csb, relationSource->getStream(), statement->as<CompoundStmtNode>(), &overrideClause);
if (pass1Store(tdbb, csb, this)) if (pass1Store(tdbb, csb, this))
makeDefaults(tdbb, csb); makeDefaults(tdbb, csb);
@ -6835,7 +6846,6 @@ void StoreNode::makeDefaults(thread_db* tdbb, CompilerScratch* csb)
} }
StmtNodeStack stack; StmtNodeStack stack;
USHORT fieldId = 0; USHORT fieldId = 0;
vec<jrd_fld*>::iterator ptr1 = vector->begin(); vec<jrd_fld*>::iterator ptr1 = vector->begin();
@ -8083,6 +8093,74 @@ void SetBindNode::execute(thread_db* tdbb, dsql_req* /*request*/) const
//-------------------- //--------------------
SetSessionNode::SetSessionNode(MemoryPool& pool, Type aType, ULONG aVal, UCHAR blr_timepart)
: SessionManagementNode(pool),
m_type(aType),
m_value(0)
{
// TYPE_IDLE_TIMEOUT should be set in seconds
// TYPE_STMT_TIMEOUT should be set in milliseconds
ULONG mult = 1;
switch (blr_timepart)
{
case blr_extract_hour:
mult = (aType == TYPE_IDLE_TIMEOUT) ? 3660 : 3660000;
break;
case blr_extract_minute:
mult = (aType == TYPE_IDLE_TIMEOUT) ? 60 : 60000;
break;
case blr_extract_second:
mult = (aType == TYPE_IDLE_TIMEOUT) ? 1 : 1000;
break;
case blr_extract_millisecond:
if (aType == TYPE_IDLE_TIMEOUT)
Arg::Gds(isc_invalid_extractpart_time).raise();
mult = 1;
break;
default:
Arg::Gds(isc_invalid_extractpart_time).raise();
break;
}
m_value = aVal * mult;
}
string SetSessionNode::internalPrint(NodePrinter& printer) const
{
Node::internalPrint(printer);
NODE_PRINT(printer, m_type);
NODE_PRINT(printer, m_value);
return "SetSessionNode";
}
void SetSessionNode::execute(thread_db* tdbb, dsql_req* request) const
{
Attachment* att = tdbb->getAttachment();
switch (m_type)
{
case TYPE_IDLE_TIMEOUT:
att->setIdleTimeout(m_value);
break;
case TYPE_STMT_TIMEOUT:
att->setStatementTimeout(m_value);
break;
}
}
//--------------------
StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{ {
thread_db* tdbb = JRD_get_thread_data(); // necessary? thread_db* tdbb = JRD_get_thread_data(); // necessary?
@ -8102,6 +8180,7 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
insert->dsqlFields = fields; insert->dsqlFields = fields;
insert->dsqlValues = values; insert->dsqlValues = values;
insert->dsqlReturning = returning; insert->dsqlReturning = returning;
insert->overrideClause = overrideClause;
insert = insert->internalDsqlPass(dsqlScratch, true, needSavePoint)->as<StoreNode>(); insert = insert->internalDsqlPass(dsqlScratch, true, needSavePoint)->as<StoreNode>();
fb_assert(insert); fb_assert(insert);
@ -9355,6 +9434,99 @@ static void preModifyEraseTriggers(thread_db* tdbb, TrigVector** trigs,
tdbb->getTransaction()->tra_rpblist->PopRpb(rpb, rpblevel); tdbb->getTransaction()->tra_rpblist->PopRpb(rpb, rpblevel);
} }
// 1. Remove assignments of DEFAULT to computed fields.
// 2. Remove assignments to identity column when OVERRIDING USER VALUE is specified in INSERT.
static void preprocessAssignments(thread_db* tdbb, CompilerScratch* csb,
StreamType stream, CompoundStmtNode* compoundNode, const Nullable<OverrideClause>* insertOverride)
{
if (!compoundNode)
return;
jrd_rel* relation = csb->csb_rpt[stream].csb_relation;
fb_assert(relation);
if (!relation)
return;
Nullable<IdentityType> identityType;
for (size_t i = compoundNode->statements.getCount(); i--; )
{
const AssignmentNode* assign = compoundNode->statements[i]->as<AssignmentNode>();
fb_assert(assign);
if (!assign)
continue;
const ExprNode* assignFrom = assign->asgnFrom;
const FieldNode* assignToField = assign->asgnTo->as<FieldNode>();
if (assignToField)
{
int fieldId = assignToField->fieldId;
jrd_fld* fld;
while (true)
{
if (assignToField->fieldStream == stream &&
relation->rel_fields &&
(fld = (*relation->rel_fields)[fieldId]))
{
if (insertOverride && fld->fld_identity_type.specified)
{
if (insertOverride->specified || !assignFrom->is<DefaultNode>())
identityType = fld->fld_identity_type;
if (*insertOverride == OverrideClause::USER_VALUE)
{
compoundNode->statements.remove(i);
break;
}
}
if (fld->fld_computation)
{
if (assignFrom->is<DefaultNode>())
compoundNode->statements.remove(i);
}
else if (relation->rel_view_rse && fld->fld_source_rel_field.first.hasData())
{
relation = MET_lookup_relation(tdbb, fld->fld_source_rel_field.first);
fb_assert(relation);
if (!relation)
return;
if ((fieldId = MET_lookup_field(tdbb, relation, fld->fld_source_rel_field.second)) >= 0)
continue;
}
}
break;
}
}
}
if (!insertOverride)
return;
if (insertOverride->specified)
{
if (!identityType.specified)
ERR_post(Arg::Gds(isc_overriding_without_identity) << relation->rel_name);
if (identityType == IDENT_TYPE_BY_DEFAULT && *insertOverride == OverrideClause::SYSTEM_VALUE)
ERR_post(Arg::Gds(isc_overriding_system_invalid) << relation->rel_name);
if (identityType == IDENT_TYPE_ALWAYS && *insertOverride == OverrideClause::USER_VALUE)
ERR_post(Arg::Gds(isc_overriding_user_invalid) << relation->rel_name);
}
else
{
if (identityType == IDENT_TYPE_ALWAYS)
ERR_post(Arg::Gds(isc_overriding_system_missing) << relation->rel_name);
}
}
// Execute a list of validation expressions. // Execute a list of validation expressions.
static void validateExpressions(thread_db* tdbb, const Array<ValidateInfo>& validations) static void validateExpressions(thread_db* tdbb, const Array<ValidateInfo>& validations)
{ {

View File

@ -112,6 +112,14 @@ struct ValidateInfo
}; };
enum OverrideClause : UCHAR
{
// Warning: used in BLR
USER_VALUE = 1,
SYSTEM_VALUE
};
class AssignmentNode : public TypedNode<StmtNode, StmtNode::TYPE_ASSIGNMENT> class AssignmentNode : public TypedNode<StmtNode, StmtNode::TYPE_ASSIGNMENT>
{ {
public: public:
@ -1048,6 +1056,7 @@ public:
Firebird::Array<NestConst<FieldNode> > fields; Firebird::Array<NestConst<FieldNode> > fields;
NestConst<ValueListNode> values; NestConst<ValueListNode> values;
NestConst<BoolExprNode> condition; NestConst<BoolExprNode> condition;
Nullable<OverrideClause> overrideClause;
}; };
explicit MergeNode(MemoryPool& pool) explicit MergeNode(MemoryPool& pool)
@ -1267,6 +1276,7 @@ public:
NestConst<StmtNode> subStore; NestConst<StmtNode> subStore;
Firebird::Array<ValidateInfo> validations; Firebird::Array<ValidateInfo> validations;
NestConst<RelationSourceNode> relationSource; NestConst<RelationSourceNode> relationSource;
Nullable<OverrideClause> overrideClause;
}; };
@ -1581,6 +1591,23 @@ public:
}; };
class SetSessionNode : public SessionManagementNode
{
public:
enum Type { TYPE_IDLE_TIMEOUT, TYPE_STMT_TIMEOUT };
SetSessionNode(MemoryPool& pool, Type aType, ULONG aVal, UCHAR blr_timepart);
public:
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual void execute(thread_db* tdbb, dsql_req* request) const;
private:
Type m_type;
ULONG m_value;
};
class SetRoundNode : public SessionManagementNode class SetRoundNode : public SessionManagementNode
{ {
public: public:
@ -1680,6 +1707,7 @@ public:
NestConst<ValueListNode> values; NestConst<ValueListNode> values;
Firebird::Array<NestConst<FieldNode> > matching; Firebird::Array<NestConst<FieldNode> > matching;
NestConst<ReturningClause> returning; NestConst<ReturningClause> returning;
Nullable<OverrideClause> overrideClause;
}; };

View File

@ -147,9 +147,11 @@ void DSQL_execute(thread_db* tdbb,
Arg::Gds(isc_bad_req_handle)); Arg::Gds(isc_bad_req_handle));
} }
// Only allow NULL trans_handle if we're starting a transaction // Only allow NULL trans_handle if we're starting a transaction or set session properties
if (!*tra_handle && statement->getType() != DsqlCompiledStatement::TYPE_START_TRANS) if (!*tra_handle &&
statement->getType() != DsqlCompiledStatement::TYPE_START_TRANS &&
statement->getType() != DsqlCompiledStatement::TYPE_SESSION_MANAGEMENT)
{ {
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) << ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
Arg::Gds(isc_bad_trans_handle)); Arg::Gds(isc_bad_trans_handle));
@ -274,6 +276,10 @@ bool DsqlDmlRequest::fetch(thread_db* tdbb, UCHAR* msgBuffer)
Jrd::Attachment* att = req_dbb->dbb_attachment; Jrd::Attachment* att = req_dbb->dbb_attachment;
TraceDSQLFetch trace(att, this); TraceDSQLFetch trace(att, this);
thread_db::TimerGuard timerGuard(tdbb, req_timer, false);
if (req_timer && req_timer->expired())
tdbb->checkCancelState(true);
UCHAR* dsqlMsgBuffer = req_msg_buffers[message->msg_buffer_number]; UCHAR* dsqlMsgBuffer = req_msg_buffers[message->msg_buffer_number];
JRD_receive(tdbb, req_request, message->msg_number, message->msg_length, dsqlMsgBuffer); JRD_receive(tdbb, req_request, message->msg_number, message->msg_length, dsqlMsgBuffer);
@ -283,6 +289,9 @@ bool DsqlDmlRequest::fetch(thread_db* tdbb, UCHAR* msgBuffer)
if (eofReached) if (eofReached)
{ {
if (req_timer)
req_timer->stop();
delayedFormat = NULL; delayedFormat = NULL;
trace.fetch(true, ITracePlugin::RESULT_SUCCESS); trace.fetch(true, ITracePlugin::RESULT_SUCCESS);
return false; return false;
@ -535,9 +544,11 @@ void DSQL_execute_immediate(thread_db* tdbb, Jrd::Attachment* attachment, jrd_tr
const DsqlCompiledStatement* statement = request->getStatement(); const DsqlCompiledStatement* statement = request->getStatement();
// Only allow NULL trans_handle if we're starting a transaction // Only allow NULL trans_handle if we're starting a transaction or set session properties
if (!*tra_handle && statement->getType() != DsqlCompiledStatement::TYPE_START_TRANS) if (!*tra_handle &&
statement->getType() != DsqlCompiledStatement::TYPE_START_TRANS &&
statement->getType() != DsqlCompiledStatement::TYPE_SESSION_MANAGEMENT)
{ {
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) << ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
Arg::Gds(isc_bad_trans_handle)); Arg::Gds(isc_bad_trans_handle));
@ -676,6 +687,12 @@ void DsqlDmlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
// manager know statement parameters values // manager know statement parameters values
TraceDSQLExecute trace(req_dbb->dbb_attachment, this); TraceDSQLExecute trace(req_dbb->dbb_attachment, this);
// Setup and start timeout timer
const bool have_cursor = reqTypeWithCursor(statement->getType()) && !singleton;
setupTimer(tdbb);
thread_db::TimerGuard timerGuard(tdbb, req_timer, !have_cursor);
if (!message) if (!message)
JRD_start(tdbb, req_request, req_transaction); JRD_start(tdbb, req_request, req_transaction);
else else
@ -798,7 +815,6 @@ void DsqlDmlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
break; break;
} }
const bool have_cursor = reqTypeWithCursor(statement->getType()) && !singleton;
trace.finish(have_cursor, ITracePlugin::RESULT_SUCCESS); trace.finish(have_cursor, ITracePlugin::RESULT_SUCCESS);
} }
@ -898,9 +914,9 @@ void DsqlTransactionRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scra
// Execute a dynamic SQL statement. // Execute a dynamic SQL statement.
void DsqlTransactionRequest::execute(thread_db* tdbb, jrd_tra** traHandle, void DsqlTransactionRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
Firebird::IMessageMetadata* inMetadata, const UCHAR* inMsg, IMessageMetadata* /*inMetadata*/, const UCHAR* /*inMsg*/,
Firebird::IMessageMetadata* outMetadata, UCHAR* outMsg, IMessageMetadata* /*outMetadata*/, UCHAR* /*outMsg*/,
bool singleton) bool /*singleton*/)
{ {
node->execute(tdbb, this, traHandle); node->execute(tdbb, this, traHandle);
} }
@ -1549,7 +1565,12 @@ dsql_req::dsql_req(MemoryPool& pool)
req_cursor_name(req_pool), req_cursor_name(req_pool),
req_cursor(NULL), req_cursor(NULL),
req_user_descs(req_pool), req_user_descs(req_pool),
req_traced(false) req_traced(false),
req_timeout(0)
{
}
dsql_req::~dsql_req()
{ {
} }
@ -1579,11 +1600,91 @@ bool dsql_req::fetch(thread_db* /*tdbb*/, UCHAR* /*msgBuffer*/)
return false; // avoid warning return false; // avoid warning
} }
unsigned int dsql_req::getTimeout()
{
return req_timeout;
}
unsigned int dsql_req::getActualTimeout()
{
if (req_timer)
return req_timer->getValue();
return 0;
}
void dsql_req::setTimeout(unsigned int timeOut)
{
req_timeout = timeOut;
}
void dsql_req::setupTimer(thread_db* tdbb)
{
if (statement->getFlags() & JrdStatement::FLAG_INTERNAL)
return;
if (req_request)
{
req_request->req_timeout = this->req_timeout;
fb_assert(!req_request->req_caller);
if (req_request->req_caller)
{
if (req_timer)
req_timer->setup(0, 0);
return;
}
}
Database* dbb = tdbb->getDatabase();
Attachment* att = tdbb->getAttachment();
ISC_STATUS toutErr = isc_cfg_stmt_timeout;
unsigned int timeOut = dbb->dbb_config->getStatementTimeout() * 1000;
if (req_timeout)
{
if (!timeOut || req_timeout < timeOut)
{
timeOut = req_timeout;
toutErr = isc_req_stmt_timeout;
}
}
else
{
const unsigned int attTout = att->getStatementTimeout();
if (!timeOut || attTout && attTout < timeOut)
{
timeOut = attTout;
toutErr = isc_att_stmt_timeout;
}
}
if (!req_timer && timeOut)
{
req_timer = FB_NEW TimeoutTimer();
req_request->req_timer = this->req_timer;
}
if (req_timer)
{
req_timer->setup(timeOut, toutErr);
req_timer->start();
}
}
// Release a dynamic request. // Release a dynamic request.
void dsql_req::destroy(thread_db* tdbb, dsql_req* request, bool drop) void dsql_req::destroy(thread_db* tdbb, dsql_req* request, bool drop)
{ {
SET_TDBB(tdbb); SET_TDBB(tdbb);
if (request->req_timer)
{
request->req_timer->stop();
request->req_timer = NULL;
}
// If request is parent, orphan the children and release a portion of their requests // If request is parent, orphan the children and release a portion of their requests
for (FB_SIZE_T i = 0; i < request->cursors.getCount(); ++i) for (FB_SIZE_T i = 0; i < request->cursors.getCount(); ++i)
@ -1849,6 +1950,15 @@ static void sql_info(thread_db* tdbb,
return; return;
break; break;
case isc_info_sql_stmt_timeout_user:
case isc_info_sql_stmt_timeout_run:
value = (item == isc_info_sql_stmt_timeout_user) ? request->getTimeout() : request->getActualTimeout();
length = put_vax_long(buffer, value);
if (!(info = put_item(item, length, buffer, info, end_info)))
return;
break;
case isc_info_sql_get_plan: case isc_info_sql_get_plan:
case isc_info_sql_explain_plan: case isc_info_sql_explain_plan:
{ {

View File

@ -94,6 +94,7 @@ namespace Jrd
class dsql_par; class dsql_par;
class dsql_map; class dsql_map;
class dsql_intlsym; class dsql_intlsym;
class TimeoutTimer;
typedef Firebird::Stack<dsql_ctx*> DsqlContextStack; typedef Firebird::Stack<dsql_ctx*> DsqlContextStack;
@ -557,6 +558,19 @@ public:
virtual void setDelayedFormat(thread_db* tdbb, Firebird::IMessageMetadata* metadata); virtual void setDelayedFormat(thread_db* tdbb, Firebird::IMessageMetadata* metadata);
// Get session-level timeout, milliseconds
unsigned int getTimeout();
// Set session-level timeout, milliseconds
void setTimeout(unsigned int timeOut);
// Get actual timeout, milliseconds
unsigned int getActualTimeout();
// Evaluate actual timeout value, consider config- and session-level timeout values,
// setup and start timer
void setupTimer(thread_db* tdbb);
static void destroy(thread_db* tdbb, dsql_req* request, bool drop); static void destroy(thread_db* tdbb, dsql_req* request, bool drop);
private: private:
@ -581,11 +595,12 @@ public:
bool req_traced; // request is traced via TraceAPI bool req_traced; // request is traced via TraceAPI
protected: protected:
unsigned int req_timeout; // query timeout in milliseconds, set by the user
Firebird::RefPtr<TimeoutTimer> req_timer; // timeout timer
// Request should never be destroyed using delete. // Request should never be destroyed using delete.
// It dies together with it's pool in release_request(). // It dies together with it's pool in release_request().
~dsql_req() ~dsql_req();
{
}
// To avoid posix warning about missing public destructor declare // To avoid posix warning about missing public destructor declare
// MemoryPool as friend class. In fact IT releases request memory! // MemoryPool as friend class. In fact IT releases request memory!

View File

@ -1 +1 @@
45 shift/reduce conflicts, 17 reduce/reduce conflicts. 46 shift/reduce conflicts, 17 reduce/reduce conflicts.

View File

@ -599,12 +599,14 @@ using namespace Firebird;
%token <metaNamePtr> DEFINER %token <metaNamePtr> DEFINER
%token <metaNamePtr> EXCLUDE %token <metaNamePtr> EXCLUDE
%token <metaNamePtr> FOLLOWING %token <metaNamePtr> FOLLOWING
%token <metaNamePtr> IDLE
%token <metaNamePtr> INVOKER %token <metaNamePtr> INVOKER
%token <metaNamePtr> MESSAGE %token <metaNamePtr> MESSAGE
%token <metaNamePtr> NATIVE %token <metaNamePtr> NATIVE
%token <metaNamePtr> NORMALIZE_DECFLOAT %token <metaNamePtr> NORMALIZE_DECFLOAT
%token <metaNamePtr> NTILE %token <metaNamePtr> NTILE
%token <metaNamePtr> OTHERS %token <metaNamePtr> OTHERS
%token <metaNamePtr> OVERRIDING
%token <metaNamePtr> PERCENT_RANK %token <metaNamePtr> PERCENT_RANK
%token <metaNamePtr> PRECEDING %token <metaNamePtr> PRECEDING
%token <metaNamePtr> PRIVILEGE %token <metaNamePtr> PRIVILEGE
@ -614,6 +616,7 @@ using namespace Firebird;
%token <metaNamePtr> RDB_ROLE_IN_USE %token <metaNamePtr> RDB_ROLE_IN_USE
%token <metaNamePtr> RDB_SYSTEM_PRIVILEGE %token <metaNamePtr> RDB_SYSTEM_PRIVILEGE
%token <metaNamePtr> SECURITY %token <metaNamePtr> SECURITY
%token <metaNamePtr> SESSION
%token <metaNamePtr> SQL %token <metaNamePtr> SQL
%token <metaNamePtr> SYSTEM %token <metaNamePtr> SYSTEM
%token <metaNamePtr> TIES %token <metaNamePtr> TIES
@ -654,6 +657,7 @@ using namespace Firebird;
BaseNullable<int> nullableIntVal; BaseNullable<int> nullableIntVal;
BaseNullable<bool> nullableBoolVal; BaseNullable<bool> nullableBoolVal;
BaseNullable<Jrd::TriggerDefinition::SqlSecurity> nullableSqlSecurityVal; BaseNullable<Jrd::TriggerDefinition::SqlSecurity> nullableSqlSecurityVal;
BaseNullable<Jrd::OverrideClause> nullableOverrideClause;
bool boolVal; bool boolVal;
int intVal; int intVal;
unsigned uintVal; unsigned uintVal;
@ -734,6 +738,7 @@ using namespace Firebird;
Jrd::RelationNode::RefActionClause* refActionClause; Jrd::RelationNode::RefActionClause* refActionClause;
Jrd::RelationNode::IndexConstraintClause* indexConstraintClause; Jrd::RelationNode::IndexConstraintClause* indexConstraintClause;
Jrd::RelationNode::IdentityOptions* identityOptions; Jrd::RelationNode::IdentityOptions* identityOptions;
IdentityType identityType;
Jrd::CreateRelationNode* createRelationNode; Jrd::CreateRelationNode* createRelationNode;
Jrd::CreateAlterViewNode* createAlterViewNode; Jrd::CreateAlterViewNode* createAlterViewNode;
Jrd::CreateIndexNode* createIndexNode; Jrd::CreateIndexNode* createIndexNode;
@ -763,6 +768,7 @@ using namespace Firebird;
Jrd::MappingNode* mappingNode; Jrd::MappingNode* mappingNode;
Jrd::MappingNode::OP mappingOp; Jrd::MappingNode::OP mappingOp;
Jrd::SetRoleNode* setRoleNode; Jrd::SetRoleNode* setRoleNode;
Jrd::SetSessionNode* setSessionNode;
Jrd::CreateAlterRoleNode* createAlterRoleNode; Jrd::CreateAlterRoleNode* createAlterRoleNode;
Jrd::SetRoundNode* setRoundNode; Jrd::SetRoundNode* setRoundNode;
Jrd::SetTrapsNode* setTrapsNode; Jrd::SetTrapsNode* setTrapsNode;
@ -827,6 +833,7 @@ mng_statement
: set_round { $$ = $1; } : set_round { $$ = $1; }
| set_traps { $$ = $1; } | set_traps { $$ = $1; }
| set_bind { $$ = $1; } | set_bind { $$ = $1; }
| session_statement { $$ = $1; }
| set_role { $$ = $1; } | set_role { $$ = $1; }
; ;
@ -2201,10 +2208,16 @@ column_def($relationNode)
%type <identityOptions> identity_clause %type <identityOptions> identity_clause
identity_clause identity_clause
: GENERATED BY DEFAULT AS IDENTITY : GENERATED identity_clause_type AS IDENTITY
{ $$ = newNode<RelationNode::IdentityOptions>(); } { $$ = newNode<RelationNode::IdentityOptions>($2); }
identity_clause_options_opt($6) identity_clause_options_opt($5)
{ $$ = $6; } { $$ = $5; }
;
%type <identityType> identity_clause_type
identity_clause_type
: BY DEFAULT { $$ = IDENT_TYPE_BY_DEFAULT; }
| ALWAYS { $$ = IDENT_TYPE_ALWAYS; }
; ;
%type identity_clause_options_opt(<identityOptions>) %type identity_clause_options_opt(<identityOptions>)
@ -3951,7 +3964,7 @@ alter_op($relationNode)
} }
| col_opt symbol_column_name | col_opt symbol_column_name
{ $<identityOptions>$ = newNode<RelationNode::IdentityOptions>(); } { $<identityOptions>$ = newNode<RelationNode::IdentityOptions>(); }
alter_identity_clause_options($<identityOptions>3) alter_identity_clause_spec($<identityOptions>3)
{ {
RelationNode::AlterColTypeClause* clause = newNode<RelationNode::AlterColTypeClause>(); RelationNode::AlterColTypeClause* clause = newNode<RelationNode::AlterColTypeClause>();
clause->field = newNode<dsql_fld>(); clause->field = newNode<dsql_fld>();
@ -4097,6 +4110,24 @@ alter_data_type_or_domain
} }
; ;
%type alter_identity_clause_spec(<identityOptions>)
alter_identity_clause_spec($identityOptions)
: alter_identity_clause_generation($identityOptions) alter_identity_clause_options_opt($identityOptions)
| alter_identity_clause_options($identityOptions)
;
%type alter_identity_clause_generation(<identityOptions>)
alter_identity_clause_generation($identityOptions)
: SET GENERATED ALWAYS { $identityOptions->type = IDENT_TYPE_ALWAYS; }
| SET GENERATED BY DEFAULT { $identityOptions->type = IDENT_TYPE_BY_DEFAULT; }
;
%type alter_identity_clause_options_opt(<identityOptions>)
alter_identity_clause_options_opt($identityOptions)
: // nothing
| alter_identity_clause_options($identityOptions)
;
%type alter_identity_clause_options(<identityOptions>) %type alter_identity_clause_options(<identityOptions>)
alter_identity_clause_options($identityOptions) alter_identity_clause_options($identityOptions)
: alter_identity_clause_options alter_identity_clause_option($identityOptions) : alter_identity_clause_options alter_identity_clause_option($identityOptions)
@ -5081,6 +5112,30 @@ scale_clause($setBindNode)
yyabandon(YYPOSNARG(2), -842, isc_scale_nogt); // Scale must be between 0 and precision yyabandon(YYPOSNARG(2), -842, isc_scale_nogt); // Scale must be between 0 and precision
$setBindNode->bind.numScale = -$2; $setBindNode->bind.numScale = -$2;
} }
%type <setSessionNode> session_statement
session_statement
: SET SESSION IDLE TIMEOUT long_integer timepart_sesion_idle_tout
{ $$ = newNode<SetSessionNode>(SetSessionNode::TYPE_IDLE_TIMEOUT, $5, $6); }
| SET STATEMENT TIMEOUT long_integer timepart_ses_stmt_tout
{ $$ = newNode<SetSessionNode>(SetSessionNode::TYPE_STMT_TIMEOUT, $4, $5); }
;
%type <blrOp> timepart_sesion_idle_tout
timepart_sesion_idle_tout
: /* nothing */ { $$ = blr_extract_minute; }
| HOUR { $$ = blr_extract_hour; }
| MINUTE { $$ = blr_extract_minute; }
| SECOND { $$ = blr_extract_second; }
;
%type <blrOp> timepart_ses_stmt_tout
timepart_ses_stmt_tout
: /* nothing */ { $$ = blr_extract_second; }
| HOUR { $$ = blr_extract_hour; }
| MINUTE { $$ = blr_extract_minute; }
| SECOND { $$ = blr_extract_second; }
| MILLISECOND { $$ = blr_extract_millisecond; }
; ;
%type tran_option_list_opt(<setTransactionNode>) %type tran_option_list_opt(<setTransactionNode>)
@ -6011,18 +6066,20 @@ fetch_first_clause
// IBO hack: replace column_parens_opt by ins_column_parens_opt. // IBO hack: replace column_parens_opt by ins_column_parens_opt.
%type <storeNode> insert %type <storeNode> insert
insert insert
: insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) VALUES '(' value_or_default_list ')' : insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) override_opt VALUES '(' value_or_default_list ')'
returning_clause returning_clause
{ {
StoreNode* node = $$ = $1; StoreNode* node = $$ = $1;
node->dsqlValues = $5; node->overrideClause = $3;
node->dsqlReturning = $7; node->dsqlValues = $6;
node->dsqlReturning = $8;
} }
| insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) select_expr returning_clause | insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) override_opt select_expr returning_clause
{ {
StoreNode* node = $$ = $1; StoreNode* node = $$ = $1;
node->dsqlRse = $3; node->overrideClause = $3;
node->dsqlReturning = $4; node->dsqlRse = $4;
node->dsqlReturning = $5;
$$ = node; $$ = node;
} }
| insert_start DEFAULT VALUES returning_clause | insert_start DEFAULT VALUES returning_clause
@ -6043,6 +6100,13 @@ insert_start
} }
; ;
%type <nullableOverrideClause> override_opt
override_opt
: /* nothing */ { $$ = Nullable<OverrideClause>::empty(); }
| OVERRIDING USER VALUE { $$ = Nullable<OverrideClause>::val(OverrideClause::USER_VALUE); }
| OVERRIDING SYSTEM VALUE { $$ = Nullable<OverrideClause>::val(OverrideClause::SYSTEM_VALUE); }
;
%type <valueListNode> value_or_default_list %type <valueListNode> value_or_default_list
value_or_default_list value_or_default_list
: value_or_default { $$ = newNode<ValueListNode>($1); } : value_or_default { $$ = newNode<ValueListNode>($1); }
@ -6111,13 +6175,17 @@ merge_update_specification($mergeMatchedClause, $relationName)
%type merge_insert_specification(<mergeNotMatchedClause>) %type merge_insert_specification(<mergeNotMatchedClause>)
merge_insert_specification($mergeNotMatchedClause) merge_insert_specification($mergeNotMatchedClause)
: THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields)) : THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields)) override_opt
VALUES '(' value_or_default_list ')'
{ $mergeNotMatchedClause->values = $6; }
| AND search_condition THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields))
VALUES '(' value_or_default_list ')' VALUES '(' value_or_default_list ')'
{ {
$mergeNotMatchedClause->values = $8; $mergeNotMatchedClause->overrideClause = $4;
$mergeNotMatchedClause->values = $7;
}
| AND search_condition THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields)) override_opt
VALUES '(' value_or_default_list ')'
{
$mergeNotMatchedClause->overrideClause = $6;
$mergeNotMatchedClause->values = $9;
$mergeNotMatchedClause->condition = $2; $mergeNotMatchedClause->condition = $2;
} }
; ;
@ -6207,12 +6275,13 @@ update_or_insert
UpdateOrInsertNode* node = $$ = newNode<UpdateOrInsertNode>(); UpdateOrInsertNode* node = $$ = newNode<UpdateOrInsertNode>();
node->relation = $5; node->relation = $5;
} }
ins_column_parens_opt(NOTRIAL(&$6->fields)) VALUES '(' value_or_default_list ')' ins_column_parens_opt(NOTRIAL(&$6->fields)) override_opt VALUES '(' value_or_default_list ')'
update_or_insert_matching_opt(NOTRIAL(&$6->matching)) returning_clause update_or_insert_matching_opt(NOTRIAL(&$6->matching)) returning_clause
{ {
UpdateOrInsertNode* node = $$ = $6; UpdateOrInsertNode* node = $$ = $6;
node->values = $10; node->overrideClause = $8;
node->returning = $13; node->values = $11;
node->returning = $14;
} }
; ;
@ -7966,6 +8035,7 @@ symbol_UDF_name
%type <metaNamePtr> symbol_blob_subtype_name %type <metaNamePtr> symbol_blob_subtype_name
symbol_blob_subtype_name symbol_blob_subtype_name
: valid_symbol_name : valid_symbol_name
| BINARY
; ;
%type <metaNamePtr> symbol_character_set_name %type <metaNamePtr> symbol_character_set_name
@ -8322,18 +8392,21 @@ non_reserved_word
| DEFINER | DEFINER
| EXCLUDE | EXCLUDE
| FOLLOWING | FOLLOWING
| IDLE
| INVOKER | INVOKER
| MESSAGE | MESSAGE
| NATIVE | NATIVE
| NORMALIZE_DECFLOAT | NORMALIZE_DECFLOAT
| NTILE | NTILE
| OTHERS | OTHERS
| OVERRIDING
| PERCENT_RANK | PERCENT_RANK
| PRECEDING | PRECEDING
| PRIVILEGE | PRIVILEGE
| QUANTIZE | QUANTIZE
| RANGE | RANGE
| SECURITY | SECURITY
| SESSION
| SQL | SQL
| SYSTEM | SYSTEM
| TIES | TIES

View File

@ -442,6 +442,11 @@ typedef ISC_STATUS API_ROUTINE prototype_fb_cancel_operation(ISC_STATUS *,
typedef ISC_STATUS API_ROUTINE prototype_fb_database_crypt_callback(ISC_STATUS *, typedef ISC_STATUS API_ROUTINE prototype_fb_database_crypt_callback(ISC_STATUS *,
void *); void *);
typedef ISC_STATUS API_ROUTINE prototype_fb_dsql_set_timeout(ISC_STATUS*,
isc_stmt_handle*,
ULONG);
struct FirebirdApiPointers struct FirebirdApiPointers
{ {
prototype_isc_attach_database *isc_attach_database; prototype_isc_attach_database *isc_attach_database;
@ -523,6 +528,7 @@ struct FirebirdApiPointers
prototype_isc_service_start *isc_service_start; prototype_isc_service_start *isc_service_start;
prototype_fb_cancel_operation *fb_cancel_operation; prototype_fb_cancel_operation *fb_cancel_operation;
prototype_fb_database_crypt_callback *fb_database_crypt_callback; prototype_fb_database_crypt_callback *fb_database_crypt_callback;
prototype_fb_dsql_set_timeout* fb_dsql_set_timeout;
}; };
#endif #endif

View File

@ -439,6 +439,11 @@ interface Statement : ReferenceCounted
void setCursorName(Status status, const string name); void setCursorName(Status status, const string name);
void free(Status status); void free(Status status);
uint getFlags(Status status); uint getFlags(Status status);
version: // 3.0 => 4.0
// Statement execution timeout, milliseconds
uint getTimeout(Status status);
void setTimeout(Status status, uint timeOut);
} }
interface Request : ReferenceCounted interface Request : ReferenceCounted
@ -516,6 +521,15 @@ interface Attachment : ReferenceCounted
void ping(Status status); void ping(Status status);
void detach(Status status); void detach(Status status);
void dropDatabase(Status status); void dropDatabase(Status status);
version: // 3.0 => 4.0
// Idle attachment timeout, seconds
uint getIdleTimeout(Status status);
void setIdleTimeout(Status status, uint timeOut);
// Statement execution timeout, milliseconds
uint getStatementTimeout(Status status);
void setStatementTimeout(Status status, uint timeOut);
} }
interface Service : ReferenceCounted interface Service : ReferenceCounted
@ -599,6 +613,7 @@ interface Server : Auth
{ {
[notImplemented(Auth::AUTH_FAILED)] [notImplemented(Auth::AUTH_FAILED)]
int authenticate(Status status, ServerBlock sBlock, Writer writerInterface); int authenticate(Status status, ServerBlock sBlock, Writer writerInterface);
version: // 3.0.1 => 4.0 version: // 3.0.1 => 4.0
void setDbCryptCallback(Status status, CryptKeyCallback cryptCallback); void setDbCryptCallback(Status status, CryptKeyCallback cryptCallback);
} }

View File

@ -1556,6 +1556,8 @@ namespace Firebird
void (CLOOP_CARG *setCursorName)(IStatement* self, IStatus* status, const char* name) throw(); void (CLOOP_CARG *setCursorName)(IStatement* self, IStatus* status, const char* name) throw();
void (CLOOP_CARG *free)(IStatement* self, IStatus* status) throw(); void (CLOOP_CARG *free)(IStatement* self, IStatus* status) throw();
unsigned (CLOOP_CARG *getFlags)(IStatement* self, IStatus* status) throw(); unsigned (CLOOP_CARG *getFlags)(IStatement* self, IStatus* status) throw();
unsigned (CLOOP_CARG *getTimeout)(IStatement* self, IStatus* status) throw();
void (CLOOP_CARG *setTimeout)(IStatement* self, IStatus* status, unsigned timeOut) throw();
}; };
protected: protected:
@ -1569,7 +1571,7 @@ namespace Firebird
} }
public: public:
static const unsigned VERSION = 3; static const unsigned VERSION = 4;
static const unsigned PREPARE_PREFETCH_NONE = 0; static const unsigned PREPARE_PREFETCH_NONE = 0;
static const unsigned PREPARE_PREFETCH_TYPE = 1; static const unsigned PREPARE_PREFETCH_TYPE = 1;
@ -1669,6 +1671,33 @@ namespace Firebird
StatusType::checkException(status); StatusType::checkException(status);
return ret; return ret;
} }
template <typename StatusType> unsigned getTimeout(StatusType* status)
{
if (cloopVTable->version < 4)
{
StatusType::setVersionError(status, "IStatement", cloopVTable->version, 4);
StatusType::checkException(status);
return 0;
}
StatusType::clearException(status);
unsigned ret = static_cast<VTable*>(this->cloopVTable)->getTimeout(this, status);
StatusType::checkException(status);
return ret;
}
template <typename StatusType> void setTimeout(StatusType* status, unsigned timeOut)
{
if (cloopVTable->version < 4)
{
StatusType::setVersionError(status, "IStatement", cloopVTable->version, 4);
StatusType::checkException(status);
return;
}
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->setTimeout(this, status, timeOut);
StatusType::checkException(status);
}
}; };
class IRequest : public IReferenceCounted class IRequest : public IReferenceCounted
@ -1862,6 +1891,10 @@ namespace Firebird
void (CLOOP_CARG *ping)(IAttachment* self, IStatus* status) throw(); void (CLOOP_CARG *ping)(IAttachment* self, IStatus* status) throw();
void (CLOOP_CARG *detach)(IAttachment* self, IStatus* status) throw(); void (CLOOP_CARG *detach)(IAttachment* self, IStatus* status) throw();
void (CLOOP_CARG *dropDatabase)(IAttachment* self, IStatus* status) throw(); void (CLOOP_CARG *dropDatabase)(IAttachment* self, IStatus* status) throw();
unsigned (CLOOP_CARG *getIdleTimeout)(IAttachment* self, IStatus* status) throw();
void (CLOOP_CARG *setIdleTimeout)(IAttachment* self, IStatus* status, unsigned timeOut) throw();
unsigned (CLOOP_CARG *getStatementTimeout)(IAttachment* self, IStatus* status) throw();
void (CLOOP_CARG *setStatementTimeout)(IAttachment* self, IStatus* status, unsigned timeOut) throw();
}; };
protected: protected:
@ -1875,7 +1908,7 @@ namespace Firebird
} }
public: public:
static const unsigned VERSION = 3; static const unsigned VERSION = 4;
template <typename StatusType> void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) template <typename StatusType> void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer)
{ {
@ -2012,6 +2045,60 @@ namespace Firebird
static_cast<VTable*>(this->cloopVTable)->dropDatabase(this, status); static_cast<VTable*>(this->cloopVTable)->dropDatabase(this, status);
StatusType::checkException(status); StatusType::checkException(status);
} }
template <typename StatusType> unsigned getIdleTimeout(StatusType* status)
{
if (cloopVTable->version < 4)
{
StatusType::setVersionError(status, "IAttachment", cloopVTable->version, 4);
StatusType::checkException(status);
return 0;
}
StatusType::clearException(status);
unsigned ret = static_cast<VTable*>(this->cloopVTable)->getIdleTimeout(this, status);
StatusType::checkException(status);
return ret;
}
template <typename StatusType> void setIdleTimeout(StatusType* status, unsigned timeOut)
{
if (cloopVTable->version < 4)
{
StatusType::setVersionError(status, "IAttachment", cloopVTable->version, 4);
StatusType::checkException(status);
return;
}
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->setIdleTimeout(this, status, timeOut);
StatusType::checkException(status);
}
template <typename StatusType> unsigned getStatementTimeout(StatusType* status)
{
if (cloopVTable->version < 4)
{
StatusType::setVersionError(status, "IAttachment", cloopVTable->version, 4);
StatusType::checkException(status);
return 0;
}
StatusType::clearException(status);
unsigned ret = static_cast<VTable*>(this->cloopVTable)->getStatementTimeout(this, status);
StatusType::checkException(status);
return ret;
}
template <typename StatusType> void setStatementTimeout(StatusType* status, unsigned timeOut)
{
if (cloopVTable->version < 4)
{
StatusType::setVersionError(status, "IAttachment", cloopVTable->version, 4);
StatusType::checkException(status);
return;
}
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->setStatementTimeout(this, status, timeOut);
StatusType::checkException(status);
}
}; };
class IService : public IReferenceCounted class IService : public IReferenceCounted
@ -8183,6 +8270,8 @@ namespace Firebird
this->setCursorName = &Name::cloopsetCursorNameDispatcher; this->setCursorName = &Name::cloopsetCursorNameDispatcher;
this->free = &Name::cloopfreeDispatcher; this->free = &Name::cloopfreeDispatcher;
this->getFlags = &Name::cloopgetFlagsDispatcher; this->getFlags = &Name::cloopgetFlagsDispatcher;
this->getTimeout = &Name::cloopgetTimeoutDispatcher;
this->setTimeout = &Name::cloopsetTimeoutDispatcher;
} }
} vTable; } vTable;
@ -8351,6 +8440,35 @@ namespace Firebird
} }
} }
static unsigned CLOOP_CARG cloopgetTimeoutDispatcher(IStatement* self, IStatus* status) throw()
{
StatusType status2(status);
try
{
return static_cast<Name*>(self)->Name::getTimeout(&status2);
}
catch (...)
{
StatusType::catchException(&status2);
return static_cast<unsigned>(0);
}
}
static void CLOOP_CARG cloopsetTimeoutDispatcher(IStatement* self, IStatus* status, unsigned timeOut) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::setTimeout(&status2, timeOut);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw() static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw()
{ {
try try
@ -8401,6 +8519,8 @@ namespace Firebird
virtual void setCursorName(StatusType* status, const char* name) = 0; virtual void setCursorName(StatusType* status, const char* name) = 0;
virtual void free(StatusType* status) = 0; virtual void free(StatusType* status) = 0;
virtual unsigned getFlags(StatusType* status) = 0; virtual unsigned getFlags(StatusType* status) = 0;
virtual unsigned getTimeout(StatusType* status) = 0;
virtual void setTimeout(StatusType* status, unsigned timeOut) = 0;
}; };
template <typename Name, typename StatusType, typename Base> template <typename Name, typename StatusType, typename Base>
@ -8825,6 +8945,10 @@ namespace Firebird
this->ping = &Name::clooppingDispatcher; this->ping = &Name::clooppingDispatcher;
this->detach = &Name::cloopdetachDispatcher; this->detach = &Name::cloopdetachDispatcher;
this->dropDatabase = &Name::cloopdropDatabaseDispatcher; this->dropDatabase = &Name::cloopdropDatabaseDispatcher;
this->getIdleTimeout = &Name::cloopgetIdleTimeoutDispatcher;
this->setIdleTimeout = &Name::cloopsetIdleTimeoutDispatcher;
this->getStatementTimeout = &Name::cloopgetStatementTimeoutDispatcher;
this->setStatementTimeout = &Name::cloopsetStatementTimeoutDispatcher;
} }
} vTable; } vTable;
@ -9093,6 +9217,64 @@ namespace Firebird
} }
} }
static unsigned CLOOP_CARG cloopgetIdleTimeoutDispatcher(IAttachment* self, IStatus* status) throw()
{
StatusType status2(status);
try
{
return static_cast<Name*>(self)->Name::getIdleTimeout(&status2);
}
catch (...)
{
StatusType::catchException(&status2);
return static_cast<unsigned>(0);
}
}
static void CLOOP_CARG cloopsetIdleTimeoutDispatcher(IAttachment* self, IStatus* status, unsigned timeOut) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::setIdleTimeout(&status2, timeOut);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static unsigned CLOOP_CARG cloopgetStatementTimeoutDispatcher(IAttachment* self, IStatus* status) throw()
{
StatusType status2(status);
try
{
return static_cast<Name*>(self)->Name::getStatementTimeout(&status2);
}
catch (...)
{
StatusType::catchException(&status2);
return static_cast<unsigned>(0);
}
}
static void CLOOP_CARG cloopsetStatementTimeoutDispatcher(IAttachment* self, IStatus* status, unsigned timeOut) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::setStatementTimeout(&status2, timeOut);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw() static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw()
{ {
try try
@ -9150,6 +9332,10 @@ namespace Firebird
virtual void ping(StatusType* status) = 0; virtual void ping(StatusType* status) = 0;
virtual void detach(StatusType* status) = 0; virtual void detach(StatusType* status) = 0;
virtual void dropDatabase(StatusType* status) = 0; virtual void dropDatabase(StatusType* status) = 0;
virtual unsigned getIdleTimeout(StatusType* status) = 0;
virtual void setIdleTimeout(StatusType* status, unsigned timeOut) = 0;
virtual unsigned getStatementTimeout(StatusType* status) = 0;
virtual void setStatementTimeout(StatusType* status, unsigned timeOut) = 0;
}; };
template <typename Name, typename StatusType, typename Base> template <typename Name, typename StatusType, typename Base>

View File

@ -828,7 +828,18 @@ static const struct {
{"dsql_window_cant_overr_frame", 335545124}, {"dsql_window_cant_overr_frame", 335545124},
{"dsql_window_duplicate", 335545125}, {"dsql_window_duplicate", 335545125},
{"sql_too_long", 335545126}, {"sql_too_long", 335545126},
{"decprecision_err", 335545127}, {"cfg_stmt_timeout", 335545127},
{"att_stmt_timeout", 335545128},
{"req_stmt_timeout", 335545129},
{"att_shut_killed", 335545130},
{"att_shut_idle", 335545131},
{"att_shut_db_down", 335545132},
{"att_shut_engine", 335545133},
{"overriding_without_identity", 335545134},
{"overriding_system_invalid", 335545135},
{"overriding_user_invalid", 335545136},
{"overriding_system_missing", 335545137},
{"decprecision_err", 335545138},
{"gfix_db_name", 335740929}, {"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930}, {"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932}, {"gfix_incmp_sw", 335740932},

View File

@ -862,7 +862,18 @@ const ISC_STATUS isc_dsql_window_cant_overr_order = 335545123L;
const ISC_STATUS isc_dsql_window_cant_overr_frame = 335545124L; const ISC_STATUS isc_dsql_window_cant_overr_frame = 335545124L;
const ISC_STATUS isc_dsql_window_duplicate = 335545125L; const ISC_STATUS isc_dsql_window_duplicate = 335545125L;
const ISC_STATUS isc_sql_too_long = 335545126L; const ISC_STATUS isc_sql_too_long = 335545126L;
const ISC_STATUS isc_decprecision_err = 335545127L; const ISC_STATUS isc_cfg_stmt_timeout = 335545127L;
const ISC_STATUS isc_att_stmt_timeout = 335545128L;
const ISC_STATUS isc_req_stmt_timeout = 335545129L;
const ISC_STATUS isc_att_shut_killed = 335545130L;
const ISC_STATUS isc_att_shut_idle = 335545131L;
const ISC_STATUS isc_att_shut_db_down = 335545132L;
const ISC_STATUS isc_att_shut_engine = 335545133L;
const ISC_STATUS isc_overriding_without_identity = 335545134L;
const ISC_STATUS isc_overriding_system_invalid = 335545135L;
const ISC_STATUS isc_overriding_user_invalid = 335545136L;
const ISC_STATUS isc_overriding_system_missing = 335545137L;
const ISC_STATUS isc_decprecision_err = 335545138L;
const ISC_STATUS isc_gfix_db_name = 335740929L; const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L; const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L; const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@ -1337,7 +1348,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
const ISC_STATUS isc_trace_switch_param_miss = 337182758L; const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L; const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L; const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
const ISC_STATUS isc_err_max = 1281; const ISC_STATUS isc_err_max = 1292;
#else /* c definitions */ #else /* c definitions */
@ -2169,7 +2180,18 @@ const ISC_STATUS isc_err_max = 1281;
#define isc_dsql_window_cant_overr_frame 335545124L #define isc_dsql_window_cant_overr_frame 335545124L
#define isc_dsql_window_duplicate 335545125L #define isc_dsql_window_duplicate 335545125L
#define isc_sql_too_long 335545126L #define isc_sql_too_long 335545126L
#define isc_decprecision_err 335545127L #define isc_cfg_stmt_timeout 335545127L
#define isc_att_stmt_timeout 335545128L
#define isc_req_stmt_timeout 335545129L
#define isc_att_shut_killed 335545130L
#define isc_att_shut_idle 335545131L
#define isc_att_shut_db_down 335545132L
#define isc_att_shut_engine 335545133L
#define isc_overriding_without_identity 335545134L
#define isc_overriding_system_invalid 335545135L
#define isc_overriding_user_invalid 335545136L
#define isc_overriding_system_missing 335545137L
#define isc_decprecision_err 335545138L
#define isc_gfix_db_name 335740929L #define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L #define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L #define isc_gfix_incmp_sw 335740932L
@ -2644,7 +2666,7 @@ const ISC_STATUS isc_err_max = 1281;
#define isc_trace_switch_param_miss 337182758L #define isc_trace_switch_param_miss 337182758L
#define isc_trace_param_act_notcompat 337182759L #define isc_trace_param_act_notcompat 337182759L
#define isc_trace_mandatory_switch_miss 337182760L #define isc_trace_mandatory_switch_miss 337182760L
#define isc_err_max 1281 #define isc_err_max 1292
#endif #endif

View File

@ -518,6 +518,9 @@
const USHORT f_mon_att_remote_os_user = 17; const USHORT f_mon_att_remote_os_user = 17;
const USHORT f_mon_att_auth_method = 18; const USHORT f_mon_att_auth_method = 18;
const USHORT f_mon_att_sys_flag = 19; const USHORT f_mon_att_sys_flag = 19;
const USHORT f_mon_att_idle_timeout = 20;
const USHORT f_mon_att_idle_timer = 21;
const USHORT f_mon_att_stmt_timeout = 22;
// Relation 35 (MON$TRANSACTIONS) // Relation 35 (MON$TRANSACTIONS)
@ -547,6 +550,8 @@
const USHORT f_mon_stmt_sql_text = 5; const USHORT f_mon_stmt_sql_text = 5;
const USHORT f_mon_stmt_stat_id = 6; const USHORT f_mon_stmt_stat_id = 6;
const USHORT f_mon_stmt_expl_plan = 7; const USHORT f_mon_stmt_expl_plan = 7;
const USHORT f_mon_stmt_timeout = 8;
const USHORT f_mon_stmt_timer = 9;
// Relation 37 (MON$CALL_STACK) // Relation 37 (MON$CALL_STACK)

View File

@ -831,7 +831,18 @@ Data source : @4"}, /* eds_statement */
{335545124, "Cannot override the window @1 because it has a frame clause. Tip: it can be used without parenthesis in OVER"}, /* dsql_window_cant_overr_frame */ {335545124, "Cannot override the window @1 because it has a frame clause. Tip: it can be used without parenthesis in OVER"}, /* dsql_window_cant_overr_frame */
{335545125, "Duplicate window definition for @1"}, /* dsql_window_duplicate */ {335545125, "Duplicate window definition for @1"}, /* dsql_window_duplicate */
{335545126, "SQL statement is too long. Maximum size is @1 bytes."}, /* sql_too_long */ {335545126, "SQL statement is too long. Maximum size is @1 bytes."}, /* sql_too_long */
{335545127, "DecFloat precision must be 16 or 34"}, /* decprecision_err */ {335545127, "Config level timeout expired."}, /* cfg_stmt_timeout */
{335545128, "Attachment level timeout expired."}, /* att_stmt_timeout */
{335545129, "Statement level timeout expired."}, /* req_stmt_timeout */
{335545130, "Killed by database administrator."}, /* att_shut_killed */
{335545131, "Idle timeout expired."}, /* att_shut_idle */
{335545132, "Database is shutdown."}, /* att_shut_db_down */
{335545133, "Engine is shutdown."}, /* att_shut_engine */
{335545134, "OVERRIDING clause can be used only when an identity column is present in the INSERT's field list for table/view @1"}, /* overriding_without_identity */
{335545135, "OVERRIDING SYSTEM VALUE can be used only for identity column defined as 'GENERATED ALWAYS' in INSERT for table/view @1"}, /* overriding_system_invalid */
{335545136, "OVERRIDING USER VALUE can be used only for identity column defined as 'GENERATED BY DEFAULT' in INSERT for table/view @1"}, /* overriding_user_invalid */
{335545137, "OVERRIDING SYSTEM VALUE should be used to override the value of an identity column defined as 'GENERATED ALWAYS' in table/view @1"}, /* overriding_system_missing */
{335545138, "DecFloat precision must be 16 or 34"}, /* decprecision_err */
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */ {335740929, "data base file name (@1) already given"}, /* gfix_db_name */
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */ {335740930, "invalid switch @1"}, /* gfix_invalid_sw */
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */ {335740932, "incompatible switch combination"}, /* gfix_incmp_sw */

View File

@ -827,7 +827,18 @@ static const struct {
{335545124, -833}, /* 804 dsql_window_cant_overr_frame */ {335545124, -833}, /* 804 dsql_window_cant_overr_frame */
{335545125, -833}, /* 805 dsql_window_duplicate */ {335545125, -833}, /* 805 dsql_window_duplicate */
{335545126, -902}, /* 806 sql_too_long */ {335545126, -902}, /* 806 sql_too_long */
{335545127, -842}, /* 807 decprecision_err */ {335545127, -901}, /* 807 cfg_stmt_timeout */
{335545128, -901}, /* 808 att_stmt_timeout */
{335545129, -901}, /* 809 req_stmt_timeout */
{335545130, -902}, /* 810 att_shut_killed */
{335545131, -902}, /* 811 att_shut_idle */
{335545132, -902}, /* 812 att_shut_db_down */
{335545133, -902}, /* 813 att_shut_engine */
{335545134, -902}, /* 814 overriding_without_identity */
{335545135, -902}, /* 815 overriding_system_invalid */
{335545136, -902}, /* 816 overriding_user_invalid */
{335545137, -902}, /* 817 overriding_system_missing */
{335545138, -842}, /* 818 decprecision_err */
{335740929, -901}, /* 1 gfix_db_name */ {335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */ {335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */ {335740932, -901}, /* 4 gfix_incmp_sw */

View File

@ -827,7 +827,18 @@ static const struct {
{335545124, "42000"}, // 804 dsql_window_cant_overr_frame {335545124, "42000"}, // 804 dsql_window_cant_overr_frame
{335545125, "42000"}, // 805 dsql_window_duplicate {335545125, "42000"}, // 805 dsql_window_duplicate
{335545126, "54001"}, // 806 sql_too_long {335545126, "54001"}, // 806 sql_too_long
{335545127, "HY104"}, // 807 decprecision_err {335545127, "HY008"}, // 807 cfg_stmt_timeout
{335545128, "HY008"}, // 808 att_stmt_timeout
{335545129, "HY008"}, // 809 req_stmt_timeout
{335545130, "08003"}, // 810 att_shut_killed
{335545131, "08003"}, // 811 att_shut_idle
{335545132, "08003"}, // 812 att_shut_db_down
{335545133, "08003"}, // 813 att_shut_engine
{335545134, "42000"}, // 814 overriding_without_identity
{335545135, "42000"}, // 815 overriding_system_invalid
{335545136, "42000"}, // 816 overriding_user_invalid
{335545137, "42000"}, // 817 overriding_system_missing
{335545138, "HY104"}, // 818 decprecision_err
{335740929, "00000"}, // 1 gfix_db_name {335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw {335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw {335740932, "00000"}, // 4 gfix_incmp_sw

View File

@ -496,7 +496,9 @@ int EXTRACT_list_table(const SCHAR* relation_name,
FOR GEN IN RDB$GENERATORS FOR GEN IN RDB$GENERATORS
WITH GEN.RDB$GENERATOR_NAME = RFR.RDB$GENERATOR_NAME WITH GEN.RDB$GENERATOR_NAME = RFR.RDB$GENERATOR_NAME
{ {
isqlGlob.printf(" GENERATED BY DEFAULT AS IDENTITY"); isqlGlob.printf(" GENERATED %s AS IDENTITY",
(RFR.RDB$IDENTITY_TYPE == IDENT_TYPE_BY_DEFAULT ? "BY DEFAULT" :
RFR.RDB$IDENTITY_TYPE == IDENT_TYPE_ALWAYS ? "ALWAYS" : ""));
if (!GEN.RDB$INITIAL_VALUE.NULL && GEN.RDB$INITIAL_VALUE != 0) if (!GEN.RDB$INITIAL_VALUE.NULL && GEN.RDB$INITIAL_VALUE != 0)
isqlGlob.printf(" (START WITH %" SQUADFORMAT ")", GEN.RDB$INITIAL_VALUE); isqlGlob.printf(" (START WITH %" SQUADFORMAT ")", GEN.RDB$INITIAL_VALUE);

View File

@ -453,6 +453,7 @@ public:
ExplainPlan = false; ExplainPlan = false;
Heading = true; Heading = true;
BailOnError = false; BailOnError = false;
StmtTimeout = 0;
ISQL_charset[0] = 0; ISQL_charset[0] = 0;
} }
@ -473,6 +474,7 @@ public:
bool ExplainPlan; bool ExplainPlan;
bool Heading; bool Heading;
bool BailOnError; bool BailOnError;
unsigned int StmtTimeout;
SCHAR ISQL_charset[MAXCHARSET_SIZE]; SCHAR ISQL_charset[MAXCHARSET_SIZE];
}; };
@ -4821,7 +4823,8 @@ static processing_state frontend_set(const char* cmd, const char* const* parms,
sqlda_display, sqlda_display,
//#endif //#endif
sql, warning, sqlCont, heading, bail, sql, warning, sqlCont, heading, bail,
bulk_insert, maxrows, wrong bulk_insert, maxrows, stmtTimeout,
wrong
}; };
SetOptions(const optionsMap* inmap, size_t insize, int wrongval) SetOptions(const optionsMap* inmap, size_t insize, int wrongval)
: OptionsBase(inmap, insize, wrongval) : OptionsBase(inmap, insize, wrongval)
@ -4859,6 +4862,7 @@ static processing_state frontend_set(const char* cmd, const char* const* parms,
{SetOptions::maxrows, "MAXROWS", 0}, {SetOptions::maxrows, "MAXROWS", 0},
{SetOptions::sqlCont, "ROLE", 0}, {SetOptions::sqlCont, "ROLE", 0},
{SetOptions::sqlCont, "TRUSTED", 0}, // TRUSTED ROLE, will get DSQL error other case {SetOptions::sqlCont, "TRUSTED", 0}, // TRUSTED ROLE, will get DSQL error other case
{SetOptions::stmtTimeout, "LOCAL_TIMEOUT", 0},
{SetOptions::sqlCont, "DECFLOAT", 0}, {SetOptions::sqlCont, "DECFLOAT", 0},
}; };
@ -5021,14 +5025,28 @@ static processing_state frontend_set(const char* cmd, const char* const* parms,
ret = newMaxRows((*lparms[2]) ? lparms[2] : "0"); ret = newMaxRows((*lparms[2]) ? lparms[2] : "0");
break; break;
default: case SetOptions::stmtTimeout:
{ {
TEXT msg_string[MSG_LENGTH]; int val = strtol(parms[2], NULL, 10);
IUTILS_msg_get(VALID_OPTIONS, msg_string); if (val < 0)
isqlGlob.printf("%s\n", msg_string);
}
setoptions.showCommands(isqlGlob.Out);
ret = ps_ERR; ret = ps_ERR;
else
{
setValues.StmtTimeout = val;
ret = SKIP;
}
}
break;
default:
//{
// TEXT msg_string[MSG_LENGTH];
// IUTILS_msg_get(VALID_OPTIONS, msg_string);
// isqlGlob.printf("%s\n", msg_string);
//}
//setoptions.showCommands(isqlGlob.Out);
//ret = ps_ERR;
ret = CONT; // pass unknown SET command to server as is
break; break;
} }
@ -5850,6 +5868,7 @@ static processing_state print_sets()
print_set("Time:", setValues.Time_display); print_set("Time:", setValues.Time_display);
print_set("Warnings:", setValues.Warnings); print_set("Warnings:", setValues.Warnings);
print_set("Bail on error:", setValues.BailOnError); print_set("Bail on error:", setValues.BailOnError);
isqlGlob.printf("%-25s%lu%s", "Local statement timeout:", setValues.StmtTimeout, NEWLINE);
return SKIP; return SKIP;
} }
@ -8217,6 +8236,10 @@ static processing_state process_statement(const TEXT* str2)
// check for warnings // check for warnings
ISQL_warning(fbStatus); ISQL_warning(fbStatus);
global_Stmt->setTimeout(fbStatus, setValues.StmtTimeout);
if (ISQL_errmsg(fbStatus))
setValues.StmtTimeout = 0;
// Find out what kind of statement this is // Find out what kind of statement this is
const int statement_type = process_request_type(); const int statement_type = process_request_type();
if (!statement_type) if (!statement_type)
@ -8280,6 +8303,7 @@ static processing_state process_statement(const TEXT* str2)
statement_type == isc_info_sql_stmt_set_generator)) statement_type == isc_info_sql_stmt_set_generator))
{ {
DB->execute(fbStatus, D__trans, 0, str2, isqlGlob.SQL_dialect, NULL, NULL, NULL, NULL); DB->execute(fbStatus, D__trans, 0, str2, isqlGlob.SQL_dialect, NULL, NULL, NULL, NULL);
setValues.StmtTimeout = 0;
if (ISQL_errmsg(fbStatus)) if (ISQL_errmsg(fbStatus))
{ {
ret = ps_ERR; ret = ps_ERR;
@ -8322,6 +8346,7 @@ static processing_state process_statement(const TEXT* str2)
// This is a non-select DML statement or trans // This is a non-select DML statement or trans
M__trans = global_Stmt->execute(fbStatus, M__trans, NULL, NULL, NULL, NULL); M__trans = global_Stmt->execute(fbStatus, M__trans, NULL, NULL, NULL, NULL);
setValues.StmtTimeout = 0;
if (ISQL_errmsg(fbStatus)) if (ISQL_errmsg(fbStatus))
{ {
// CVC: Make this conditional if it causes problems. For example // CVC: Make this conditional if it causes problems. For example
@ -8424,6 +8449,7 @@ static processing_state process_statement(const TEXT* str2)
if (statement_type == isc_info_sql_stmt_exec_procedure) if (statement_type == isc_info_sql_stmt_exec_procedure)
{ {
global_Stmt->execute(fbStatus, M__trans, NULL, NULL, message, buffer); global_Stmt->execute(fbStatus, M__trans, NULL, NULL, message, buffer);
setValues.StmtTimeout = 0;
if (ISQL_errmsg(fbStatus)) if (ISQL_errmsg(fbStatus))
{ {
ret = ps_ERR; ret = ps_ERR;
@ -8453,6 +8479,7 @@ static processing_state process_statement(const TEXT* str2)
Firebird::IResultSet* curs = global_Stmt->openCursor(fbStatus, M__trans, Firebird::IResultSet* curs = global_Stmt->openCursor(fbStatus, M__trans,
NULL, NULL, message, 0); NULL, NULL, message, 0);
setValues.StmtTimeout = 0;
if (ISQL_errmsg(fbStatus)) if (ISQL_errmsg(fbStatus))
{ {
return ps_ERR; return ps_ERR;
@ -8614,7 +8641,8 @@ static bool stdin_redirected()
{ {
#ifdef WIN_NT #ifdef WIN_NT
HANDLE in = GetStdHandle(STD_INPUT_HANDLE); HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
if (GetFileType(in) == FILE_TYPE_CHAR) //FILE_TYPE_DISK) const DWORD file_type = GetFileType(in);
if (file_type == FILE_TYPE_CHAR || file_type == FILE_TYPE_PIPE)
return false; return false;
#else #else
if (isatty(fileno(stdin))) if (isatty(fileno(stdin)))

View File

@ -5838,7 +5838,11 @@ static processing_state show_table(const SCHAR* relation_name, bool isView)
} }
if (!RFR.RDB$GENERATOR_NAME.NULL) if (!RFR.RDB$GENERATOR_NAME.NULL)
isqlGlob.printf("Identity (by default)"); {
isqlGlob.printf("Identity (%s)",
(RFR.RDB$IDENTITY_TYPE == IDENT_TYPE_BY_DEFAULT ? "by default" :
RFR.RDB$IDENTITY_TYPE == IDENT_TYPE_ALWAYS ? "always" : ""));
}
// Handle defaults for columns // Handle defaults for columns

View File

@ -45,6 +45,7 @@
#include "../common/classes/MetaName.h" #include "../common/classes/MetaName.h"
#include "../common/StatusArg.h" #include "../common/StatusArg.h"
#include "../common/isc_proto.h" #include "../common/isc_proto.h"
#include "../common/classes/RefMutex.h"
using namespace Jrd; using namespace Jrd;
@ -205,7 +206,9 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb)
att_dec_status(DEC_Errors), att_dec_status(DEC_Errors),
att_charsets(*pool), att_charsets(*pool),
att_charset_ids(*pool), att_charset_ids(*pool),
att_pools(*pool) att_pools(*pool),
att_idle_timeout(0),
att_stmt_timeout(0)
{ {
att_internal.grow(irq_MAX); att_internal.grow(irq_MAX);
att_dyn_req.grow(drq_MAX); att_dyn_req.grow(drq_MAX);
@ -372,9 +375,11 @@ void Jrd::Attachment::signalCancel()
} }
void Jrd::Attachment::signalShutdown() void Jrd::Attachment::signalShutdown(ISC_STATUS code)
{ {
att_flags |= ATT_shutdown; att_flags |= ATT_shutdown;
if (getStable())
getStable()->setShutError(code);
if (att_ext_connection && att_ext_connection->isConnected()) if (att_ext_connection && att_ext_connection->isConnected())
att_ext_connection->cancelExecution(); att_ext_connection->cancelExecution();
@ -640,7 +645,7 @@ int Jrd::Attachment::blockingAstShutdown(void* ast_object)
AsyncContextHolder tdbb(dbb, FB_FUNCTION, attachment->att_id_lock); AsyncContextHolder tdbb(dbb, FB_FUNCTION, attachment->att_id_lock);
attachment->signalShutdown(); attachment->signalShutdown(isc_att_shut_killed);
JRD_shutdown_attachment(attachment); JRD_shutdown_attachment(attachment);
} }
@ -766,3 +771,122 @@ JAttachment* Attachment::getInterface() throw()
return att_stable->getInterface(); return att_stable->getInterface();
} }
unsigned int Attachment::getActualIdleTimeout() const
{
unsigned int timeout = att_database->dbb_config->getConnIdleTimeout() * 60;
if (att_idle_timeout && (att_idle_timeout < timeout || !timeout))
timeout = att_idle_timeout;
return timeout;
}
void Attachment::setupIdleTimer(bool clear)
{
unsigned int timeout = clear ? 0 : getActualIdleTimeout();
if (!timeout)
{
if (att_idle_timer)
att_idle_timer->reset(0);
}
else
{
if (!att_idle_timer)
att_idle_timer = FB_NEW IdleTimer(getInterface());
att_idle_timer->reset(timeout);
}
}
bool Attachment::getIdleTimerTimestamp(TimeStamp& ts) const
{
if (!att_idle_timer)
return false;
time_t value = att_idle_timer->getExpiryTime();
if (!value)
return false;
struct tm* times = localtime(&value);
if (!times)
return false;
ts = TimeStamp::encode_timestamp(times);
return true;
}
/// Attachment::IdleTimer
void Attachment::IdleTimer::handler()
{
m_fireTime = 0;
if (!m_expTime) // Timer was reset to zero, do nothing
return;
// Ensure attachment is still alive and idle
StableAttachmentPart* stable = m_attachment->getStable();
if (!stable)
return;
MutexEnsureUnlock guard(*stable->getMutex(), FB_FUNCTION);
if (!guard.tryEnter())
return;
if (!m_expTime)
return;
// If timer was reset to fire later, restart ITimer
time_t curTime = time(NULL);
if (curTime < m_expTime)
{
reset(m_expTime - curTime);
return;
}
Attachment* att = stable->getHandle();
att->signalShutdown(isc_att_shut_idle);
JRD_shutdown_attachment(att);
}
int Attachment::IdleTimer::release()
{
if (--refCounter == 0)
{
delete this;
return 0;
}
return 1;
}
void Attachment::IdleTimer::reset(unsigned int timeout)
{
// Start timer if necessary. If timer was already started, don't restart
// (or stop) it - handler() will take care about it.
if (!timeout)
{
m_expTime = 0;
return;
}
const time_t curTime = time(NULL);
m_expTime = curTime + timeout;
FbLocalStatus s;
ITimerControl* timerCtrl = Firebird::TimerInterfacePtr();
if (m_fireTime)
{
if (m_fireTime <= m_expTime)
return;
timerCtrl->stop(&s, this);
check(&s);
m_fireTime = 0;
}
timerCtrl->start(&s, this, (m_expTime - curTime) * 1000 * 1000);
check(&s);
m_fireTime = m_expTime;
}

View File

@ -152,7 +152,7 @@ class StableAttachmentPart : public Firebird::RefCounted, public Firebird::Globa
{ {
public: public:
explicit StableAttachmentPart(Attachment* handle) explicit StableAttachmentPart(Attachment* handle)
: att(handle), jAtt(NULL) : att(handle), jAtt(NULL), shutError(0)
{ } { }
Attachment* getHandle() throw() Attachment* getHandle() throw()
@ -171,6 +171,7 @@ public:
jAtt->detachEngine(); jAtt->detachEngine();
jAtt = ja; jAtt = ja;
shutError = 0;
} }
Firebird::Mutex* getMutex(bool useAsync = false, bool forceAsync = false) Firebird::Mutex* getMutex(bool useAsync = false, bool forceAsync = false)
@ -208,9 +209,21 @@ public:
void manualUnlock(ULONG& flags); void manualUnlock(ULONG& flags);
void manualAsyncUnlock(ULONG& flags); void manualAsyncUnlock(ULONG& flags);
void setShutError(ISC_STATUS code)
{
if (!shutError)
shutError = code;
}
ISC_STATUS getShutError() const
{
return shutError;
}
private: private:
Attachment* att; Attachment* att;
JAttachment* jAtt; JAttachment* jAtt;
ISC_STATUS shutError;
// These mutexes guarantee attachment existence. After releasing both of them with possibly // These mutexes guarantee attachment existence. After releasing both of them with possibly
// zero att_use_count one should check does attachment still exists calling getHandle(). // zero att_use_count one should check does attachment still exists calling getHandle().
@ -393,7 +406,7 @@ public:
const Firebird::ByteChunk& chunk); const Firebird::ByteChunk& chunk);
void signalCancel(); void signalCancel();
void signalShutdown(); void signalShutdown(ISC_STATUS code);
void mergeStats(); void mergeStats();
@ -414,9 +427,69 @@ public:
JAttachment* getInterface() throw(); JAttachment* getInterface() throw();
unsigned int getIdleTimeout() const
{
return att_idle_timeout;
}
void setIdleTimeout(unsigned int timeOut)
{
att_idle_timeout = timeOut;
}
unsigned int getActualIdleTimeout() const;
unsigned int getStatementTimeout() const
{
return att_stmt_timeout;
}
void setStatementTimeout(unsigned int timeOut)
{
att_stmt_timeout = timeOut;
}
// evaluate new value or clear idle timer
void setupIdleTimer(bool clear);
// returns time when idle timer will be expired, if set
bool getIdleTimerTimestamp(Firebird::TimeStamp& ts) const;
private: private:
Attachment(MemoryPool* pool, Database* dbb); Attachment(MemoryPool* pool, Database* dbb);
~Attachment(); ~Attachment();
class IdleTimer FB_FINAL :
public Firebird::RefCntIface<Firebird::ITimerImpl<IdleTimer, Firebird::CheckStatusWrapper> >
{
public:
explicit IdleTimer(JAttachment* jAtt) :
m_attachment(jAtt),
m_fireTime(0),
m_expTime(0)
{ }
// ITimer implementation
void handler();
int release();
// Set timeout, seconds
void reset(unsigned int timeout);
time_t getExpiryTime() const
{
return m_expTime;
}
private:
Firebird::RefPtr<JAttachment> m_attachment;
time_t m_fireTime; // when ITimer will fire, could be less than m_expTime
time_t m_expTime; // when actual idle timeout will expire
};
unsigned int att_idle_timeout; // seconds
unsigned int att_stmt_timeout; // milliseconds
Firebird::RefPtr<IdleTimer> att_idle_timer;
}; };

View File

@ -1040,7 +1040,6 @@ namespace Jrd {
if (page->pag_flags & Ods::crypted_page) if (page->pag_flags & Ods::crypted_page)
{ {
fb_assert(cryptPlugin);
if (!cryptPlugin) if (!cryptPlugin)
{ {
Arg::Gds(isc_decrypt_error).copyTo(sv); Arg::Gds(isc_decrypt_error).copyTo(sv);
@ -1362,14 +1361,14 @@ namespace Jrd {
} }
if (!found) if (!found)
att->signalShutdown(); att->signalShutdown(0 /* no special shutdown code */);
} }
// Loop through internal attachments list closing one missing valid holders // Loop through internal attachments list closing one missing valid holders
for (unsigned i = 0; i < knownHolders.getCount(); ++i) for (unsigned i = 0; i < knownHolders.getCount(); ++i)
{ {
if (!validateHoldersGroup(knownHolders[i], keyName)) if (!validateHoldersGroup(knownHolders[i], keyName))
knownHolders[i].first->signalShutdown(); knownHolders[i].first->signalShutdown(0);
} }
} }

View File

@ -205,6 +205,9 @@ public:
void setCursorName(Firebird::CheckStatusWrapper* status, const char* name); void setCursorName(Firebird::CheckStatusWrapper* status, const char* name);
unsigned getFlags(Firebird::CheckStatusWrapper* status); unsigned getFlags(Firebird::CheckStatusWrapper* status);
unsigned int getTimeout(Firebird::CheckStatusWrapper* status);
void setTimeout(Firebird::CheckStatusWrapper* status, unsigned int timeOut);
public: public:
JStatement(dsql_req* handle, StableAttachmentPart* sa, Firebird::Array<UCHAR>& meta); JStatement(dsql_req* handle, StableAttachmentPart* sa, Firebird::Array<UCHAR>& meta);
@ -345,6 +348,11 @@ public:
void detach(Firebird::CheckStatusWrapper* status); void detach(Firebird::CheckStatusWrapper* status);
void dropDatabase(Firebird::CheckStatusWrapper* status); void dropDatabase(Firebird::CheckStatusWrapper* status);
unsigned int getIdleTimeout(Firebird::CheckStatusWrapper* status);
void setIdleTimeout(Firebird::CheckStatusWrapper* status, unsigned int timeOut);
unsigned int getStatementTimeout(Firebird::CheckStatusWrapper* status);
void setStatementTimeout(Firebird::CheckStatusWrapper* status, unsigned int timeOut);
public: public:
explicit JAttachment(StableAttachmentPart* js); explicit JAttachment(StableAttachmentPart* js);

View File

@ -728,7 +728,7 @@ public:
try try
{ {
sharedMemory.reset(FB_NEW_POOL(*getDefaultMemoryPool()) sharedMemory.reset(FB_NEW_POOL(*getDefaultMemoryPool())
SharedMemory<MappingHeader>("fb_user_mapping", DEFAULT_SIZE, this)); SharedMemory<MappingHeader>(USER_MAP_FILE, DEFAULT_SIZE, this));
} }
catch (const Exception& ex) catch (const Exception& ex)
{ {

View File

@ -922,6 +922,15 @@ void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Atta
temp = (attachment->att_flags & ATT_system) ? 1 : 0; temp = (attachment->att_flags & ATT_system) ? 1 : 0;
record.storeInteger(f_mon_att_sys_flag, temp); record.storeInteger(f_mon_att_sys_flag, temp);
// session idle timeout, seconds
record.storeInteger(f_mon_att_idle_timeout, attachment->getIdleTimeout());
// when idle timer expires, NULL if not running
TimeStamp idleTimer;
if (attachment->getIdleTimerTimestamp(idleTimer))
record.storeTimestamp(f_mon_att_idle_timer, idleTimer);
// statement timeout, milliseconds
record.storeInteger(f_mon_att_stmt_timeout, attachment->getStatementTimeout());
record.write(); record.write();
if (attachment->att_database->dbb_flags & DBB_shared) if (attachment->att_database->dbb_flags & DBB_shared)
@ -1020,6 +1029,13 @@ void Monitoring::putRequest(SnapshotData::DumpRecord& record, const jrd_req* req
if (request->req_transaction) if (request->req_transaction)
record.storeInteger(f_mon_stmt_tra_id, request->req_transaction->tra_number); record.storeInteger(f_mon_stmt_tra_id, request->req_transaction->tra_number);
record.storeTimestamp(f_mon_stmt_timestamp, request->req_timestamp); record.storeTimestamp(f_mon_stmt_timestamp, request->req_timestamp);
ISC_TIMESTAMP ts;
if (request->req_timer &&
request->req_timer->getExpireTimestamp(request->req_timestamp.value(), ts))
{
record.storeTimestamp(f_mon_stmt_timer, ts);
}
} }
else else
record.storeInteger(f_mon_stmt_state, mon_state_idle); record.storeInteger(f_mon_stmt_state, mon_state_idle);
@ -1038,6 +1054,8 @@ void Monitoring::putRequest(SnapshotData::DumpRecord& record, const jrd_req* req
const int stat_id = fb_utils::genUniqueId(); const int stat_id = fb_utils::genUniqueId();
record.storeGlobalId(f_mon_stmt_stat_id, getGlobalId(stat_id)); record.storeGlobalId(f_mon_stmt_stat_id, getGlobalId(stat_id));
// statement timeout, milliseconds
record.storeInteger(f_mon_stmt_timeout, request->req_timeout);
record.write(); record.write();
putStatistics(record, request->req_stats, stat_id, stat_statement); putStatistics(record, request->req_stats, stat_id, stat_statement);

View File

@ -137,6 +137,11 @@ public:
storeField(field_id, VALUE_TIMESTAMP, sizeof(ISC_TIMESTAMP), &value.value()); storeField(field_id, VALUE_TIMESTAMP, sizeof(ISC_TIMESTAMP), &value.value());
} }
void storeTimestamp(int field_id, const ISC_TIMESTAMP& value)
{
storeField(field_id, VALUE_TIMESTAMP, sizeof(ISC_TIMESTAMP), &value);
}
void storeString(int field_id, const Firebird::string& value) void storeString(int field_id, const Firebird::string& value)
{ {
if (value.length()) if (value.length())

View File

@ -1249,12 +1249,16 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
inversion[i]->used = false; inversion[i]->used = false;
const IndexScratch* const indexScratch = inversion[i]->scratch; const IndexScratch* const indexScratch = inversion[i]->scratch;
if (indexScratch && (indexScratch->idx->idx_runtime_flags & idx_plan_dont_use)) if (indexScratch &&
(indexScratch == navigationCandidate ||
(indexScratch->idx->idx_runtime_flags & idx_plan_dont_use)))
{
inversion[i]->used = true; inversion[i]->used = true;
} }
}
// The matches returned in this inversion are always sorted. // The matches returned in this inversion are always sorted.
SortedArray<BoolExprNode*> matches; SortedArray<BoolExprNode*> matches, navigationMatches;
if (navigationCandidate) if (navigationCandidate)
{ {
@ -1269,11 +1273,13 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
for (FB_SIZE_T j = 0; j < segment->matches.getCount(); j++) for (FB_SIZE_T j = 0; j < segment->matches.getCount(); j++)
{ {
if (!matches.exist(segment->matches[j])) if (!navigationMatches.exist(segment->matches[j]))
matches.add(segment->matches[j]); navigationMatches.add(segment->matches[j]);
} }
} }
matches.join(navigationMatches);
// If the navigational candidate includes any matching segments, // If the navigational candidate includes any matching segments,
// reset the selectivity/cost prerequisites to account these matches // reset the selectivity/cost prerequisites to account these matches
if (matchedSegments) if (matchedSegments)
@ -1338,12 +1344,14 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
} }
// Look if a match is already used by previous matches. // Look if a match is already used by previous matches.
bool anyMatchAlreadyUsed = false; bool anyMatchAlreadyUsed = false, matchUsedByNavigation = false;
for (FB_SIZE_T k = 0; k < currentInv->matches.getCount(); k++) for (FB_SIZE_T k = 0; k < currentInv->matches.getCount(); k++)
{ {
if (matches.exist(currentInv->matches[k])) if (matches.exist(currentInv->matches[k]))
{ {
anyMatchAlreadyUsed = true; anyMatchAlreadyUsed = true;
if (navigationMatches.exist(currentInv->matches[k]))
matchUsedByNavigation = true;
break; break;
} }
} }
@ -1351,6 +1359,8 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
if (anyMatchAlreadyUsed && !customPlan) if (anyMatchAlreadyUsed && !customPlan)
{ {
currentInv->used = true; currentInv->used = true;
if (matchUsedByNavigation)
continue;
// If a match on this index was already used by another // If a match on this index was already used by another
// index, add also the other matches from this index. // index, add also the other matches from this index.
for (FB_SIZE_T j = 0; j < currentInv->matches.getCount(); j++) for (FB_SIZE_T j = 0; j < currentInv->matches.getCount(); j++)

View File

@ -940,6 +940,8 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch
*tdbb->getDefaultPool()); *tdbb->getDefaultPool());
node->procedure = procedure; node->procedure = procedure;
node->isSubRoutine = procedure->isSubRoutine();
node->procedureId = node->isSubRoutine ? 0 : procedure->getId();
node->stream = PAR_context(csb, &node->context); node->stream = PAR_context(csb, &node->context);
csb->csb_rpt[node->stream].csb_procedure = procedure; csb->csb_rpt[node->stream].csb_procedure = procedure;
@ -1108,16 +1110,17 @@ ProcedureSourceNode* ProcedureSourceNode::copy(thread_db* tdbb, NodeCopier& copi
newSource->targetList = copier.copy(tdbb, targetList); newSource->targetList = copier.copy(tdbb, targetList);
} }
jrd_prc* const new_procedure =
MET_lookup_procedure_id(tdbb, procedure->getId(), false, false, 0);
newSource->stream = copier.csb->nextStream(); newSource->stream = copier.csb->nextStream();
copier.remap[stream] = newSource->stream; copier.remap[stream] = newSource->stream;
newSource->context = context; newSource->context = context;
newSource->procedure = new_procedure; newSource->procedure = isSubRoutine ? procedure :
MET_lookup_procedure_id(tdbb, procedureId, false, false, 0);
newSource->isSubRoutine = isSubRoutine;
newSource->procedureId = procedureId;
newSource->view = view; newSource->view = view;
CompilerScratch::csb_repeat* element = CMP_csb_element(copier.csb, newSource->stream); CompilerScratch::csb_repeat* element = CMP_csb_element(copier.csb, newSource->stream);
element->csb_procedure = new_procedure; element->csb_procedure = newSource->procedure;
element->csb_view = newSource->view; element->csb_view = newSource->view;
element->csb_view_stream = copier.remap[0]; element->csb_view_stream = copier.remap[0];
@ -1148,10 +1151,10 @@ void ProcedureSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, Rse
pass1(tdbb, csb); pass1(tdbb, csb);
if (!procedure->isSubRoutine()) if (!isSubRoutine)
{ {
CMP_post_procedure_access(tdbb, csb, procedure); CMP_post_procedure_access(tdbb, csb, procedure);
CMP_post_resource(&csb->csb_resources, procedure, Resource::rsc_procedure, procedure->getId()); CMP_post_resource(&csb->csb_resources, procedure, Resource::rsc_procedure, procedureId);
} }
jrd_rel* const parentView = csb->csb_view; jrd_rel* const parentView = csb->csb_view;

View File

@ -355,6 +355,8 @@ public:
targetList(NULL), targetList(NULL),
in_msg(NULL), in_msg(NULL),
procedure(NULL), procedure(NULL),
isSubRoutine(false),
procedureId(0),
view(NULL), view(NULL),
context(0) context(0)
{ {
@ -416,7 +418,27 @@ public:
private: private:
NestConst<MessageNode> in_msg; NestConst<MessageNode> in_msg;
/***
dimitr: Referencing procedures via a pointer is not currently reliable, because
procedures can be removed from the metadata cache after ALTER/DROP.
Usually, this is prevented via the reference counting, but it's incremented
only for compiled requests. Node trees without requests (e.g. computed fields)
are not protected and may end with dead procedure pointers, causing problems
(up to crashing) when they're copied the next time. See CORE-5456 / CORE-5457.
ExecProcedureNode is a lucky exception because it's never (directly) used in
expressions. Sub-procedures are safe too. In other cases the procedure object
must be refetched from the metadata cache while copying the node.
A better (IMO) solution would be to add a second-level reference counting for
metadata objects since the parsing stage till either request creation or
explicit unload from the metadata cache. But we don't have clearly established
cache management policies yet, so I leave it for the other day.
***/
jrd_prc* procedure; jrd_prc* procedure;
bool isSubRoutine;
USHORT procedureId;
jrd_rel* view; jrd_rel* view;
SSHORT context; SSHORT context;
}; };

View File

@ -485,6 +485,7 @@ public:
Firebird::MetaName fld_security_name; // security class name for field Firebird::MetaName fld_security_name; // security class name for field
Firebird::MetaName fld_generator_name; // identity generator name Firebird::MetaName fld_generator_name; // identity generator name
Firebird::MetaNamePair fld_source_rel_field; // Relation/field source name Firebird::MetaNamePair fld_source_rel_field; // Relation/field source name
Nullable<IdentityType> fld_identity_type;
public: public:
explicit jrd_fld(MemoryPool& p) explicit jrd_fld(MemoryPool& p)

View File

@ -225,6 +225,8 @@ const char
CLIENT_PROCESS_NAME[] = "CLIENT_PROCESS", CLIENT_PROCESS_NAME[] = "CLIENT_PROCESS",
CURRENT_USER_NAME[] = "CURRENT_USER", CURRENT_USER_NAME[] = "CURRENT_USER",
CURRENT_ROLE_NAME[] = "CURRENT_ROLE", CURRENT_ROLE_NAME[] = "CURRENT_ROLE",
SESSION_IDLE_TIMEOUT[] = "SESSION_IDLE_TIMEOUT",
STATEMENT_TIMEOUT[] = "STATEMENT_TIMEOUT",
// SYSTEM namespace: transaction wise items // SYSTEM namespace: transaction wise items
TRANSACTION_ID_NAME[] = "TRANSACTION_ID", TRANSACTION_ID_NAME[] = "TRANSACTION_ID",
ISOLATION_LEVEL_NAME[] = "ISOLATION_LEVEL", ISOLATION_LEVEL_NAME[] = "ISOLATION_LEVEL",
@ -2419,6 +2421,10 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar
return NULL; return NULL;
resultStr = role.c_str(); resultStr = role.c_str();
} }
else if (nameStr == SESSION_IDLE_TIMEOUT)
resultStr.printf("%" ULONGFORMAT, attachment->getIdleTimeout());
else if (nameStr == STATEMENT_TIMEOUT)
resultStr.printf("%" ULONGFORMAT, attachment->getStatementTimeout());
else if (nameStr == TRANSACTION_ID_NAME) else if (nameStr == TRANSACTION_ID_NAME)
resultStr.printf("%" SQUADFORMAT, transaction->tra_number); resultStr.printf("%" SQUADFORMAT, transaction->tra_number);
else if (nameStr == ISOLATION_LEVEL_NAME) else if (nameStr == ISOLATION_LEVEL_NAME)

View File

@ -243,5 +243,6 @@ static const struct
{"gen_id2", gen_id2}, // 210 {"gen_id2", gen_id2}, // 210
{"window_win", window_win}, {"window_win", window_win},
{"default", relation_field}, {"default", relation_field},
{"store3", store3},
{0, 0} {0, 0}
}; };

View File

@ -423,5 +423,6 @@
#define blr_window_win_exclusion (unsigned char) 7 #define blr_window_win_exclusion (unsigned char) 7
#define blr_default (unsigned char) 212 #define blr_default (unsigned char) 212
#define blr_store3 (unsigned char) 213
#endif // JRD_BLR_H #endif // JRD_BLR_H

View File

@ -5923,76 +5923,7 @@ string print_key(thread_db* tdbb, jrd_rel* relation, index_desc* idx, Record* re
MET_scan_relation(tdbb, relation); MET_scan_relation(tdbb, relation);
} }
class Printer
{
public:
explicit Printer(thread_db* tdbb, const dsc* desc)
{
const int MAX_KEY_STRING_LEN = 250; const int MAX_KEY_STRING_LEN = 250;
const char* const NULL_KEY_STRING = "NULL";
if (!desc)
{
value = NULL_KEY_STRING;
return;
}
fb_assert(!desc->isBlob());
value = MOV_make_string2(tdbb, desc, ttype_dynamic);
const int len = (int) value.length();
const char* const str = value.c_str();
if (desc->isText() || desc->isDateTime())
{
if (desc->dsc_dtype == dtype_text)
{
const char* const pad = (desc->dsc_sub_type == ttype_binary) ? "\0": " ";
value.rtrim(pad);
}
if (desc->isText() && desc->getTextType() == ttype_binary)
{
string hex;
char* s = hex.getBuffer(2 * len);
for (int i = 0; i < len; i++)
{
sprintf(s, "%02X", (int) (unsigned char) str[i]);
s += 2;
}
value = "x'" + hex + "'";
}
else
{
value = "'" + value + "'";
}
}
if (value.length() > MAX_KEY_STRING_LEN)
{
fb_assert(desc->isText());
value.resize(MAX_KEY_STRING_LEN);
const CharSet* const cs = INTL_charset_lookup(tdbb, desc->getCharSet());
while (value.hasData() && !cs->wellFormed(value.length(), (const UCHAR*) value.c_str()))
value.resize(value.length() - 1);
value += "...";
}
}
const string& get() const
{
return value;
}
private:
string value;
};
string key, value; string key, value;
try try
@ -6001,7 +5932,7 @@ string print_key(thread_db* tdbb, jrd_rel* relation, index_desc* idx, Record* re
{ {
bool notNull = false; bool notNull = false;
const dsc* const desc = BTR_eval_expression(tdbb, idx, record, notNull); const dsc* const desc = BTR_eval_expression(tdbb, idx, record, notNull);
value = Printer(tdbb, notNull ? desc : NULL).get(); value = DescPrinter(tdbb, notNull ? desc : NULL, MAX_KEY_STRING_LEN).get();
key += "<expression> = " + value; key += "<expression> = " + value;
} }
else else
@ -6020,7 +5951,7 @@ string print_key(thread_db* tdbb, jrd_rel* relation, index_desc* idx, Record* re
dsc desc; dsc desc;
const bool notNull = EVL_field(relation, record, field_id, &desc); const bool notNull = EVL_field(relation, record, field_id, &desc);
value = Printer(tdbb, notNull ? &desc : NULL).get(); value = DescPrinter(tdbb, notNull ? &desc : NULL, MAX_KEY_STRING_LEN).get();
key += " = " + value; key += " = " + value;
if (i < idx->idx_count - 1) if (i < idx->idx_count - 1)

View File

@ -3,16 +3,16 @@
*** DO NOT EDIT *** *** DO NOT EDIT ***
TO CHANGE ANY INFORMATION IN HERE PLEASE TO CHANGE ANY INFORMATION IN HERE PLEASE
EDIT src/misc/writeBuildNum.sh EDIT src/misc/writeBuildNum.sh
FORMAL BUILD NUMBER:537 FORMAL BUILD NUMBER:581
*/ */
#define PRODUCT_VER_STRING "4.0.0.537" #define PRODUCT_VER_STRING "4.0.0.581"
#define FILE_VER_STRING "WI-T4.0.0.537" #define FILE_VER_STRING "WI-T4.0.0.581"
#define LICENSE_VER_STRING "WI-T4.0.0.537" #define LICENSE_VER_STRING "WI-T4.0.0.581"
#define FILE_VER_NUMBER 4, 0, 0, 537 #define FILE_VER_NUMBER 4, 0, 0, 581
#define FB_MAJOR_VER "4" #define FB_MAJOR_VER "4"
#define FB_MINOR_VER "0" #define FB_MINOR_VER "0"
#define FB_REV_NO "0" #define FB_REV_NO "0"
#define FB_BUILD_NO "537" #define FB_BUILD_NO "581"
#define FB_BUILD_TYPE "T" #define FB_BUILD_TYPE "T"
#define FB_BUILD_SUFFIX "Firebird 4.0 Unstable" #define FB_BUILD_SUFFIX "Firebird 4.0 Unstable"

View File

@ -5757,6 +5757,10 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_
(UCHAR*) RFR.RDB$GENERATOR_NAME, n); (UCHAR*) RFR.RDB$GENERATOR_NAME, n);
} }
n = RFR.RDB$IDENTITY_TYPE;
if (!RFR.RDB$IDENTITY_TYPE.NULL)
put_summary_record(tdbb, blob, RSR_field_identity_type, (UCHAR*) &n, sizeof(n));
// Make a temporary field block // Make a temporary field block
TemporaryField* tfb = FB_NEW_POOL(*tdbb->getDefaultPool()) TemporaryField; TemporaryField* tfb = FB_NEW_POOL(*tdbb->getDefaultPool()) TemporaryField;

View File

@ -849,6 +849,11 @@ void Statement::prepare(thread_db* tdbb, Transaction* tran, const string& sql, b
m_preparedByReq = m_callerPrivileges ? tdbb->getRequest() : NULL; m_preparedByReq = m_callerPrivileges ? tdbb->getRequest() : NULL;
} }
void Statement::setTimeout(thread_db* tdbb, unsigned int timeout)
{
doSetTimeout(tdbb, timeout);
}
void Statement::execute(thread_db* tdbb, Transaction* tran, void Statement::execute(thread_db* tdbb, Transaction* tran,
const MetaName* const* in_names, const ValueListNode* in_params, const MetaName* const* in_names, const ValueListNode* in_params,
const ValueListNode* out_params) const ValueListNode* out_params)

View File

@ -318,6 +318,7 @@ public:
Transaction* getTransaction() { return m_transaction; } Transaction* getTransaction() { return m_transaction; }
void prepare(Jrd::thread_db* tdbb, Transaction* tran, const Firebird::string& sql, bool named); void prepare(Jrd::thread_db* tdbb, Transaction* tran, const Firebird::string& sql, bool named);
void setTimeout(Jrd::thread_db* tdbb, unsigned int timeout);
void execute(Jrd::thread_db* tdbb, Transaction* tran, void execute(Jrd::thread_db* tdbb, Transaction* tran,
const Firebird::MetaName* const* in_names, const Jrd::ValueListNode* in_params, const Firebird::MetaName* const* in_names, const Jrd::ValueListNode* in_params,
const Jrd::ValueListNode* out_params); const Jrd::ValueListNode* out_params);
@ -352,6 +353,7 @@ public:
protected: protected:
virtual void doPrepare(Jrd::thread_db* tdbb, const Firebird::string& sql) = 0; virtual void doPrepare(Jrd::thread_db* tdbb, const Firebird::string& sql) = 0;
virtual void doSetTimeout(Jrd::thread_db* tdbb, unsigned int timeout) = 0;
virtual void doExecute(Jrd::thread_db* tdbb) = 0; virtual void doExecute(Jrd::thread_db* tdbb) = 0;
virtual void doOpen(Jrd::thread_db* tdbb) = 0; virtual void doOpen(Jrd::thread_db* tdbb) = 0;
virtual bool doFetch(Jrd::thread_db* tdbb) = 0; virtual bool doFetch(Jrd::thread_db* tdbb) = 0;

View File

@ -507,6 +507,21 @@ void InternalStatement::doPrepare(thread_db* tdbb, const string& sql)
} }
void InternalStatement::doSetTimeout(thread_db* tdbb, unsigned int timeout)
{
FbLocalStatus status;
{
EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);
m_request->setTimeout(&status, timeout);
}
if (status->getState() & IStatus::STATE_ERRORS)
raise(&status, tdbb, "JStatement::setTimeout");
}
void InternalStatement::doExecute(thread_db* tdbb) void InternalStatement::doExecute(thread_db* tdbb)
{ {
JTransaction* transaction = getIntTransaction()->getJrdTran(); JTransaction* transaction = getIntTransaction()->getJrdTran();

View File

@ -130,6 +130,7 @@ protected:
protected: protected:
virtual void doPrepare(Jrd::thread_db* tdbb, const Firebird::string& sql); virtual void doPrepare(Jrd::thread_db* tdbb, const Firebird::string& sql);
virtual void doSetTimeout(Jrd::thread_db* tdbb, unsigned int timeout);
virtual void doExecute(Jrd::thread_db* tdbb); virtual void doExecute(Jrd::thread_db* tdbb);
virtual void doOpen(Jrd::thread_db* tdbb); virtual void doOpen(Jrd::thread_db* tdbb);
virtual bool doFetch(Jrd::thread_db* tdbb); virtual bool doFetch(Jrd::thread_db* tdbb);

View File

@ -492,6 +492,26 @@ void IscStatement::doPrepare(thread_db* tdbb, const string& sql)
} }
} }
void IscStatement::doSetTimeout(thread_db* tdbb, unsigned int timeout)
{
FbLocalStatus status;
{
EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);
m_iscProvider.fb_dsql_set_timeout(&status, &m_handle, timeout);
}
if (status->getState() & IStatus::STATE_ERRORS)
{
// silently ignore error if timeouts is not supported by remote server
// or loaded client library
if (status[0] == isc_arg_gds && (status[1] == isc_wish_list || status[1] == isc_unavailable))
return;
raise(&status, tdbb, "fb_dsql_set_timeout");
}
}
void IscStatement::doExecute(thread_db* tdbb) void IscStatement::doExecute(thread_db* tdbb)
{ {
FB_API_HANDLE& h_tran = getIscTransaction()->getAPIHandle(); FB_API_HANDLE& h_tran = getIscTransaction()->getAPIHandle();
@ -1502,6 +1522,16 @@ ISC_STATUS ISC_EXPORT IscProvider::fb_database_crypt_callback(FbStatusVector* us
return notImplemented(user_status); return notImplemented(user_status);
} }
ISC_STATUS ISC_EXPORT IscProvider::fb_dsql_set_timeout(Jrd::FbStatusVector* user_status,
isc_stmt_handle* stmt_handle,
ULONG timeout)
{
if (m_api.fb_dsql_set_timeout)
return m_api.fb_dsql_set_timeout(IscStatus(user_status), stmt_handle, timeout);
return notImplemented(user_status);
}
void IscProvider::loadAPI() void IscProvider::loadAPI()
{ {
FbLocalStatus status; FbLocalStatus status;
@ -1594,7 +1624,8 @@ static FirebirdApiPointers isc_callbacks =
PROTO(isc_service_query), PROTO(isc_service_query),
PROTO(isc_service_start), PROTO(isc_service_start),
PROTO(fb_cancel_operation), PROTO(fb_cancel_operation),
PROTO(fb_database_crypt_callback) PROTO(fb_database_crypt_callback),
PROTO(fb_dsql_set_timeout)
}; };

View File

@ -485,6 +485,10 @@ public:
virtual ISC_STATUS ISC_EXPORT fb_database_crypt_callback(Jrd::FbStatusVector*, virtual ISC_STATUS ISC_EXPORT fb_database_crypt_callback(Jrd::FbStatusVector*,
void*); void*);
virtual ISC_STATUS API_ROUTINE fb_dsql_set_timeout(Jrd::FbStatusVector*,
isc_stmt_handle*,
ULONG);
}; };
@ -576,6 +580,7 @@ protected:
protected: protected:
virtual void doPrepare(Jrd::thread_db* tdbb, const Firebird::string& sql); virtual void doPrepare(Jrd::thread_db* tdbb, const Firebird::string& sql);
virtual void doSetTimeout(Jrd::thread_db* tdbb, unsigned int timeout);
virtual void doExecute(Jrd::thread_db* tdbb); virtual void doExecute(Jrd::thread_db* tdbb);
virtual void doOpen(Jrd::thread_db* tdbb); virtual void doOpen(Jrd::thread_db* tdbb);
virtual bool doFetch(Jrd::thread_db* tdbb); virtual bool doFetch(Jrd::thread_db* tdbb);

View File

@ -195,3 +195,8 @@
FIELD(fld_system_privileges, nam_system_privileges, dtype_text, 8 , dsc_text_type_fixed , dflt_no_privs, true) FIELD(fld_system_privileges, nam_system_privileges, dtype_text, 8 , dsc_text_type_fixed , dflt_no_privs, true)
FIELD(fld_b_sql_security, nam_sql_security , dtype_boolean , 1 , 0 , NULL , true) FIELD(fld_b_sql_security, nam_sql_security , dtype_boolean , 1 , 0 , NULL , true)
FIELD(fld_idle_timeout , nam_idle_timeout , dtype_long , sizeof(SLONG) , 0 , NULL , false)
FIELD(fld_idle_timer , nam_idle_timer , dtype_timestamp, TIMESTAMP_SIZE , 0 , NULL , true)
FIELD(fld_stmt_timeout , nam_stmt_timeout , dtype_long , sizeof(SLONG) , 0 , NULL , false)
FIELD(fld_stmt_timer , nam_stmt_timer , dtype_timestamp, TIMESTAMP_SIZE , 0 , NULL , true)

View File

@ -39,6 +39,7 @@
#include "../yvalve/gds_proto.h" #include "../yvalve/gds_proto.h"
#include "../jrd/intl_proto.h" #include "../jrd/intl_proto.h"
#include "../jrd/DebugInterface.h" #include "../jrd/DebugInterface.h"
#include "../jrd/mov_proto.h"
using namespace Firebird; using namespace Firebird;
using namespace Jrd; using namespace Jrd;
@ -297,24 +298,56 @@ ISC_STATUS filter_format(USHORT action, BlobControl* control)
* Get next segment from a record format blob. * Get next segment from a record format blob.
* *
**************************************/ **************************************/
// Unless this is a get segment call, just return success
if (action != isc_blob_filter_get_segment) if (action != isc_blob_filter_open)
return FB_SUCCESS; return string_filter(action, control);
// Try to get next descriptor // 1 2 3 4 5 6
// 12345678901234567890123456789012345678901234567890123456789012345678
const char* head1 = " id offset type length sub_type flags"; // descriptors
const char* sep1 = "--- ------ -------------- ------ -------- -----";
const char* head2 = " id type length default value"; // defaults
const char* sep2 = "--- -------------- ------ -----------------------------------";
const char* fmt1 = "%3d %6d %2d %-11s %6d %8d 0x%02x"; // descriptors
const char* fmt2 = "%3d %2d %-11s %6d %s"; // defaults
const char* name1 = "Fields:";
const char* name2 = "Defaults:";
string str;
USHORT length;
ISC_STATUS status;
// read number of fields descriptors
USHORT num;
status = caller(isc_blob_filter_get_segment, control,
sizeof(USHORT), reinterpret_cast<UCHAR*>(&num), &length);
if (status != FB_SUCCESS && status != isc_segment)
return status;
if (num)
{
string_put(control, name1);
string_put(control, head1);
string_put(control, sep1);
}
// read fields descriptors
for (int id = 0; num; --num, id++)
{
Ods::Descriptor desc; Ods::Descriptor desc;
memset(&desc, 0, sizeof(desc)); memset(&desc, 0, sizeof(desc));
USHORT length; status = caller(isc_blob_filter_get_segment, control,
const ISC_STATUS status = caller(isc_blob_filter_get_segment, control,
sizeof(desc), reinterpret_cast<UCHAR*>(&desc), &length); sizeof(desc), reinterpret_cast<UCHAR*>(&desc), &length);
if (status != FB_SUCCESS && status != isc_segment) if (status != FB_SUCCESS && status != isc_segment)
return status; return status;
char buffer[256]; str.printf(fmt1,
id,
sprintf(buffer, "%5d: type=%d (%s) length=%d sub_type=%d flags=0x%X",
desc.dsc_offset, desc.dsc_offset,
desc.dsc_dtype, desc.dsc_dtype,
desc.dsc_dtype >= DTYPE_TYPE_MAX ? "unknown" : dtypes[desc.dsc_dtype], desc.dsc_dtype >= DTYPE_TYPE_MAX ? "unknown" : dtypes[desc.dsc_dtype],
@ -322,13 +355,66 @@ ISC_STATUS filter_format(USHORT action, BlobControl* control)
desc.dsc_sub_type, desc.dsc_sub_type,
desc.dsc_flags); desc.dsc_flags);
length = static_cast<USHORT>(strlen(buffer)); string_put(control, str.c_str());
if (length > control->ctl_buffer_length) }
length = control->ctl_buffer_length;
control->ctl_segment_length = length; // read number of default values
memcpy(control->ctl_buffer, buffer, length); num = 0;
status = caller(isc_blob_filter_get_segment, control,
sizeof(USHORT), reinterpret_cast<UCHAR*>(&num), &length);
if (status != FB_SUCCESS && status != isc_segment)
return status;
if (num)
{
string_put(control, "");
string_put(control, name2);
string_put(control, head2);
string_put(control, sep2);
}
// defaults descriptors and values
for (; num; --num)
{
USHORT fieldId;
status = caller(isc_blob_filter_get_segment, control,
sizeof(fieldId), reinterpret_cast<UCHAR*>(&fieldId), &length);
if (status != FB_SUCCESS && status != isc_segment)
return status;
Ods::Descriptor desc;
memset(&desc, 0, sizeof(desc));
status = caller(isc_blob_filter_get_segment, control,
sizeof(desc), reinterpret_cast<UCHAR*>(&desc), &length);
if (status != FB_SUCCESS && status != isc_segment)
return status;
UCharBuffer buff;
UCHAR* pBuff = buff.getBuffer(desc.dsc_length);
status = caller(isc_blob_filter_get_segment, control,
desc.dsc_length, pBuff, &length);
if (status != FB_SUCCESS && status != isc_segment)
return status;
dsc d;
d = desc;
d.dsc_address = pBuff;
DescPrinter val(JRD_get_thread_data(), &d, 32);
str.printf(fmt2,
fieldId,
desc.dsc_dtype,
desc.dsc_dtype >= DTYPE_TYPE_MAX ? "unknown" : dtypes[desc.dsc_dtype],
desc.dsc_length,
val.get().c_str());
string_put(control, str.c_str());
}
control->ctl_data[1] = control->ctl_data[0];
return FB_SUCCESS; return FB_SUCCESS;
} }
@ -449,6 +535,10 @@ ISC_STATUS filter_runtime(USHORT action, BlobControl* control)
sprintf(line, " field_generator_name: %s", p); sprintf(line, " field_generator_name: %s", p);
break; break;
case RSR_field_identity_type:
sprintf(line, "Field identity type: %d", n);
break;
default: default:
sprintf(line, "*** unknown verb %d ***", (int) buff[0]); sprintf(line, "*** unknown verb %d ***", (int) buff[0]);
} }

View File

@ -475,6 +475,10 @@ ISC_STATUS ISC_EXPORT isc_dsql_sql_info(ISC_STATUS*,
short, short,
ISC_SCHAR*); ISC_SCHAR*);
ISC_STATUS ISC_EXPORT fb_dsql_set_timeout(ISC_STATUS*,
isc_stmt_handle*,
ISC_ULONG);
void ISC_EXPORT isc_encode_date(const void*, void ISC_EXPORT isc_encode_date(const void*,
ISC_QUAD*); ISC_QUAD*);

View File

@ -238,7 +238,7 @@ void INF_database_info(thread_db* tdbb,
const UCHAR* const end_items = items + item_length; const UCHAR* const end_items = items + item_length;
const UCHAR* const end = info + output_length; const UCHAR* const end = info + output_length;
const Jrd::Attachment* const err_att = tdbb->getAttachment(); const Jrd::Attachment* const att = tdbb->getAttachment();
while (items < end_items && *items != isc_info_end) while (items < end_items && *items != isc_info_end)
{ {
@ -633,7 +633,7 @@ void INF_database_info(thread_db* tdbb,
case fb_info_tpage_warns: case fb_info_tpage_warns:
case fb_info_pip_errors: case fb_info_pip_errors:
case fb_info_pip_warns: case fb_info_pip_warns:
err_val = (err_att->att_validation) ? err_att->att_validation->getInfo(item) : 0; err_val = (att->att_validation) ? att->att_validation->getInfo(item) : 0;
length = INF_convert(err_val, buffer); length = INF_convert(err_val, buffer);
break; break;
@ -769,6 +769,26 @@ void INF_database_info(thread_db* tdbb,
dbb->dbb_crypto_manager->getCurrentState() : 0, buffer); dbb->dbb_crypto_manager->getCurrentState() : 0, buffer);
break; break;
case fb_info_statement_timeout_db:
length = INF_convert(dbb->dbb_config->getStatementTimeout(), buffer);
break;
case fb_info_statement_timeout_att:
length = INF_convert(att->getStatementTimeout(), buffer);
break;
case fb_info_ses_idle_timeout_db:
length = INF_convert(dbb->dbb_config->getConnIdleTimeout() * 60, buffer);
break;
case fb_info_ses_idle_timeout_att:
length = INF_convert(att->getIdleTimeout(), buffer);
break;
case fb_info_ses_idle_timeout_run:
length = INF_convert(att->getActualIdleTimeout(), buffer);
break;
default: default:
buffer[0] = item; buffer[0] = item;
item = isc_info_error; item = isc_info_error;

View File

@ -142,6 +142,13 @@ enum db_info_types
fb_info_crypt_state = 126, fb_info_crypt_state = 126,
fb_info_statement_timeout_db,
fb_info_statement_timeout_att,
fb_info_ses_idle_timeout_db,
fb_info_ses_idle_timeout_att,
fb_info_ses_idle_timeout_run,
isc_info_db_last_value /* Leave this LAST! */ isc_info_db_last_value /* Leave this LAST! */
}; };
@ -419,6 +426,8 @@ enum info_db_provider
#define isc_info_sql_relation_alias 25 #define isc_info_sql_relation_alias 25
#define isc_info_sql_explain_plan 26 #define isc_info_sql_explain_plan 26
#define isc_info_sql_stmt_flags 27 #define isc_info_sql_stmt_flags 27
#define isc_info_sql_stmt_timeout_user 28
#define isc_info_sql_stmt_timeout_run 29
/*********************************/ /*********************************/
/* SQL information return values */ /* SQL information return values */

View File

@ -680,14 +680,21 @@ namespace
// with the flag set cause shutdownMutex mutex is not locked here. // with the flag set cause shutdownMutex mutex is not locked here.
// That's not a danger cause check of att_use_count // That's not a danger cause check of att_use_count
// in shutdown code makes it anyway safe. // in shutdown code makes it anyway safe.
status_exception::raise(Arg::Gds(isc_att_shutdown)); Arg::Gds err(isc_att_shutdown);
if (sAtt->getShutError())
err << Arg::Gds(sAtt->getShutError());
err.raise();
} }
tdbb->setAttachment(attachment); tdbb->setAttachment(attachment);
tdbb->setDatabase(attachment->att_database); tdbb->setDatabase(attachment->att_database);
if (!async) if (!async)
{
attachment->att_use_count++; attachment->att_use_count++;
attachment->setupIdleTimer(true);
}
} }
catch (const Firebird::Exception&) catch (const Firebird::Exception&)
{ {
@ -709,7 +716,11 @@ namespace
Jrd::Attachment* attachment = sAtt->getHandle(); Jrd::Attachment* attachment = sAtt->getHandle();
if (attachment && !async) if (attachment && !async)
{
attachment->att_use_count--; attachment->att_use_count--;
if (!attachment->att_use_count)
attachment->setupIdleTimer(false);
}
if (!nolock) if (!nolock)
sAtt->getMutex(async)->leave(); sAtt->getMutex(async)->leave();
@ -1681,8 +1692,12 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
if (attachment->att_flags & ATT_shutdown) if (attachment->att_flags & ATT_shutdown)
{ {
const ISC_STATUS err = jAtt->getStable()->getShutError();
if (dbb->dbb_ast_flags & DBB_shutdown) if (dbb->dbb_ast_flags & DBB_shutdown)
ERR_post(Arg::Gds(isc_shutdown) << Arg::Str(org_filename)); ERR_post(Arg::Gds(isc_shutdown) << Arg::Str(org_filename));
else if (err)
ERR_post(Arg::Gds(isc_att_shutdown) << Arg::Gds(err));
else else
ERR_post(Arg::Gds(isc_att_shutdown)); ERR_post(Arg::Gds(isc_att_shutdown));
} }
@ -2915,7 +2930,15 @@ void JAttachment::freeEngineData(CheckStatusWrapper* user_status, bool forceFree
if (forceFree) if (forceFree)
flags |= PURGE_NOCHECK; flags |= PURGE_NOCHECK;
attachment->signalShutdown(); ISC_STATUS reason = 0;
if (!forceFree)
reason = 0;
else if (engineShutdown)
reason = isc_att_shut_engine;
else if (dbb->dbb_ast_flags & DBB_shutdown)
reason = isc_att_shut_db_down;
attachment->signalShutdown(reason);
purge_attachment(tdbb, getStable(), flags); purge_attachment(tdbb, getStable(), flags);
att->release(); att->release();
@ -2985,15 +3008,15 @@ void JAttachment::dropDatabase(CheckStatusWrapper* user_status)
if (attachment->att_flags & ATT_shutdown) if (attachment->att_flags & ATT_shutdown)
{ {
const ISC_STATUS err = getStable()->getShutError();
if (dbb->dbb_ast_flags & DBB_shutdown) if (dbb->dbb_ast_flags & DBB_shutdown)
{
ERR_post(Arg::Gds(isc_shutdown) << Arg::Str(file_name)); ERR_post(Arg::Gds(isc_shutdown) << Arg::Str(file_name));
} else if (err)
ERR_post(Arg::Gds(isc_att_shutdown) << Arg::Gds(err));
else else
{
ERR_post(Arg::Gds(isc_att_shutdown)); ERR_post(Arg::Gds(isc_att_shutdown));
} }
}
if (!CCH_exclusive(tdbb, LCK_PW, WAIT_PERIOD, NULL)) if (!CCH_exclusive(tdbb, LCK_PW, WAIT_PERIOD, NULL))
{ {
@ -4331,6 +4354,82 @@ void JAttachment::transactRequest(CheckStatusWrapper* user_status, ITransaction*
successful_completion(user_status); successful_completion(user_status);
} }
unsigned int JAttachment::getIdleTimeout(Firebird::CheckStatusWrapper* user_status)
{
unsigned int result = 0;
try
{
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
check_database(tdbb);
result = getHandle()->getIdleTimeout();
}
catch (const Exception& ex)
{
ex.stuffException(user_status);
return 0;
}
successful_completion(user_status);
return result;
}
void JAttachment::setIdleTimeout(Firebird::CheckStatusWrapper* user_status, unsigned int timeOut)
{
try
{
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
check_database(tdbb);
getHandle()->setIdleTimeout(timeOut);
}
catch (const Exception& ex)
{
ex.stuffException(user_status);
return;
}
successful_completion(user_status);
}
unsigned int JAttachment::getStatementTimeout(Firebird::CheckStatusWrapper* user_status)
{
unsigned int result = 0;
try
{
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
check_database(tdbb);
result = getHandle()->getStatementTimeout();
}
catch (const Exception& ex)
{
ex.stuffException(user_status);
return 0;
}
successful_completion(user_status);
return result;
}
void JAttachment::setStatementTimeout(Firebird::CheckStatusWrapper* user_status, unsigned int timeOut)
{
try
{
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
check_database(tdbb);
getHandle()->setStatementTimeout(timeOut);
}
catch (const Exception& ex)
{
ex.stuffException(user_status);
return;
}
successful_completion(user_status);
}
void JTransaction::getInfo(CheckStatusWrapper* user_status, void JTransaction::getInfo(CheckStatusWrapper* user_status,
unsigned int itemsLength, const unsigned char* items, unsigned int itemsLength, const unsigned char* items,
@ -5287,6 +5386,66 @@ void JStatement::getInfo(CheckStatusWrapper* user_status,
successful_completion(user_status); successful_completion(user_status);
} }
unsigned int JStatement::getTimeout(CheckStatusWrapper* user_status)
{
try
{
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
check_database(tdbb);
try
{
Jrd::dsql_req* req = getHandle();
return req->getTimeout();
}
catch (const Exception& ex)
{
transliterateException(tdbb, ex, user_status, FB_FUNCTION);
return 0;
}
trace_warning(tdbb, user_status, FB_FUNCTION);
}
catch (const Exception& ex)
{
ex.stuffException(user_status);
return 0;
}
successful_completion(user_status);
return 0;
}
void JStatement::setTimeout(CheckStatusWrapper* user_status, unsigned int timeOut)
{
try
{
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
check_database(tdbb);
try
{
Jrd::dsql_req* req = getHandle();
req->setTimeout(timeOut);
}
catch (const Exception& ex)
{
transliterateException(tdbb, ex, user_status, FB_FUNCTION);
return;
}
trace_warning(tdbb, user_status, FB_FUNCTION);
}
catch (const Exception& ex)
{
ex.stuffException(user_status);
return;
}
successful_completion(user_status);
}
void JAttachment::ping(CheckStatusWrapper* user_status) void JAttachment::ping(CheckStatusWrapper* user_status)
{ {
/************************************** /**************************************
@ -5442,7 +5601,11 @@ static void check_database(thread_db* tdbb, bool async)
} }
else else
{ {
status_exception::raise(Arg::Gds(isc_att_shutdown)); Arg::Gds err(isc_att_shutdown);
if (attachment->getStable() && attachment->getStable()->getShutError())
err << Arg::Gds(attachment->getStable()->getShutError());
err.raise();
} }
} }
@ -7338,7 +7501,7 @@ namespace
Attachment* attachment = sAtt->getHandle(); Attachment* attachment = sAtt->getHandle();
if (attachment) if (attachment)
attachment->signalShutdown(); attachment->signalShutdown(isc_att_shut_engine);
} }
} }
@ -7478,6 +7641,139 @@ static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM arg)
} }
/// TimeoutTimer
#ifdef USE_ITIMER
void TimeoutTimer::handler()
{
m_expired = true;
m_started = 0;
}
int TimeoutTimer::release()
{
if (--refCounter == 0)
{
delete this;
return 0;
}
return 1;
}
unsigned int TimeoutTimer::timeToExpire() const
{
if (!m_started || m_expired)
return 0;
const SINT64 t = fb_utils::query_performance_counter() * 1000 / fb_utils::query_performance_frequency();
const SINT64 r = m_started + m_value - t;
return r > 0 ? r : 0;
}
bool TimeoutTimer::getExpireTimestamp(const ISC_TIMESTAMP start, ISC_TIMESTAMP& exp) const
{
if (!m_started || m_expired)
return false;
static const SINT64 ISC_TICKS_PER_DAY = 24 * 60 * 60 * ISC_TIME_SECONDS_PRECISION;
SINT64 ticks = start.timestamp_date * ISC_TICKS_PER_DAY + start.timestamp_time;
ticks += m_value * ISC_TIME_SECONDS_PRECISION / 1000;
exp.timestamp_date = ticks / ISC_TICKS_PER_DAY;
exp.timestamp_time = ticks % ISC_TICKS_PER_DAY;
return true;
}
void TimeoutTimer::start()
{
FbLocalStatus s;
ITimerControl* timerCtrl = Firebird::TimerInterfacePtr();
m_expired = false;
// todo: timerCtrl->restart to avoid 2 times acquire timerCtrl mutex
if (m_started)
{
timerCtrl->stop(&s, this);
m_started = 0;
}
if (m_value != 0)
{
timerCtrl->start(&s, this, m_value * 1000);
check(&s); // ?? todo
m_started = fb_utils::query_performance_counter() * 1000 / fb_utils::query_performance_frequency();
}
fb_assert(m_value && m_started || !m_value && !m_started);
}
void TimeoutTimer::stop()
{
if (m_started)
{
m_started = 0;
FbLocalStatus s;
ITimerControl* timerCtrl = Firebird::TimerInterfacePtr();
timerCtrl->stop(&s, this);
}
}
#else
bool TimeoutTimer::expired() const
{
if (!m_start)
return false;
const SINT64 t = currTime();
return t > m_start + m_value;
}
unsigned int TimeoutTimer::timeToExpire() const
{
if (!m_start)
return 0;
const SINT64 t = currTime();
const SINT64 r = m_start + m_value - t;
return r > 0 ? r : 0;
}
bool TimeoutTimer::getExpireTimestamp(const ISC_TIMESTAMP start, ISC_TIMESTAMP& exp) const
{
if (!m_start)
return false;
static const SINT64 ISC_TICKS_PER_DAY = 24 * 60 * 60 * ISC_TIME_SECONDS_PRECISION;
SINT64 ticks = start.timestamp_date * ISC_TICKS_PER_DAY + start.timestamp_time;
ticks += m_value * ISC_TIME_SECONDS_PRECISION / 1000;
exp.timestamp_date = ticks / ISC_TICKS_PER_DAY;
exp.timestamp_time = ticks % ISC_TICKS_PER_DAY;
return true;
}
void TimeoutTimer::start()
{
m_start = 0;
if (m_value != 0)
m_start = currTime();
}
void TimeoutTimer::stop()
{
m_start = 0;
}
#endif // USE_ITIMER
// begin thread_db methods // begin thread_db methods
void thread_db::setDatabase(Database* val) void thread_db::setDatabase(Database* val)
@ -7515,7 +7811,7 @@ SSHORT thread_db::getCharSet() const
return attachment->att_charset; return attachment->att_charset;
} }
ISC_STATUS thread_db::checkCancelState() ISC_STATUS thread_db::checkCancelState(ISC_STATUS* secondary)
{ {
// Test for asynchronous shutdown/cancellation requests. // Test for asynchronous shutdown/cancellation requests.
// But do that only if we're neither in the verb cleanup state // But do that only if we're neither in the verb cleanup state
@ -7535,8 +7831,13 @@ ISC_STATUS thread_db::checkCancelState()
if (database->dbb_ast_flags & DBB_shutdown) if (database->dbb_ast_flags & DBB_shutdown)
return isc_shutdown; return isc_shutdown;
else if (!(tdbb_flags & TDBB_shutdown_manager)) else if (!(tdbb_flags & TDBB_shutdown_manager))
{
if (secondary)
*secondary = attachment->getStable() ? attachment->getStable()->getShutError() : 0;
return isc_att_shutdown; return isc_att_shutdown;
} }
}
// If a cancel has been raised, defer its acknowledgement // If a cancel has been raised, defer its acknowledgement
// when executing in the context of an internal request or // when executing in the context of an internal request or
@ -7556,6 +7857,14 @@ ISC_STATUS thread_db::checkCancelState()
} }
} }
if (tdbb_reqTimer && tdbb_reqTimer->expired())
{
if (secondary)
*secondary = tdbb_reqTimer->getErrCode();
return isc_cancelled;
}
// Check the thread state for already posted system errors. If any still persists, // Check the thread state for already posted system errors. If any still persists,
// then someone tries to ignore our attempts to interrupt him. Let's insist. // then someone tries to ignore our attempts to interrupt him. Let's insist.
@ -7567,7 +7876,8 @@ ISC_STATUS thread_db::checkCancelState()
bool thread_db::checkCancelState(bool punt) bool thread_db::checkCancelState(bool punt)
{ {
const ISC_STATUS error = checkCancelState(); ISC_STATUS secondary = 0;
const ISC_STATUS error = checkCancelState(&secondary);
if (!error) if (!error)
return false; return false;
@ -7577,6 +7887,9 @@ bool thread_db::checkCancelState(bool punt)
if (error == isc_shutdown) if (error == isc_shutdown)
status << Arg::Str(attachment->att_filename); status << Arg::Str(attachment->att_filename);
if (secondary)
status << Arg::Gds(secondary);
if (attachment) if (attachment)
attachment->att_flags &= ~ATT_cancel_raise; attachment->att_flags &= ~ATT_cancel_raise;

View File

@ -349,6 +349,110 @@ const USHORT WIN_garbage_collector = 4; // garbage collector's window
const USHORT WIN_garbage_collect = 8; // scan left a page for garbage collector const USHORT WIN_garbage_collect = 8; // scan left a page for garbage collector
#ifdef USE_ITIMER
class TimeoutTimer FB_FINAL :
public Firebird::RefCntIface<Firebird::ITimerImpl<TimeoutTimer, Firebird::CheckStatusWrapper> >
{
public:
explicit TimeoutTimer()
: m_started(0),
m_expired(false),
m_value(0),
m_error(0)
{ }
// ITimer implementation
void handler();
int release();
bool expired() const
{
return m_expired;
}
unsigned int getValue() const
{
return m_value;
}
unsigned int getErrCode() const
{
return m_error;
}
// milliseconds left before timer expiration
unsigned int timeToExpire() const;
// evaluate expire timestamp using start timestamp
bool getExpireTimestamp(const ISC_TIMESTAMP start, ISC_TIMESTAMP& exp) const;
// set timeout value in milliseconds and secondary error code
void setup(unsigned int value, ISC_STATUS error)
{
m_value = value;
m_error = error;
}
void start();
void stop();
private:
SINT64 m_started;
bool m_expired;
unsigned int m_value; // milliseconds
ISC_STATUS m_error;
};
#else
class TimeoutTimer : public Firebird::RefCounted
{
public:
explicit TimeoutTimer()
: m_start(0),
m_value(0),
m_error(0)
{ }
bool expired() const;
unsigned int getValue() const
{
return m_value;
}
unsigned int getErrCode() const
{
return m_error;
}
// milliseconds left before timer expiration
unsigned int timeToExpire() const;
// evaluate expire timestamp using start timestamp
bool getExpireTimestamp(const ISC_TIMESTAMP start, ISC_TIMESTAMP& exp) const;
// set timeout value in milliseconds and secondary error code
void setup(unsigned int value, ISC_STATUS error)
{
m_start = 0;
m_value = value;
m_error = error;
}
void start();
void stop();
private:
SINT64 currTime() const
{
return fb_utils::query_performance_counter() * 1000 / fb_utils::query_performance_frequency();
}
SINT64 m_start;
unsigned int m_value; // milliseconds
ISC_STATUS m_error;
};
#endif // USE_ITIMER
// Thread specific database block // Thread specific database block
// tdbb_flags // tdbb_flags
@ -516,9 +620,13 @@ public:
attStat->bumpRelValue(index, relation_id, delta); attStat->bumpRelValue(index, relation_id, delta);
} }
ISC_STATUS checkCancelState(); ISC_STATUS checkCancelState(ISC_STATUS* secondary = NULL);
bool checkCancelState(bool punt); bool checkCancelState(bool punt);
bool reschedule(SLONG quantum, bool punt); bool reschedule(SLONG quantum, bool punt);
const TimeoutTimer* getTimeoutTimer() const
{
return tdbb_reqTimer;
}
void registerBdb(BufferDesc* bdb) void registerBdb(BufferDesc* bdb)
{ {
@ -587,6 +695,37 @@ public:
#endif #endif
} }
} }
class TimerGuard
{
public:
TimerGuard(thread_db* tdbb, TimeoutTimer* timer, bool autoStop)
: m_tdbb(tdbb),
m_autoStop(autoStop && timer)
{
fb_assert(m_tdbb->tdbb_reqTimer == NULL);
m_tdbb->tdbb_reqTimer = timer;
if (timer && timer->expired())
m_tdbb->tdbb_quantum = 0;
}
~TimerGuard()
{
if (m_autoStop)
m_tdbb->tdbb_reqTimer->stop();
m_tdbb->tdbb_reqTimer = NULL;
}
private:
thread_db* m_tdbb;
bool m_autoStop;
};
private:
Firebird::RefPtr<TimeoutTimer> tdbb_reqTimer;
}; };
class ThreadContextHolder class ThreadContextHolder

View File

@ -56,6 +56,7 @@
using namespace Jrd; using namespace Jrd;
using namespace Firebird; using namespace Firebird;
static SSHORT adjust_wait(thread_db* tdbb, SSHORT wait);
static void bug_lck(const TEXT*); static void bug_lck(const TEXT*);
static bool compatible(const Lock*, const Lock*, USHORT); static bool compatible(const Lock*, const Lock*, USHORT);
static void enqueue(thread_db*, CheckStatusWrapper*, Lock*, USHORT, SSHORT); static void enqueue(thread_db*, CheckStatusWrapper*, Lock*, USHORT, SSHORT);
@ -340,6 +341,7 @@ bool LCK_convert(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait)
WaitCancelGuard guard(tdbb, lock, wait); WaitCancelGuard guard(tdbb, lock, wait);
FbLocalStatus statusVector; FbLocalStatus statusVector;
wait = adjust_wait(tdbb, wait);
const bool result = CONVERT(tdbb, &statusVector, lock, level, wait); const bool result = CONVERT(tdbb, &statusVector, lock, level, wait);
if (!result) if (!result)
@ -657,6 +659,7 @@ bool LCK_lock(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait)
WaitCancelGuard guard(tdbb, lock, wait); WaitCancelGuard guard(tdbb, lock, wait);
FbLocalStatus statusVector; FbLocalStatus statusVector;
wait = adjust_wait(tdbb, wait);
ENQUEUE(tdbb, &statusVector, lock, level, wait); ENQUEUE(tdbb, &statusVector, lock, level, wait);
fb_assert(LCK_CHECK_LOCK(lock)); fb_assert(LCK_CHECK_LOCK(lock));
@ -856,6 +859,40 @@ void LCK_write_data(thread_db* tdbb, Lock* lock, SINT64 data)
} }
static SSHORT adjust_wait(thread_db* tdbb, SSHORT wait)
{
/**************************************
*
* a d j u s t _ w a i t
*
**************************************
*
* Functional description
* If wait is cancellable and if statement timer was started - calc new wait
* time to ensure it will not take longer than rest of timeout.
*
**************************************/
if ((wait == LCK_NO_WAIT) || (tdbb->tdbb_flags & TDBB_wait_cancel_disable) || !tdbb->getTimeoutTimer())
return wait;
unsigned int tout = tdbb->getTimeoutTimer()->timeToExpire();
if (tout > 0)
{
SSHORT t;
if (tout < 1000)
t = 1;
else if (tout < MAX_SSHORT * 1000)
t = (tout + 999) / 1000;
else
t = MAX_SSHORT;
if ((wait == LCK_WAIT) || (-wait > t))
return -t;
}
return wait;
}
static void bug_lck(const TEXT* string) static void bug_lck(const TEXT* string)
{ {
/************************************** /**************************************

View File

@ -4046,6 +4046,12 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
case RSR_field_generator_name: case RSR_field_generator_name:
field->fld_generator_name = (const TEXT*) p; field->fld_generator_name = (const TEXT*) p;
if (!field->fld_identity_type.specified)
field->fld_identity_type = IDENT_TYPE_BY_DEFAULT;
break;
case RSR_field_identity_type:
field->fld_identity_type = static_cast<IdentityType>(n);
break; break;
default: // Shut up compiler warning default: // Shut up compiler warning

View File

@ -50,7 +50,8 @@ enum rsr_t {
RSR_field_length, RSR_field_length,
RSR_field_sub_type, RSR_field_sub_type,
RSR_field_not_null, RSR_field_not_null,
RSR_field_generator_name RSR_field_generator_name,
RSR_field_identity_type
}; };
// Temporary field block // Temporary field block

View File

@ -450,3 +450,65 @@ Decimal128 MOV_get_dec128(Jrd::thread_db* tdbb, const dsc* desc)
} }
namespace Jrd
{
DescPrinter::DescPrinter(thread_db* tdbb, const dsc* desc, int mLen)
: maxLen(mLen)
{
const char* const NULL_KEY_STRING = "NULL";
if (!desc)
{
value = NULL_KEY_STRING;
return;
}
fb_assert(!desc->isBlob());
value = MOV_make_string2(tdbb, desc, ttype_dynamic);
const int len = (int) value.length();
const char* const str = value.c_str();
if (desc->isText() || desc->isDateTime())
{
if (desc->dsc_dtype == dtype_text)
{
const char* const pad = (desc->dsc_sub_type == ttype_binary) ? "\0" : " ";
value.rtrim(pad);
}
if (desc->isText() && desc->getTextType() == ttype_binary)
{
Firebird::string hex;
char* s = hex.getBuffer(2 * len);
for (int i = 0; i < len; i++)
{
sprintf(s, "%02X", (int)(unsigned char) str[i]);
s += 2;
}
value = "x'" + hex + "'";
}
else
value = "'" + value + "'";
}
if (value.length() > maxLen)
{
fb_assert(desc->isText());
value.resize(maxLen);
const CharSet* const cs = INTL_charset_lookup(tdbb, desc->getCharSet());
while (value.hasData() && !cs->wellFormed(value.length(), (const UCHAR*) value.c_str()))
value.resize(value.length() - 1);
value += "...";
}
}
} // namespace Jrd

View File

@ -53,4 +53,24 @@ void MOV_move(Jrd::thread_db*, /*const*/ dsc*, dsc*);
Firebird::Decimal64 MOV_get_dec64(Jrd::thread_db*, const dsc*); Firebird::Decimal64 MOV_get_dec64(Jrd::thread_db*, const dsc*);
Firebird::Decimal128 MOV_get_dec128(Jrd::thread_db*, const dsc*); Firebird::Decimal128 MOV_get_dec128(Jrd::thread_db*, const dsc*);
namespace Jrd
{
class DescPrinter
{
public:
DescPrinter(thread_db* tdbb, const dsc* desc, int mLen);
const Firebird::string& get() const
{
return value;
}
private:
Firebird::string value;
int maxLen;
};
} // namespace Jrd
#endif // JRD_MOV_PROTO_H #endif // JRD_MOV_PROTO_H

View File

@ -408,3 +408,8 @@ NAME("SEC$USER_TYPE", nam_sec_user_type)
NAME("RDB$SYSTEM_PRIVILEGES", nam_system_privileges) NAME("RDB$SYSTEM_PRIVILEGES", nam_system_privileges)
NAME("RDB$SQL_SECURITY", nam_sql_security) NAME("RDB$SQL_SECURITY", nam_sql_security)
NAME("MON$IDLE_TIMEOUT", nam_idle_timeout)
NAME("MON$IDLE_TIMER", nam_idle_timer)
NAME("MON$STATEMENT_TIMEOUT", nam_stmt_timeout)
NAME("MON$STATEMENT_TIMER", nam_stmt_timer)

View File

@ -1,196 +0,0 @@
/*
* PROGRAM: JRD Access Method
* MODULE: win9x_nt.h
* DESCRIPTION: Windows 9X IO support module
*
* This file needs to be included in winnt.cpp. It is designed to
* mimic Windows NT overlapped API when application runs on Win9X.
*
* 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 Alexander Peshkoff
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2009 Nikolay Samofatov <skidder at users.sourceforge.net>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
// This file needs to be explicitly included in winnt.cpp
#include "../common/classes/fb_pair.h"
namespace Jrd {
using Firebird::MutexLockGuard;
Firebird::Mutex file_locks_mutex;
struct LocksArrayItem {
HANDLE first;
Firebird::Mutex* second;
LocksArrayItem() {}
LocksArrayItem(HANDLE handle, Firebird::Mutex* mutex) : first(handle), second(mutex) { }
static HANDLE generate(LocksArrayItem value) {
return value.first;
}
};
Firebird::SortedArray<
LocksArrayItem,
Firebird::InlineStorage<LocksArrayItem, 16>,
HANDLE,
LocksArrayItem > file_locks_9X(*getDefaultMemoryPool());
// This header can be included in winnt.h
// It converts Win32 overlapped API calls to synchronized regular API calls
HANDLE CreateFile_9X(
LPCSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile)
{
if (!ISC_is_WinNT())
dwShareMode &= ~FILE_SHARE_DELETE;
HANDLE file = CreateFileA(
lpFileName,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile);
DWORD dwLastError = GetLastError();
if (!ISC_is_WinNT() && file != INVALID_HANDLE_VALUE) {
MutexLockGuard sync(file_locks_mutex);
file_locks_9X.add(
LocksArrayItem(
file,
FB_NEW Firebird::Mutex()));
}
SetLastError(dwLastError);
return file;
}
BOOL CloseHandle_9X(HANDLE hObject)
{
if (!ISC_is_WinNT()) {
MutexLockGuard sync(file_locks_mutex);
size_t pos;
if (file_locks_9X.find(hObject, pos)) {
delete file_locks_9X[pos].second;
file_locks_9X.remove(pos);
}
}
return CloseHandle(hObject);
}
BOOL ReadFile_9X(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped)
{
if (ISC_is_WinNT())
return ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
Firebird::Mutex* fileMutex = NULL;
{
MutexLockGuard sync(file_locks_mutex);
size_t pos;
if (file_locks_9X.find(hFile, pos))
fileMutex = file_locks_9X[pos].second;
}
BOOL result;
DWORD dwLastError;
{
MutexLockGuard sync(*fileMutex);
if (lpOverlapped != NULL) {
const DWORD ret = SetFilePointer(hFile, lpOverlapped->Offset,
(PLONG)&lpOverlapped->OffsetHigh, FILE_BEGIN);
if (ret == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
return 0;
}
result = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, NULL);
dwLastError = GetLastError();
}
SetLastError(dwLastError);
return result;
}
BOOL WriteFile_9X(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
)
{
if (ISC_is_WinNT())
return WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
Firebird::Mutex* fileMutex = NULL;
{
MutexLockGuard sync(file_locks_mutex);
size_t pos;
if (file_locks_9X.find(hFile, pos))
fileMutex = file_locks_9X[pos].second;
}
BOOL result;
DWORD dwLastError;
{
MutexLockGuard sync(*fileMutex);
if (lpOverlapped != NULL) {
const DWORD ret = SetFilePointer(hFile, lpOverlapped->Offset,
(PLONG)&lpOverlapped->OffsetHigh, FILE_BEGIN);
if (ret == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
return 0;
lpOverlapped = NULL;
}
result = WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL);
dwLastError = GetLastError();
}
SetLastError(dwLastError);
return result;
}
}
#if defined CreateFile
#undef CreateFile
#endif
#define CreateFile CreateFile_9X
#define CloseHandle CloseHandle_9X
#define ReadFile ReadFile_9X
#define WriteFile WriteFile_9X

View File

@ -54,10 +54,6 @@
#include <windows.h> #include <windows.h>
#ifdef WIN9X_SUPPORT
#include "win9x_nt.h"
#endif
namespace Jrd { namespace Jrd {
class FileExtendLockGuard class FileExtendLockGuard
@ -997,14 +993,8 @@ static jrd_file* setup_file(Database* dbb,
if (pageSpace && pageSpace->file) if (pageSpace && pageSpace->file)
return file; return file;
#ifdef WIN9X_SUPPORT
// Disable sophisticated file extension when running on 9X
if (ISC_is_WinNT())
#endif
{
file->fil_ext_lock = FB_NEW_POOL(*dbb->dbb_permanent) Firebird::RWLock(); file->fil_ext_lock = FB_NEW_POOL(*dbb->dbb_permanent) Firebird::RWLock();
} }
}
catch (const Firebird::Exception&) catch (const Firebird::Exception&)
{ {
CloseHandle(desc); CloseHandle(desc);

View File

@ -318,45 +318,38 @@ int IndexTableScan::compareKeys(const index_desc* idx,
// figure out what segment we're on; if it's a // figure out what segment we're on; if it's a
// character segment we've matched the partial string // character segment we've matched the partial string
const UCHAR* segment = NULL; const UCHAR* segment = NULL;
const index_desc::idx_repeat* tail; USHORT segnum = 0;
if (idx->idx_count > 1) if (idx->idx_count > 1)
{ {
segment = key_string1 + ((length2 - 1) / (Ods::STUFF_COUNT + 1)) * (Ods::STUFF_COUNT + 1); segment = key_string1 + ((length2 - 1) / (Ods::STUFF_COUNT + 1)) * (Ods::STUFF_COUNT + 1);
tail = idx->idx_rpt + (idx->idx_count - *segment); segnum = idx->idx_count - (UCHAR) ((flags & irb_descending) ? ((*segment) ^ -1) : *segment);
}
else
{
tail = &idx->idx_rpt[0];
} }
// If it's a string type key, and we're allowing "starting with" fuzzy // If it's a string type key, and we're allowing "starting with" fuzzy
// type matching, we're done // type matching, we're done
if ((flags & irb_starting) && if (flags & irb_starting)
(tail->idx_itype == idx_string || {
const index_desc::idx_repeat* const tail = idx->idx_rpt + segnum;
if (tail->idx_itype == idx_string ||
tail->idx_itype == idx_byte_array || tail->idx_itype == idx_byte_array ||
tail->idx_itype == idx_metadata || tail->idx_itype == idx_metadata ||
tail->idx_itype >= idx_first_intl_string)) tail->idx_itype >= idx_first_intl_string)
{ {
return 0; return 0;
} }
}
if (idx->idx_count > 1) if (idx->idx_count > 1)
{ {
// If we search for NULLs at the beginning then we're done if the first // If we search for NULLs at the beginning then we're done if the first
// segment isn't the first one possible (0 for ASC, 255 for DESC). // segment isn't the first one possible
if (length2 == 0) if (length2 == 0)
{ {
if (flags & irb_descending) if (segnum != 0)
{
if (*segment != 255)
return 0; return 0;
} }
else
{
if (*segment != 0)
return 0;
}
}
// if we've exhausted the segment, we've found a match // if we've exhausted the segment, we've found a match
USHORT remainder = length2 % (Ods::STUFF_COUNT + 1); USHORT remainder = length2 % (Ods::STUFF_COUNT + 1);

View File

@ -517,6 +517,9 @@ RELATION(nam_mon_attachments, rel_mon_attachments, ODS_11_1, rel_virtual)
FIELD(f_mon_att_remote_os_user, nam_mon_remote_os_user, fld_os_user, 0, ODS_12_0) FIELD(f_mon_att_remote_os_user, nam_mon_remote_os_user, fld_os_user, 0, ODS_12_0)
FIELD(f_mon_att_auth_method, nam_mon_auth_method, fld_auth_method, 0, ODS_12_0) FIELD(f_mon_att_auth_method, nam_mon_auth_method, fld_auth_method, 0, ODS_12_0)
FIELD(f_mon_att_sys_flag, nam_mon_sys_flag, fld_flag, 0, ODS_12_0) FIELD(f_mon_att_sys_flag, nam_mon_sys_flag, fld_flag, 0, ODS_12_0)
FIELD(f_mon_att_idle_timeout, nam_idle_timeout, fld_idle_timeout, 0, ODS_13_0)
FIELD(f_mon_att_idle_timer, nam_idle_timer, fld_idle_timer, 0, ODS_13_0)
FIELD(f_mon_att_stmt_timeout, nam_stmt_timeout, fld_stmt_timeout, 0, ODS_13_0)
END_RELATION END_RELATION
// Relation 35 (MON$TRANSACTIONS) // Relation 35 (MON$TRANSACTIONS)
@ -546,6 +549,8 @@ RELATION(nam_mon_statements, rel_mon_statements, ODS_11_1, rel_virtual)
FIELD(f_mon_stmt_sql_text, nam_mon_sql_text, fld_source, 0, ODS_11_1) FIELD(f_mon_stmt_sql_text, nam_mon_sql_text, fld_source, 0, ODS_11_1)
FIELD(f_mon_stmt_stat_id, nam_mon_stat_id, fld_stat_id, 0, ODS_11_1) FIELD(f_mon_stmt_stat_id, nam_mon_stat_id, fld_stat_id, 0, ODS_11_1)
FIELD(f_mon_stmt_expl_plan, nam_mon_expl_plan, fld_source, 0, ODS_11_1) FIELD(f_mon_stmt_expl_plan, nam_mon_expl_plan, fld_source, 0, ODS_11_1)
FIELD(f_mon_stmt_timeout, nam_stmt_timeout, fld_stmt_timeout, 0, ODS_13_0)
FIELD(f_mon_stmt_timer, nam_stmt_timer, fld_stmt_timer, 0, ODS_13_0)
END_RELATION END_RELATION
// Relation 37 (MON$CALL_STACK) // Relation 37 (MON$CALL_STACK)

View File

@ -175,6 +175,7 @@ public:
req_ext_stmt(NULL), req_ext_stmt(NULL),
req_cursors(*req_pool), req_cursors(*req_pool),
req_ext_resultset(NULL), req_ext_resultset(NULL),
req_timeout(0),
req_domain_validation(NULL), req_domain_validation(NULL),
req_auto_trans(*req_pool), req_auto_trans(*req_pool),
req_sorts(*req_pool), req_sorts(*req_pool),
@ -252,6 +253,8 @@ public:
Savepoint* req_savepoints; // Looper savepoint list Savepoint* req_savepoints; // Looper savepoint list
Savepoint* req_proc_sav_point; // procedure savepoint list Savepoint* req_proc_sav_point; // procedure savepoint list
Firebird::TimeStamp req_timestamp; // Start time of request Firebird::TimeStamp req_timestamp; // Start time of request
unsigned int req_timeout; // query timeout in milliseconds, set by the dsql_req::setupTimer
Firebird::RefPtr<TimeoutTimer> req_timer; // timeout timer, shared with dsql_req
Firebird::AutoPtr<Jrd::RuntimeStatistics> req_fetch_baseline; // State of request performance counters when we reported it last time Firebird::AutoPtr<Jrd::RuntimeStatistics> req_fetch_baseline; // State of request performance counters when we reported it last time
SINT64 req_fetch_elapsed; // Number of clock ticks spent while fetching rows for this request since we reported it last time SINT64 req_fetch_elapsed; // Number of clock ticks spent while fetching rows for this request since we reported it last time

View File

@ -532,7 +532,7 @@ static bool shutdown(thread_db* tdbb, SSHORT flag, bool force)
{ {
if (!(attachment->att_flags & ATT_shutdown)) if (!(attachment->att_flags & ATT_shutdown))
{ {
attachment->signalShutdown(); attachment->signalShutdown(isc_att_shut_db_down);
found = true; found = true;
} }
} }

View File

@ -255,7 +255,7 @@ void TRA_cleanup(thread_db* tdbb)
window.win_page = inventory_page(tdbb, sequence); window.win_page = inventory_page(tdbb, sequence);
tx_inv_page* tip = (tx_inv_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_transactions); tx_inv_page* tip = (tx_inv_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_transactions);
TraNumber max = ceiling - (TraNumber) sequence * trans_per_tip; TraNumber max = ceiling - (TraNumber) sequence * trans_per_tip;
if (max > trans_per_tip) if (max >= trans_per_tip)
max = trans_per_tip - 1; max = trans_per_tip - 1;
for (; number <= max; number++) for (; number <= max; number++)
{ {

View File

@ -75,11 +75,11 @@ enum lck_t {
LCK_btr_dont_gc, // Prevent removal of b-tree page from index LCK_btr_dont_gc, // Prevent removal of b-tree page from index
LCK_shared_counter, // Database-wide shared counter LCK_shared_counter, // Database-wide shared counter
LCK_tra_pc, // Precommitted transaction lock LCK_tra_pc, // Precommitted transaction lock
LCK_rel_gc, // Allow garbage collection for relation
LCK_fun_exist, // Function existence lock LCK_fun_exist, // Function existence lock
LCK_rel_rescan, // Relation forced rescan lock LCK_rel_rescan, // Relation forced rescan lock
LCK_crypt, // Crypt lock for single crypt thread LCK_crypt, // Crypt lock for single crypt thread
LCK_crypt_status, // Notifies about changed database encryption status LCK_crypt_status, // Notifies about changed database encryption status
LCK_idx_reserve, // Index reservation lock
LCK_record_gc // Record-level GC lock LCK_record_gc // Record-level GC lock
}; };
@ -1240,22 +1240,74 @@ static void prt_lock(OUTFILE outfile, const lhb* LOCK_header, const lbl* lock, U
// in <page_space>:<page_number> format // in <page_space>:<page_number> format
const UCHAR* q = lock->lbl_key; const UCHAR* q = lock->lbl_key;
SLONG key; ULONG pageno;
memcpy(&key, q, sizeof(SLONG)); memcpy(&pageno, q, sizeof(ULONG));
q += sizeof(SLONG); q += sizeof(ULONG);
ULONG pg_space; ULONG pg_space;
memcpy(&pg_space, q, sizeof(SLONG)); memcpy(&pg_space, q, sizeof(ULONG));
FPRINTF(outfile, "\tKey: %04" ULONGFORMAT":%06" SLONGFORMAT",", pg_space, key); FPRINTF(outfile, "\tKey: %04" ULONGFORMAT":%06" ULONGFORMAT",", pg_space, pageno);
} }
else if (lock->lbl_length == 4) else if ((lock->lbl_series == Jrd::LCK_relation || lock->lbl_series == Jrd::LCK_rel_gc) &&
lock->lbl_length == sizeof(ULONG) + sizeof(SINT64)) // Jrd::jrd_rel::getRelLockKeyLength()
{
const UCHAR* q = lock->lbl_key;
ULONG rel_id;
memcpy(&rel_id, q, sizeof(ULONG));
q += sizeof(ULONG);
SINT64 instance_id;
memcpy(&instance_id, q, sizeof(SINT64));
FPRINTF(outfile, "\tKey: %04" ULONGFORMAT":%09" SQUADFORMAT",", rel_id, instance_id);
}
else if ((lock->lbl_series == Jrd::LCK_tra ||
lock->lbl_series == Jrd::LCK_tra_pc ||
lock->lbl_series == Jrd::LCK_attachment ||
lock->lbl_series == Jrd::LCK_monitor ||
lock->lbl_series == Jrd::LCK_cancel) &&
lock->lbl_length == sizeof(SINT64))
{
SINT64 key;
memcpy(&key, lock->lbl_key, lock->lbl_length);
FPRINTF(outfile, "\tKey: %09" SQUADFORMAT",", key);
}
else if (lock->lbl_series == Jrd::LCK_record_gc &&
lock->lbl_length == sizeof(SINT64))
{
SINT64 key;
memcpy(&key, lock->lbl_key, lock->lbl_length);
const ULONG pageno = key >> 16;
const ULONG line = (ULONG) (key & MAX_USHORT);
FPRINTF(outfile, "\tKey: %06" ULONGFORMAT":%04" ULONGFORMAT",", pageno, line);
}
else if ((lock->lbl_series == Jrd::LCK_idx_exist || lock->lbl_series == Jrd::LCK_expression) &&
lock->lbl_length == sizeof(SLONG))
{ {
SLONG key; SLONG key;
memcpy(&key, lock->lbl_key, 4); memcpy(&key, lock->lbl_key, lock->lbl_length);
const ULONG rel_id = key >> 16;
const ULONG idx_id = (ULONG) (key & MAX_USHORT);
FPRINTF(outfile, "\tKey: %04" ULONGFORMAT":%04" ULONGFORMAT",", rel_id, idx_id);
}
else if (lock->lbl_length == sizeof(SLONG))
{
SLONG key;
memcpy(&key, lock->lbl_key, lock->lbl_length);
FPRINTF(outfile, "\tKey: %06" SLONGFORMAT",", key); FPRINTF(outfile, "\tKey: %06" SLONGFORMAT",", key);
} }
else if (lock->lbl_length == 0)
{
FPRINTF(outfile, "\tKey: <none>");
}
else else
{ {
UCHAR temp[512]; UCHAR temp[512];

View File

@ -9,7 +9,7 @@ BuildType=T
MajorVer=4 MajorVer=4
MinorVer=0 MinorVer=0
RevNo=0 RevNo=0
BuildNum=537 BuildNum=581
NowAt=`pwd` NowAt=`pwd`
cd `dirname $0` cd `dirname $0`

View File

@ -1,7 +1,7 @@
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */ /* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?); set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
-- --
('2016-11-11 11:46:00', 'JRD', 0, 808) ('2017-02-24 22:00:00', 'JRD', 0, 819)
('2015-03-17 18:33:00', 'QLI', 1, 533) ('2015-03-17 18:33:00', 'QLI', 1, 533)
('2015-01-07 18:01:51', 'GFIX', 3, 134) ('2015-01-07 18:01:51', 'GFIX', 3, 134)
('1996-11-07 13:39:40', 'GPRE', 4, 1) ('1996-11-07 13:39:40', 'GPRE', 4, 1)
@ -15,7 +15,7 @@ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUM
('2006-09-10 03:04:31', 'JRD_BUGCHK', 15, 307) ('2006-09-10 03:04:31', 'JRD_BUGCHK', 15, 307)
('2016-05-26 13:53:45', 'ISQL', 17, 196) ('2016-05-26 13:53:45', 'ISQL', 17, 196)
('2010-07-10 10:50:30', 'GSEC', 18, 105) ('2010-07-10 10:50:30', 'GSEC', 18, 105)
('2015-01-07 18:01:51', 'GSTAT', 21, 58) ('2017-03-09 21:51:33', 'GSTAT', 21, 59)
('2013-12-19 17:31:31', 'FBSVCMGR', 22, 58) ('2013-12-19 17:31:31', 'FBSVCMGR', 22, 58)
('2009-07-18 12:12:12', 'UTL', 23, 2) ('2009-07-18 12:12:12', 'UTL', 23, 2)
('2016-03-20 15:30:00', 'NBACKUP', 24, 80) ('2016-03-20 15:30:00', 'NBACKUP', 24, 80)

View File

@ -914,7 +914,18 @@ Data source : @4', NULL, NULL)
('dsql_window_cant_overr_frame', NULL, 'ExprNodes.cpp', NULL, 0, 804, NULL, 'Cannot override the window @1 because it has a frame clause. Tip: it can be used without parenthesis in OVER', NULL, NULL); ('dsql_window_cant_overr_frame', NULL, 'ExprNodes.cpp', NULL, 0, 804, NULL, 'Cannot override the window @1 because it has a frame clause. Tip: it can be used without parenthesis in OVER', NULL, NULL);
('dsql_window_duplicate', NULL, 'ExprNodes.cpp', NULL, 0, 805, NULL, 'Duplicate window definition for @1', NULL, NULL); ('dsql_window_duplicate', NULL, 'ExprNodes.cpp', NULL, 0, 805, NULL, 'Duplicate window definition for @1', NULL, NULL);
('sql_too_long', 'prepareStatement', 'dsql.cpp', NULL, 0, 806, NULL, 'SQL statement is too long. Maximum size is @1 bytes.', NULL, NULL); ('sql_too_long', 'prepareStatement', 'dsql.cpp', NULL, 0, 806, NULL, 'SQL statement is too long. Maximum size is @1 bytes.', NULL, NULL);
('decprecision_err', NULL, 'dsql parse.y', NULL, 0, 807, NULL, 'DecFloat precision must be 16 or 34', NULL, NULL); ('cfg_stmt_timeout', 'thread_db::checkCancelState', 'jrd.cpp', NULL, 0, 807, NULL, 'Config level timeout expired.', NULL, NULL);
('att_stmt_timeout', 'thread_db::checkCancelState', 'jrd.cpp', NULL, 0, 808, NULL, 'Attachment level timeout expired.', NULL, NULL);
('req_stmt_timeout', 'thread_db::checkCancelState', 'jrd.cpp', NULL, 0, 809, NULL, 'Statement level timeout expired.', NULL, NULL);
('att_shut_killed', NULL, 'jrd.cpp', NULL, 0, 810, NULL, 'Killed by database administrator.', NULL, NULL);
('att_shut_idle', NULL, 'jrd.cpp', NULL, 0, 811, NULL, 'Idle timeout expired.', NULL, NULL);
('att_shut_db_down', NULL, 'jrd.cpp', NULL, 0, 812, NULL, 'Database is shutdown.', NULL, NULL);
('att_shut_engine', NULL, 'jrd.cpp', NULL, 0, 813, NULL, 'Engine is shutdown.', NULL, NULL);
('overriding_without_identity', NULL, 'StmtNodes.cpp', NULL, 0, 814, NULL, 'OVERRIDING clause can be used only when an identity column is present in the INSERT''s field list for table/view @1', NULL, NULL);
('overriding_system_invalid', NULL, 'StmtNodes.cpp', NULL, 0, 815, NULL, 'OVERRIDING SYSTEM VALUE can be used only for identity column defined as ''GENERATED ALWAYS'' in INSERT for table/view @1', NULL, NULL);
('overriding_user_invalid', NULL, 'StmtNodes.cpp', NULL, 0, 816, NULL, 'OVERRIDING USER VALUE can be used only for identity column defined as ''GENERATED BY DEFAULT'' in INSERT for table/view @1', NULL, NULL);
('overriding_system_missing', NULL, 'StmtNodes.cpp', NULL, 0, 817, NULL, 'OVERRIDING SYSTEM VALUE should be used to override the value of an identity column defined as ''GENERATED ALWAYS'' in table/view @1', NULL, NULL);
('decprecision_err', NULL, 'dsql parse.y', NULL, 0, 818, NULL, 'DecFloat precision must be 16 or 34', NULL, NULL);
-- QLI -- QLI
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL); (NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL); (NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
@ -3249,6 +3260,7 @@ Analyzing database pages ...', NULL, NULL);
(NULL, 'main', 'dba.epp', NULL, 21, 55, NULL, 'no encrypted database support, only -e and -h can be used', NULL, NULL) (NULL, 'main', 'dba.epp', NULL, 21, 55, NULL, 'no encrypted database support, only -e and -h can be used', NULL, NULL)
(NULL, 'main', 'dba.epp', NULL, 21, 56, NULL, ' Empty pages: @1, full pages: @2', NULL, NULL); (NULL, 'main', 'dba.epp', NULL, 21, 56, NULL, ' Empty pages: @1, full pages: @2', NULL, NULL);
(NULL, 'dba_in_sw_table', 'dbaswi.h', NULL, 21, 57, NULL, ' -role SQL role name', NULL, NULL); (NULL, 'dba_in_sw_table', 'dbaswi.h', NULL, 21, 57, NULL, ' -role SQL role name', NULL, NULL);
(NULL, 'main', 'dba.epp', NULL, 21, 58, NULL, 'Other pages: total @1, ENCRYPTED @2 (DB problem!), non-crypted @3', NULL, NULL)
-- FBSVCMGR -- FBSVCMGR
-- All messages use the new format. -- All messages use the new format.
('fbsvcmgr_bad_am', 'putAccessMode', 'fbsvcmgr.cpp', NULL, 22, 1, NULL, 'Wrong value for access mode', NULL, NULL); ('fbsvcmgr_bad_am', 'putAccessMode', 'fbsvcmgr.cpp', NULL, 22, 1, NULL, 'Wrong value for access mode', NULL, NULL);

View File

@ -29,7 +29,7 @@ CREATE DOMAIN SQL_STATE AS CHAR(5);
CREATE DOMAIN SQL_SUBCLASS AS CHAR(3); CREATE DOMAIN SQL_SUBCLASS AS CHAR(3);
CREATE DOMAIN SYMBOL AS VARCHAR(32); CREATE DOMAIN SYMBOL AS VARCHAR(32);
CREATE DOMAIN TEMPLATE AS BLOB SUB_TYPE 0 SEGMENT SIZE 256; CREATE DOMAIN TEMPLATE AS BLOB SUB_TYPE 0 SEGMENT SIZE 256;
CREATE DOMAIN TEXT AS VARCHAR(118); CREATE DOMAIN TEXT AS VARCHAR(138);
CREATE DOMAIN TRANSLATOR AS VARCHAR(32); CREATE DOMAIN TRANSLATOR AS VARCHAR(32);
CREATE DOMAIN TRANS_DATE AS TIMESTAMP; CREATE DOMAIN TRANS_DATE AS TIMESTAMP;
CREATE DOMAIN TRANS_NOTES AS BLOB SUB_TYPE 0 SEGMENT SIZE 0; CREATE DOMAIN TRANS_NOTES AS BLOB SUB_TYPE 0 SEGMENT SIZE 0;

View File

@ -813,7 +813,18 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
(-833, '42', '000', 0, 804, 'dsql_window_cant_overr_frame', NULL, NULL) (-833, '42', '000', 0, 804, 'dsql_window_cant_overr_frame', NULL, NULL)
(-833, '42', '000', 0, 805, 'dsql_window_duplicate', NULL, NULL) (-833, '42', '000', 0, 805, 'dsql_window_duplicate', NULL, NULL)
(-902, '54', '001', 0, 806, 'sql_too_long', NULL, NULL) (-902, '54', '001', 0, 806, 'sql_too_long', NULL, NULL)
(-842, 'HY', '104', 0, 807, 'decprecision_err', NULL, NULL) (-901, 'HY', '008', 0, 807, 'cfg_stmt_timeout', NULL, NULL)
(-901, 'HY', '008', 0, 808, 'att_stmt_timeout', NULL, NULL)
(-901, 'HY', '008', 0, 809, 'req_stmt_timeout', NULL, NULL)
(-902, '08', '003', 0, 810, 'att_shut_killed', NULL, NULL)
(-902, '08', '003', 0, 811, 'att_shut_idle', NULL, NULL)
(-902, '08', '003', 0, 812, 'att_shut_db_down', NULL, NULL)
(-902, '08', '003', 0, 813, 'att_shut_engine', NULL, NULL)
(-902, '42', '000', 0, 814, 'overriding_without_identity', NULL, NULL)
(-902, '42', '000', 0, 815, 'overriding_system_invalid', NULL, NULL)
(-902, '42', '000', 0, 816, 'overriding_user_invalid', NULL, NULL)
(-902, '42', '000', 0, 817, 'overriding_system_missing', NULL, NULL)
(-842, 'HY', '104', 0, 818, 'decprecision_err', NULL, NULL)
-- GFIX -- GFIX
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL) (-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL) (-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)

View File

@ -56,6 +56,8 @@ private:
socklen_t len; socklen_t len;
static const unsigned MAX_LEN = sizeof(sa_data); static const unsigned MAX_LEN = sizeof(sa_data);
void checkAndFixFamily();
public: public:
void clear(); void clear();
const SockAddr& operator = (const SockAddr& x); const SockAddr& operator = (const SockAddr& x);
@ -83,6 +85,27 @@ public:
void unmapV4(); void unmapV4();
}; };
// Definitions below taken from sources at correspondent operating systems.
// If something else arrives, it should be added here and into checkAndFixFamily() also.
#define AF_INET6_POSIX 10
#define AF_INET6_WINDOWS 23
inline void SockAddr::checkAndFixFamily()
{
#if AF_INET6 == AF_INET6_POSIX
if (data.sock.sa_family == AF_INET6_WINDOWS)
#elif AF_INET6 == AF_INET6_WINDOWS
if (data.sock.sa_family == AF_INET6_POSIX)
#else
#error Unknown value of AF_INET6 !
#endif
{
data.sock.sa_family = AF_INET6;
fb_assert(len == sizeof(sockaddr_in6));
}
}
inline void SockAddr::clear() inline void SockAddr::clear()
{ {
@ -95,6 +118,8 @@ inline const SockAddr& SockAddr::operator = (const SockAddr& x)
{ {
memcpy(&data, &x.data, MAX_LEN); memcpy(&data, &x.data, MAX_LEN);
len = x.len; len = x.len;
checkAndFixFamily();
return *this; return *this;
} }
@ -105,6 +130,8 @@ inline SockAddr::SockAddr(const unsigned char* p_data, unsigned p_len)
p_len = MAX_LEN; p_len = MAX_LEN;
memcpy(&data, p_data, p_len); memcpy(&data, p_data, p_len);
len = p_len; len = p_len;
checkAndFixFamily();
} }

Some files were not shown because too many files have changed in this diff Show More