mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 18:43:02 +01:00
Merge branch 'master' into read_consistency
This commit is contained in:
parent
e46ee70c72
commit
2a2a991fe0
34
.travis.yml
34
.travis.yml
@ -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"
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
2
builds/make.new/config/.gitignore
vendored
2
builds/make.new/config/.gitignore
vendored
@ -1,4 +1,4 @@
|
|||||||
config.guess
|
config.guess
|
||||||
config.h.in
|
config.h.in*
|
||||||
config.sub
|
config.sub
|
||||||
ltmain.sh
|
ltmain.sh
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
113
doc/README.session_idle_timeouts
Normal file
113
doc/README.session_idle_timeouts
Normal 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.
|
159
doc/README.statement_timeouts
Normal file
159
doc/README.statement_timeouts
Normal 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.
|
||||||
|
|
@ -5,8 +5,10 @@
|
|||||||
<title></title>
|
<title></title>
|
||||||
<meta name="generator" content="LibreOffice 5.2.3.3 (Linux)"/>
|
<meta name="generator" content="LibreOffice 5.2.3.3 (Linux)"/>
|
||||||
<meta name="author" content="alex "/>
|
<meta name="author" content="alex "/>
|
||||||
<meta name="created" content="2013-05-31T00:00:00.010003100"/>
|
<meta name="created" content="00:00:00"/>
|
||||||
<meta name="changed" content="2017-01-31T17:08:57.272616325"/>
|
<meta name="changed" content="2017-02-02T17:00:07.121995034"/>
|
||||||
|
<meta name="created" content="2013-05-31T00:00:00.010003100">
|
||||||
|
<meta name="changed" content="2017-01-31T17:08:57.272616325">
|
||||||
<meta name="CHANGEDBY" content="Alex Peshkoff">
|
<meta name="CHANGEDBY" content="Alex Peshkoff">
|
||||||
<meta name="CHANGEDBY" content="Alex Peshkoff">
|
<meta name="CHANGEDBY" content="Alex Peshkoff">
|
||||||
<meta name="CHANGEDBY" content="Alex Peshkoff">
|
<meta name="CHANGEDBY" content="Alex Peshkoff">
|
||||||
@ -3161,8 +3163,7 @@ or using some own encryption of a key is also very good idea in case
|
|||||||
when network access to the server is used. All this job should be
|
when network access to the server is used. All this job should be
|
||||||
done in plugin (and application working with it) i.e. database block
|
done in plugin (and application working with it) i.e. database block
|
||||||
encryption algorithm by itself may happen to be easiest part of db
|
encryption algorithm by itself may happen to be easiest part of db
|
||||||
crypt plugin, </font><font size="4" style="font-size: 14pt">specially
|
crypt plugin, specially when some standard library is used for it.</font></p>
|
||||||
when some standard library is used for it.</font></p>
|
|
||||||
<p style="margin-bottom: 0in"><br/>
|
<p style="margin-bottom: 0in"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
@ -3180,6 +3181,19 @@ plugin or key holder plugin.</font></p>
|
|||||||
</ol>
|
</ol>
|
||||||
<p style="margin-bottom: 0in"><br/>
|
<p style="margin-bottom: 0in"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p style="margin-bottom: 0in"><a name="DbCryptInfo"></a><font size="4" style="font-size: 14pt">DbCryptInfo
|
||||||
|
interface is passed to DbCryptPlugin by engine. Plugin may save this
|
||||||
|
interface and use when needed to obtain additional informatio about
|
||||||
|
database.</font></p>
|
||||||
|
<ol>
|
||||||
|
<li/>
|
||||||
|
<p style="margin-bottom: 0in"><font size="4" style="font-size: 14pt">const
|
||||||
|
char* getDatabaseFullPath(StatusType* status) – returns full
|
||||||
|
(including path) name of primary database file.</font></p>
|
||||||
|
</ol>
|
||||||
|
<p style="margin-bottom: 0in"><br/>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom: 0in"><a name="DbCryptPlugin"></a><font size="4" style="font-size: 14pt">DbCryptPlugin
|
<p style="margin-bottom: 0in"><a name="DbCryptPlugin"></a><font size="4" style="font-size: 14pt">DbCryptPlugin
|
||||||
interface is main interface of database crypt plugin.</font></p>
|
interface is main interface of database crypt plugin.</font></p>
|
||||||
@ -3202,6 +3216,10 @@ interface is main interface of database crypt plugin.</font></p>
|
|||||||
<p style="margin-bottom: 0in"><font size="4" style="font-size: 14pt">void
|
<p style="margin-bottom: 0in"><font size="4" style="font-size: 14pt">void
|
||||||
decrypt(StatusType* status, unsigned length, const void* from, void*
|
decrypt(StatusType* status, unsigned length, const void* from, void*
|
||||||
to) – decrypts data after reading block from database file.</font></p>
|
to) – decrypts data after reading block from database file.</font></p>
|
||||||
|
<li/>
|
||||||
|
<p style="margin-bottom: 0in"><font size="4" style="font-size: 14pt">void
|
||||||
|
setInfo(StatusType* status, IDbCryptInfo* info) – in this method
|
||||||
|
crypt plugin typically saves informational interface for future use.</font></p>
|
||||||
</ol>
|
</ol>
|
||||||
<p style="margin-bottom: 0in"><br/>
|
<p style="margin-bottom: 0in"><br/>
|
||||||
|
|
||||||
@ -3251,11 +3269,11 @@ interface is main interface of database crypt key holder plugin.</font></p>
|
|||||||
letting it to work with database.</font></p>
|
letting it to work with database.</font></p>
|
||||||
<li/>
|
<li/>
|
||||||
<p style="margin-bottom: 0in"><font size="4" style="font-size: 14pt">ICryptKeyCallback*
|
<p style="margin-bottom: 0in"><font size="4" style="font-size: 14pt">ICryptKeyCallback*
|
||||||
chainHandle(StatusType* status) – support of a chain of key holders. In
|
chainHandle(StatusType* status) – support of a chain of key
|
||||||
some cases key has to pass through more than single key holder
|
holders. In some cases key has to pass through more than single key
|
||||||
before it reaches db crypt plugin. This is needed (for example) to
|
holder before it reaches db crypt plugin. This is needed (for
|
||||||
support execute statement in encrypted database. This is just a
|
example) to support execute statement in encrypted database. This is
|
||||||
sample – chains are also used in some other cases. Callback
|
just a sample – chains are also used in some other cases. Callback
|
||||||
interface, returned by this method, may differ from one returned by
|
interface, returned by this method, may differ from one returned by
|
||||||
keyHandle() function (see above). Typically is should be able to
|
keyHandle() function (see above). Typically is should be able to
|
||||||
duplicate one-to-one keys, received by KeyHolderPlugin when
|
duplicate one-to-one keys, received by KeyHolderPlugin when
|
||||||
|
@ -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
|
||||||
|
@ -81,6 +81,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum Action {NONE, ENC, DEC, EX_LCL, EX_RMT};
|
enum Action {NONE, ENC, DEC, EX_LCL, EX_RMT};
|
||||||
|
// Switches/actions have the following meanings:
|
||||||
|
// ENC(-e) - encrypt database
|
||||||
|
// DEC(-d) - decrypt database
|
||||||
|
// EX_LCL(-l) - execute some predefined select command (demonstrates that database can respond to select request)
|
||||||
|
// EX_RMT(-r) - execute select using execute statement in remote datasource (demonstrates that dbcrypt key is
|
||||||
|
// passed to target database when using execute statement)
|
||||||
|
|
||||||
void execute(const char* dbName, const Action a)
|
void execute(const char* dbName, const Action a)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
@ -1,2 +1,39 @@
|
|||||||
All files in this directory are trivial samples.
|
**************************************************************************************
|
||||||
They do not perform any real data encryption and should not be used in production!
|
* All files in this directory are trivial samples. *
|
||||||
|
* They do not perform any real data encryption and should not be used in production! *
|
||||||
|
**************************************************************************************
|
||||||
|
|
||||||
|
Brief description of the sample.
|
||||||
|
|
||||||
|
Sample contains 3 components - DbCrypt plugin, KeyHolder plugin and application, which can pass
|
||||||
|
crypt key to server. Plugins do not perform any real encryption (XOR with single byte hardly can
|
||||||
|
be treated as encryption though makes database useless without crypt plugin), key is sent between
|
||||||
|
components in plain form - they just demonstrate what calls in plugins should be done and what
|
||||||
|
methods should be implemented in order for plugin to start to work.
|
||||||
|
|
||||||
|
Depending upon settings in configuration file plugins may use different ways to manage encryption
|
||||||
|
key. DbCrypt's configuration file may contain following parameters:
|
||||||
|
Auto - boolean value, when FALSE plugin queries KeyHolder plugin for key value (this is default),
|
||||||
|
when TRUE get key value from "Value" configuration parameter.
|
||||||
|
Value - integer value (lower byte is actually used), used in "Auto" mode as key value (default 90).
|
||||||
|
|
||||||
|
CryptKeyHolder's configuration file may contain following parameters:
|
||||||
|
Auto - boolean value, when FALSE plugin queries client application for key value (this is default),
|
||||||
|
when TRUE get key value from configuration file by name or use default (90) for unnamed key.
|
||||||
|
Key{Name} - integer value, a key with name "Name" (i.e. when one issues "ALTER DATABASE ENCRYPT ...
|
||||||
|
KEY Doggy" configuration parameter KeyDoggy should be present).
|
||||||
|
OnlyOwnKey - boolean value, enables/disables use of a key from another key holder in SuperServer.
|
||||||
|
Default value is TRUE (i.e. only key, owned by this KeyHolder, can be used by related
|
||||||
|
attachment).
|
||||||
|
|
||||||
|
Crypt application has a few parameters making it possible to demonstrate different operations.
|
||||||
|
-e - Encrypt database (use gstat to monitor crypt progress).
|
||||||
|
-d - Decrypt database.
|
||||||
|
-l - Locally execute SELECT statement returning name of currently attached user.
|
||||||
|
-r - Execute same statement using remote datasource 'localhost:employee'. To make it work
|
||||||
|
user "test" with password "test" should be created in employee database. If employee was
|
||||||
|
encrypted in advance this demonstrates passing database crypt key through the chain of
|
||||||
|
key holders.
|
||||||
|
|
||||||
|
cryptDb.pas is a minimum (XOR using fixed key hardcoded in plugin body) sample of database crypt
|
||||||
|
plugin written on Pascal. Was tested with both FreePascal and Delphi.
|
||||||
|
@ -1664,6 +1664,28 @@ 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__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
|
||||||
@ -1796,6 +1818,8 @@ C --
|
|||||||
PARAMETER (GDS__dsql_wrong_param_num = 336003111)
|
PARAMETER (GDS__dsql_wrong_param_num = 336003111)
|
||||||
INTEGER*4 GDS__dsql_invalid_drop_ss_clause
|
INTEGER*4 GDS__dsql_invalid_drop_ss_clause
|
||||||
PARAMETER (GDS__dsql_invalid_drop_ss_clause = 336003112)
|
PARAMETER (GDS__dsql_invalid_drop_ss_clause = 336003112)
|
||||||
|
INTEGER*4 GDS__upd_ins_cannot_default
|
||||||
|
PARAMETER (GDS__upd_ins_cannot_default = 336003113)
|
||||||
INTEGER*4 GDS__dyn_filter_not_found
|
INTEGER*4 GDS__dyn_filter_not_found
|
||||||
PARAMETER (GDS__dyn_filter_not_found = 336068645)
|
PARAMETER (GDS__dyn_filter_not_found = 336068645)
|
||||||
INTEGER*4 GDS__dyn_func_not_found
|
INTEGER*4 GDS__dyn_func_not_found
|
||||||
|
@ -1659,6 +1659,28 @@ 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_cfg_stmt_timeout = 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_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;
|
||||||
@ -1791,6 +1813,8 @@ const
|
|||||||
gds_dsql_wrong_param_num = 336003111;
|
gds_dsql_wrong_param_num = 336003111;
|
||||||
isc_dsql_invalid_drop_ss_clause = 336003112;
|
isc_dsql_invalid_drop_ss_clause = 336003112;
|
||||||
gds_dsql_invalid_drop_ss_clause = 336003112;
|
gds_dsql_invalid_drop_ss_clause = 336003112;
|
||||||
|
isc_upd_ins_cannot_default = 336003113;
|
||||||
|
gds_upd_ins_cannot_default = 336003113;
|
||||||
isc_dyn_filter_not_found = 336068645;
|
isc_dyn_filter_not_found = 336068645;
|
||||||
gds_dyn_filter_not_found = 336068645;
|
gds_dyn_filter_not_found = 336068645;
|
||||||
isc_dyn_func_not_found = 336068649;
|
isc_dyn_func_not_found = 336068649;
|
||||||
|
@ -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 = ?";
|
||||||
|
@ -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);
|
||||||
|
@ -585,18 +585,33 @@ UCHAR MVOL_write(const UCHAR c, int* io_cnt, UCHAR** io_ptr)
|
|||||||
|
|
||||||
const size_t nBytesToWrite = size_t(longBytesToWrite);
|
const size_t nBytesToWrite = size_t(longBytesToWrite);
|
||||||
|
|
||||||
|
bool error = false;
|
||||||
|
bool disk_full = false;
|
||||||
|
cnt = 0;
|
||||||
#ifndef WIN_NT
|
#ifndef WIN_NT
|
||||||
cnt = write(tdgbl->file_desc, ptr, nBytesToWrite);
|
ssize_t ret = write(tdgbl->file_desc, ptr, nBytesToWrite);
|
||||||
#else
|
|
||||||
|
|
||||||
DWORD ret = 0;
|
if (ret == -1)
|
||||||
|
{
|
||||||
|
error = true;
|
||||||
|
|
||||||
|
if (errno == ENOSPC || errno == EIO || errno == ENXIO || errno == EFBIG)
|
||||||
|
disk_full = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cnt = ret;
|
||||||
|
#else
|
||||||
if (!WriteFile(tdgbl->file_desc, ptr, (DWORD) nBytesToWrite, &cnt, NULL))
|
if (!WriteFile(tdgbl->file_desc, ptr, (DWORD) nBytesToWrite, &cnt, NULL))
|
||||||
{
|
{
|
||||||
ret = GetLastError();
|
error = true;
|
||||||
|
DWORD ret = GetLastError();
|
||||||
|
|
||||||
|
if (ret == ERROR_DISK_FULL || ret == ERROR_HANDLE_DISK_FULL)
|
||||||
|
disk_full = true;
|
||||||
}
|
}
|
||||||
#endif // !WIN_NT
|
#endif // !WIN_NT
|
||||||
tdgbl->mvol_io_buffer = tdgbl->mvol_io_data;
|
tdgbl->mvol_io_buffer = tdgbl->mvol_io_data;
|
||||||
if (cnt > 0)
|
if (!error)
|
||||||
{
|
{
|
||||||
tdgbl->mvol_cumul_count += cnt;
|
tdgbl->mvol_cumul_count += cnt;
|
||||||
file_not_empty();
|
file_not_empty();
|
||||||
@ -610,13 +625,7 @@ UCHAR MVOL_write(const UCHAR c, int* io_cnt, UCHAR** io_ptr)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!cnt ||
|
if (disk_full)
|
||||||
#ifndef WIN_NT
|
|
||||||
errno == ENOSPC || errno == EIO || errno == ENXIO ||
|
|
||||||
errno == EFBIG)
|
|
||||||
#else
|
|
||||||
ret == ERROR_DISK_FULL || ret == ERROR_HANDLE_DISK_FULL)
|
|
||||||
#endif // !WIN_NT
|
|
||||||
{
|
{
|
||||||
if (tdgbl->action->act_action == ACT_backup_split)
|
if (tdgbl->action->act_action == ACT_backup_split)
|
||||||
{
|
{
|
||||||
|
@ -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))
|
||||||
|
@ -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> >
|
||||||
{
|
{
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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())
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,13 +79,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;
|
||||||
@ -207,7 +209,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},
|
||||||
{TYPE_INTEGER, "SnapshotsMemSize", (ConfigValue) 65536}, // bytes
|
{TYPE_INTEGER, "SnapshotsMemSize", (ConfigValue) 65536}, // bytes
|
||||||
{TYPE_INTEGER, "TpcBlockSize", (ConfigValue) 4194304}, // bytes
|
{TYPE_INTEGER, "TpcBlockSize", (ConfigValue) 4194304}, // bytes
|
||||||
{TYPE_BOOLEAN, "ReadConsistency", (ConfigValue) true}
|
{TYPE_BOOLEAN, "ReadConsistency", (ConfigValue) true}
|
||||||
@ -852,6 +856,16 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
bool Config::getReadConsistency() const
|
bool Config::getReadConsistency() const
|
||||||
{
|
{
|
||||||
return get<bool>(KEY_READ_CONSISTENCY);
|
return get<bool>(KEY_READ_CONSISTENCY);
|
||||||
|
@ -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,
|
||||||
KEY_SNAPSHOTS_MEM_SIZE,
|
KEY_SNAPSHOTS_MEM_SIZE,
|
||||||
KEY_TPC_BLOCK_SIZE,
|
KEY_TPC_BLOCK_SIZE,
|
||||||
KEY_READ_CONSISTENCY,
|
KEY_READ_CONSISTENCY,
|
||||||
@ -356,6 +358,11 @@ public:
|
|||||||
|
|
||||||
bool getCryptSecurityDatabase() const;
|
bool getCryptSecurityDatabase() const;
|
||||||
|
|
||||||
|
// set in seconds
|
||||||
|
unsigned int getStatementTimeout() const;
|
||||||
|
// set in minutes
|
||||||
|
unsigned int getConnIdleTimeout() const;
|
||||||
|
|
||||||
ULONG getSnapshotsMemSize() const;
|
ULONG getSnapshotsMemSize() const;
|
||||||
|
|
||||||
ULONG getTpcBlockSize() const;
|
ULONG getTpcBlockSize() const;
|
||||||
|
@ -32,13 +32,16 @@
|
|||||||
#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 TPC_HDR_FILE = "fb13_tpc_%s";
|
static const char* const USER_MAP_FILE = "fb" COMMON_FILE_PREFIX "_user_mapping";
|
||||||
static const char* const TPC_BLOCK_FILE = "fb13_tpc_%s_%d";
|
static const char* const TPC_HDR_FILE = "fb" COMMON_FILE_PREFIX "_tpc_%s";
|
||||||
static const char* const SNAPSHOTS_FILE = "fb13_snap_%s";
|
static const char* const TPC_BLOCK_FILE = "fb" COMMON_FILE_PREFIX "_tpc_%s_%d";
|
||||||
|
static const char* const SNAPSHOTS_FILE = "fb" COMMON_FILE_PREFIX "_snap_%s";
|
||||||
|
|
||||||
#ifdef UNIX
|
#ifdef UNIX
|
||||||
static const char* const INIT_FILE = "fb_init";
|
static const char* const INIT_FILE = "fb_init";
|
||||||
|
@ -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()
|
||||||
{
|
{
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
#include "../common/classes/Aligner.h"
|
#include "../common/classes/Aligner.h"
|
||||||
#include "../common/utils_proto.h"
|
#include "../common/utils_proto.h"
|
||||||
#include "../common/os/os_utils.h"
|
#include "../common/os/os_utils.h"
|
||||||
|
#include "../common/os/path_utils.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#ifdef HAVE_SYS_IPC_H
|
#ifdef HAVE_SYS_IPC_H
|
||||||
@ -84,6 +85,9 @@
|
|||||||
#ifdef HAVE_ICONV_H
|
#ifdef HAVE_ICONV_H
|
||||||
#include <iconv.h>
|
#include <iconv.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef LINUX
|
||||||
|
#include <sys/sysmacros.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "../common/config/config.h"
|
#include "../common/config/config.h"
|
||||||
|
|
||||||
@ -224,10 +228,34 @@ 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;
|
||||||
|
|
||||||
|
#ifdef LINUX
|
||||||
|
// In order to avoid analyzing mtab in most cases check for non-device mounts first
|
||||||
|
struct stat fileStat;
|
||||||
|
unsigned m = 1; // use something that is known to be not non-device major
|
||||||
|
|
||||||
|
if (os_utils::stat(expanded_filename.c_str(), &fileStat) == 0)
|
||||||
|
m = major(fileStat.st_dev);
|
||||||
|
else // stat error - let's try with path component
|
||||||
|
{
|
||||||
|
tstring path, name;
|
||||||
|
PathUtils::splitLastComponent(path, name, expanded_filename);
|
||||||
|
|
||||||
|
if (path.hasData() && os_utils::stat(path.c_str(), &fileStat) == 0)
|
||||||
|
m = major(fileStat.st_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m != 0 && m != 144 && m != 145 && m != 146)
|
||||||
|
{
|
||||||
|
// device mount or stat for file/path is impossible - definitely not NFS
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// proceed with deeper analysis
|
||||||
|
#endif
|
||||||
|
|
||||||
tstring max_node, max_path;
|
tstring max_node, max_path;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -70,23 +70,15 @@ public:
|
|||||||
/// Destructor
|
/// Destructor
|
||||||
virtual ~Module() {}
|
virtual ~Module() {}
|
||||||
|
|
||||||
#ifdef WIN_NT
|
|
||||||
const Firebird::PathName fileName;
|
const Firebird::PathName fileName;
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// The constructor is protected so normal code can't allocate instances
|
/// The constructor is protected so normal code can't allocate instances
|
||||||
/// of the class, but the class itself is still able to be subclassed.
|
/// of the class, but the class itself is still able to be subclassed.
|
||||||
#ifdef WIN_NT
|
|
||||||
Module(MemoryPool& pool, const Firebird::PathName& aFileName)
|
Module(MemoryPool& pool, const Firebird::PathName& aFileName)
|
||||||
: fileName(pool, aFileName)
|
: fileName(pool, aFileName)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
Module()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Copy construction is not supported, hence the copy constructor is private
|
/// Copy construction is not supported, hence the copy constructor is private
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "firebird.h"
|
#include "firebird.h"
|
||||||
#include "../common/os/mod_loader.h"
|
#include "../common/os/mod_loader.h"
|
||||||
#include "../common/os/os_utils.h"
|
#include "../common/os/os_utils.h"
|
||||||
|
#include "../common/os/path_utils.h"
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
@ -40,8 +41,9 @@
|
|||||||
class DlfcnModule : public ModuleLoader::Module
|
class DlfcnModule : public ModuleLoader::Module
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DlfcnModule(void* m)
|
DlfcnModule(MemoryPool& pool, const Firebird::PathName& aFileName, void* m)
|
||||||
: module(m)
|
: ModuleLoader::Module(pool, aFileName),
|
||||||
|
module(m)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~DlfcnModule();
|
~DlfcnModule();
|
||||||
@ -109,7 +111,7 @@ ModuleLoader::Module* ModuleLoader::loadModule(const Firebird::PathName& modPath
|
|||||||
system(command.c_str());
|
system(command.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return FB_NEW_POOL(*getDefaultMemoryPool()) DlfcnModule(module);
|
return FB_NEW_POOL(*getDefaultMemoryPool()) DlfcnModule(*getDefaultMemoryPool(), modPath, module);
|
||||||
}
|
}
|
||||||
|
|
||||||
DlfcnModule::~DlfcnModule()
|
DlfcnModule::~DlfcnModule()
|
||||||
@ -127,6 +129,17 @@ void* DlfcnModule::findSymbol(const Firebird::string& symName)
|
|||||||
|
|
||||||
result = dlsym(module, newSym.c_str());
|
result = dlsym(module, newSym.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DLADDR
|
||||||
|
if (!PathUtils::isRelative(fileName))
|
||||||
|
{
|
||||||
|
Dl_info info;
|
||||||
|
if (!dladdr(result, &info))
|
||||||
|
return NULL;
|
||||||
|
if (fileName != info.dli_fname)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +103,8 @@ public:
|
|||||||
"msvcr120.dll",
|
"msvcr120.dll",
|
||||||
#elif _MSC_VER == 1900
|
#elif _MSC_VER == 1900
|
||||||
"vcruntime140.dll",
|
"vcruntime140.dll",
|
||||||
|
#elif _MSC_VER == 1910
|
||||||
|
"vcruntime140.dll",
|
||||||
#else
|
#else
|
||||||
#error Specify CRT DLL name here !
|
#error Specify CRT DLL name here !
|
||||||
#endif
|
#endif
|
||||||
|
@ -5951,7 +5951,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)
|
||||||
@ -6296,6 +6296,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,
|
||||||
@ -6881,6 +6882,8 @@ void RelationNode::defineSetDefaultTrigger(DsqlCompilerScratch* dsqlScratch,
|
|||||||
// DEFAULT and null flag) and another blr_domain_full with DEFAULT and null flag. We swallow the error when
|
// DEFAULT and null flag) and another blr_domain_full with DEFAULT and null flag. We swallow the error when
|
||||||
// transfering the value from the second to the first variable.
|
// transfering the value from the second to the first variable.
|
||||||
|
|
||||||
|
// This could be better done with blr_default, but let's maintain backward compatible BLR for now.
|
||||||
|
|
||||||
blrWriter.appendUChar(blr_dcl_variable);
|
blrWriter.appendUChar(blr_dcl_variable);
|
||||||
blrWriter.appendUShort(index);
|
blrWriter.appendUShort(index);
|
||||||
|
|
||||||
@ -7856,6 +7859,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)
|
||||||
|
@ -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
|
||||||
|
@ -4118,6 +4118,155 @@ dsc* DecodeNode::execute(thread_db* tdbb, jrd_req* request) const
|
|||||||
//--------------------
|
//--------------------
|
||||||
|
|
||||||
|
|
||||||
|
static RegisterNode<DefaultNode> regDefaultNode(blr_default);
|
||||||
|
|
||||||
|
DefaultNode::DefaultNode(MemoryPool& pool, const Firebird::MetaName& aRelationName,
|
||||||
|
const Firebird::MetaName& aFieldName)
|
||||||
|
: DsqlNode<DefaultNode, ExprNode::TYPE_DEFAULT>(pool),
|
||||||
|
relationName(aRelationName),
|
||||||
|
fieldName(aFieldName),
|
||||||
|
field(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DmlNode* DefaultNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/)
|
||||||
|
{
|
||||||
|
MetaName relationName, fieldName;
|
||||||
|
csb->csb_blr_reader.getMetaName(relationName);
|
||||||
|
csb->csb_blr_reader.getMetaName(fieldName);
|
||||||
|
|
||||||
|
CompilerScratch::Dependency dependency(obj_relation);
|
||||||
|
dependency.relation = MET_lookup_relation(tdbb, relationName);
|
||||||
|
dependency.subName = FB_NEW_POOL(pool) MetaName(fieldName);
|
||||||
|
csb->csb_dependencies.push(dependency);
|
||||||
|
|
||||||
|
jrd_fld* fld = NULL;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
jrd_rel* relation = MET_lookup_relation(tdbb, relationName);
|
||||||
|
|
||||||
|
if (relation && relation->rel_fields)
|
||||||
|
{
|
||||||
|
int fieldId = MET_lookup_field(tdbb, relation, fieldName);
|
||||||
|
|
||||||
|
if (fieldId >= 0)
|
||||||
|
{
|
||||||
|
fld = (*relation->rel_fields)[fieldId];
|
||||||
|
|
||||||
|
if (fld)
|
||||||
|
{
|
||||||
|
if (fld->fld_source_rel_field.first.hasData())
|
||||||
|
{
|
||||||
|
relationName = fld->fld_source_rel_field.first;
|
||||||
|
fieldName = fld->fld_source_rel_field.second;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DefaultNode* node = FB_NEW_POOL(pool) DefaultNode(pool, relationName, fieldName);
|
||||||
|
node->field = fld;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FB_NEW_POOL(pool) NullNode(pool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueExprNode* DefaultNode::createFromField(thread_db* tdbb, CompilerScratch* csb,
|
||||||
|
StreamType* map, jrd_fld* fld)
|
||||||
|
{
|
||||||
|
if (fld->fld_generator_name.hasData())
|
||||||
|
{
|
||||||
|
// Make a (next value for <generator name>) expression.
|
||||||
|
|
||||||
|
GenIdNode* const genNode = FB_NEW_POOL(csb->csb_pool) GenIdNode(
|
||||||
|
csb->csb_pool, (csb->blrVersion == 4), fld->fld_generator_name, NULL, true, true);
|
||||||
|
|
||||||
|
bool sysGen = false;
|
||||||
|
if (!MET_load_generator(tdbb, genNode->generator, &sysGen, &genNode->step))
|
||||||
|
PAR_error(csb, Arg::Gds(isc_gennotdef) << Arg::Str(fld->fld_generator_name));
|
||||||
|
|
||||||
|
if (sysGen)
|
||||||
|
PAR_error(csb, Arg::Gds(isc_cant_modify_sysobj) << "generator" << fld->fld_generator_name);
|
||||||
|
|
||||||
|
return genNode;
|
||||||
|
}
|
||||||
|
else if (fld->fld_default_value)
|
||||||
|
{
|
||||||
|
StreamMap localMap;
|
||||||
|
if (!map)
|
||||||
|
map = localMap.getBuffer(STREAM_MAP_LENGTH);
|
||||||
|
|
||||||
|
return NodeCopier(csb, map).copy(tdbb, fld->fld_default_value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return FB_NEW_POOL(csb->csb_pool) NullNode(csb->csb_pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
string DefaultNode::internalPrint(NodePrinter& printer) const
|
||||||
|
{
|
||||||
|
ValueExprNode::internalPrint(printer);
|
||||||
|
|
||||||
|
NODE_PRINT(printer, relationName);
|
||||||
|
NODE_PRINT(printer, fieldName);
|
||||||
|
|
||||||
|
return "DefaultNode";
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueExprNode* DefaultNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||||
|
{
|
||||||
|
DefaultNode* node = FB_NEW_POOL(getPool()) DefaultNode(getPool(),
|
||||||
|
relationName, fieldName);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultNode::setParameterName(dsql_par* parameter) const
|
||||||
|
{
|
||||||
|
parameter->par_name = parameter->par_alias = "DEFAULT";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefaultNode::setParameterType(DsqlCompilerScratch* /*dsqlScratch*/, const dsc* /*desc*/, bool /*forceVarChar*/)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultNode::genBlr(DsqlCompilerScratch* dsqlScratch)
|
||||||
|
{
|
||||||
|
dsqlScratch->appendUChar(blr_default);
|
||||||
|
dsqlScratch->appendMetaString(relationName.c_str());
|
||||||
|
dsqlScratch->appendMetaString(fieldName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* /*desc*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefaultNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const
|
||||||
|
{
|
||||||
|
if (!ExprNode::dsqlMatch(other, ignoreMapCast))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const DefaultNode* o = other->as<DefaultNode>();
|
||||||
|
fb_assert(o);
|
||||||
|
|
||||||
|
return relationName == o->relationName && fieldName == o->fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueExprNode* DefaultNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
||||||
|
{
|
||||||
|
ValueExprNode* node = createFromField(tdbb, csb, NULL, field);
|
||||||
|
doPass1(tdbb, csb, &node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------
|
||||||
|
|
||||||
|
|
||||||
static RegisterNode<DerivedExprNode> regDerivedExprNode(blr_derived_expr);
|
static RegisterNode<DerivedExprNode> regDerivedExprNode(blr_derived_expr);
|
||||||
|
|
||||||
DmlNode* DerivedExprNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/)
|
DmlNode* DerivedExprNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/)
|
||||||
@ -10133,17 +10282,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(&desc1, 0);
|
|
||||||
|
|
||||||
if (decrementNode && decrementNode->is<LiteralNode>() && desc3.dsc_dtype == dtype_long)
|
|
||||||
offset -= MOV_get_long(&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(&desc2, 0);
|
const SLONG len = MOV_get_long(&desc2, 0);
|
||||||
@ -10200,20 +10338,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(startDsc, 0);
|
SINT64 sStart = MOV_get_long(startDsc, 0);
|
||||||
const SLONG sLength = MOV_get_long(lengthDsc, 0);
|
SINT64 sLength = MOV_get_long(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;
|
||||||
|
|
||||||
@ -10235,8 +10377,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())
|
||||||
{
|
{
|
||||||
@ -11134,7 +11276,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);
|
||||||
}
|
}
|
||||||
@ -11197,6 +11340,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.
|
||||||
@ -11289,7 +11434,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,6 +476,36 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultNode : public DsqlNode<DefaultNode, ExprNode::TYPE_DEFAULT>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit DefaultNode(MemoryPool& pool, const Firebird::MetaName& aRelationName,
|
||||||
|
const Firebird::MetaName& aFieldName);
|
||||||
|
|
||||||
|
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
|
||||||
|
static ValueExprNode* createFromField(thread_db* tdbb, CompilerScratch* csb, StreamType* map, jrd_fld* fld);
|
||||||
|
|
||||||
|
virtual Firebird::string internalPrint(NodePrinter& printer) const;
|
||||||
|
virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
|
||||||
|
virtual void setParameterName(dsql_par* parameter) const;
|
||||||
|
virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch,
|
||||||
|
const dsc* desc, bool forceVarChar);
|
||||||
|
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
|
||||||
|
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc);
|
||||||
|
|
||||||
|
virtual bool dsqlMatch(const ExprNode* other, bool ignoreMapCast) const;
|
||||||
|
|
||||||
|
virtual ValueExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Firebird::MetaName relationName;
|
||||||
|
const Firebird::MetaName fieldName;
|
||||||
|
|
||||||
|
private:
|
||||||
|
jrd_fld* field;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class DerivedExprNode : public TypedNode<ValueExprNode, ExprNode::TYPE_DERIVED_EXPR>
|
class DerivedExprNode : public TypedNode<ValueExprNode, ExprNode::TYPE_DERIVED_EXPR>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -1720,6 +1750,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
dsql_udf* dsqlFunction;
|
dsql_udf* dsqlFunction;
|
||||||
|
bool isSubRoutine;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -281,6 +281,24 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SetSessionNode : public Node
|
||||||
|
{
|
||||||
|
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 SetSessionNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
|
||||||
|
virtual void execute(thread_db* tdbb, dsql_req* request) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type m_type;
|
||||||
|
ULONG m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class DmlNode : public Node
|
class DmlNode : public Node
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -408,6 +426,7 @@ public:
|
|||||||
TYPE_CURRENT_USER,
|
TYPE_CURRENT_USER,
|
||||||
TYPE_DERIVED_EXPR,
|
TYPE_DERIVED_EXPR,
|
||||||
TYPE_DECODE,
|
TYPE_DECODE,
|
||||||
|
TYPE_DEFAULT,
|
||||||
TYPE_DERIVED_FIELD,
|
TYPE_DERIVED_FIELD,
|
||||||
TYPE_DOMAIN_VALIDATION,
|
TYPE_DOMAIN_VALIDATION,
|
||||||
TYPE_EXTRACT,
|
TYPE_EXTRACT,
|
||||||
@ -853,13 +872,13 @@ public:
|
|||||||
fb_assert(false);
|
fb_assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual DsqlNode* pass1(thread_db* /*tdbb*/, CompilerScratch* /*csb*/)
|
virtual ValueExprNode* pass1(thread_db* /*tdbb*/, CompilerScratch* /*csb*/)
|
||||||
{
|
{
|
||||||
fb_assert(false);
|
fb_assert(false);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual DsqlNode* pass2(thread_db* /*tdbb*/, CompilerScratch* /*csb*/)
|
virtual ValueExprNode* pass2(thread_db* /*tdbb*/, CompilerScratch* /*csb*/)
|
||||||
{
|
{
|
||||||
fb_assert(false);
|
fb_assert(false);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -97,7 +97,7 @@ Parser::Parser(thread_db* tdbb, MemoryPool& pool, DsqlCompilerScratch* aScratch,
|
|||||||
yylexemes = 0;
|
yylexemes = 0;
|
||||||
|
|
||||||
lex.start = string;
|
lex.start = string;
|
||||||
lex.line_start = lex.ptr = string;
|
lex.line_start = lex.last_token = lex.ptr = string;
|
||||||
lex.end = string + length;
|
lex.end = string + length;
|
||||||
lex.lines = 1;
|
lex.lines = 1;
|
||||||
lex.att_charset = characterSet;
|
lex.att_charset = characterSet;
|
||||||
|
@ -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,6 +5884,8 @@ void ModifyNode::genBlr(DsqlCompilerScratch* dsqlScratch)
|
|||||||
|
|
||||||
ModifyNode* ModifyNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
ModifyNode* ModifyNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
||||||
{
|
{
|
||||||
|
preprocessAssignments(tdbb, csb, newStream, statement->as<CompoundStmtNode>(), NULL);
|
||||||
|
|
||||||
pass1Modify(tdbb, csb, this);
|
pass1Modify(tdbb, csb, this);
|
||||||
|
|
||||||
doPass1(tdbb, csb, statement.getAddress());
|
doPass1(tdbb, csb, statement.getAddress());
|
||||||
@ -6414,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)
|
||||||
@ -6422,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>();
|
||||||
@ -6436,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;
|
||||||
}
|
}
|
||||||
@ -6449,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
|
||||||
|
|
||||||
@ -6556,6 +6589,22 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch,
|
|||||||
NestConst<ValueExprNode>* ptr = fields.begin();
|
NestConst<ValueExprNode>* ptr = fields.begin();
|
||||||
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)
|
||||||
|
{
|
||||||
|
// *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;
|
||||||
@ -6565,6 +6614,7 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch,
|
|||||||
PASS1_set_parameter_type(dsqlScratch, *ptr2, temp->asgnTo, false);
|
PASS1_set_parameter_type(dsqlScratch, *ptr2, temp->asgnTo, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (updateOrInsert)
|
if (updateOrInsert)
|
||||||
{
|
{
|
||||||
@ -6639,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);
|
||||||
@ -6652,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);
|
||||||
|
|
||||||
@ -6787,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();
|
||||||
|
|
||||||
@ -6830,32 +6888,9 @@ void StoreNode::makeDefaults(thread_db* tdbb, CompilerScratch* csb)
|
|||||||
AssignmentNode* assign = FB_NEW_POOL(*tdbb->getDefaultPool()) AssignmentNode(
|
AssignmentNode* assign = FB_NEW_POOL(*tdbb->getDefaultPool()) AssignmentNode(
|
||||||
*tdbb->getDefaultPool());
|
*tdbb->getDefaultPool());
|
||||||
assign->asgnTo = PAR_gen_field(tdbb, stream, fieldId);
|
assign->asgnTo = PAR_gen_field(tdbb, stream, fieldId);
|
||||||
|
assign->asgnFrom = DefaultNode::createFromField(tdbb, csb, map, *ptr1);
|
||||||
|
|
||||||
stack.push(assign);
|
stack.push(assign);
|
||||||
|
|
||||||
const MetaName& generatorName = (*ptr1)->fld_generator_name;
|
|
||||||
|
|
||||||
if (generatorName.hasData())
|
|
||||||
{
|
|
||||||
// Make a (next value for <generator name>) expression.
|
|
||||||
|
|
||||||
GenIdNode* const genNode = FB_NEW_POOL(csb->csb_pool) GenIdNode(
|
|
||||||
csb->csb_pool, (csb->blrVersion == 4), generatorName, NULL, true, true);
|
|
||||||
|
|
||||||
bool sysGen = false;
|
|
||||||
if (!MET_load_generator(tdbb, genNode->generator, &sysGen, &genNode->step))
|
|
||||||
PAR_error(csb, Arg::Gds(isc_gennotdef) << Arg::Str(generatorName));
|
|
||||||
|
|
||||||
if (sysGen)
|
|
||||||
PAR_error(csb, Arg::Gds(isc_cant_modify_sysobj) << "generator" << generatorName);
|
|
||||||
|
|
||||||
assign->asgnFrom = genNode;
|
|
||||||
}
|
|
||||||
else //if (value)
|
|
||||||
{
|
|
||||||
// Clone the field default value.
|
|
||||||
assign->asgnFrom = RemapFieldNodeCopier(csb, map, fieldId).copy(tdbb, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7951,6 +7986,80 @@ void SetRoleNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** transact
|
|||||||
//--------------------
|
//--------------------
|
||||||
|
|
||||||
|
|
||||||
|
SetSessionNode::SetSessionNode(MemoryPool& pool, Type aType, ULONG aVal, UCHAR blr_timepart)
|
||||||
|
: Node(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";
|
||||||
|
}
|
||||||
|
|
||||||
|
SetSessionNode* SetSessionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||||
|
{
|
||||||
|
dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_SET_SESSION);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
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?
|
||||||
@ -7970,6 +8079,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);
|
||||||
|
|
||||||
@ -8047,7 +8157,10 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
for (; fieldPtr != fieldsCopy.end(); ++fieldPtr, ++valuePtr)
|
for (; fieldPtr != fieldsCopy.end(); ++fieldPtr, ++valuePtr)
|
||||||
{
|
{
|
||||||
AssignmentNode* assign = FB_NEW_POOL(pool) AssignmentNode(pool);
|
AssignmentNode* assign = FB_NEW_POOL(pool) AssignmentNode(pool);
|
||||||
assign->asgnFrom = *valuePtr;
|
|
||||||
|
if (!(assign->asgnFrom = *valuePtr)) // it's NULL for DEFAULT
|
||||||
|
assign->asgnFrom = FB_NEW_POOL(pool) DefaultNode(pool, relation_name, (*fieldPtr)->dsqlName);
|
||||||
|
|
||||||
assign->asgnTo = *fieldPtr;
|
assign->asgnTo = *fieldPtr;
|
||||||
assignments->statements.add(assign);
|
assignments->statements.add(assign);
|
||||||
|
|
||||||
@ -8071,6 +8184,9 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
|
|
||||||
if (testField == fieldName)
|
if (testField == fieldName)
|
||||||
{
|
{
|
||||||
|
if (!*valuePtr) // it's NULL for DEFAULT
|
||||||
|
ERRD_post(Arg::Gds(isc_upd_ins_cannot_default) << fieldName);
|
||||||
|
|
||||||
++matchCount;
|
++matchCount;
|
||||||
|
|
||||||
const FB_SIZE_T fieldPos = fieldPtr - fieldsCopy.begin();
|
const FB_SIZE_T fieldPos = fieldPtr - fieldsCopy.begin();
|
||||||
@ -9217,6 +9333,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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1609,6 +1619,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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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_SET_SESSION)
|
||||||
{
|
{
|
||||||
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_SET_SESSION)
|
||||||
{
|
{
|
||||||
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,14 +914,32 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SetSessionRequest::execute(thread_db* tdbb, jrd_tra** /*traHandle*/,
|
||||||
|
IMessageMetadata* /*inMetadata*/, const UCHAR* /*inMsg*/,
|
||||||
|
IMessageMetadata* /*outMetadata*/, UCHAR* /*outMsg*/,
|
||||||
|
bool /*singleton*/)
|
||||||
|
{
|
||||||
|
node->execute(tdbb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSessionRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
|
||||||
|
ntrace_result_t* /*traceResult*/)
|
||||||
|
{
|
||||||
|
node = Node::doDsqlPass(scratch, node);
|
||||||
|
|
||||||
|
// Don't trace pseudo-statements (without requests associated).
|
||||||
|
req_traced = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
get_request_info
|
get_request_info
|
||||||
@ -1530,7 +1564,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()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1560,11 +1599,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)
|
||||||
@ -1757,6 +1876,7 @@ static void sql_info(thread_db* tdbb,
|
|||||||
case DsqlCompiledStatement::TYPE_CREATE_DB:
|
case DsqlCompiledStatement::TYPE_CREATE_DB:
|
||||||
case DsqlCompiledStatement::TYPE_DDL:
|
case DsqlCompiledStatement::TYPE_DDL:
|
||||||
case DsqlCompiledStatement::TYPE_SET_ROLE:
|
case DsqlCompiledStatement::TYPE_SET_ROLE:
|
||||||
|
case DsqlCompiledStatement::TYPE_SET_SESSION:
|
||||||
number = isc_info_sql_stmt_ddl;
|
number = isc_info_sql_stmt_ddl;
|
||||||
break;
|
break;
|
||||||
case DsqlCompiledStatement::TYPE_COMMIT:
|
case DsqlCompiledStatement::TYPE_COMMIT:
|
||||||
@ -1828,6 +1948,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:
|
||||||
{
|
{
|
||||||
|
@ -80,6 +80,7 @@ namespace Jrd
|
|||||||
class RseNode;
|
class RseNode;
|
||||||
class StmtNode;
|
class StmtNode;
|
||||||
class TransactionNode;
|
class TransactionNode;
|
||||||
|
class SetSessionNode;
|
||||||
class ValueExprNode;
|
class ValueExprNode;
|
||||||
class ValueListNode;
|
class ValueListNode;
|
||||||
class WindowClause;
|
class WindowClause;
|
||||||
@ -93,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;
|
||||||
|
|
||||||
@ -431,7 +433,7 @@ public:
|
|||||||
TYPE_SELECT, TYPE_SELECT_UPD, TYPE_INSERT, TYPE_DELETE, TYPE_UPDATE, TYPE_UPDATE_CURSOR,
|
TYPE_SELECT, TYPE_SELECT_UPD, TYPE_INSERT, TYPE_DELETE, TYPE_UPDATE, TYPE_UPDATE_CURSOR,
|
||||||
TYPE_DELETE_CURSOR, TYPE_COMMIT, TYPE_ROLLBACK, TYPE_CREATE_DB, TYPE_DDL, TYPE_START_TRANS,
|
TYPE_DELETE_CURSOR, TYPE_COMMIT, TYPE_ROLLBACK, TYPE_CREATE_DB, TYPE_DDL, TYPE_START_TRANS,
|
||||||
TYPE_EXEC_PROCEDURE, TYPE_COMMIT_RETAIN, TYPE_ROLLBACK_RETAIN, TYPE_SET_GENERATOR,
|
TYPE_EXEC_PROCEDURE, TYPE_COMMIT_RETAIN, TYPE_ROLLBACK_RETAIN, TYPE_SET_GENERATOR,
|
||||||
TYPE_SAVEPOINT, TYPE_EXEC_BLOCK, TYPE_SELECT_BLOCK, TYPE_SET_ROLE
|
TYPE_SAVEPOINT, TYPE_EXEC_BLOCK, TYPE_SELECT_BLOCK, TYPE_SET_ROLE, TYPE_SET_SESSION
|
||||||
};
|
};
|
||||||
|
|
||||||
// Statement flags.
|
// Statement flags.
|
||||||
@ -556,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:
|
||||||
@ -580,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!
|
||||||
@ -670,6 +686,28 @@ private:
|
|||||||
NestConst<TransactionNode> node;
|
NestConst<TransactionNode> node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SetSessionRequest : public dsql_req
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SetSessionRequest(MemoryPool& pool, SetSessionNode* aNode)
|
||||||
|
: dsql_req(pool),
|
||||||
|
node(aNode)
|
||||||
|
{
|
||||||
|
req_traced = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch,
|
||||||
|
ntrace_result_t* traceResult);
|
||||||
|
|
||||||
|
virtual void execute(thread_db* tdbb, jrd_tra** traHandle,
|
||||||
|
Firebird::IMessageMetadata* inMetadata, const UCHAR* inMsg,
|
||||||
|
Firebird::IMessageMetadata* outMetadata, UCHAR* outMsg,
|
||||||
|
bool singleton);
|
||||||
|
|
||||||
|
private:
|
||||||
|
NestConst<SetSessionNode> node;
|
||||||
|
};
|
||||||
|
|
||||||
//! Implicit (NATURAL and USING) joins
|
//! Implicit (NATURAL and USING) joins
|
||||||
class ImplicitJoin : public pool_alloc<dsql_type_imp_join>
|
class ImplicitJoin : public pool_alloc<dsql_type_imp_join>
|
||||||
{
|
{
|
||||||
|
@ -1 +1 @@
|
|||||||
45 shift/reduce conflicts, 17 reduce/reduce conflicts.
|
46 shift/reduce conflicts, 17 reduce/reduce conflicts.
|
||||||
|
186
src/dsql/parse.y
186
src/dsql/parse.y
@ -596,10 +596,12 @@ 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> 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
|
||||||
@ -608,6 +610,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
|
||||||
@ -646,6 +649,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;
|
||||||
@ -725,6 +729,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;
|
||||||
@ -754,6 +759,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -773,6 +779,7 @@ statement
|
|||||||
: dml_statement { $$ = newNode<DsqlDmlRequest>($1); }
|
: dml_statement { $$ = newNode<DsqlDmlRequest>($1); }
|
||||||
| ddl_statement { $$ = newNode<DsqlDdlRequest>($1); }
|
| ddl_statement { $$ = newNode<DsqlDdlRequest>($1); }
|
||||||
| tra_statement { $$ = newNode<DsqlTransactionRequest>($1); }
|
| tra_statement { $$ = newNode<DsqlTransactionRequest>($1); }
|
||||||
|
| session_statement { $$ = newNode<SetSessionRequest>($1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
%type <stmtNode> dml_statement
|
%type <stmtNode> dml_statement
|
||||||
@ -2181,10 +2188,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>)
|
||||||
@ -3931,7 +3944,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>();
|
||||||
@ -4077,6 +4090,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)
|
||||||
@ -4985,6 +5016,31 @@ set_role
|
|||||||
{ $$ = newNode<SetRoleNode>(); }
|
{ $$ = newNode<SetRoleNode>(); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
%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>)
|
||||||
tran_option_list_opt($setTransactionNode)
|
tran_option_list_opt($setTransactionNode)
|
||||||
: // nothing
|
: // nothing
|
||||||
@ -5913,18 +5969,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_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
|
||||||
@ -5945,6 +6003,25 @@ 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
|
||||||
|
value_or_default_list
|
||||||
|
: value_or_default { $$ = newNode<ValueListNode>($1); }
|
||||||
|
| value_or_default_list ',' value_or_default { $$ = $1->add($3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
%type <valueExprNode> value_or_default
|
||||||
|
value_or_default
|
||||||
|
: value
|
||||||
|
| DEFAULT { $$ = NULL; }
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
// MERGE statement
|
// MERGE statement
|
||||||
%type <mergeNode> merge
|
%type <mergeNode> merge
|
||||||
@ -5975,7 +6052,7 @@ merge_when_clause($mergeNode)
|
|||||||
merge_when_matched_clause($mergeNode)
|
merge_when_matched_clause($mergeNode)
|
||||||
: WHEN MATCHED
|
: WHEN MATCHED
|
||||||
{ $<mergeMatchedClause>$ = &$mergeNode->whenMatched.add(); }
|
{ $<mergeMatchedClause>$ = &$mergeNode->whenMatched.add(); }
|
||||||
merge_update_specification(NOTRIAL($<mergeMatchedClause>3))
|
merge_update_specification(NOTRIAL($<mergeMatchedClause>3), NOTRIAL(&$mergeNode->relation->dsqlName))
|
||||||
;
|
;
|
||||||
|
|
||||||
%type merge_when_not_matched_clause(<mergeNode>)
|
%type merge_when_not_matched_clause(<mergeNode>)
|
||||||
@ -5985,11 +6062,11 @@ merge_when_not_matched_clause($mergeNode)
|
|||||||
merge_insert_specification(NOTRIAL($<mergeNotMatchedClause>4))
|
merge_insert_specification(NOTRIAL($<mergeNotMatchedClause>4))
|
||||||
;
|
;
|
||||||
|
|
||||||
%type merge_update_specification(<mergeMatchedClause>)
|
%type merge_update_specification(<mergeMatchedClause>, <metaNamePtr>)
|
||||||
merge_update_specification($mergeMatchedClause)
|
merge_update_specification($mergeMatchedClause, $relationName)
|
||||||
: THEN UPDATE SET assignments
|
: THEN UPDATE SET update_assignments(NOTRIAL($relationName))
|
||||||
{ $mergeMatchedClause->assignments = $4; }
|
{ $mergeMatchedClause->assignments = $4; }
|
||||||
| AND search_condition THEN UPDATE SET assignments
|
| AND search_condition THEN UPDATE SET update_assignments(NOTRIAL($relationName))
|
||||||
{
|
{
|
||||||
$mergeMatchedClause->condition = $2;
|
$mergeMatchedClause->condition = $2;
|
||||||
$mergeMatchedClause->assignments = $6;
|
$mergeMatchedClause->assignments = $6;
|
||||||
@ -6001,13 +6078,17 @@ merge_update_specification($mergeMatchedClause)
|
|||||||
|
|
||||||
%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_list ')'
|
VALUES '(' value_or_default_list ')'
|
||||||
{ $mergeNotMatchedClause->values = $6; }
|
|
||||||
| AND search_condition THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields))
|
|
||||||
VALUES '(' value_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;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -6059,7 +6140,7 @@ update
|
|||||||
|
|
||||||
%type <stmtNode> update_searched
|
%type <stmtNode> update_searched
|
||||||
update_searched
|
update_searched
|
||||||
: UPDATE table_name SET assignments where_clause plan_clause
|
: UPDATE table_name SET update_assignments(NOTRIAL(&$2->dsqlName)) where_clause plan_clause
|
||||||
order_clause_opt rows_clause_optional returning_clause
|
order_clause_opt rows_clause_optional returning_clause
|
||||||
{
|
{
|
||||||
ModifyNode* node = newNode<ModifyNode>();
|
ModifyNode* node = newNode<ModifyNode>();
|
||||||
@ -6076,7 +6157,7 @@ update_searched
|
|||||||
|
|
||||||
%type <stmtNode> update_positioned
|
%type <stmtNode> update_positioned
|
||||||
update_positioned
|
update_positioned
|
||||||
: UPDATE table_name SET assignments cursor_clause returning_clause
|
: UPDATE table_name SET update_assignments(NOTRIAL(&$2->dsqlName)) cursor_clause returning_clause
|
||||||
{
|
{
|
||||||
ModifyNode* node = newNode<ModifyNode>();
|
ModifyNode* node = newNode<ModifyNode>();
|
||||||
node->dsqlRelation = $2;
|
node->dsqlRelation = $2;
|
||||||
@ -6097,12 +6178,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_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;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -6144,20 +6226,6 @@ cursor_clause
|
|||||||
|
|
||||||
// Assignments
|
// Assignments
|
||||||
|
|
||||||
%type <compoundStmtNode> assignments
|
|
||||||
assignments
|
|
||||||
: assignment
|
|
||||||
{
|
|
||||||
$$ = newNode<CompoundStmtNode>();
|
|
||||||
$$->statements.add($1);
|
|
||||||
}
|
|
||||||
| assignments ',' assignment
|
|
||||||
{
|
|
||||||
$1->statements.add($3);
|
|
||||||
$$ = $1;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
%type <stmtNode> assignment
|
%type <stmtNode> assignment
|
||||||
assignment
|
assignment
|
||||||
: update_column_name '=' value
|
: update_column_name '=' value
|
||||||
@ -6169,6 +6237,38 @@ assignment
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
%type <compoundStmtNode> update_assignments(<metaNamePtr>)
|
||||||
|
update_assignments($relationName)
|
||||||
|
: update_assignment($relationName)
|
||||||
|
{
|
||||||
|
$$ = newNode<CompoundStmtNode>();
|
||||||
|
$$->statements.add($1);
|
||||||
|
}
|
||||||
|
| update_assignments ',' update_assignment($relationName)
|
||||||
|
{
|
||||||
|
$1->statements.add($3);
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
%type <stmtNode> update_assignment(<metaNamePtr>)
|
||||||
|
update_assignment($relationName)
|
||||||
|
: update_column_name '=' value
|
||||||
|
{
|
||||||
|
AssignmentNode* node = newNode<AssignmentNode>();
|
||||||
|
node->asgnTo = $1;
|
||||||
|
node->asgnFrom = $3;
|
||||||
|
$$ = node;
|
||||||
|
}
|
||||||
|
| update_column_name '=' DEFAULT
|
||||||
|
{
|
||||||
|
AssignmentNode* node = newNode<AssignmentNode>();
|
||||||
|
node->asgnTo = $1;
|
||||||
|
node->asgnFrom = newNode<DefaultNode>(*$relationName, $1->dsqlName);
|
||||||
|
$$ = node;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
%type <stmtNode> exec_function
|
%type <stmtNode> exec_function
|
||||||
exec_function
|
exec_function
|
||||||
: udf
|
: udf
|
||||||
@ -7832,6 +7932,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
|
||||||
@ -8185,15 +8286,18 @@ non_reserved_word
|
|||||||
| DEFINER
|
| DEFINER
|
||||||
| EXCLUDE
|
| EXCLUDE
|
||||||
| FOLLOWING
|
| FOLLOWING
|
||||||
|
| IDLE
|
||||||
| INVOKER
|
| INVOKER
|
||||||
| MESSAGE
|
| MESSAGE
|
||||||
| NTILE
|
| NTILE
|
||||||
| OTHERS
|
| OTHERS
|
||||||
|
| OVERRIDING
|
||||||
| PERCENT_RANK
|
| PERCENT_RANK
|
||||||
| PRECEDING
|
| PRECEDING
|
||||||
| PRIVILEGE
|
| PRIVILEGE
|
||||||
| RANGE
|
| RANGE
|
||||||
| SECURITY
|
| SECURITY
|
||||||
|
| SESSION
|
||||||
| SQL
|
| SQL
|
||||||
| SYSTEM
|
| SYSTEM
|
||||||
| TIES
|
| TIES
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -828,6 +828,17 @@ 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},
|
||||||
|
{"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},
|
||||||
{"gfix_db_name", 335740929},
|
{"gfix_db_name", 335740929},
|
||||||
{"gfix_invalid_sw", 335740930},
|
{"gfix_invalid_sw", 335740930},
|
||||||
{"gfix_incmp_sw", 335740932},
|
{"gfix_incmp_sw", 335740932},
|
||||||
@ -894,6 +905,7 @@ static const struct {
|
|||||||
{"dsql_no_output_sqlda", 336003110},
|
{"dsql_no_output_sqlda", 336003110},
|
||||||
{"dsql_wrong_param_num", 336003111},
|
{"dsql_wrong_param_num", 336003111},
|
||||||
{"dsql_invalid_drop_ss_clause", 336003112},
|
{"dsql_invalid_drop_ss_clause", 336003112},
|
||||||
|
{"upd_ins_cannot_default", 336003113},
|
||||||
{"dyn_filter_not_found", 336068645},
|
{"dyn_filter_not_found", 336068645},
|
||||||
{"dyn_func_not_found", 336068649},
|
{"dyn_func_not_found", 336068649},
|
||||||
{"dyn_index_not_found", 336068656},
|
{"dyn_index_not_found", 336068656},
|
||||||
|
@ -862,6 +862,17 @@ 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_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_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;
|
||||||
@ -928,6 +939,7 @@ const ISC_STATUS isc_dsql_no_input_sqlda = 336003109L;
|
|||||||
const ISC_STATUS isc_dsql_no_output_sqlda = 336003110L;
|
const ISC_STATUS isc_dsql_no_output_sqlda = 336003110L;
|
||||||
const ISC_STATUS isc_dsql_wrong_param_num = 336003111L;
|
const ISC_STATUS isc_dsql_wrong_param_num = 336003111L;
|
||||||
const ISC_STATUS isc_dsql_invalid_drop_ss_clause = 336003112L;
|
const ISC_STATUS isc_dsql_invalid_drop_ss_clause = 336003112L;
|
||||||
|
const ISC_STATUS isc_upd_ins_cannot_default = 336003113L;
|
||||||
const ISC_STATUS isc_dyn_filter_not_found = 336068645L;
|
const ISC_STATUS isc_dyn_filter_not_found = 336068645L;
|
||||||
const ISC_STATUS isc_dyn_func_not_found = 336068649L;
|
const ISC_STATUS isc_dyn_func_not_found = 336068649L;
|
||||||
const ISC_STATUS isc_dyn_index_not_found = 336068656L;
|
const ISC_STATUS isc_dyn_index_not_found = 336068656L;
|
||||||
@ -1335,7 +1347,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 = 1279;
|
const ISC_STATUS isc_err_max = 1291;
|
||||||
|
|
||||||
#else /* c definitions */
|
#else /* c definitions */
|
||||||
|
|
||||||
@ -2167,6 +2179,17 @@ const ISC_STATUS isc_err_max = 1279;
|
|||||||
#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_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_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
|
||||||
@ -2233,6 +2256,7 @@ const ISC_STATUS isc_err_max = 1279;
|
|||||||
#define isc_dsql_no_output_sqlda 336003110L
|
#define isc_dsql_no_output_sqlda 336003110L
|
||||||
#define isc_dsql_wrong_param_num 336003111L
|
#define isc_dsql_wrong_param_num 336003111L
|
||||||
#define isc_dsql_invalid_drop_ss_clause 336003112L
|
#define isc_dsql_invalid_drop_ss_clause 336003112L
|
||||||
|
#define isc_upd_ins_cannot_default 336003113L
|
||||||
#define isc_dyn_filter_not_found 336068645L
|
#define isc_dyn_filter_not_found 336068645L
|
||||||
#define isc_dyn_func_not_found 336068649L
|
#define isc_dyn_func_not_found 336068649L
|
||||||
#define isc_dyn_index_not_found 336068656L
|
#define isc_dyn_index_not_found 336068656L
|
||||||
@ -2640,7 +2664,7 @@ const ISC_STATUS isc_err_max = 1279;
|
|||||||
#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 1279
|
#define isc_err_max 1291
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -831,6 +831,17 @@ 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, "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 */
|
||||||
{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 */
|
||||||
@ -897,6 +908,7 @@ Data source : @4"}, /* eds_statement */
|
|||||||
{336003110, "No SQLDA for output values provided"}, /* dsql_no_output_sqlda */
|
{336003110, "No SQLDA for output values provided"}, /* dsql_no_output_sqlda */
|
||||||
{336003111, "Wrong number of parameters (expected @1, got @2)"}, /* dsql_wrong_param_num */
|
{336003111, "Wrong number of parameters (expected @1, got @2)"}, /* dsql_wrong_param_num */
|
||||||
{336003112, "Invalid DROP SQL SECURITY clause"}, /* dsql_invalid_drop_ss_clause */
|
{336003112, "Invalid DROP SQL SECURITY clause"}, /* dsql_invalid_drop_ss_clause */
|
||||||
|
{336003113, "UPDATE OR INSERT value for field @1, part of the implicit or explicit MATCHING clause, cannot be DEFAULT"}, /* upd_ins_cannot_default */
|
||||||
{336068645, "BLOB Filter @1 not found"}, /* dyn_filter_not_found */
|
{336068645, "BLOB Filter @1 not found"}, /* dyn_filter_not_found */
|
||||||
{336068649, "Function @1 not found"}, /* dyn_func_not_found */
|
{336068649, "Function @1 not found"}, /* dyn_func_not_found */
|
||||||
{336068656, "Index not found"}, /* dyn_index_not_found */
|
{336068656, "Index not found"}, /* dyn_index_not_found */
|
||||||
|
@ -827,6 +827,17 @@ 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, -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 */
|
||||||
{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 */
|
||||||
@ -893,6 +904,7 @@ static const struct {
|
|||||||
{336003110, -802}, /* 38 dsql_no_output_sqlda */
|
{336003110, -802}, /* 38 dsql_no_output_sqlda */
|
||||||
{336003111, -313}, /* 39 dsql_wrong_param_num */
|
{336003111, -313}, /* 39 dsql_wrong_param_num */
|
||||||
{336003112, -817}, /* 40 dsql_invalid_drop_ss_clause */
|
{336003112, -817}, /* 40 dsql_invalid_drop_ss_clause */
|
||||||
|
{336003113, -313}, /* 41 upd_ins_cannot_default */
|
||||||
{336068645, -901}, /* 37 dyn_filter_not_found */
|
{336068645, -901}, /* 37 dyn_filter_not_found */
|
||||||
{336068649, -901}, /* 41 dyn_func_not_found */
|
{336068649, -901}, /* 41 dyn_func_not_found */
|
||||||
{336068656, -901}, /* 48 dyn_index_not_found */
|
{336068656, -901}, /* 48 dyn_index_not_found */
|
||||||
|
@ -827,6 +827,17 @@ 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, "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
|
||||||
{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
|
||||||
@ -893,6 +904,7 @@ static const struct {
|
|||||||
{336003110, "07002"}, // 38 dsql_no_output_sqlda
|
{336003110, "07002"}, // 38 dsql_no_output_sqlda
|
||||||
{336003111, "07001"}, // 39 dsql_wrong_param_num
|
{336003111, "07001"}, // 39 dsql_wrong_param_num
|
||||||
{336003112, "42000"}, // 40 dsql_invalid_drop_ss_clause
|
{336003112, "42000"}, // 40 dsql_invalid_drop_ss_clause
|
||||||
|
{336003113, "42000"}, // 41 upd_ins_cannot_default
|
||||||
{336068645, "42000"}, // 37 dyn_filter_not_found
|
{336068645, "42000"}, // 37 dyn_filter_not_found
|
||||||
{336068649, "42000"}, // 41 dyn_func_not_found
|
{336068649, "42000"}, // 41 dyn_func_not_found
|
||||||
{336068656, "42000"}, // 48 dyn_index_not_found
|
{336068656, "42000"}, // 48 dyn_index_not_found
|
||||||
|
@ -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);
|
||||||
|
@ -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];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -4765,7 +4767,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)
|
||||||
@ -4803,6 +4806,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},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Display current set options
|
// Display current set options
|
||||||
@ -4964,14 +4968,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5793,6 +5811,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8130,6 +8149,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)
|
||||||
@ -8193,6 +8216,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;
|
||||||
@ -8235,6 +8259,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
|
||||||
@ -8337,6 +8362,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;
|
||||||
@ -8366,6 +8392,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;
|
||||||
@ -8527,7 +8554,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)))
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
@ -204,7 +205,9 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb)
|
|||||||
att_dyn_req(*pool),
|
att_dyn_req(*pool),
|
||||||
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);
|
||||||
@ -371,9 +374,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();
|
||||||
@ -639,7 +644,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);
|
||||||
}
|
}
|
||||||
@ -765,3 +770,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;
|
||||||
|
}
|
||||||
|
@ -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().
|
||||||
@ -391,7 +404,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();
|
||||||
|
|
||||||
@ -412,9 +425,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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
@ -1351,21 +1350,25 @@ namespace Jrd {
|
|||||||
SyncLockGuard dsGuard(&mgr->dbb.dbb_sync, SYNC_EXCLUSIVE, FB_FUNCTION);
|
SyncLockGuard dsGuard(&mgr->dbb.dbb_sync, SYNC_EXCLUSIVE, FB_FUNCTION);
|
||||||
for (Attachment* att = mgr->dbb.dbb_attachments; att; att = att->att_next)
|
for (Attachment* att = mgr->dbb.dbb_attachments; att; att = att->att_next)
|
||||||
{
|
{
|
||||||
|
bool found = false;
|
||||||
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
||||||
{
|
{
|
||||||
if (knownHolders[i].first == att)
|
if (knownHolders[i].first == att)
|
||||||
goto found;
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
att->signalShutdown();
|
if (!found)
|
||||||
found:;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
@ -433,7 +441,7 @@ public:
|
|||||||
int release();
|
int release();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JAttachment* internalAttach(Firebird::CheckStatusWrapper* status, const char* fileName,
|
JAttachment* internalAttach(Firebird::CheckStatusWrapper* status, const char* const fileName,
|
||||||
unsigned int dpbLength, const unsigned char* dpb, const UserId* existingId);
|
unsigned int dpbLength, const unsigned char* dpb, const UserId* existingId);
|
||||||
Firebird::ICryptKeyCallback* cryptCallback;
|
Firebird::ICryptKeyCallback* cryptCallback;
|
||||||
Firebird::IPluginConfig* pluginConfig;
|
Firebird::IPluginConfig* pluginConfig;
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
@ -947,12 +947,14 @@ public:
|
|||||||
embeddedSysdba.insertByte(isc_dpb_map_attach, TRUE);
|
embeddedSysdba.insertByte(isc_dpb_map_attach, TRUE);
|
||||||
embeddedSysdba.insertByte(isc_dpb_no_db_triggers, TRUE);
|
embeddedSysdba.insertByte(isc_dpb_no_db_triggers, TRUE);
|
||||||
|
|
||||||
|
MAP_DEBUG(fprintf(stderr, "Attach %s\n", aliasDb));
|
||||||
IAttachment* att = prov->attachDatabase(&st, aliasDb,
|
IAttachment* att = prov->attachDatabase(&st, aliasDb,
|
||||||
embeddedSysdba.getBufferLength(), embeddedSysdba.getBuffer());
|
embeddedSysdba.getBufferLength(), embeddedSysdba.getBuffer());
|
||||||
|
|
||||||
if (st->getState() & IStatus::STATE_ERRORS)
|
if (st->getState() & IStatus::STATE_ERRORS)
|
||||||
{
|
{
|
||||||
const ISC_STATUS* s = st->getErrors();
|
const ISC_STATUS* s = st->getErrors();
|
||||||
|
MAP_DEBUG(isc_print_status(s));
|
||||||
bool missing = fb_utils::containsErrorCode(s, isc_io_error);
|
bool missing = fb_utils::containsErrorCode(s, isc_io_error);
|
||||||
down = fb_utils::containsErrorCode(s, isc_shutdown);
|
down = fb_utils::containsErrorCode(s, isc_shutdown);
|
||||||
if (!(missing || down))
|
if (!(missing || down))
|
||||||
@ -962,6 +964,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
reset(att);
|
reset(att);
|
||||||
|
MAP_DEBUG(fprintf(stderr, "Att=%p\n", att));
|
||||||
|
|
||||||
return down;
|
return down;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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())
|
||||||
|
@ -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++)
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -484,11 +484,17 @@ public:
|
|||||||
Firebird::MetaName fld_name; // Field name
|
Firebird::MetaName fld_name; // Field name
|
||||||
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
|
||||||
|
Nullable<IdentityType> fld_identity_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit jrd_fld(MemoryPool& p)
|
explicit jrd_fld(MemoryPool& p)
|
||||||
: fld_name(p), fld_security_name(p), fld_generator_name(p)
|
: fld_name(p),
|
||||||
{ }
|
fld_security_name(p),
|
||||||
|
fld_generator_name(p),
|
||||||
|
fld_source_rel_field(p)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -218,6 +218,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",
|
||||||
@ -2254,6 +2256,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)
|
||||||
|
@ -242,5 +242,7 @@ static const struct
|
|||||||
{"record_version2", byte_line},
|
{"record_version2", byte_line},
|
||||||
{"gen_id2", gen_id2}, // 210
|
{"gen_id2", gen_id2}, // 210
|
||||||
{"window_win", window_win},
|
{"window_win", window_win},
|
||||||
|
{"default", relation_field},
|
||||||
|
{"store3", store3},
|
||||||
{0, 0}
|
{0, 0}
|
||||||
};
|
};
|
||||||
|
@ -420,4 +420,7 @@
|
|||||||
#define blr_window_win_extent_frame_value (unsigned char) 6
|
#define blr_window_win_extent_frame_value (unsigned char) 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_store3 (unsigned char) 213
|
||||||
|
|
||||||
#endif // JRD_BLR_H
|
#endif // JRD_BLR_H
|
||||||
|
@ -5911,76 +5911,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
|
||||||
@ -5989,7 +5920,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
|
||||||
@ -6008,7 +5939,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)
|
||||||
|
@ -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:514
|
FORMAL BUILD NUMBER:582
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PRODUCT_VER_STRING "4.0.0.514"
|
#define PRODUCT_VER_STRING "4.0.0.582"
|
||||||
#define FILE_VER_STRING "WI-T4.0.0.514"
|
#define FILE_VER_STRING "WI-T4.0.0.582"
|
||||||
#define LICENSE_VER_STRING "WI-T4.0.0.514"
|
#define LICENSE_VER_STRING "WI-T4.0.0.582"
|
||||||
#define FILE_VER_NUMBER 4, 0, 0, 514
|
#define FILE_VER_NUMBER 4, 0, 0, 582
|
||||||
#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 "514"
|
#define FB_BUILD_NO "582"
|
||||||
#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"
|
||||||
|
@ -5754,6 +5754,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;
|
||||||
@ -5827,7 +5831,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_
|
|||||||
FLD.RDB$FIELD_SUB_TYPE,
|
FLD.RDB$FIELD_SUB_TYPE,
|
||||||
FLD.RDB$CHARACTER_SET_ID, collation))
|
FLD.RDB$CHARACTER_SET_ID, collation))
|
||||||
{
|
{
|
||||||
if (REL.RDB$FORMAT.NULL)
|
if (null_view && REL.RDB$FORMAT.NULL)
|
||||||
DPM_delete_relation(tdbb, relation);
|
DPM_delete_relation(tdbb, relation);
|
||||||
|
|
||||||
ERR_post(Arg::Gds(isc_no_meta_update) <<
|
ERR_post(Arg::Gds(isc_no_meta_update) <<
|
||||||
@ -5837,7 +5841,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_
|
|||||||
// Make sure the text type specified is implemented
|
// Make sure the text type specified is implemented
|
||||||
if (!validate_text_type(tdbb, tfb))
|
if (!validate_text_type(tdbb, tfb))
|
||||||
{
|
{
|
||||||
if (REL.RDB$FORMAT.NULL)
|
if (null_view && REL.RDB$FORMAT.NULL)
|
||||||
DPM_delete_relation(tdbb, relation);
|
DPM_delete_relation(tdbb, relation);
|
||||||
|
|
||||||
ERR_post_nothrow(Arg::Gds(isc_no_meta_update) <<
|
ERR_post_nothrow(Arg::Gds(isc_no_meta_update) <<
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
@ -126,6 +126,8 @@ void IscConnection::attach(thread_db* tdbb, const PathName& dbName, const MetaNa
|
|||||||
EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);
|
EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);
|
||||||
|
|
||||||
ICryptKeyCallback* cb = tdbb->getAttachment()->att_crypt_callback;
|
ICryptKeyCallback* cb = tdbb->getAttachment()->att_crypt_callback;
|
||||||
|
try
|
||||||
|
{
|
||||||
m_iscProvider.fb_database_crypt_callback(&status, cb);
|
m_iscProvider.fb_database_crypt_callback(&status, cb);
|
||||||
if (status->getState() & IStatus::STATE_ERRORS) {
|
if (status->getState() & IStatus::STATE_ERRORS) {
|
||||||
raise(&status, tdbb, "crypt_callback");
|
raise(&status, tdbb, "crypt_callback");
|
||||||
@ -137,6 +139,12 @@ void IscConnection::attach(thread_db* tdbb, const PathName& dbName, const MetaNa
|
|||||||
if (status->getState() & IStatus::STATE_ERRORS) {
|
if (status->getState() & IStatus::STATE_ERRORS) {
|
||||||
raise(&status, tdbb, "attach");
|
raise(&status, tdbb, "attach");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (const Exception&)
|
||||||
|
{
|
||||||
|
m_iscProvider.fb_database_crypt_callback(&status, NULL);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
m_iscProvider.fb_database_crypt_callback(&status, NULL);
|
m_iscProvider.fb_database_crypt_callback(&status, NULL);
|
||||||
if (status->getState() & IStatus::STATE_ERRORS) {
|
if (status->getState() & IStatus::STATE_ERRORS) {
|
||||||
@ -485,6 +493,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();
|
||||||
@ -1495,6 +1523,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;
|
||||||
@ -1587,7 +1625,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)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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]);
|
||||||
}
|
}
|
||||||
|
@ -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*);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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 */
|
||||||
|
341
src/jrd/jrd.cpp
341
src/jrd/jrd.cpp
@ -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();
|
||||||
@ -1322,7 +1333,7 @@ JAttachment* JProvider::attachDatabase(CheckStatusWrapper* user_status, const ch
|
|||||||
return internalAttach(user_status, filename, dpb_length, dpb, NULL);
|
return internalAttach(user_status, filename, dpb_length, dpb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const char* filename,
|
JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const char* const filename,
|
||||||
unsigned int dpb_length, const unsigned char* dpb, const UserId* existingId)
|
unsigned int dpb_length, const unsigned char* dpb, const UserId* existingId)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
@ -1647,7 +1658,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
|
|||||||
jAtt->getStable()->manualUnlock(attachment->att_flags);
|
jAtt->getStable()->manualUnlock(attachment->att_flags);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
getUserInfo(userId, options, org_filename.c_str(), expanded_name.c_str(),
|
getUserInfo(userId, options, filename, expanded_name.c_str(),
|
||||||
&config, false, jAtt, cryptCallback);
|
&config, false, jAtt, cryptCallback);
|
||||||
}
|
}
|
||||||
catch(const Exception&)
|
catch(const Exception&)
|
||||||
@ -1684,8 +1695,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));
|
||||||
}
|
}
|
||||||
@ -1850,6 +1865,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
|
|||||||
|
|
||||||
CCH_release_exclusive(tdbb);
|
CCH_release_exclusive(tdbb);
|
||||||
|
|
||||||
|
attachment->att_trace_manager->activate();
|
||||||
if (attachment->att_trace_manager->needs(ITraceFactory::TRACE_EVENT_ATTACH))
|
if (attachment->att_trace_manager->needs(ITraceFactory::TRACE_EVENT_ATTACH))
|
||||||
{
|
{
|
||||||
TraceConnectionImpl conn(attachment);
|
TraceConnectionImpl conn(attachment);
|
||||||
@ -2474,7 +2490,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
|
|||||||
ERR_post(Arg::Gds(isc_unavailable));
|
ERR_post(Arg::Gds(isc_unavailable));
|
||||||
|
|
||||||
// Check for correct credentials supplied
|
// Check for correct credentials supplied
|
||||||
getUserInfo(userId, options, org_filename.c_str(), NULL, &config, true, nullptr, cryptCallback);
|
getUserInfo(userId, options, filename, NULL, &config, true, nullptr, cryptCallback);
|
||||||
|
|
||||||
#ifdef WIN_NT
|
#ifdef WIN_NT
|
||||||
guardDbInit.enter(); // Required to correctly expand name of just created database
|
guardDbInit.enter(); // Required to correctly expand name of just created database
|
||||||
@ -2784,6 +2800,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
|
|||||||
guardDbInit.leave();
|
guardDbInit.leave();
|
||||||
|
|
||||||
// Report that we created attachment to Trace API
|
// Report that we created attachment to Trace API
|
||||||
|
attachment->att_trace_manager->activate();
|
||||||
if (attachment->att_trace_manager->needs(ITraceFactory::TRACE_EVENT_ATTACH))
|
if (attachment->att_trace_manager->needs(ITraceFactory::TRACE_EVENT_ATTACH))
|
||||||
{
|
{
|
||||||
TraceConnectionImpl conn(attachment);
|
TraceConnectionImpl conn(attachment);
|
||||||
@ -2918,7 +2935,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();
|
||||||
@ -2988,15 +3013,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))
|
||||||
{
|
{
|
||||||
@ -4334,6 +4359,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,
|
||||||
@ -5290,6 +5391,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)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
@ -5445,7 +5606,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7343,7 +7508,7 @@ namespace
|
|||||||
Attachment* attachment = sAtt->getHandle();
|
Attachment* attachment = sAtt->getHandle();
|
||||||
|
|
||||||
if (attachment)
|
if (attachment)
|
||||||
attachment->signalShutdown();
|
attachment->signalShutdown(isc_att_shut_engine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7483,6 +7648,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)
|
||||||
@ -7520,7 +7818,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
|
||||||
@ -7540,8 +7838,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
|
||||||
@ -7561,6 +7864,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.
|
||||||
|
|
||||||
@ -7572,7 +7883,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;
|
||||||
@ -7582,6 +7894,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;
|
||||||
|
|
||||||
|
141
src/jrd/jrd.h
141
src/jrd/jrd.h
@ -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
|
||||||
|
@ -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)
|
||||||
@ -656,6 +658,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));
|
||||||
|
|
||||||
@ -855,6 +858,40 @@ void LCK_write_data(thread_db* tdbb, Lock* lock, LOCK_DATA_T 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)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
|
@ -3972,6 +3972,18 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
field->fld_source = PAR_make_field(tdbb, csb, view_context, (TEXT*) p);
|
field->fld_source = PAR_make_field(tdbb, csb, view_context, (TEXT*) p);
|
||||||
|
|
||||||
|
{ // scope
|
||||||
|
const ViewContexts& ctx = relation->rel_view_contexts;
|
||||||
|
FB_SIZE_T pos;
|
||||||
|
|
||||||
|
if (ctx.find(view_context, pos) &&
|
||||||
|
(ctx[pos]->vcx_type == VCT_TABLE || ctx[pos]->vcx_type == VCT_VIEW))
|
||||||
|
{
|
||||||
|
field->fld_source_rel_field = MetaNamePair(ctx[pos]->vcx_relation_name, (TEXT*) p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RSR_computed_blr:
|
case RSR_computed_blr:
|
||||||
@ -4034,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
|
||||||
|
@ -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
|
||||||
|
@ -412,3 +412,66 @@ void MOV_move(Jrd::thread_db* tdbb, /*const*/ dsc* from, dsc* to)
|
|||||||
else
|
else
|
||||||
CVT_move(from, to);
|
CVT_move(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
@ -52,4 +52,24 @@ Firebird::string MOV_make_string2(Jrd::thread_db* tdbb, const dsc* desc, USHORT
|
|||||||
bool limit = true);
|
bool limit = true);
|
||||||
void MOV_move(Jrd::thread_db*, /*const*/ dsc*, dsc*);
|
void MOV_move(Jrd::thread_db*, /*const*/ dsc*, 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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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),
|
||||||
@ -267,6 +268,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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user