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

Merge branch 'master' into read_consistency

This commit is contained in:
hvlad 2018-07-16 16:16:22 +03:00
commit ca71a54609
112 changed files with 4916 additions and 1417 deletions

View File

@ -422,22 +422,29 @@
#
# Type: string
# AuthServer and AuthClient determine what authentication methods will be used
# by network server and client redirector. Secure remote passwords plugin
# is default one. Except configured by default SRP plugin firebird also has
# Legacy_Auth plugin which is used to emulate pre-FB3 login protocol making it
# possible for client to talk to old servers and for server to listen to requests
# from old clients. Legacy_Auth is VERY unsecure. On windows Win_Sspi plugin may
# be also used - it implements windows trusted authentication and backward
# AuthServer and AuthClient determine which authentication methods will be used
# by network server and client redirector. The Secure remote password plugin
# using SHA-256 for the client proof is the default for both client and Server.
# Additionally, the default client configuration (AuthClient) also supports old Srp
# plugin using SHA-1 for the client proof. This enables backwards compatibility
# with old Firebird 3 servers but does not comply with NIST security requirements.
#
# The default client configuration (AuthClient) also supports the pre-Firebird 3 legacy
# authentication protocol (Legacy_Auth). This is again for backwards
# compatibility but has many known weaknesses and is deprecated for current use.
#
# The default Windows client configuration (AuthClient) also includes support for
# the Win_Sspi plugin. This implements windows trusted authentication and is backward
# compatible with 2.1 and 2.5 clients and servers running on windows.
#
# Per-database configurable.
#
#AuthServer = Srp
#AuthServer = Srp256
#
# Per-connection and per-database configurable.
#
#AuthClient = Srp, Win_Sspi, Legacy_Auth
#AuthClient = Srp256, Srp, Legacy_Auth #Non Windows clients
#AuthClient = Srp256, Srp, Win_Sspi, Legacy_Auth #Windows clients
#
# If you need to use server plugins that do not provide encryption key (both Legacy_Auth
# & Win_Sspi) you should also turn off required encryption on the wire with WireCrypt
@ -1029,3 +1036,22 @@
# Type: string
#
#ServerMode = Super
# ============================
# Settings of External Connections Pool
# ============================
# Set the maximum number of inactive (idle) external connections to retain at
# the pool. Valid values are between 0 and 1000. If set to zero, pool is disabed,
# i.e. external connection is destroyed immediately after the use.
#
# Type: integer
#
#ExtConnPoolSize = 0
# Set the time before destroyng inactive external connection, seconds.
# Valid values are between 1 and 86400.
#
# Type: integer
#
#ExtConnPoolLifeTime = 7200

View File

@ -27,7 +27,7 @@ AllObjects=
CO1:= $(call dirObjects,common)
CO2:= $(call dirObjects,common/classes)
CO3:= $(call dirObjects,common/config)
CO4:= $(call dirObjects,common/tomcrypt)
CO4:= $(call dirObjects,common/sha2)
#CO5:= $(call dirObjects,common/exceptions)
#CO6:= $(call dirObjects,common/sync)
Common_Objects:= $(CO1) $(CO2) $(CO3) $(CO4)

View File

@ -0,0 +1,28 @@
# The contents of this file are subject to the Interbase 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.Inprise.com/IPL.html
#
# Software distributed under the License is distributed on an
# "AS IS" basis, 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 Inprise Corporation
# and its predecessors. Portions created by Inprise Corporation are
# Copyright (C) Inprise Corporation.
#
# All Rights Reserved.
# Contributor(s): ______________________________________.
# Start of file prefix.linux: $(VERSION) $(PLATFORM)
# 14 Apr 2008 Alan Barclay alan AT escribe.co.uk
# 2018, "Manuel A. Fernandez Montecelo" <manuel.montezelo@gmail.com>
#LD=@CXX@
#PROD_FLAGS=-ggdb -O3 -fno-omit-frame-pointer -DLINUX -pipe -MMD -fPIC
#DEV_FLAGS=-ggdb -DLINUX -DDEBUG_GDS_ALLOC -pipe -MMD -p -fPIC -Wall -Wno-switch
PROD_FLAGS=-O3 -DLINUX -DRISCV64 -pipe -p -MMD -fPIC -fsigned-char -fmessage-length=0 -std=gnu++03 -fno-delete-null-pointer-checks
DEV_FLAGS=-ggdb -DLINUX -DRISCV64 -pipe -p -MMD -fPIC -Wall -fsigned-char -fmessage-length=0 -Wno-non-virtual-dtor

View File

@ -87,6 +87,7 @@
<ClCompile Include="..\..\..\src\common\sdl.cpp" />
<ClCompile Include="..\..\..\src\common\security.cpp" />
<ClCompile Include="..\..\..\src\common\sha.cpp" />
<ClCompile Include="..\..\..\src\common\sha2\sha2.cpp" />
<ClCompile Include="..\..\..\src\common\StatementMetadata.cpp" />
<ClCompile Include="..\..\..\src\common\StatusArg.cpp" />
<ClCompile Include="..\..\..\src\common\StatusHolder.cpp" />
@ -193,6 +194,7 @@
<ClInclude Include="..\..\..\src\common\sdltable.h" />
<ClInclude Include="..\..\..\src\common\sdl_proto.h" />
<ClInclude Include="..\..\..\src\common\sha.h" />
<ClInclude Include="..\..\..\src\common\sha2\sha2.h" />
<ClInclude Include="..\..\..\src\common\SimpleStatusVector.h" />
<ClInclude Include="..\..\..\src\common\StatementMetadata.h" />
<ClInclude Include="..\..\..\src\common\StatusArg.h" />

View File

@ -219,6 +219,9 @@
<ClCompile Include="..\..\..\src\common\DecFloat.cpp">
<Filter>classes</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\common\sha2\sha2.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\common\classes\TomCryptHash.cpp">
<Filter>classes</Filter>
</ClCompile>
@ -548,5 +551,8 @@
<ClInclude Include="..\..\..\src\common\classes\BlobWrapper.h">
<Filter>headers</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\common\sha2\sha2.h">
<Filter>headers</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -83,6 +83,7 @@
<ClCompile Include="..\..\..\src\common\sdl.cpp" />
<ClCompile Include="..\..\..\src\common\security.cpp" />
<ClCompile Include="..\..\..\src\common\sha.cpp" />
<ClCompile Include="..\..\..\src\common\sha2\sha2.cpp" />
<ClCompile Include="..\..\..\src\common\StatementMetadata.cpp" />
<ClCompile Include="..\..\..\src\common\StatusArg.cpp" />
<ClCompile Include="..\..\..\src\common\StatusHolder.cpp" />
@ -189,6 +190,7 @@
<ClInclude Include="..\..\..\src\common\sdltable.h" />
<ClInclude Include="..\..\..\src\common\sdl_proto.h" />
<ClInclude Include="..\..\..\src\common\sha.h" />
<ClInclude Include="..\..\..\src\common\sha2\sha2.h" />
<ClInclude Include="..\..\..\src\common\SimpleStatusVector.h" />
<ClInclude Include="..\..\..\src\common\StatementMetadata.h" />
<ClInclude Include="..\..\..\src\common\StatusArg.h" />

View File

@ -225,6 +225,9 @@
<ClCompile Include="..\..\..\src\common\classes\BlobWrapper.cpp">
<Filter>classes</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\common\sha2\sha2.cpp">
<Filter>common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\common\xdr_proto.h">
@ -548,5 +551,8 @@
<ClInclude Include="..\..\..\src\common\classes\BlobWrapper.h">
<Filter>headers</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\common\sha2\sha2.h">
<Filter>headers</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -83,6 +83,7 @@
<ClCompile Include="..\..\..\src\common\sdl.cpp" />
<ClCompile Include="..\..\..\src\common\security.cpp" />
<ClCompile Include="..\..\..\src\common\sha.cpp" />
<ClCompile Include="..\..\..\src\common\sha2\sha2.cpp" />
<ClCompile Include="..\..\..\src\common\StatementMetadata.cpp" />
<ClCompile Include="..\..\..\src\common\StatusArg.cpp" />
<ClCompile Include="..\..\..\src\common\StatusHolder.cpp" />
@ -189,6 +190,7 @@
<ClInclude Include="..\..\..\src\common\sdltable.h" />
<ClInclude Include="..\..\..\src\common\sdl_proto.h" />
<ClInclude Include="..\..\..\src\common\sha.h" />
<ClInclude Include="..\..\..\src\common\sha2\sha2.h" />
<ClInclude Include="..\..\..\src\common\SimpleStatusVector.h" />
<ClInclude Include="..\..\..\src\common\StatementMetadata.h" />
<ClInclude Include="..\..\..\src\common\StatusArg.h" />

View File

@ -225,6 +225,9 @@
<ClCompile Include="..\..\..\src\common\classes\BlobWrapper.cpp">
<Filter>classes</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\common\sha2\sha2.cpp">
<Filter>common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\common\xdr_proto.h">
@ -548,5 +551,8 @@
<ClInclude Include="..\..\..\src\common\classes\BlobWrapper.h">
<Filter>headers</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\common\sha2\sha2.h">
<Filter>headers</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,204 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>- no title specified</title>
<meta name="generator" content="LibreOffice 5.1.6.2 (Linux)"/>
<meta name="created" content="00:00:00"/>
<meta name="changed" content="2018-06-21T14:25:04.182337599"/>
<meta name="DCTERMS.issued" content="2018-04-09T10:14:20.507318741"/>
<meta name="DCTERMS.language" content="en-US"/>
<meta name="DCTERMS.modified" content="2018-04-09T10:14:29.569131327"/>
<meta name="DCTERMS.provenance" content=""/>
<meta name="DCTERMS.source" content="http://xml.openoffice.org/odf2xhtml"/>
<meta name="DCTERMS.subject" content=","/>
<meta name="DCTERMS.title" content=""/>
<style type="text/css">
p { margin-left: 0.79in; margin-right: 0.79in; color: #000000 }
td p { margin-left: 0.79in; margin-right: 0.79in; color: #000000; font-size: 12pt }
h1 { margin-left: 0.79in; margin-right: 0.79in; color: #000000 }
h2 { margin-left: 0.79in; margin-right: 0.79in; color: #000000 }
h2.cjk { font-family: "Noto Sans CJK SC Regular" }
h2.ctl { font-family: "FreeSans" }
p.p1 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
p.p4 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
td p.p6 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
p.p5 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
p.p7 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
p.p2 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
p.p9 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
p.p10 { margin-bottom: 0in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
</style>
</head>
<body lang="en-US" text="#000000" dir="ltr">
<p>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<!--This file was converted to xhtml by LibreOffice - see http://cgit.freedesktop.org/libreoffice/core/tree/filter/source/xslt for the code.-->
</p>
<h1><a name="a__Replacement_of_use_of_SHA-1_in_the_SRP_Client_Proof_with_a_SHA-2_Message_Digest"></a>
Replacement of use of SHA-1 in the SRP Client Proof with a SHA-2
Message Digest</h1>
<p class="p1">The Firebird implementation of the Secure Remote
Protocol (SRP) for password based user authentication has been
updated following a security review of the original Firebird SRP-6a
implementation taking into account current NIST guidance on the use
of SHA-1 see NIST Special Publication 800-131A, Revision 1,
Transitions: Recommendation for Transitioning the Use of
Cryptographic Algorithms and Key Lengths
(<a href="http://dx.doi.org/10.6028/NIST.SP.800-131Ar1">http://dx.doi.org/10.6028/NIST.SP.800-131Ar1</a>)
chapter 9. This guidance disallows the general use of SHA-1 for
“Digital Signature Generation” whilst permitting continued use
for “Digital Signature Verification”. The background to making
this change is given below.</p>
<p class="p4">By default, the SHA-256 message digest is now used
instead of SHA-1 for generating the Client Proof. Alternatively,
SHA-1 (deprecated and for legacy use only) may be used for the Client
Proof. Separate AuthServer and AuthClient plugins are available for
each supported message digest, with the following names:</p>
<table width="703" cellpadding="0" cellspacing="0">
<col width="174">
<col width="528">
<tr>
<td width="174" style="border: none; padding: 0in">
<ul>
<li/>
<p class="p6" align="left" style="margin-right: 0in">•Srp&nbsp;</p>
</ul>
</td>
<td width="528" style="border: none; padding: 0in">
<p class="p4" align="left">SHA-1 Client Proof</p>
</td>
</tr>
<tr>
<td width="174" style="border: none; padding: 0in">
<ul>
<li/>
<p class="p6" align="left" style="margin-right: 0in">•Srp256&nbsp;</p>
</ul>
</td>
<td width="528" style="border: none; padding: 0in">
<p class="p4" align="left">SHA-256 Client Proof</p>
</td>
</tr>
</table>
<p class="p5">Both client and server must have an SRP authentication
plugin in common in order to enable successfully authentication of a
user's password.
</p>
<p class="p5">There is no change to the SRP User Manager. This is
still called (“Srp”) and the User Manager and the security
database are not affected by the choice of message digest used to
compute the client proof.</p>
<p class="p4">The “firebird.conf” default configuration file
entries for AuthServer and AuthClient are now:</p>
<p class="p4">AuthServer = Srp256<br/>
AuthClient = Srp256, Srp,
Legacy_Auth (Non -windows clients)<br/>
AuthClient = Srp256, Srp,
Win_Sspi, Legacy_Auth (windows clients)</p>
<p class="p4">With these settings, a Firebird Server is using Srp256
to authenticate a client using SHA-256 to compute the client proof
and is thus compatible with Firebird 3.0.4 or newer clients. On the
other hand, a Firebird client will authenticate the user with any
server version down to at least 2.5.</p>
<p class="p7">A deployment where both client and servers support the
legacy Srp (using SHA-1) and one or more of the SHA-2 authentication
plugins (e.g. Srp256) should be avoided. This is because an attacker
might be able to disrupt the Srp256 authentication thereby forcing
Firebird to use the weaker Srp SHA-1 client proof without the user
being aware.</p>
<h2 class="western"><a name="a__REASON_FOR_CHANGE"></a>REASON FOR
CHANGE</h2>
<p class="p1">Review of the Firebird SRP implementation appears to
indicate that most uses of SHA-1 continue to be permitted under NIST
guidance except for its use in generating the client proof. The SRP
client proof may be characterised as a “Poor Man's Digital
Signature” in that it provides a two party proof of identity rather
than the third party proof normally expected from a Digital Signature
i.e. it is not a non-repudiable proof. Nevertheless, it is believed
that generation of the client proof falls under the heading of
“Digital Signature Generation” when considering the NIST
Guidance.</p>
<p class="p2">Continued use of SHA-1 in order to generate the client
proof appears to risk leakage of the encryption key used to encrypt
“over-the-wire” encryption and which hence also provides peer
entity authentication during the lifetime of the connection. This may
result in an attacker being able to monitor confidential
communication either during the connection or at some later date and
this could include leakage of an encryption key used to encrypt the
user database, if this is passed from client to server during the
connection.</p>
<p class="p2">Such an attack is viable if weaknesses in SHA-1 can be
exploited to allow a brute force attack on the client proof to be
computationally feasible. All parts of the message on which the
client proof is based may be known to an attacker with the exception
of the shared session key and such an attack would concentrate on
revealing this key. If it were possible to reveal the shared session
key in real time then additionally a man-in-the-middle attack would
be feasible.</p>
<p class="p2">The severity of this issue is viewed as Important but
not Critical. Users that rely on SRP (using SHA-1)/over the wire
encryption to protect confidential communication have a long term
risk that the confidentiality of &nbsp;their data may be compromised.
The attack may also be mitigated through the use of other procedures
to protect communications (e.g. a secure VPN).</p>
<p class="p9">The update adds a new directory to the source code tree
(src/common/sha2) containing an implementation of the SHA-2 family of
message digests derived from the implementation published by Olivier
Gay &lt;<a href="mailto:olivier.gay@a3.epfl.ch">olivier.gay@a3.epfl.ch</a>&gt;
(see https://github.com/ouah/sha2). The following copyright notice is
included at the request of the original author and applies to the
files in src/common/sha2:</p>
<p class="p10" style="margin-bottom: 0.2in">FIPS 180-2
SHA-224/256/384/512 implementation</p>
<p class="p10" style="margin-bottom: 0.2in">Last update: 02/02/2007</p>
<p class="p10" style="margin-bottom: 0.2in">Issue date: &nbsp;04/30/2005</p>
<p class="p10" style="margin-bottom: 0.2in">https://github.com/ouah/sha2</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp;</p>
<p class="p10" style="margin-bottom: 0.2in">Copyright (C) 2005, 2007
Olivier Gay &lt;olivier.gay@a3.epfl.ch&gt;</p>
<p class="p10" style="margin-bottom: 0.2in">All rights reserved.</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp;</p>
<p class="p10" style="margin-bottom: 0.2in">Redistribution and use in
source and binary forms, with or without</p>
<p class="p10" style="margin-bottom: 0.2in">modification, are
permitted provided that the following conditions</p>
<p class="p10" style="margin-bottom: 0.2in">are met:</p>
<p class="p10" style="margin-bottom: 0.2in">1. Redistributions of
source code must retain the above copyright</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp; &nbsp;notice, this
list of conditions and the following disclaimer.</p>
<p class="p10" style="margin-bottom: 0.2in">2. Redistributions in
binary form must reproduce the above copyright</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp; &nbsp;notice, this
list of conditions and the following disclaimer in the</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp; &nbsp;documentation
and/or other materials provided with the distribution.</p>
<p class="p10" style="margin-bottom: 0.2in">3. Neither the name of
the project nor the names of its contributors</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp; &nbsp;may be used
to endorse or promote products derived from this software</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp; &nbsp;without
specific prior written permission.</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp;</p>
<p class="p10" style="margin-bottom: 0.2in">THIS SOFTWARE IS PROVIDED
BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND</p>
<p class="p10" style="margin-bottom: 0.2in">ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE</p>
<p class="p10" style="margin-bottom: 0.2in">IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE</p>
<p class="p10" style="margin-bottom: 0.2in">ARE DISCLAIMED. &nbsp;IN
NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE</p>
<p class="p10" style="margin-bottom: 0.2in">FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</p>
<p class="p10" style="margin-bottom: 0.2in">DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS</p>
<p class="p10" style="margin-bottom: 0.2in">OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION)</p>
<p class="p10" style="margin-bottom: 0.2in">HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT</p>
<p class="p10" style="margin-bottom: 0.2in">LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY</p>
<p class="p10" style="margin-bottom: 0.2in">OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF</p>
<p class="p10" style="margin-bottom: 0.2in">SUCH DAMAGE.</p>
</body>
</html>

View File

@ -55,7 +55,10 @@ GRANT TINS TO US2;
Use RDB$ROLE_IN_USE function to check if privileges of specified role are currently available to the current user.
Syntax:
RDB$ROLE_IN_USE(role_name varchar(32)) RETURNS BOOLEAN
RDB$ROLE_IN_USE(role_name varchar(N)) RETURNS BOOLEAN
Pay attention - role name should be entered exactly as it's returned by CURRENT_ROLE, function is case-sensitive!
Sample:
To get a list of currently active roles you can run:
SELECT * FROM RDB$ROLES WHERE RDB$ROLE_IN_USE(RDB$ROLE_NAME)

View File

@ -555,6 +555,7 @@ USE_GRANTED_BY_CLAUSE Use GRANTED BY in GRANT and REVOKE operators
GRANT_REVOKE_ON_ANY_OBJECT GRANT and REVOKE rights on any object in database
GRANT_REVOKE_ANY_DDL_RIGHT GRANT and REVOKE any DDL rights
CREATE_PRIVILEGED_ROLES Use SET SYSTEM PRIVILEGES in roles
MODIFY_EXT_CONN_POOL Manage properties of pool of external connections
22) New grantee type in GRANT and REVOKE operators - SYSTEM PRIVILEGE.

View File

@ -0,0 +1,100 @@
The pool of external connections.
To avoid delays when external connections established frequently, external
data source (EDS) subsystem is supplemented by the pool of external connections.
The pool keeps unused external connections for some time and allows to avoid the
cost of connecting / disconnecting for frequently used connection strings.
Author:
Vlad Khorsun <hvlad@users.sourceforge.net>
How pool works:
- every external connection is associated with a pool when created
- pool maintains two lists: idle connections and active connections
- when some connection become unused (i.e. it have no active requests and no
active transactions), it is reset and placed into idle list (on successful
reset) or closed (if reset failed).
Connection is reset using ALTER SESSION RESET statement. It is considered
successful if no error occurs.
- if the pool has reached max. size, the oldest idle connection is closed
- when engine ask to create a new external connection, the pool first looks
for candidate at the idle list. The search is based on 4 parameters:
- connection string,
- username,
- password,
- role.
The search is case sensitive.
- if suitable connection is found, then it tested if it is still alive
- if it did not pass the check, it is deleted and the search is repeated
(the error is not reported to the user)
- found (and alive) connection is moved from idle list to active list and
returned to the caller
- if there are several suitable connections, the most recently used is chosen
- if there is no suitable connection, the new one is created (and put into
active list)
- when idle connection gets expired (exceeded the lifetime), it is deleted from
the pool and closed.
Key characteristics:
- absence of "eternal" external connections
- limited number of inactive (idle) external connections at the pool
- support a quick search among the connections (using 4 parameters above)
- the pool is common for all external databases
- the pool is common for all local connections handled by the given Firebird
process
Pool parameters:
- connection life time: the time interval from the moment of the last usage of
connection after which it will be forcibly closed
- pool size: the maximum allowed number of idle connections in the pool
Pool management:
New SQL statement is introduced to manage the pool:
ALTER EXTERNAL CONNECTIONS POOL.
When prepared it is described as DDL statement but have immediate effect: i.e.
it is executed immediately and completely, not waiting for transaction commit.
Changes applied to the in-memory instance of the pool in current Firebird
process. Therefore change in one Classic process doesn't affect other Classic
processes. Changes is not persistent and after restart Firebird will use pool
settings at firebird.conf (see below).
New system privilege "MODIFY_EXT_CONN_POOL" is required to run the statement.
The full syntax is:
- ALTER EXTERNAL CONNECTIONS POOL SET SIZE <int>
set maximum number of idle connections.
Valid values are from 0 to 1000.
Value of zero means that pool is disabled.
Default value is set in firebird.conf (see below).
- ALTER EXTERNAL CONNECTIONS POOL SET LIFETIME <int> <time_part>,
where <time_part> is SECOND | MINUTE | HOUR
Set idle connection lifetime, in seconds.
Valid values are from 1 SECOND to 24 HOUR.
Default value is set in firebird.conf (see below).
- ALTER EXTERNAL CONNECTIONS POOL CLEAR ALL
Closes all idle connections.
Disassociates all active connections off the pool (such connections will be
closed immediately when gets unused).
- ALTER EXTERNAL CONNECTIONS POOL CLEAR OLDEST
Closes expired idle connections.
The state of external connections pool could be queried using new context
variables in 'SYSTEM' namespace:
- EXT_CONN_POOL_SIZE pool size
- EXT_CONN_POOL_LIFETIME idle connection lifetime, in seconds
- EXT_CONN_POOL_IDLE_COUNT count of currently inactive connections
- EXT_CONN_POOL_ACTIVE_COUNT count of active connections, associated with pool
Firebird configuration (firebird.conf) got two new settings related with pool:
- ExtConnPoolSize = 0, pool size, and
- ExtConnPoolLifeTime = 7200, idle connection lifetime, seconds

View File

@ -1822,6 +1822,14 @@ C --
PARAMETER (GDS__db_crypt_key = 335545204)
INTEGER*4 GDS__no_keyholder_plugin
PARAMETER (GDS__no_keyholder_plugin = 335545205)
INTEGER*4 GDS__ses_reset_err
PARAMETER (GDS__ses_reset_err = 335545206)
INTEGER*4 GDS__ses_reset_open_trans
PARAMETER (GDS__ses_reset_open_trans = 335545207)
INTEGER*4 GDS__ses_reset_warn
PARAMETER (GDS__ses_reset_warn = 335545208)
INTEGER*4 GDS__ses_reset_tran_rollback
PARAMETER (GDS__ses_reset_tran_rollback = 335545209)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw

View File

@ -1817,6 +1817,14 @@ const
gds_db_crypt_key = 335545204;
isc_no_keyholder_plugin = 335545205;
gds_no_keyholder_plugin = 335545205;
isc_ses_reset_err = 335545206;
gds_ses_reset_err = 335545206;
isc_ses_reset_open_trans = 335545207;
gds_ses_reset_open_trans = 335545207;
isc_ses_reset_warn = 335545208;
gds_ses_reset_warn = 335545208;
isc_ses_reset_tran_rollback = 335545209;
gds_ses_reset_tran_rollback = 335545209;
isc_gfix_db_name = 335740929;
gds_gfix_db_name = 335740929;
isc_gfix_invalid_sw = 335740930;

View File

@ -364,7 +364,7 @@ add_library (burp ${burp_src} ${burp_generated_src_master})
# LIBRARY common
########################################
file(GLOB common_src "common/*.cpp" "common/classes/*.cpp" "common/config/*.cpp" "common/os/${OS_DIR}/*.cpp")
file(GLOB common_src "common/*.cpp" "common/classes/*.cpp" "common/config/*.cpp" "common/os/${OS_DIR}/*.cpp" "common/sha2/*.cpp")
file(GLOB_RECURSE common_include "common/*.h")
if (APPLE)

View File

@ -34,7 +34,7 @@ using namespace Firebird;
namespace Auth {
class SrpClient FB_FINAL : public StdPlugin<IClientImpl<SrpClient, CheckStatusWrapper> >
class SrpClient : public StdPlugin<IClientImpl<SrpClient, CheckStatusWrapper> >
{
public:
explicit SrpClient(IPluginConfig*)
@ -55,6 +55,20 @@ private:
RemotePassword* client;
string data;
UCharBuffer sessionKey;
protected:
virtual RemotePassword* RemotePasswordFactory()=0;
};
template <class SHA> class SrpClientImpl FB_FINAL : public SrpClient
{
public:
explicit SrpClientImpl<SHA>(IPluginConfig* ipc)
: SrpClient(ipc) {}
protected:
RemotePassword* RemotePasswordFactory()
{
return FB_NEW RemotePasswordImpl<SHA>;
}
};
int SrpClient::authenticate(CheckStatusWrapper* status, IClientBlock* cb)
@ -76,7 +90,7 @@ int SrpClient::authenticate(CheckStatusWrapper* status, IClientBlock* cb)
return AUTH_CONTINUE;
}
client = FB_NEW RemotePassword;
client = RemotePasswordFactory();
client->genClientKey(data);
dumpIt("Clnt: clientPubKey", data);
cb->putData(status, data.length(), data.begin());
@ -130,7 +144,7 @@ int SrpClient::authenticate(CheckStatusWrapper* status, IClientBlock* cb)
BigInteger cProof = client->clientProof(cb->getLogin(), salt.c_str(), sessionKey);
cProof.getText(data);
dumpIt("Clnt: Client Proof",cProof);
cb->putData(status, data.length(), data.c_str());
if (status->getState() & IStatus::STATE_ERRORS)
{
@ -170,12 +184,20 @@ int SrpClient::release()
namespace
{
SimpleFactory<SrpClient> factory;
SimpleFactory<SrpClientImpl<Sha1> > factory_sha1;
SimpleFactory<SrpClientImpl<sha224> > factory_sha224;
SimpleFactory<SrpClientImpl<sha256> > factory_sha256;
SimpleFactory<SrpClientImpl<sha384> > factory_sha384;
SimpleFactory<SrpClientImpl<sha512> > factory_sha512;
}
void registerSrpClient(IPluginManager* iPlugin)
{
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, RemotePassword::plugName, &factory);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, RemotePassword::plugName, &factory_sha1);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, RemotePassword::pluginName(224).c_str(), &factory_sha224);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, RemotePassword::pluginName(256).c_str(), &factory_sha256);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, RemotePassword::pluginName(384).c_str(), &factory_sha384);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, RemotePassword::pluginName(512).c_str(), &factory_sha512);
}
} // namespace Auth

View File

@ -688,7 +688,7 @@ private:
Firebird::RefPtr<Firebird::IFirebirdConf> config;
Firebird::RefPtr<Firebird::IAttachment> att;
Firebird::RefPtr<Firebird::ITransaction> tra;
RemotePassword server;
RemotePasswordImpl<Firebird::Sha1> server;
int upCount, delCount;
bool checkCount(Firebird::CheckStatusWrapper* status, int* count, UCHAR item)

View File

@ -4,9 +4,8 @@ compile()
file=test_${1}
g++ -I../../../include -DLINUX -DAMD64 -DDEV_BUILD ${file}.cpp \
../../../../temp/Debug/auth/SecureRemotePassword/srp.o \
../../../../temp/Debug/auth/SecureRemotePassword/BigInteger.o \
../../../../temp/Debug/common.a -ltommath ../../../../gen/Debug/firebird/lib/libfbclient.so \
-Wl,-rpath,../../../../gen/Debug/firebird/lib -lrt -o ${file} && ./${file}
-lpthread -Wl,-rpath,../../../../gen/Debug/firebird/lib -lrt -o ${file} && ./${file}
}
compile srp

View File

@ -2,19 +2,19 @@
using namespace Auth;
int main(int argc, char** argv)
template<class SHA>void runTest(int argc, char** argv)
{
Firebird::string salt;
#if SRP_DEBUG > 1
BigInteger s("02E268803000000079A478A700000002D1A6979000000026E1601C000000054F");
Firebird::BigInteger s("02E268803000000079A478A700000002D1A6979000000026E1601C000000054F");
#else
BigInteger s;
Firebird::BigInteger s;
s.random(128);
#endif
s.getText(salt);
RemotePassword* server = FB_NEW RemotePassword();
RemotePassword* client = FB_NEW RemotePassword();
RemotePassword* server = FB_NEW RemotePasswordImpl<SHA>();
RemotePassword* client = FB_NEW RemotePasswordImpl<SHA>();
const char* account = "SYSDBA";
const char* password = "masterkey";
@ -37,8 +37,20 @@ int main(int argc, char** argv)
client->clientSessionKey(key1, account, salt.c_str(), argc > 1 ? argv[1] : password, serverPubKey.c_str());
server->serverSessionKey(key2, clientPubKey.c_str(), verifier);
BigInteger cProof = client->clientProof(account, salt.c_str(), key1);
BigInteger sProof = server->clientProof(account, salt.c_str(), key2);
Firebird::BigInteger cProof = client->clientProof(account, salt.c_str(), key1);
Firebird::BigInteger sProof = server->clientProof(account, salt.c_str(), key2);
printf("Proof length = %d\n",cProof.length());
printf("%s\n", cProof == sProof ? "OK" : "differ");
}
int main(int argc, char** argv)
{
runTest<Firebird::Sha1>(argc,argv);
runTest<Firebird::sha224>(argc,argv);
runTest<Firebird::sha256>(argc,argv);
runTest<Firebird::sha384>(argc,argv);
runTest<Firebird::sha512>(argc,argv);
}

View File

@ -48,7 +48,7 @@ const unsigned int SZ_LOGIN = 31;
namespace Auth {
class SrpServer FB_FINAL : public StdPlugin<IServerImpl<SrpServer, CheckStatusWrapper> >
class SrpServer : public StdPlugin<IServerImpl<SrpServer, CheckStatusWrapper> >
{
public:
explicit SrpServer(IPluginConfig* par)
@ -68,12 +68,12 @@ public:
void setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback);
int release();
private:
~SrpServer()
{
delete server;
}
private:
RemotePassword* server;
string data;
string account;
@ -84,6 +84,20 @@ private:
RefPtr<IFirebirdConf> config;
const char* secDbName;
ICryptKeyCallback* cryptCallback;
protected:
virtual RemotePassword* RemotePasswordFactory()=0;
};
template <class SHA> class SrpServerImpl FB_FINAL : public SrpServer
{
public:
explicit SrpServerImpl<SHA>(IPluginConfig* ipc)
: SrpServer(ipc) {}
protected:
RemotePassword* RemotePasswordFactory()
{
return FB_NEW RemotePasswordImpl<SHA>;
}
};
int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWriter* writerInterface)
@ -215,7 +229,7 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite
throw;
}
server = FB_NEW RemotePassword;
server = RemotePasswordFactory();
server->genServerKey(serverPubKey, verifier);
// Ready to prepare data for client and calculate session key
@ -248,6 +262,9 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite
proof.assign(val, length);
BigInteger clientProof(proof.c_str());
BigInteger serverProof = server->clientProof(account.c_str(), salt.c_str(), sessionKey);
HANDSHAKE_DEBUG(fprintf(stderr, "Client Proof Received, Length = %d\n", clientProof.length()));
dumpIt("Srv: Client Proof",clientProof);
dumpIt("Srv: Server Proof",serverProof);
if (clientProof == serverProof)
{
// put the record into authentication block
@ -311,12 +328,20 @@ int SrpServer::release()
namespace
{
SimpleFactory<SrpServer> factory;
SimpleFactory<SrpServerImpl<Sha1> > factory_sha1;
SimpleFactory<SrpServerImpl<sha224> > factory_sha224;
SimpleFactory<SrpServerImpl<sha256> > factory_sha256;
SimpleFactory<SrpServerImpl<sha384> > factory_sha384;
SimpleFactory<SrpServerImpl<sha512> > factory_sha512;
}
void registerSrpServer(IPluginManager* iPlugin)
{
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, RemotePassword::plugName, &factory);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, RemotePassword::plugName, &factory_sha1);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, RemotePassword::pluginName(224).c_str(), &factory_sha224);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, RemotePassword::pluginName(256).c_str(), &factory_sha256);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, RemotePassword::pluginName(384).c_str(), &factory_sha384);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, RemotePassword::pluginName(512).c_str(), &factory_sha512);
}
} // namespace Auth

View File

@ -29,7 +29,7 @@ public:
explicit RemoteGroup(Firebird::MemoryPool&)
: prime(primeStr), generator(genStr), k()
{
Auth::Sha1 hash;
Auth::SecureHash<Firebird::Sha1> hash;
hash.processInt(prime);
if (prime.length() > generator.length())
@ -59,6 +59,13 @@ InitInstance<RemoteGroup> RemoteGroup::group;
const char* RemotePassword::plugName = "Srp";
string RemotePassword::pluginName(unsigned bits)
{
string plg;
plg.printf("%s%u", plugName, bits);
return plg;
}
RemotePassword::RemotePassword()
: group(RemoteGroup::getGroup())
{
@ -187,18 +194,7 @@ BigInteger RemotePassword::clientProof(const char* account, const char* salt, co
hash.reset();
hash.process(account);
hash.getInt(n2);
hash.reset();
hash.processInt(n1); // H(prime) ^ H(g)
hash.processInt(n2); // H(I)
hash.process(salt); // s
hash.processInt(clientPublicKey); // A
hash.processInt(serverPublicKey); // B
hash.process(sessionKey); // K
BigInteger rc;
hash.getInt(rc);
return rc;
return MakeProof(n1,n2,salt,sessionKey);
}
#if SRP_DEBUG > 0

View File

@ -2,6 +2,7 @@
#include "../common/classes/alloc.h"
#include "../common/classes/fb_string.h"
#include "../common/sha.h"
#include "../common/sha2/sha2.h"
#define SRP_DEBUG 0 // >0 - prints some debug info
// >1 - uses consts instead randoms, NEVER use in PRODUCTION!
@ -46,13 +47,13 @@ namespace Auth {
class RemoteGroup;
class Sha1 : public Firebird::Sha1
template <class SHA> class SecureHash : public SHA
{
public:
void getInt(Firebird::BigInteger& hash)
{
Firebird::UCharBuffer tmp;
getHash(tmp);
SHA::getHash(tmp);
hash.assign(tmp.getCount(), tmp.begin());
}
@ -60,7 +61,7 @@ public:
{
Firebird::UCharBuffer bytes;
data.getBytes(bytes);
process(bytes);
SHA::process(bytes);
}
void processStrippedInt(const Firebird::BigInteger& data)
@ -70,19 +71,24 @@ public:
if (bytes.getCount())
{
unsigned int n = (bytes[0] == 0) ? 1u : 0;
process(bytes.getCount() - n, bytes.begin() + n);
SHA::process(bytes.getCount() - n, bytes.begin() + n);
}
}
};
class RemotePassword : public Firebird::GlobalStorage
{
private:
const RemoteGroup* group;
Auth::Sha1 hash;
Auth::SecureHash<Firebird::Sha1> hash;
Firebird::BigInteger privateKey;
Firebird::BigInteger scramble;
protected:
virtual Firebird::BigInteger MakeProof(const Firebird::BigInteger n1, const Firebird::BigInteger n2,
const char* salt, const Firebird::UCharBuffer& sessionKey) = 0;
public:
Firebird::BigInteger clientPublicKey;
Firebird::BigInteger serverPublicKey;
@ -95,6 +101,8 @@ public:
static const unsigned SRP_VERIFIER_SIZE = SRP_KEY_SIZE;
static const unsigned SRP_SALT_SIZE = 32;
static Firebird::string pluginName(unsigned bits);
Firebird::BigInteger getUserHash(const char* account,
const char* salt,
const char* password);
@ -115,6 +123,27 @@ public:
const Firebird::UCharBuffer& sessionKey);
};
template <class SHA> class RemotePasswordImpl : public RemotePassword
{
protected:
Firebird::BigInteger MakeProof(const Firebird::BigInteger n1, const Firebird::BigInteger n2,
const char* salt, const Firebird::UCharBuffer& sessionKey)
{
Auth::SecureHash<SHA> digest;
digest.processInt(n1); // H(prime) ^ H(g)
digest.processInt(n2); // H(I)
digest.process(salt); // s
digest.processInt(clientPublicKey); // A
digest.processInt(serverPublicKey); // B
digest.process(sessionKey); // K
Firebird::BigInteger rc;
digest.getInt(rc);
return rc;
}
};
#if SRP_DEBUG > 0
void dumpIt(const char* name, const Firebird::BigInteger& bi);

View File

@ -830,7 +830,7 @@ SINT64 get_gen_id( const TEXT* name, SSHORT name_len)
sql = "select first(1) gen_id(" + nm + ", 0) from rdb$database";
BurpSql getGenerator(tdgbl, sql.c_str());
FB_MESSAGE(GetGen, Firebird::ThrowStatusWrapper, (FB_BIGINT, id));
FB_MESSAGE(GetGen, Firebird::ThrowWrapper, (FB_BIGINT, id));
GetGen getGen(&tdgbl->throwStatus, Firebird::MasterInterfacePtr());
getGenerator.singleSelect(tdgbl->tr_handle, &getGen);
@ -2562,7 +2562,7 @@ void write_database( const TEXT* dbb_file)
// msg 31 isc_database_info failed
}
USHORT page_size = 0, forced_writes, no_reserve, SQL_dialect, db_read_only;
USHORT page_size = 0, forced_writes, no_reserve, db_read_only;
ULONG sweep_interval, page_buffers;
USHORT length = 0;
for (const UCHAR* d = buffer; *d != isc_info_end; d += length)
@ -2604,8 +2604,8 @@ void write_database( const TEXT* dbb_file)
break; // parameter and returns isc_info_error. skip it
case isc_info_db_sql_dialect:
SQL_dialect = (USHORT) gds__vax_integer(d, length);
put_int32(att_SQL_dialect, SQL_dialect);
tdgbl->gbl_dialect = (USHORT) gds__vax_integer(d, length);
put_int32(att_SQL_dialect, tdgbl->gbl_dialect);
break;
case isc_info_db_read_only:

View File

@ -3155,7 +3155,7 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_DETAILED_ERRORS, GBAK_BATCH_STEP);
pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_BUFFER_BYTES_SIZE, 0);
Firebird::RefPtr<Firebird::IBatch> batch(DB->
Firebird::RefPtr<Firebird::IBatch> batch(Firebird::REF_NO_INCR, DB->
createBatch(fbStatus, gds_trans, sqlStatement.length(), sqlStatement.c_str(), tdgbl->gbl_dialect,
meta, pb->getBufferLength(&tdgbl->throwStatus), pb->getBuffer(&tdgbl->throwStatus)));
if (fbStatus->hasData())

View File

@ -480,7 +480,7 @@ static int get_file_size(const SCHAR* prog_name, const SCHAR* string, SINT64* fi
UCHAR c;
for (const SCHAR* p = string; c = *p++;)
for (const SCHAR* p = string; (c = *p++);)
{
if (c == '\0')
break;

View File

@ -31,6 +31,7 @@
#include "StatusArg.h"
#include "gen/iberror.h"
#include "status.h"
extern "C"
{
@ -613,9 +614,26 @@ void DecimalFixed::exactInt(DecimalStatus decSt, int scale)
{
setScale(decSt, -scale);
DecimalContext context(this, decSt);
decQuadToIntegralExact(&dec, &dec, &context);
decQuadQuantize(&dec, &dec, &c1.dec, &context);
try
{
DecimalContext context(this, decSt);
decQuadToIntegralExact(&dec, &dec, &context);
decQuadQuantize(&dec, &dec, &c1.dec, &context);
}
catch(const Exception& ex)
{
FbLocalStatus st;
ex.stuffException(&st);
switch(st->getErrors()[1])
{
case isc_decfloat_invalid_operation:
(Arg::Gds(isc_decfloat_invalid_operation) <<
Arg::Gds(isc_numeric_out_of_range)).raise();
break;
}
throw;
}
}
Decimal128 Decimal128::operator=(Decimal64 d64)

View File

@ -144,6 +144,9 @@ public:
const FB_SIZE_T len = getBufferLength();
return (len == other.getBufferLength()) && (memcmp(getBuffer(), other.getBuffer(), len) == 0);
}
// Methods are virtual so writer can override 'em
virtual const UCHAR* getBuffer() const;
virtual const UCHAR* getBufferEnd() const;
protected:
enum ClumpletType {TraditionalDpb, SingleTpb, StringSpb, IntSpb, BigIntSpb, ByteSpb, Wide};
@ -155,10 +158,6 @@ protected:
Kind kind;
UCHAR spbState; // Reflects state of spb parser/writer
// Methods are virtual so writer can override 'em
virtual const UCHAR* getBuffer() const;
virtual const UCHAR* getBufferEnd() const;
// These functions are called when error condition is detected by this class.
// They may throw exceptions. If they don't reader tries to do something
// sensible, certainly not overwrite memory or read past the end of buffer

View File

@ -99,7 +99,7 @@ static void* stopAddress = (void*) 0x2254938;
#endif
#ifdef MEM_DEBUG
static const int GUARD_BYTES = Firebird::ALLOC_ALIGNMENT; // * 2048;
static const int GUARD_BYTES = ALLOC_ALIGNMENT; // * 2048;
static const UCHAR INIT_BYTE = 0xCC;
static const UCHAR GUARD_BYTE = 0xDD;
static const UCHAR DEL_BYTE = 0xEE;
@ -136,6 +136,10 @@ size_t delayedExtentCount = 0;
size_t delayedExtentsPos = 0;
#endif
// Uncomment to validate pool on every alloc\release operation.
// Could slowdown pool significantly !
//#define VALIDATE_POOL
// We cache this amount of extents to avoid memory mapping overhead
const int MAP_CACHE_SIZE = 16; // == 1 MB
const size_t DEFAULT_ALLOCATION = 65536;
@ -218,7 +222,7 @@ namespace SemiDoubleLink
#ifdef USE_VALGRIND
// Size of Valgrind red zone applied before and after memory block allocated for user
#define VALGRIND_REDZONE 8
#define VALGRIND_REDZONE MEM_ALIGN
#undef MEM_DEBUG // valgrind works instead
#else
#define VALGRIND_REDZONE 0
@ -253,6 +257,8 @@ public:
#ifdef DEBUG_GDS_ALLOC
INT32 lineNumber;
const char *fileName;
#elif (SIZEOF_VOID_P == 4) && (ALLOC_ALIGNMENT == 16)
FB_UINT64 dummyAlign;
#endif
#if defined(USE_VALGRIND) && (VALGRIND_REDZONE != 0)
char mbk_valgrind_redzone[VALGRIND_REDZONE];
@ -540,10 +546,11 @@ public:
MemBigHunk* next;
MemBigHunk** prev;
const size_t length;
MemBlock block;
MemBlock* block;
MemBigHunk(MemBigHunk** top, size_t l)
: next(NULL), prev(NULL), length(l), block(MemBlock::HUGE_BLOCK, length - hdrSize())
: next(NULL), prev(NULL), length(l),
block(new(((UCHAR*) this) + hdrSize()) MemBlock(MemBlock::HUGE_BLOCK, length - hdrSize()))
{
SemiDoubleLink::push(top, this);
}
@ -553,8 +560,8 @@ public:
const char* filter_path, const size_t filter_len) FB_NOTHROW
{
fprintf(file, "Big hunk %p: memory=%p length=%" SIZEFORMAT "\n",
this, &block, length);
block.print_contents(true, file, used_only, filter_path, filter_len);
this, block, length);
block->print_contents(true, file, used_only, filter_path, filter_len);
if (next)
next->print_contents(file, pool, used_only, filter_path, filter_len);
}
@ -562,20 +569,21 @@ public:
static size_t hdrSize()
{
return offsetof(MemBigHunk, block);
return MEM_ALIGN(sizeof(MemBigHunk));
}
void validate()
{
SemiDoubleLink::validate(this);
block.assertBig();
fb_assert(block.getSize() + hdrSize() == length);
block->assertBig();
fb_assert(block->getSize() + hdrSize() == length);
}
};
enum GetSlotFor { SLOT_ALLOC, SLOT_FREE };
#if ALLOC_ALIGNMENT == 8
const unsigned char lowSlots[] =
{
0, // 24
@ -739,6 +747,106 @@ const unsigned short lowLimits[] =
1024, // 28
};
const int SLOT_SHIFT = 3;
#elif ALLOC_ALIGNMENT == 16
const unsigned char lowSlots[] =
{
0, // 32
1, // 48
2, // 64
3, // 80
4, // 96
5, // 112
6, // 128
7, // 144
8, // 160
9, // 176
9, // 192
10, // 208
10, // 224
11, // 240
11, // 256
12, // 272
12, // 288
13, // 304
13, // 320
14, // 336
14, // 352
14, // 368
15, // 384
15, // 400
15, // 416
16, // 432
16, // 448
16, // 464
17, // 480
17, // 496
17, // 512
17, // 528
18, // 544
18, // 560
18, // 576
18, // 592
19, // 608
19, // 624
19, // 640
19, // 656
19, // 672
20, // 688
20, // 704
20, // 720
20, // 736
20, // 752
21, // 768
21, // 784
21, // 800
21, // 816
21, // 832
21, // 848
22, // 864
22, // 880
22, // 896
22, // 912
22, // 928
22, // 944
23, // 960
23, // 976
23, // 992
23, // 1008
23, // 1024
};
const unsigned short lowLimits[] =
{
32, // 0
48, // 1
64, // 2
80, // 3
96, // 4
112, // 5
128, // 6
144, // 7
160, // 8
192, // 9
224, // 10
256, // 11
288, // 12
320, // 13
368, // 14
416, // 15
464, // 16
528, // 17
592, // 18
672, // 19
752, // 20
848, // 21
944, // 22
1024, // 23
};
const int SLOT_SHIFT = 4;
#endif
const size_t TINY_SLOTS = FB_NELEM(lowLimits);
const unsigned short* TINY_BLOCK_LIMIT = &lowLimits[TINY_SLOTS - 1];
@ -747,7 +855,11 @@ const unsigned short* TINY_BLOCK_LIMIT = &lowLimits[TINY_SLOTS - 1];
class LowLimits
{
public:
#if ALLOC_ALIGNMENT == 8
static const unsigned TOTAL_ELEMENTS = 29; // TINY_SLOTS
#elif ALLOC_ALIGNMENT == 16
static const unsigned TOTAL_ELEMENTS = 24; // TINY_SLOTS
#endif
static const unsigned TOP_LIMIT = 1024; // TINY_BLOCK_LIMIT
static unsigned getSlot(size_t size, GetSlotFor mode)
@ -762,7 +874,7 @@ public:
size = LOW_LIMIT;
fb_assert(MEM_ALIGN(size) == size);
unsigned slot = lowSlots[(size - LOW_LIMIT) >> 3];
unsigned slot = lowSlots[(size - LOW_LIMIT) >> SLOT_SHIFT];
fb_assert(size <= lowLimits[slot]);
if (lowLimits[slot] > size && mode == SLOT_FREE)
{
@ -1548,7 +1660,7 @@ public:
private:
static const size_t minAllocation = 65536;
static const size_t roundingSize = 8;
static const size_t roundingSize = ALLOC_ALIGNMENT;
FreeObjects<LinkedList, LowLimits> smallObjects;
Vector<MemBlock*, 16> parentRedirected;
@ -1568,6 +1680,32 @@ private:
AtomicCounter used_memory, mapped_memory;
private:
#ifdef VALIDATE_POOL
class Validator
{
public:
Validator(MemPool* p) :
m_pool(p)
{
m_pool->validate();
}
~Validator()
{
m_pool->validate();
}
private:
MemPool* m_pool;
};
#else
class Validator
{
public:
Validator(MemPool*) {}
};
#endif // VALIDATE_POOL
MemBlock* alloc(size_t from, size_t& length, bool flagRedirect) FB_THROW (OOM_EXCEPTION);
void releaseBlock(MemBlock *block) FB_NOTHROW;
@ -1868,6 +2006,7 @@ void MemoryPool::cleanup()
MemPool::MemPool()
: pool_destroying(false), parent_redirect(false), stats(MemoryPool::default_stats_group), parent(NULL)
{
fb_assert(offsetof(MemBlock, body) == MEM_ALIGN(offsetof(MemBlock, body)));
initialize();
}
@ -2033,6 +2172,8 @@ MemBlock* MemPool::alloc(size_t from, size_t& length, bool flagRedirect) FB_THRO
MutexEnsureUnlock guard(mutex, "MemPool::alloc");
guard.enter();
Validator vld(this);
// If this is a small block, look for it there
MemBlock* block = smallObjects.allocateBlock(this, from, length);
@ -2080,7 +2221,7 @@ MemBlock* MemPool::alloc(size_t from, size_t& length, bool flagRedirect) FB_THRO
// Allocate the new hunk
MemBigHunk* hunk = new(allocRaw(hunkLength)) MemBigHunk(&bigHunks, hunkLength);
return &hunk->block;
return hunk->block;
}
MemBlock* MemPool::allocate2(size_t from, size_t& size
@ -2112,6 +2253,7 @@ MemBlock* MemPool::allocate2(size_t from, size_t& size
++blocksAllocated;
++blocksActive;
fb_assert((U_IPTR)(&memory->body) % ALLOC_ALIGNMENT == 0);
return memory;
}
@ -2207,6 +2349,8 @@ void MemPool::releaseBlock(MemBlock* block) FB_NOTHROW
MutexEnsureUnlock guard(mutex, "MemPool::release");
guard.enter();
Validator vld(this);
// If length is less than threshold, this is a small block
if (smallObjects.deallocateBlock(block))
return;

View File

@ -79,7 +79,8 @@
namespace Firebird {
// Alignment for all memory blocks
const size_t ALLOC_ALIGNMENT = 8;
//#define ALLOC_ALIGNMENT 8
#define ALLOC_ALIGNMENT 16
static inline size_t MEM_ALIGN(size_t value)
{

View File

@ -413,6 +413,17 @@ public:
return false;
}
bool findAndRemove(const T& item)
{
size_type pos;
if (find(item, pos))
{
remove(pos);
return true;
}
return false;
}
bool exist(const T& item) const
{
size_type pos; // ignored

View File

@ -27,13 +27,13 @@
#include <stdio.h>
main(int ac, char** av)
int main(int ac, char** av)
{
int mode = ac < 2 ? 0 : ((*av[1]) - '0');
int cur = 24;
int cur = 32;
int prev = 0;
const int dstep = 8;
const int dstep = 16;
int limit = 1024;
int slot = 0;
@ -55,4 +55,6 @@ main(int ac, char** av)
if (mode == 1)
printf ("\t%d, // %d\n", cur, slot);
return 0;
}

View File

@ -300,6 +300,8 @@ public:
key++;
lt = locGreatEqual;
break;
default:
break;
}
// Look up a bucket for our key
@ -396,6 +398,9 @@ public:
// Bucket must contain one bit at least
fb_assert(false);
}
default:
break;
}
fb_assert(false); // Invalid constant is used ?
return false;

View File

@ -191,11 +191,11 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] =
{TYPE_INTEGER, "MaxUserTraceLogSize", (ConfigValue) 10}, // maximum size of user session trace log
{TYPE_INTEGER, "FileSystemCacheSize", (ConfigValue) 0}, // percent
{TYPE_STRING, "Providers", (ConfigValue) "Remote, " CURRENT_ENGINE ", Loopback"},
{TYPE_STRING, "AuthServer", (ConfigValue) "Srp"},
{TYPE_STRING, "AuthServer", (ConfigValue) "Srp256"},
#ifdef WIN_NT
{TYPE_STRING, "AuthClient", (ConfigValue) "Srp, Win_Sspi, Legacy_Auth"},
{TYPE_STRING, "AuthClient", (ConfigValue) "Srp256, Srp, Win_Sspi, Legacy_Auth"},
#else
{TYPE_STRING, "AuthClient", (ConfigValue) "Srp, Legacy_Auth"},
{TYPE_STRING, "AuthClient", (ConfigValue) "Srp256, Srp, Legacy_Auth"},
#endif
{TYPE_STRING, "UserManager", (ConfigValue) "Srp"},
{TYPE_STRING, "TracePlugin", (ConfigValue) "fbtrace"},
@ -222,6 +222,8 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] =
{TYPE_STRING, "OutputRedirectionFile", (ConfigValue) "/dev/null"},
#endif
#endif
{TYPE_INTEGER, "ExtConnPoolSize", (ConfigValue) 0},
{TYPE_INTEGER, "ExtConnPoolLifeTime", (ConfigValue) 7200},
{TYPE_INTEGER, "SnapshotsMemSize", (ConfigValue) 65536}, // bytes
{TYPE_INTEGER, "TpcBlockSize", (ConfigValue) 4194304}, // bytes
{TYPE_BOOLEAN, "ReadConsistency", (ConfigValue) true}
@ -887,6 +889,16 @@ const char* Config::getOutputRedirectionFile()
return file;
}
int Config::getExtConnPoolSize()
{
return getDefaultConfig()->get<int>(KEY_EXT_CONN_POOL_SIZE);
}
int Config::getExtConnPoolLifeTime()
{
return getDefaultConfig()->get<int>(KEY_EXT_CONN_POOL_LIFETIME);
}
bool Config::getReadConsistency() const
{
return get<bool>(KEY_READ_CONSISTENCY);

View File

@ -147,6 +147,8 @@ public:
KEY_CONN_IDLE_TIMEOUT,
KEY_CLIENT_BATCH_BUFFER,
KEY_OUTPUT_REDIRECTION_FILE,
KEY_EXT_CONN_POOL_SIZE,
KEY_EXT_CONN_POOL_LIFETIME,
KEY_SNAPSHOTS_MEM_SIZE,
KEY_TPC_BLOCK_SIZE,
KEY_READ_CONSISTENCY,
@ -369,6 +371,10 @@ public:
static const char* getOutputRedirectionFile();
static int getExtConnPoolSize();
static int getExtConnPoolLifeTime();
ULONG getSnapshotsMemSize() const;
ULONG getTpcBlockSize() const;

17
src/common/sha2/ChangeLog Normal file
View File

@ -0,0 +1,17 @@
2007-02-02 Olivier Gay <olivier.gay@a3.epfl.ch>
* sha2.c (sha512_transf) [UNROLL_LOOPS]: Group together SHA512_EXP calls
in a loop to optimize speed in SHA-384 and SHA-512.
* sha2.h, sha2.c: Remove HAVE_STDINT and use new typedef for fixed-width
integer types.
2007-02-02 Tad <sha2@ds3switch.com>
* sha2.c (sha224_update, sha256_update, sha384_update, sha512_update): Check
the read size is within the buffer limits when updating small data.
2005-05-23 Olivier Gay <olivier.gay@a3.epfl.ch>
* sha2.h, sha2.c: Support of SHA-224 functions.

954
src/common/sha2/sha2.cpp Normal file
View File

@ -0,0 +1,954 @@
/*
* FIPS 180-2 SHA-224/256/384/512 implementation
* Last update: 02/02/2007
* Issue date: 04/30/2005
* https://github.com/ouah/sha2
*
* Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* Updated for use in Firebird by Tony Whyman <tony@mwasoftware.co.uk>
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if 0
#define UNROLL_LOOPS /* Enable loops unrolling */
#endif
#include "sha2.h"
#define SHFR(x, n) (x >> n)
#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
#define CH(x, y, z) ((x & y) ^ (~x & z))
#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3))
#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
#define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39))
#define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41))
#define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7))
#define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6))
#define UNPACK32(x, str) \
{ \
*((str) + 3) = (uint8) ((x) ); \
*((str) + 2) = (uint8) ((x) >> 8); \
*((str) + 1) = (uint8) ((x) >> 16); \
*((str) + 0) = (uint8) ((x) >> 24); \
}
#define PACK32(str, x) \
{ \
*(x) = ((uint32) *((str) + 3) ) \
| ((uint32) *((str) + 2) << 8) \
| ((uint32) *((str) + 1) << 16) \
| ((uint32) *((str) + 0) << 24); \
}
#define UNPACK64(x, str) \
{ \
*((str) + 7) = (uint8) ((x) ); \
*((str) + 6) = (uint8) ((x) >> 8); \
*((str) + 5) = (uint8) ((x) >> 16); \
*((str) + 4) = (uint8) ((x) >> 24); \
*((str) + 3) = (uint8) ((x) >> 32); \
*((str) + 2) = (uint8) ((x) >> 40); \
*((str) + 1) = (uint8) ((x) >> 48); \
*((str) + 0) = (uint8) ((x) >> 56); \
}
#define PACK64(str, x) \
{ \
*(x) = ((uint64) *((str) + 7) ) \
| ((uint64) *((str) + 6) << 8) \
| ((uint64) *((str) + 5) << 16) \
| ((uint64) *((str) + 4) << 24) \
| ((uint64) *((str) + 3) << 32) \
| ((uint64) *((str) + 2) << 40) \
| ((uint64) *((str) + 1) << 48) \
| ((uint64) *((str) + 0) << 56); \
}
/* Macros used for loops unrolling */
#define SHA256_SCR(i) \
{ \
w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \
+ SHA256_F3(w[i - 15]) + w[i - 16]; \
}
#define SHA512_SCR(i) \
{ \
w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \
+ SHA512_F3(w[i - 15]) + w[i - 16]; \
}
#define SHA256_EXP(a, b, c, d, e, f, g, h, j) \
{ \
t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \
+ sha256_k[j] + w[j]; \
t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \
wv[d] += t1; \
wv[h] = t1 + t2; \
}
#define SHA512_EXP(a, b, c, d, e, f, g ,h, j) \
{ \
t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \
+ sha512_k[j] + w[j]; \
t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \
wv[d] += t1; \
wv[h] = t1 + t2; \
}
namespace Firebird {
sha2_base::uint32 sha224_h0[8] =
{0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4};
sha2_base::uint32 sha256_h0[8] =
{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
sha2_base::uint64 sha384_h0[8] =
{0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL,
0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL,
0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL,
0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL};
sha2_base::uint64 sha512_h0[8] =
{0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};
sha2_base::uint32 sha256_k[64] =
{0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
sha2_base::uint64 sha512_k[80] =
{0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};
/* sha2_base */
void sha2_base::getHash(unsigned char *digest)
{
sha_final(digest);
reset();
};
#ifndef NIST_COMPLIANCY_TESTS
void sha2_base::getHash(UCharBuffer& h)
{
sha_final(h.getBuffer(get_DigestSize()));
reset();
};
#endif
/* SHA-256 functions */
sha256::sha256() : sha2_base()
{
sha256_init(&ctx);
}
void sha256::sha256_transf(sha256_ctx * ctx, const unsigned char *message,
unsigned int block_nb)
{
uint32 w[64];
uint32 wv[8];
uint32 t1, t2;
const unsigned char *sub_block;
int i;
#ifndef UNROLL_LOOPS
int j;
#endif
for (i = 0; i < (int) block_nb; i++) {
sub_block = message + (i << 6);
#ifndef UNROLL_LOOPS
for (j = 0; j < 16; j++) {
PACK32(&sub_block[j << 2], &w[j]);
}
for (j = 16; j < 64; j++) {
SHA256_SCR(j);
}
for (j = 0; j < 8; j++) {
wv[j] = ctx->h[j];
}
for (j = 0; j < 64; j++) {
t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
+ sha256_k[j] + w[j];
t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
wv[7] = wv[6];
wv[6] = wv[5];
wv[5] = wv[4];
wv[4] = wv[3] + t1;
wv[3] = wv[2];
wv[2] = wv[1];
wv[1] = wv[0];
wv[0] = t1 + t2;
}
for (j = 0; j < 8; j++) {
ctx->h[j] += wv[j];
}
#else
PACK32(&sub_block[ 0], &w[ 0]); PACK32(&sub_block[ 4], &w[ 1]);
PACK32(&sub_block[ 8], &w[ 2]); PACK32(&sub_block[12], &w[ 3]);
PACK32(&sub_block[16], &w[ 4]); PACK32(&sub_block[20], &w[ 5]);
PACK32(&sub_block[24], &w[ 6]); PACK32(&sub_block[28], &w[ 7]);
PACK32(&sub_block[32], &w[ 8]); PACK32(&sub_block[36], &w[ 9]);
PACK32(&sub_block[40], &w[10]); PACK32(&sub_block[44], &w[11]);
PACK32(&sub_block[48], &w[12]); PACK32(&sub_block[52], &w[13]);
PACK32(&sub_block[56], &w[14]); PACK32(&sub_block[60], &w[15]);
SHA256_SCR(16); SHA256_SCR(17); SHA256_SCR(18); SHA256_SCR(19);
SHA256_SCR(20); SHA256_SCR(21); SHA256_SCR(22); SHA256_SCR(23);
SHA256_SCR(24); SHA256_SCR(25); SHA256_SCR(26); SHA256_SCR(27);
SHA256_SCR(28); SHA256_SCR(29); SHA256_SCR(30); SHA256_SCR(31);
SHA256_SCR(32); SHA256_SCR(33); SHA256_SCR(34); SHA256_SCR(35);
SHA256_SCR(36); SHA256_SCR(37); SHA256_SCR(38); SHA256_SCR(39);
SHA256_SCR(40); SHA256_SCR(41); SHA256_SCR(42); SHA256_SCR(43);
SHA256_SCR(44); SHA256_SCR(45); SHA256_SCR(46); SHA256_SCR(47);
SHA256_SCR(48); SHA256_SCR(49); SHA256_SCR(50); SHA256_SCR(51);
SHA256_SCR(52); SHA256_SCR(53); SHA256_SCR(54); SHA256_SCR(55);
SHA256_SCR(56); SHA256_SCR(57); SHA256_SCR(58); SHA256_SCR(59);
SHA256_SCR(60); SHA256_SCR(61); SHA256_SCR(62); SHA256_SCR(63);
wv[0] = ctx->h[0]; wv[1] = ctx->h[1];
wv[2] = ctx->h[2]; wv[3] = ctx->h[3];
wv[4] = ctx->h[4]; wv[5] = ctx->h[5];
wv[6] = ctx->h[6]; wv[7] = ctx->h[7];
SHA256_EXP(0,1,2,3,4,5,6,7, 0); SHA256_EXP(7,0,1,2,3,4,5,6, 1);
SHA256_EXP(6,7,0,1,2,3,4,5, 2); SHA256_EXP(5,6,7,0,1,2,3,4, 3);
SHA256_EXP(4,5,6,7,0,1,2,3, 4); SHA256_EXP(3,4,5,6,7,0,1,2, 5);
SHA256_EXP(2,3,4,5,6,7,0,1, 6); SHA256_EXP(1,2,3,4,5,6,7,0, 7);
SHA256_EXP(0,1,2,3,4,5,6,7, 8); SHA256_EXP(7,0,1,2,3,4,5,6, 9);
SHA256_EXP(6,7,0,1,2,3,4,5,10); SHA256_EXP(5,6,7,0,1,2,3,4,11);
SHA256_EXP(4,5,6,7,0,1,2,3,12); SHA256_EXP(3,4,5,6,7,0,1,2,13);
SHA256_EXP(2,3,4,5,6,7,0,1,14); SHA256_EXP(1,2,3,4,5,6,7,0,15);
SHA256_EXP(0,1,2,3,4,5,6,7,16); SHA256_EXP(7,0,1,2,3,4,5,6,17);
SHA256_EXP(6,7,0,1,2,3,4,5,18); SHA256_EXP(5,6,7,0,1,2,3,4,19);
SHA256_EXP(4,5,6,7,0,1,2,3,20); SHA256_EXP(3,4,5,6,7,0,1,2,21);
SHA256_EXP(2,3,4,5,6,7,0,1,22); SHA256_EXP(1,2,3,4,5,6,7,0,23);
SHA256_EXP(0,1,2,3,4,5,6,7,24); SHA256_EXP(7,0,1,2,3,4,5,6,25);
SHA256_EXP(6,7,0,1,2,3,4,5,26); SHA256_EXP(5,6,7,0,1,2,3,4,27);
SHA256_EXP(4,5,6,7,0,1,2,3,28); SHA256_EXP(3,4,5,6,7,0,1,2,29);
SHA256_EXP(2,3,4,5,6,7,0,1,30); SHA256_EXP(1,2,3,4,5,6,7,0,31);
SHA256_EXP(0,1,2,3,4,5,6,7,32); SHA256_EXP(7,0,1,2,3,4,5,6,33);
SHA256_EXP(6,7,0,1,2,3,4,5,34); SHA256_EXP(5,6,7,0,1,2,3,4,35);
SHA256_EXP(4,5,6,7,0,1,2,3,36); SHA256_EXP(3,4,5,6,7,0,1,2,37);
SHA256_EXP(2,3,4,5,6,7,0,1,38); SHA256_EXP(1,2,3,4,5,6,7,0,39);
SHA256_EXP(0,1,2,3,4,5,6,7,40); SHA256_EXP(7,0,1,2,3,4,5,6,41);
SHA256_EXP(6,7,0,1,2,3,4,5,42); SHA256_EXP(5,6,7,0,1,2,3,4,43);
SHA256_EXP(4,5,6,7,0,1,2,3,44); SHA256_EXP(3,4,5,6,7,0,1,2,45);
SHA256_EXP(2,3,4,5,6,7,0,1,46); SHA256_EXP(1,2,3,4,5,6,7,0,47);
SHA256_EXP(0,1,2,3,4,5,6,7,48); SHA256_EXP(7,0,1,2,3,4,5,6,49);
SHA256_EXP(6,7,0,1,2,3,4,5,50); SHA256_EXP(5,6,7,0,1,2,3,4,51);
SHA256_EXP(4,5,6,7,0,1,2,3,52); SHA256_EXP(3,4,5,6,7,0,1,2,53);
SHA256_EXP(2,3,4,5,6,7,0,1,54); SHA256_EXP(1,2,3,4,5,6,7,0,55);
SHA256_EXP(0,1,2,3,4,5,6,7,56); SHA256_EXP(7,0,1,2,3,4,5,6,57);
SHA256_EXP(6,7,0,1,2,3,4,5,58); SHA256_EXP(5,6,7,0,1,2,3,4,59);
SHA256_EXP(4,5,6,7,0,1,2,3,60); SHA256_EXP(3,4,5,6,7,0,1,2,61);
SHA256_EXP(2,3,4,5,6,7,0,1,62); SHA256_EXP(1,2,3,4,5,6,7,0,63);
ctx->h[0] += wv[0]; ctx->h[1] += wv[1];
ctx->h[2] += wv[2]; ctx->h[3] += wv[3];
ctx->h[4] += wv[4]; ctx->h[5] += wv[5];
ctx->h[6] += wv[6]; ctx->h[7] += wv[7];
#endif /* !UNROLL_LOOPS */
}
}
void sha256::sha256_init(sha256_ctx * ctx)
{
#ifndef UNROLL_LOOPS
int i;
for (i = 0; i < 8; i++) {
ctx->h[i] = sha256_h0[i];
}
#else
ctx->h[0] = sha256_h0[0]; ctx->h[1] = sha256_h0[1];
ctx->h[2] = sha256_h0[2]; ctx->h[3] = sha256_h0[3];
ctx->h[4] = sha256_h0[4]; ctx->h[5] = sha256_h0[5];
ctx->h[6] = sha256_h0[6]; ctx->h[7] = sha256_h0[7];
#endif /* !UNROLL_LOOPS */
ctx->len = 0;
ctx->tot_len = 0;
}
void sha256::sha256_update(sha256_ctx * ctx, const unsigned char *message,
unsigned int len)
{
unsigned int block_nb;
unsigned int new_len, rem_len, tmp_len;
const unsigned char *shifted_message;
tmp_len = SHA256_BLOCK_SIZE - ctx->len;
rem_len = len < tmp_len ? len : tmp_len;
memcpy(&ctx->block[ctx->len], message, rem_len);
if (ctx->len + len < SHA256_BLOCK_SIZE) {
ctx->len += len;
return;
}
new_len = len - rem_len;
block_nb = new_len / SHA256_BLOCK_SIZE;
shifted_message = message + rem_len;
sha256_transf(ctx, ctx->block, 1);
sha256_transf(ctx, shifted_message, block_nb);
rem_len = new_len % SHA256_BLOCK_SIZE;
memcpy(ctx->block, &shifted_message[block_nb << 6],
rem_len);
ctx->len = rem_len;
ctx->tot_len += (block_nb + 1) << 6;
}
void sha256::sha256_final(sha256_ctx * ctx, unsigned char *digest)
{
unsigned int block_nb;
unsigned int pm_len;
unsigned int len_b;
#ifndef UNROLL_LOOPS
int i;
#endif
block_nb = (1 + ((SHA256_BLOCK_SIZE - 9)
< (ctx->len % SHA256_BLOCK_SIZE)));
len_b = (ctx->tot_len + ctx->len) << 3;
pm_len = block_nb << 6;
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
UNPACK32(len_b, ctx->block + pm_len - 4);
sha256_transf(ctx, ctx->block, block_nb);
#ifndef UNROLL_LOOPS
for (i = 0 ; i < 8; i++) {
UNPACK32(ctx->h[i], &digest[i << 2]);
}
#else
UNPACK32(ctx->h[0], &digest[ 0]);
UNPACK32(ctx->h[1], &digest[ 4]);
UNPACK32(ctx->h[2], &digest[ 8]);
UNPACK32(ctx->h[3], &digest[12]);
UNPACK32(ctx->h[4], &digest[16]);
UNPACK32(ctx->h[5], &digest[20]);
UNPACK32(ctx->h[6], &digest[24]);
UNPACK32(ctx->h[7], &digest[28]);
#endif /* !UNROLL_LOOPS */
}
/* SHA-512 functions */
sha512::sha512() : sha2_base()
{
sha512_init(&ctx);
}
void sha512::sha512_transf(sha512_ctx *ctx, const unsigned char *message,
unsigned int block_nb)
{
uint64 w[80];
uint64 wv[8];
uint64 t1, t2;
const unsigned char *sub_block;
int i, j;
for (i = 0; i < (int) block_nb; i++) {
sub_block = message + (i << 7);
#ifndef UNROLL_LOOPS
for (j = 0; j < 16; j++) {
PACK64(&sub_block[j << 3], &w[j]);
}
for (j = 16; j < 80; j++) {
SHA512_SCR(j);
}
for (j = 0; j < 8; j++) {
wv[j] = ctx->h[j];
}
for (j = 0; j < 80; j++) {
t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
+ sha512_k[j] + w[j];
t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
wv[7] = wv[6];
wv[6] = wv[5];
wv[5] = wv[4];
wv[4] = wv[3] + t1;
wv[3] = wv[2];
wv[2] = wv[1];
wv[1] = wv[0];
wv[0] = t1 + t2;
}
for (j = 0; j < 8; j++) {
ctx->h[j] += wv[j];
}
#else
PACK64(&sub_block[ 0], &w[ 0]); PACK64(&sub_block[ 8], &w[ 1]);
PACK64(&sub_block[ 16], &w[ 2]); PACK64(&sub_block[ 24], &w[ 3]);
PACK64(&sub_block[ 32], &w[ 4]); PACK64(&sub_block[ 40], &w[ 5]);
PACK64(&sub_block[ 48], &w[ 6]); PACK64(&sub_block[ 56], &w[ 7]);
PACK64(&sub_block[ 64], &w[ 8]); PACK64(&sub_block[ 72], &w[ 9]);
PACK64(&sub_block[ 80], &w[10]); PACK64(&sub_block[ 88], &w[11]);
PACK64(&sub_block[ 96], &w[12]); PACK64(&sub_block[104], &w[13]);
PACK64(&sub_block[112], &w[14]); PACK64(&sub_block[120], &w[15]);
SHA512_SCR(16); SHA512_SCR(17); SHA512_SCR(18); SHA512_SCR(19);
SHA512_SCR(20); SHA512_SCR(21); SHA512_SCR(22); SHA512_SCR(23);
SHA512_SCR(24); SHA512_SCR(25); SHA512_SCR(26); SHA512_SCR(27);
SHA512_SCR(28); SHA512_SCR(29); SHA512_SCR(30); SHA512_SCR(31);
SHA512_SCR(32); SHA512_SCR(33); SHA512_SCR(34); SHA512_SCR(35);
SHA512_SCR(36); SHA512_SCR(37); SHA512_SCR(38); SHA512_SCR(39);
SHA512_SCR(40); SHA512_SCR(41); SHA512_SCR(42); SHA512_SCR(43);
SHA512_SCR(44); SHA512_SCR(45); SHA512_SCR(46); SHA512_SCR(47);
SHA512_SCR(48); SHA512_SCR(49); SHA512_SCR(50); SHA512_SCR(51);
SHA512_SCR(52); SHA512_SCR(53); SHA512_SCR(54); SHA512_SCR(55);
SHA512_SCR(56); SHA512_SCR(57); SHA512_SCR(58); SHA512_SCR(59);
SHA512_SCR(60); SHA512_SCR(61); SHA512_SCR(62); SHA512_SCR(63);
SHA512_SCR(64); SHA512_SCR(65); SHA512_SCR(66); SHA512_SCR(67);
SHA512_SCR(68); SHA512_SCR(69); SHA512_SCR(70); SHA512_SCR(71);
SHA512_SCR(72); SHA512_SCR(73); SHA512_SCR(74); SHA512_SCR(75);
SHA512_SCR(76); SHA512_SCR(77); SHA512_SCR(78); SHA512_SCR(79);
wv[0] = ctx->h[0]; wv[1] = ctx->h[1];
wv[2] = ctx->h[2]; wv[3] = ctx->h[3];
wv[4] = ctx->h[4]; wv[5] = ctx->h[5];
wv[6] = ctx->h[6]; wv[7] = ctx->h[7];
j = 0;
do {
SHA512_EXP(0,1,2,3,4,5,6,7,j); j++;
SHA512_EXP(7,0,1,2,3,4,5,6,j); j++;
SHA512_EXP(6,7,0,1,2,3,4,5,j); j++;
SHA512_EXP(5,6,7,0,1,2,3,4,j); j++;
SHA512_EXP(4,5,6,7,0,1,2,3,j); j++;
SHA512_EXP(3,4,5,6,7,0,1,2,j); j++;
SHA512_EXP(2,3,4,5,6,7,0,1,j); j++;
SHA512_EXP(1,2,3,4,5,6,7,0,j); j++;
} while (j < 80);
ctx->h[0] += wv[0]; ctx->h[1] += wv[1];
ctx->h[2] += wv[2]; ctx->h[3] += wv[3];
ctx->h[4] += wv[4]; ctx->h[5] += wv[5];
ctx->h[6] += wv[6]; ctx->h[7] += wv[7];
#endif /* !UNROLL_LOOPS */
}
}
void sha512::sha512_init(sha512_ctx *ctx)
{
#ifndef UNROLL_LOOPS
int i;
for (i = 0; i < 8; i++) {
ctx->h[i] = sha512_h0[i];
}
#else
ctx->h[0] = sha512_h0[0]; ctx->h[1] = sha512_h0[1];
ctx->h[2] = sha512_h0[2]; ctx->h[3] = sha512_h0[3];
ctx->h[4] = sha512_h0[4]; ctx->h[5] = sha512_h0[5];
ctx->h[6] = sha512_h0[6]; ctx->h[7] = sha512_h0[7];
#endif /* !UNROLL_LOOPS */
ctx->len = 0;
ctx->tot_len = 0;
}
void sha512::sha512_update(sha512_ctx *ctx, const unsigned char *message,
unsigned int len)
{
unsigned int block_nb;
unsigned int new_len, rem_len, tmp_len;
const unsigned char *shifted_message;
tmp_len = SHA512_BLOCK_SIZE - ctx->len;
rem_len = len < tmp_len ? len : tmp_len;
memcpy(&ctx->block[ctx->len], message, rem_len);
if (ctx->len + len < SHA512_BLOCK_SIZE) {
ctx->len += len;
return;
}
new_len = len - rem_len;
block_nb = new_len / SHA512_BLOCK_SIZE;
shifted_message = message + rem_len;
sha512_transf(ctx, ctx->block, 1);
sha512_transf(ctx, shifted_message, block_nb);
rem_len = new_len % SHA512_BLOCK_SIZE;
memcpy(ctx->block, &shifted_message[block_nb << 7],
rem_len);
ctx->len = rem_len;
ctx->tot_len += (block_nb + 1) << 7;
}
void sha512::sha512_final(sha512_ctx *ctx, unsigned char *digest)
{
unsigned int block_nb;
unsigned int pm_len;
unsigned int len_b;
#ifndef UNROLL_LOOPS
int i;
#endif
block_nb = 1 + ((SHA512_BLOCK_SIZE - 17)
< (ctx->len % SHA512_BLOCK_SIZE));
len_b = (ctx->tot_len + ctx->len) << 3;
pm_len = block_nb << 7;
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
UNPACK32(len_b, ctx->block + pm_len - 4);
sha512_transf(ctx, ctx->block, block_nb);
#ifndef UNROLL_LOOPS
for (i = 0 ; i < 8; i++) {
UNPACK64(ctx->h[i], &digest[i << 3]);
}
#else
UNPACK64(ctx->h[0], &digest[ 0]);
UNPACK64(ctx->h[1], &digest[ 8]);
UNPACK64(ctx->h[2], &digest[16]);
UNPACK64(ctx->h[3], &digest[24]);
UNPACK64(ctx->h[4], &digest[32]);
UNPACK64(ctx->h[5], &digest[40]);
UNPACK64(ctx->h[6], &digest[48]);
UNPACK64(ctx->h[7], &digest[56]);
#endif /* !UNROLL_LOOPS */
}
/* SHA-384 functions */
sha384::sha384() : sha512()
{
sha384_init(&ctx);
}
void sha384::sha384_init(sha384_ctx *ctx)
{
#ifndef UNROLL_LOOPS
int i;
for (i = 0; i < 8; i++) {
ctx->h[i] = sha384_h0[i];
}
#else
ctx->h[0] = sha384_h0[0]; ctx->h[1] = sha384_h0[1];
ctx->h[2] = sha384_h0[2]; ctx->h[3] = sha384_h0[3];
ctx->h[4] = sha384_h0[4]; ctx->h[5] = sha384_h0[5];
ctx->h[6] = sha384_h0[6]; ctx->h[7] = sha384_h0[7];
#endif /* !UNROLL_LOOPS */
ctx->len = 0;
ctx->tot_len = 0;
}
void sha384::sha384_update(sha384_ctx *ctx,const unsigned char *message,
unsigned int len)
{
unsigned int block_nb;
unsigned int new_len, rem_len, tmp_len;
const unsigned char *shifted_message;
tmp_len = SHA384_BLOCK_SIZE - ctx->len;
rem_len = len < tmp_len ? len : tmp_len;
memcpy(&ctx->block[ctx->len], message, rem_len);
if (ctx->len + len < SHA384_BLOCK_SIZE) {
ctx->len += len;
return;
}
new_len = len - rem_len;
block_nb = new_len / SHA384_BLOCK_SIZE;
shifted_message = message + rem_len;
sha512_transf(ctx, ctx->block, 1);
sha512_transf(ctx, shifted_message, block_nb);
rem_len = new_len % SHA384_BLOCK_SIZE;
memcpy(ctx->block, &shifted_message[block_nb << 7],
rem_len);
ctx->len = rem_len;
ctx->tot_len += (block_nb + 1) << 7;
}
void sha384::sha384_final(sha384_ctx *ctx, unsigned char *digest)
{
unsigned int block_nb;
unsigned int pm_len;
unsigned int len_b;
#ifndef UNROLL_LOOPS
int i;
#endif
block_nb = (1 + ((SHA384_BLOCK_SIZE - 17)
< (ctx->len % SHA384_BLOCK_SIZE)));
len_b = (ctx->tot_len + ctx->len) << 3;
pm_len = block_nb << 7;
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
UNPACK32(len_b, ctx->block + pm_len - 4);
sha512_transf(ctx, ctx->block, block_nb);
#ifndef UNROLL_LOOPS
for (i = 0 ; i < 6; i++) {
UNPACK64(ctx->h[i], &digest[i << 3]);
}
#else
UNPACK64(ctx->h[0], &digest[ 0]);
UNPACK64(ctx->h[1], &digest[ 8]);
UNPACK64(ctx->h[2], &digest[16]);
UNPACK64(ctx->h[3], &digest[24]);
UNPACK64(ctx->h[4], &digest[32]);
UNPACK64(ctx->h[5], &digest[40]);
#endif /* !UNROLL_LOOPS */
}
/* SHA-224 functions */
sha224::sha224() : sha256()
{
sha224_init(&ctx);
}
void sha224::sha224_init(sha224_ctx *ctx)
{
#ifndef UNROLL_LOOPS
int i;
for (i = 0; i < 8; i++) {
ctx->h[i] = sha224_h0[i];
}
#else
ctx->h[0] = sha224_h0[0]; ctx->h[1] = sha224_h0[1];
ctx->h[2] = sha224_h0[2]; ctx->h[3] = sha224_h0[3];
ctx->h[4] = sha224_h0[4]; ctx->h[5] = sha224_h0[5];
ctx->h[6] = sha224_h0[6]; ctx->h[7] = sha224_h0[7];
#endif /* !UNROLL_LOOPS */
ctx->len = 0;
ctx->tot_len = 0;
}
void sha224::sha224_update(sha224_ctx *ctx, const unsigned char *message,
unsigned int len)
{
unsigned int block_nb;
unsigned int new_len, rem_len, tmp_len;
const unsigned char *shifted_message;
tmp_len = SHA224_BLOCK_SIZE - ctx->len;
rem_len = len < tmp_len ? len : tmp_len;
memcpy(&ctx->block[ctx->len], message, rem_len);
if (ctx->len + len < SHA224_BLOCK_SIZE) {
ctx->len += len;
return;
}
new_len = len - rem_len;
block_nb = new_len / SHA224_BLOCK_SIZE;
shifted_message = message + rem_len;
sha256_transf(ctx,ctx->block, 1);
sha256_transf(ctx, shifted_message, block_nb);
rem_len = new_len % SHA224_BLOCK_SIZE;
memcpy(ctx->block, &shifted_message[block_nb << 6],
rem_len);
ctx->len = rem_len;
ctx->tot_len += (block_nb + 1) << 6;
}
void sha224::sha224_final(sha224_ctx *ctx, unsigned char *digest)
{
unsigned int block_nb;
unsigned int pm_len;
unsigned int len_b;
#ifndef UNROLL_LOOPS
int i;
#endif
block_nb = (1 + ((SHA224_BLOCK_SIZE - 9)
< (ctx->len % SHA224_BLOCK_SIZE)));
len_b = (ctx->tot_len + ctx->len) << 3;
pm_len = block_nb << 6;
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
UNPACK32(len_b, ctx->block + pm_len - 4);
sha256_transf(ctx, ctx->block, block_nb);
#ifndef UNROLL_LOOPS
for (i = 0 ; i < 7; i++) {
UNPACK32(ctx->h[i], &digest[i << 2]);
}
#else
UNPACK32(ctx->h[0], &digest[ 0]);
UNPACK32(ctx->h[1], &digest[ 4]);
UNPACK32(ctx->h[2], &digest[ 8]);
UNPACK32(ctx->h[3], &digest[12]);
UNPACK32(ctx->h[4], &digest[16]);
UNPACK32(ctx->h[5], &digest[20]);
UNPACK32(ctx->h[6], &digest[24]);
#endif /* !UNROLL_LOOPS */
}
} // namespace Firebird
#ifdef NIST_COMPLIANCY_TESTS
/* FIPS 180-2 Validation tests */
#include <stdio.h>
#include <stdlib.h>
void test(const char *vector, unsigned char *digest,
unsigned int digest_size)
{
char output[2 * SHA_MAX_DIGEST_SIZE + 1];
int i;
output[2 * digest_size] = '\0';
for (i = 0; i < (int) digest_size ; i++) {
sprintf(output + 2 * i, "%02x", digest[i]);
}
printf("H: %s\n", output);
if (strcmp(vector, output)) {
fprintf(stderr, "Test failed.\n");
exit(EXIT_FAILURE);
}
}
using namespace Firebird;
int main(void)
{
static const char *vectors[4][3] =
{ /* SHA-224 */
{
"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7",
"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525",
"20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67",
},
/* SHA-256 */
{
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",
"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0",
},
/* SHA-384 */
{
"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed"
"8086072ba1e7cc2358baeca134c825a7",
"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712"
"fcc7c71a557e2db966c3e9fa91746039",
"9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b"
"07b8b3dc38ecc4ebae97ddd87f3d8985",
},
/* SHA-512 */
{
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a"
"2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018"
"501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909",
"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"
"de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"
}
};
static const char message1[] = "abc";
static const char message2a[] = "abcdbcdecdefdefgefghfghighijhi"
"jkijkljklmklmnlmnomnopnopq";
static const char message2b[] = "abcdefghbcdefghicdefghijdefghijkefghij"
"klfghijklmghijklmnhijklmnoijklmnopjklm"
"nopqklmnopqrlmnopqrsmnopqrstnopqrstu";
unsigned char *message3;
unsigned int message3_len = 1000000;
unsigned char digest[SHA512_DIGEST_SIZE];
message3 = (unsigned char *) malloc(message3_len);
if (message3 == NULL) {
fprintf(stderr, "Can't allocate memory\n");
return -1;
}
memset(message3, 'a', message3_len);
printf("SHA-2 FIPS 180-2 Validation tests\n\n");
printf("SHA-224 Test vectors\n");
get_digest<sha224>((const unsigned char *) message1, strlen(message1), digest);
test(vectors[0][0], digest, SHA224_DIGEST_SIZE);
get_digest<sha224>((const unsigned char *) message2a, strlen(message2a), digest);
test(vectors[0][1], digest, SHA224_DIGEST_SIZE);
get_digest<sha224>(message3, message3_len, digest);
test(vectors[0][2], digest, SHA224_DIGEST_SIZE);
printf("\n");
printf("SHA-256 Test vectors\n");
get_digest<sha256>((const unsigned char *) message1, strlen(message1), digest);
test(vectors[1][0], digest, SHA256_DIGEST_SIZE);
get_digest<sha256>((const unsigned char *) message2a, strlen(message2a), digest);
test(vectors[1][1], digest, SHA256_DIGEST_SIZE);
get_digest<sha256>(message3, message3_len, digest);
test(vectors[1][2], digest, SHA256_DIGEST_SIZE);
printf("\n");
printf("SHA-384 Test vectors\n");
get_digest<sha384>((const unsigned char *) message1, strlen(message1), digest);
test(vectors[2][0], digest, SHA384_DIGEST_SIZE);
get_digest<sha384>((const unsigned char *)message2b, strlen(message2b), digest);
test(vectors[2][1], digest, SHA384_DIGEST_SIZE);
get_digest<sha384>(message3, message3_len, digest);
test(vectors[2][2], digest, SHA384_DIGEST_SIZE);
printf("\n");
printf("SHA-512 Test vectors\n");
get_digest<sha512>((const unsigned char *) message1, strlen(message1), digest);
test(vectors[3][0], digest, SHA512_DIGEST_SIZE);
get_digest<sha512>((const unsigned char *) message2b, strlen(message2b), digest);
test(vectors[3][1], digest, SHA512_DIGEST_SIZE);
get_digest<sha512>(message3, message3_len, digest);
test(vectors[3][2], digest, SHA512_DIGEST_SIZE);
printf("\n");
printf("All tests passed.\n");
return 0;
}
#endif /* TEST_VECTORS */

276
src/common/sha2/sha2.h Normal file
View File

@ -0,0 +1,276 @@
/*
* FIPS 180-2 SHA-224/256/384/512 implementation
* Last update: 02/02/2007
* Issue date: 04/30/2005
* https://github.com/ouah/sha2
*
* Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* Updated for use in Firebird by Tony Whyman <tony@mwasoftware.co.uk>
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* This update is intended to make available the SHA-2 family of message
* digests as C++ classes for use in Firebird. sha224, sha256, sha384 and
* sha512 are each implemented as separate classes. The class methods are
* intended to be as similar as possible to the legacy class sha1 in order
* to facilitate straightforward replacement.
*
* This implementation also comes with a NIST compliancy test for each
* digest. This is enabled by building with the NIST_COMPLIANCY_TESTS symbol
* defined.
*/
#ifndef _SHA2_H
#define _SHA2_H
#include <string>
#include <string.h>
#ifndef NIST_COMPLIANCY_TESTS
#include "firebird.h"
#include "../../common/classes/alloc.h"
#include "../../common/classes/array.h"
#include "../../common/classes/fb_string.h"
#include "../../common/utils_proto.h"
#endif
#define SHA224_DIGEST_SIZE ( 224 / 8)
#define SHA256_DIGEST_SIZE ( 256 / 8)
#define SHA384_DIGEST_SIZE ( 384 / 8)
#define SHA512_DIGEST_SIZE ( 512 / 8)
#define SHA_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
#define SHA256_BLOCK_SIZE ( 512 / 8)
#define SHA512_BLOCK_SIZE (1024 / 8)
#define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE
#define SHA224_BLOCK_SIZE SHA256_BLOCK_SIZE
namespace Firebird {
/* This template function provides a simple one line means of computing a SHA-2
* digest from an arbitrary length message.
*/
template<class SHA>void get_digest(const unsigned char *message, size_t len, unsigned char *digest)
{
SHA sha;
sha.process(len, message);
sha.getHash(digest);
}
#ifndef NIST_COMPLIANCY_TESTS
/* This template class provides a simple one line means of computing a SHA-2
* digest from an arbitrary length message, and encoding the result in BASE64.
*/
template<class SHA> void hashBased64(Firebird::string& hash, const Firebird::string& data)
{
SHA digest;
digest.process(data.length(), data.c_str());
UCharBuffer b;
digest.getHash(b);
fb_utils::base64(hash, b);
}
/* The sha2_base class is an abstract class that is the ancestor for all
* the SHA-2 classes. It defines all public methods for the classes and
* a common model of use.
*
* When instatiated a SHA-2 class is already initialized for use. The message
* for which a digest is required is then fed to the class using one of
* the "process" methods, either as a single action or accumulatively.
*
* When the entire message has been input, the resulting digest is returned
* by a "getHash" method. Calling "getHash" also clears the digest and
* re-initializes the SHA-2 generator ready to compute a new digest.
*
* A SHA-2 generator can be cleared down and re-initialized at any time
* by calling the "reset" method.
*/
class sha2_base : public GlobalStorage {
#else
class sha2_base {
#endif
public:
sha2_base() {};
virtual ~sha2_base() {};
virtual const unsigned int get_DigestSize()=0;
virtual const unsigned int get_BlockSize()=0;
typedef unsigned char uint8;
typedef unsigned int uint32;
typedef unsigned long long uint64;
protected:
virtual void sha_init() {};
virtual void sha_update(const unsigned char *message, unsigned int len)=0;
virtual void sha_final(unsigned char *digest)=0;
public:
void reset() {sha_init();};
void process(size_t length, const void* bytes)
{
sha_update(static_cast<const unsigned char*>(bytes), length);
}
void process(size_t length, const unsigned char* message)
{
sha_update(message, length);
}
void process(const std::string& str)
{
process(str.length(), str.c_str());
}
void process(const char* str)
{
process(strlen(str), str);
}
void getHash(unsigned char *digest);
#ifndef NIST_COMPLIANCY_TESTS
void process(const UCharBuffer& bytes)
{
process(bytes.getCount(), bytes.begin());
}
void getHash(UCharBuffer& h);
#endif
};
class sha256 : public sha2_base {
public:
sha256();
const unsigned int get_DigestSize() {return SHA256_DIGEST_SIZE;};
const unsigned int get_BlockSize() {return SHA256_BLOCK_SIZE;};
protected:
typedef struct {
unsigned int tot_len;
unsigned int len;
unsigned char block[2 * SHA256_BLOCK_SIZE];
uint32 h[8];
} sha256_ctx;
private:
void sha256_init(sha256_ctx * ctx);
void sha256_update(sha256_ctx *ctx, const unsigned char *message,
unsigned int len);
void sha256_final(sha256_ctx *ctx, unsigned char *digest);
protected:
sha256_ctx ctx;
void sha256_transf(sha256_ctx * ctx, const unsigned char *message,
unsigned int block_nb);
void sha_init() {sha256_init(&ctx);};
void sha_update(const unsigned char *message, unsigned int len) {sha256_update(&ctx,message,len);};
void sha_final(unsigned char *digest) {sha256_final(&ctx,digest);};
};
class sha224 : public sha256 {
public:
sha224();
const unsigned int get_DigestSize() {return SHA224_DIGEST_SIZE;};
const unsigned int get_BlockSize() {return SHA224_BLOCK_SIZE;};
private:
typedef sha256_ctx sha224_ctx;
void sha224_init(sha224_ctx *ctx);
void sha224_update(sha224_ctx *ctx, const unsigned char *message,
unsigned int len);
void sha224_final(sha224_ctx *ctx, unsigned char *digest);
protected:
void sha_init() {sha224_init(&ctx);};
void sha_update(const unsigned char *message, unsigned int len) {sha224_update(&ctx, message, len);};
void sha_final(unsigned char *digest) {sha224_final(&ctx,digest);};
};
class sha512 : public sha2_base {
public:
sha512();
const unsigned int get_DigestSize() {return SHA512_DIGEST_SIZE;};
const unsigned int get_BlockSize() {return SHA512_BLOCK_SIZE;};
protected:
typedef struct {
unsigned int tot_len;
unsigned int len;
unsigned char block[2 * SHA512_BLOCK_SIZE];
uint64 h[8];
} sha512_ctx;
private:
void sha512_init(sha512_ctx *ctx);
void sha512_update(sha512_ctx *ctx, const unsigned char *message,
unsigned int len);
void sha512_final(sha512_ctx *ctx, unsigned char *digest);
protected:
sha512_ctx ctx;
void sha512_transf(sha512_ctx *ctx, const unsigned char *message,
unsigned int block_nb);
void sha_init() {sha512_init(&ctx);};
void sha_update(const unsigned char *message, unsigned int len) {sha512_update(&ctx, message, len);};
void sha_final(unsigned char *digest) {sha512_final(&ctx, digest);};
};
class sha384 : public sha512 {
public:
sha384();
const unsigned int get_DigestSize() {return SHA384_DIGEST_SIZE;};
const unsigned int get_BlockSize() {return SHA384_BLOCK_SIZE;};
private:
typedef sha512_ctx sha384_ctx;
void sha384_init(sha384_ctx *ctx);
void sha384_update(sha384_ctx *ctx, const unsigned char *message,
unsigned int len);
void sha384_final(sha384_ctx *ctx, unsigned char *digest);
protected:
void sha_init() {sha384_init(&ctx);};
void sha_update(const unsigned char *message, unsigned int len) {sha384_update(&ctx,message,len);};
void sha_final(unsigned char *digest) {sha384_final(&ctx, digest);};
};
} //Firebird
#endif /* !_SHA2_H */

View File

@ -29,6 +29,7 @@
#ifndef COMMON_STATUS_H
#define COMMON_STATUS_H
#include "fb_exception.h"
#include "../common/StatusHolder.h"
#include "../common/utils_proto.h"
@ -110,7 +111,24 @@ namespace Firebird
};
typedef LocalStatusWrapper<CheckStatusWrapper> FbLocalStatus;
typedef LocalStatusWrapper<ThrowStatusWrapper> ThrowLocalStatus;
class ThrowWrapper : public BaseStatusWrapper<ThrowWrapper>
{
public:
ThrowWrapper(IStatus* aStatus)
: BaseStatusWrapper(aStatus)
{
}
public:
static void checkException(ThrowWrapper* status)
{
if (status->dirty && (status->getState() & IStatus::STATE_ERRORS))
status_exception::raise(status->status);
}
};
typedef LocalStatusWrapper<ThrowWrapper> ThrowLocalStatus;
}
#endif // COMMON_STATUS_H

View File

@ -63,6 +63,7 @@
#include "../common/StatusArg.h"
#include "../auth/SecureRemotePassword/Message.h"
#include "../jrd/Mapping.h"
#include "../jrd/extds/ExtDS.h"
namespace Jrd {
@ -329,6 +330,7 @@ void defineComputed(DsqlCompilerScratch* dsqlScratch, RelationSourceNode* relati
// Save the size of the field if it is specified.
dsc saveDesc;
saveDesc.dsc_dtype = 0;
bool saveCharSetIdSpecified;
if (field && field->dtype)
{
@ -338,6 +340,7 @@ void defineComputed(DsqlCompilerScratch* dsqlScratch, RelationSourceNode* relati
fb_assert(field->scale <= MAX_SCHAR);
saveDesc.dsc_scale = (SCHAR) field->scale;
saveDesc.dsc_sub_type = field->subType;
saveCharSetIdSpecified = field->charSetId.specified;
field->dtype = 0;
field->length = 0;
@ -373,6 +376,7 @@ void defineComputed(DsqlCompilerScratch* dsqlScratch, RelationSourceNode* relati
if (field->dtype <= dtype_any_text)
{
field->charSetId = DSC_GET_CHARSET(&saveDesc);
field->charSetId.specified = saveCharSetIdSpecified;
field->collationId = DSC_GET_COLLATE(&saveDesc);
}
else
@ -806,7 +810,7 @@ static void updateRdbFields(const TypeClause* type,
if (type->subType == isc_blob_text)
{
characterSetIdNull = FALSE;
characterSetId = type->charSetId;
characterSetId = type->charSetId.value;
collationIdNull = FALSE;
collationId = type->collationId;
@ -833,7 +837,7 @@ static void updateRdbFields(const TypeClause* type,
}
characterSetIdNull = FALSE;
characterSetId = type->charSetId;
characterSetId = type->charSetId.value;
collationIdNull = FALSE;
collationId = type->collationId;
@ -1161,6 +1165,86 @@ void AlterCharSetNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
}
bool AlterEDSPoolSetNode::checkPermission(thread_db* tdbb, jrd_tra* transaction)
{
if (!tdbb->getAttachment()->locksmith(tdbb, MODIFY_EXT_CONN_POOL))
status_exception::raise(Arg::Gds(isc_miss_prvlg) << "MODIFY_EXT_CONN_POOL");
return true;
}
string AlterEDSPoolSetNode::internalPrint(NodePrinter& printer) const
{
DdlNode::internalPrint(printer);
NODE_PRINT(printer, m_param);
NODE_PRINT(printer, m_value);
return "AlterEDSPoolSetNode";
}
void AlterEDSPoolSetNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScratch*/, jrd_tra* /*transaction*/)
{
switch (m_param)
{
case POOL_SIZE:
EDS::Manager::getConnPool()->setMaxCount(m_value);
break;
case POOL_LIFETIME:
EDS::Manager::getConnPool()->setLifeTime(m_value);
break;
default:
status_exception::raise(
Arg::Gds(isc_random) << Arg::Str("Unknown param for ALTER EXTERNAL CONNECTIONS POOL statement"));
}
}
bool AlterEDSPoolClearNode::checkPermission(thread_db* tdbb, jrd_tra* transaction)
{
if (!tdbb->getAttachment()->locksmith(tdbb, MODIFY_EXT_CONN_POOL))
status_exception::raise(Arg::Gds(isc_miss_prvlg) << "MODIFY_EXT_CONN_POOL");
return true;
}
string AlterEDSPoolClearNode::internalPrint(NodePrinter& printer) const
{
DdlNode::internalPrint(printer);
NODE_PRINT(printer, m_param);
NODE_PRINT(printer, m_value);
return "AlterEDSPoolClearNode";
}
void AlterEDSPoolClearNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScratch*/, jrd_tra* /*transaction*/)
{
switch (m_param)
{
case POOL_ALL:
{
EDS::Manager::getConnPool()->clearIdle(tdbb, true);
break;
}
case POOL_OLDEST:
{
EDS::Manager::getConnPool()->clearIdle(tdbb, false);
break;
}
case POOL_DB:
//break;
default:
status_exception::raise(
Arg::Gds(isc_random) << Arg::Str("Unknown param for ALTER EXTERNAL CONNECTIONS POOL statement"));
}
}
//----------------------
@ -4382,6 +4466,9 @@ void AlterDomainNode::checkUpdate(const dyn_fld& origFld, const dyn_fld& newFld)
case blr_d_float:
case blr_double:
case blr_float:
case blr_dec64:
case blr_dec128:
case blr_dec_fixed:
// Cannot convert column %s from character to non-character data.
errorCode = isc_dyn_dtype_conv_invalid;
break;
@ -5024,7 +5111,7 @@ void AlterDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
}
DSC_make_descriptor(&newDom.dyn_dsc, blr_dtypes[type->dtype], type->scale,
typeLength, type->subType, type->charSetId, type->collationId);
typeLength, type->subType, type->charSetId.value, type->collationId);
newDom.dyn_fld_name = name;
newDom.dyn_charbytelen = typeLength;
@ -8877,7 +8964,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
const USHORT adjust =
(desc.dsc_dtype == dtype_varying) ? sizeof(USHORT) : 0;
const USHORT bpc =
METD_get_charset_bpc(dsqlScratch->getTransaction(), newField.charSetId);
METD_get_charset_bpc(dsqlScratch->getTransaction(), newField.charSetId.value);
newField.charLength = (newField.length - adjust) / bpc;
}
@ -10316,7 +10403,7 @@ void MappingNode::addItem(string& ddl, const char* text)
{
ddl += '"';
char c;
while (c = *text++)
while ((c = *text++))
{
ddl += c;
if (c == '"')
@ -11194,6 +11281,119 @@ void GrantRevokeNode::modifyPrivileges(thread_db* tdbb, jrd_tra* transaction, SS
}
static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaName& name, int type)
{
bool rc = false;
switch (type)
{
case obj_procedure:
{
AutoCacheRequest request(tdbb, drq_proc_exist, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
X IN RDB$PROCEDURES
WITH X.RDB$PROCEDURE_NAME EQ name.c_str() AND X.RDB$PACKAGE_NAME MISSING
{
rc = true;
}
END_FOR
break;
}
case obj_udf:
{
AutoCacheRequest request(tdbb, drq_udf_exist, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
X IN RDB$FUNCTIONS
WITH X.RDB$FUNCTION_NAME EQ name.c_str() AND X.RDB$PACKAGE_NAME MISSING
{
rc = true;
}
END_FOR
break;
}
case obj_package_header:
{
AutoCacheRequest request(tdbb, drq_package_exist, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
X IN RDB$PACKAGES
WITH X.RDB$PACKAGE_NAME EQ name.c_str()
{
rc = true;
}
END_FOR
break;
}
case obj_trigger:
{
AutoCacheRequest request(tdbb, drq_trigger_exist, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
X IN RDB$TRIGGERS
WITH X.RDB$TRIGGER_NAME EQ name.c_str()
{
rc = true;
}
END_FOR
break;
}
case obj_relation:
case obj_view:
{
AutoCacheRequest request(tdbb, drq_rel_exist, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
X IN RDB$RELATIONS
WITH X.RDB$RELATION_NAME EQ name.c_str()
{
rc = (type != obj_view) || (X.RDB$RELATION_TYPE == rel_view);
}
END_FOR
break;
}
case obj_exception:
{
AutoCacheRequest request(tdbb, drq_exception_exist, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
X IN RDB$EXCEPTIONS
WITH X.RDB$EXCEPTION_NAME EQ name.c_str()
{
rc = true;
}
END_FOR
break;
}
case obj_generator:
{
AutoCacheRequest request(tdbb, drq_generator_exist, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
X IN RDB$GENERATORS
WITH X.RDB$GENERATOR_NAME EQ name.c_str()
{
rc = true;
}
END_FOR
break;
}
}
return rc;
}
static bool checkFieldExist(thread_db* tdbb, jrd_tra* transaction, const MetaName& relation, const MetaName& field)
{
bool rc = false;
AutoCacheRequest request(tdbb, drq_rel_field_exist, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
X IN RDB$RELATION_FIELDS
WITH X.RDB$RELATION_NAME EQ relation.c_str() AND
X.RDB$FIELD_NAME EQ field.c_str()
{
rc = true;
}
END_FOR
return rc;
}
// Execute SQL grant/revoke operation.
void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const GranteeClause* object,
const GranteeClause* userNod, const char* privs,
@ -11203,6 +11403,7 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
MetaName user(userNod->second);
MetaName dummyName;
const SSHORT objType = object ? object->first : obj_type_MAX;
const MetaName objName(object ? object->second : "");
bool crdb = false;
char privileges[16];
@ -11231,6 +11432,7 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
memmove(cPtr, cPtr + 1, len);
}
// Check if grant object exists
switch (userType)
{
case obj_user_or_role:
@ -11245,12 +11447,36 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
}
}
else
{
userType = obj_user;
}
break;
case obj_user:
// We may grant privilege to non existing user
break;
case obj_udf:
if (!checkObjectExist(tdbb, transaction, user, userType))
status_exception::raise(Arg::PrivateDyn(301) << user.c_str()); // Function @1 does not exist
break;
case obj_procedure:
if (!checkObjectExist(tdbb, transaction, user, userType))
status_exception::raise(Arg::PrivateDyn(302) << user.c_str()); // Procedure @1 does not exist
break;
case obj_package_header:
if (!checkObjectExist(tdbb, transaction, user, userType))
status_exception::raise(Arg::PrivateDyn(303) << user.c_str()); // Package @1 does not exist
break;
case obj_trigger:
if (!checkObjectExist(tdbb, transaction, user, userType))
status_exception::raise(Arg::PrivateDyn(304) << user.c_str()); // Trigger @1 does not exist
break;
case obj_view:
if (!checkObjectExist(tdbb, transaction, user, userType))
status_exception::raise(Arg::PrivateDyn(305) << user.c_str()); // View @1 does not exist
break;
case obj_sql_role:
@ -11275,6 +11501,61 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
}
// Check if grant subject exists
switch (objType)
{
case obj_view:
if (!checkObjectExist(tdbb, transaction, objName, objType))
status_exception::raise(Arg::PrivateDyn(305) << objName.c_str()); // View @1 does not exist
break;
case obj_relation:
if (!checkObjectExist(tdbb, transaction, objName, objType))
status_exception::raise(Arg::PrivateDyn(306) << objName.c_str()); // Table @1 does not exist
if (field.hasData() && !checkFieldExist(tdbb, transaction, objName, field))
status_exception::raise(Arg::PrivateDyn(309) << field.c_str() << objName.c_str()); // Field @1 of table @2 does not exist
break;
case obj_trigger:
if (!checkObjectExist(tdbb, transaction, objName, objType))
status_exception::raise(Arg::PrivateDyn(304) << objName.c_str()); // Trigger @1 does not exist
break;
case obj_procedure:
if (!checkObjectExist(tdbb, transaction, objName, objType))
status_exception::raise(Arg::PrivateDyn(302) << objName.c_str()); // Procedure @1 does not exist
break;
case obj_exception:
if (!checkObjectExist(tdbb, transaction, objName, objType))
status_exception::raise(Arg::PrivateDyn(307) << objName.c_str()); // Exception @1 does not exist
break;
case obj_generator:
if (!checkObjectExist(tdbb, transaction, objName, objType))
status_exception::raise(Arg::PrivateDyn(308) << objName.c_str()); // Generator/Sequence @1 does not exist
break;
case obj_udf:
if (!checkObjectExist(tdbb, transaction, objName, objType))
status_exception::raise(Arg::PrivateDyn(301) << objName.c_str()); // Function @1 does not exist
break;
case obj_package_header:
if (!checkObjectExist(tdbb, transaction, objName, objType))
status_exception::raise(Arg::PrivateDyn(303) << objName.c_str()); // Package @1 does not exist
break;
case obj_sql_role:
if (!isItSqlRole(tdbb, transaction, objName, dummyName))
status_exception::raise(Arg::PrivateDyn(188) << objName.c_str()); // Role doesn't exist.
break;
default:
fb_assert(object == NULL || objType >= obj_database);
}
if (options == 1) // with grant option
{
switch (userType)
@ -11352,8 +11633,6 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
return;
}
const MetaName objName(object->second);
if (objType == obj_sql_role && objName == NULL_ROLE)
{
if (isGrant)
@ -11469,8 +11748,11 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
break;
}
case obj_procedure:
case obj_udf:
case obj_exception:
case obj_generator:
case obj_package_header:
{
checkGrantorCanGrantObject(tdbb, transaction, currentUser.c_str(), priv, objName, objType);
break;
@ -11481,10 +11763,8 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
{
checkGrantorCanGrantDdl(tdbb, transaction, currentUser.c_str(), priv, objName);
}
// Prevent silent eating checks. In this case we can remove RDB$TRIGGER_9 (trigger1)
// but add every object type above in switch
// else
// fb_assert(false);
else
fb_assert(false);
}
}
@ -11612,6 +11892,8 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra
const char* grantor, const char* privilege, const MetaName& relationName,
const MetaName& fieldName, bool topLevel)
{
const Attachment* attachment = tdbb->getAttachment();
// Verify that the input relation exists.
AutoCacheRequest request(tdbb, drq_gcg4, DYN_REQUESTS);
@ -11662,7 +11944,7 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra
// If the current user is locksmith - allow all grants to occur
if (tdbb->getAttachment()->locksmith(tdbb, GRANT_REVOKE_ON_ANY_OBJECT))
if (attachment->locksmith(tdbb, GRANT_REVOKE_ON_ANY_OBJECT))
return;
// If this is a non-sql table, then the owner will probably not have any
@ -11699,32 +11981,35 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
PRV IN RDB$USER_PRIVILEGES WITH
PRV.RDB$USER = UPPERCASE(grantor) AND
PRV.RDB$USER_TYPE = obj_user AND
((PRV.RDB$USER = UPPERCASE(grantor) AND
PRV.RDB$USER_TYPE = obj_user) OR (PRV.RDB$USER_TYPE = obj_sql_role)) AND
PRV.RDB$RELATION_NAME = relationName.c_str() AND
PRV.RDB$OBJECT_TYPE = obj_relation AND
PRV.RDB$PRIVILEGE = privilege
{
if ( (PRV.RDB$USER_TYPE == obj_sql_role) && !attachment->att_user->roleInUse(tdbb, PRV.RDB$USER))
continue;
const bool hasGrantOption = !PRV.RDB$GRANT_OPTION.NULL && PRV.RDB$GRANT_OPTION;
if (PRV.RDB$FIELD_NAME.NULL)
{
if (PRV.RDB$GRANT_OPTION.NULL || !PRV.RDB$GRANT_OPTION)
goRel = 0;
else if (goRel)
if (goRel == -1)
goRel = hasGrantOption ? WITH_GRANT_OPTION : 0;
else if ((goRel == 0) && hasGrantOption)
goRel = WITH_GRANT_OPTION;
}
else
{
if (PRV.RDB$GRANT_OPTION.NULL || !PRV.RDB$GRANT_OPTION)
if (fieldName.hasData() && fieldName == PRV.RDB$FIELD_NAME)
{
if (fieldName.hasData() && fieldName == PRV.RDB$FIELD_NAME)
goFld = 0;
}
else
{
if (fieldName.hasData() && fieldName == PRV.RDB$FIELD_NAME)
goFld = 1;
if (goFld == -1)
goFld = hasGrantOption ? WITH_GRANT_OPTION : 0;
else if ((goFld == 0) && hasGrantOption)
goFld = WITH_GRANT_OPTION;
}
}
if ( (goRel > 0) && (goFld > 0 || !fieldName.hasData()) )
break; // We've found a privilege with grant option and can break the loop
}
END_FOR
@ -11734,7 +12019,7 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra
{
// no grant option for privilege .. on column .. of [base] table/view ..
status_exception::raise(Arg::PrivateDyn(topLevel ? 167 : 168) <<
privilege << fieldName.c_str() << relationName.c_str());
privilegeName(*privilege) << fieldName.c_str() << relationName.c_str());
}
if (goFld == -1)
@ -11743,14 +12028,14 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra
{
// no grant option for privilege .. on [base] table/view .. (for column ..)
status_exception::raise(Arg::PrivateDyn(topLevel ? 169 : 170) <<
privilege << relationName.c_str() << fieldName.c_str());
privilegeName(*privilege) << relationName.c_str() << fieldName.c_str());
}
if (goRel == -1)
{
// no .. privilege with grant option on [base] table/view .. (for column ..)
status_exception::raise(Arg::PrivateDyn(topLevel ? 171 : 172) <<
privilege << relationName.c_str() << fieldName.c_str());
privilegeName(*privilege) << relationName.c_str() << fieldName.c_str());
}
}
}
@ -11759,13 +12044,13 @@ void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra
if (goRel == 0)
{
// no grant option for privilege .. on table/view ..
status_exception::raise(Arg::PrivateDyn(173) << privilege << relationName.c_str());
status_exception::raise(Arg::PrivateDyn(173) << privilegeName(*privilege) << relationName.c_str());
}
if (goRel == -1)
{
// no .. privilege with grant option on table/view ..
status_exception::raise(Arg::PrivateDyn(174) << privilege << relationName.c_str());
status_exception::raise(Arg::PrivateDyn(174) << privilegeName(*privilege) << relationName.c_str());
}
}
@ -11904,15 +12189,19 @@ void GrantRevokeNode::checkGrantorCanGrantDdl(thread_db* tdbb, jrd_tra* transact
{
if ( (PRV.RDB$USER_TYPE == obj_sql_role) && !attachment->att_user->roleInUse(tdbb, PRV.RDB$USER))
continue;
if (PRV.RDB$GRANT_OPTION == WITH_GRANT_OPTION)
{
grantable = true;
break; // We've found a privilege with grant option and can break the loop
}
}
END_FOR
if (!grantable)
{
// no @1 privilege with grant option on DDL @2
status_exception::raise(Arg::PrivateDyn(299) << privilege << objName.c_str());
status_exception::raise(Arg::PrivateDyn(299) << privilegeName(*privilege) << objName.c_str());
}
}
@ -11939,15 +12228,19 @@ void GrantRevokeNode::checkGrantorCanGrantObject(thread_db* tdbb, jrd_tra* trans
{
if ( (PRV.RDB$USER_TYPE == obj_sql_role) && !attachment->att_user->roleInUse(tdbb, PRV.RDB$USER))
continue;
if (PRV.RDB$GRANT_OPTION == WITH_GRANT_OPTION)
{
grantable = true;
break; // We've found a privilege with grant option and can break the loop
}
}
END_FOR
if (!grantable)
{
// no @1 privilege with grant option on object @2
status_exception::raise(Arg::PrivateDyn(300) << privilege << objName.c_str());
status_exception::raise(Arg::PrivateDyn(300) << privilegeName(*privilege) << objName.c_str());
}
}

View File

@ -295,6 +295,65 @@ private:
};
class AlterEDSPoolSetNode : public DdlNode
{
public:
enum PARAM {POOL_SIZE, POOL_LIFETIME};
AlterEDSPoolSetNode(MemoryPool& pool, PARAM prm, int val) :
DdlNode(pool),
m_param(prm),
m_value(val)
{
}
public:
virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction);
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction);
protected:
virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector)
{
// TODO: statusVector << Firebird::Arg::Gds(??);
}
private:
PARAM m_param;
int m_value;
};
class AlterEDSPoolClearNode : public DdlNode
{
public:
enum PARAM {POOL_ALL, POOL_OLDEST, POOL_DB};
AlterEDSPoolClearNode(MemoryPool& pool, PARAM prm, const Firebird::string& val = "") :
DdlNode(pool),
m_param(prm),
m_value(pool)
{
m_value = val;
}
public:
virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction);
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction);
protected:
virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector)
{
// TODO: statusVector << Firebird::Arg::Gds(??);
}
private:
PARAM m_param;
Firebird::string m_value;
};
class CommentOnNode : public DdlNode
{
public:
@ -2231,19 +2290,19 @@ private:
{
switch (UPPER7(symbol))
{
case 'A': return "All";
case 'I': return "Insert";
case 'U': return "Update";
case 'D': return "Delete";
case 'S': return "Select";
case 'X': return "Execute";
case 'G': return "Usage";
case 'M': return "Role";
case 'R': return "Reference";
case 'A': return "ALL";
case 'I': return "INSERT";
case 'U': return "UPDATE";
case 'D': return "DELETE";
case 'S': return "SELECT";
case 'X': return "EXECUTE";
case 'G': return "USAGE";
case 'M': return "ROLE";
case 'R': return "REFERENCE";
// ddl
case 'C': return "Create";
case 'L': return "Alter";
case 'O': return "Drop";
case 'C': return "CREATE";
case 'L': return "ALTER";
case 'O': return "DROP";
}
return "<Unknown>";

View File

@ -656,7 +656,7 @@ private:
// prepare completion interface
AutoPtr<BatchCompletionState, SimpleDispose> completionState
(FB_NEW BatchCompletionState(m_flags & (1 << IBatch::TAG_RECORD_COUNTS), m_detailed));
AutoSetRestore<bool> batchFlag(&req->req_batch, true);
AutoSetRestore<bool> batchFlag(&req->req_batch_mode, true);
const dsql_msg* message = m_request->getStatement()->getSendMsg();
bool startRequest = true;

View File

@ -101,7 +101,7 @@ private:
dsql_req* const m_request;
JBatch* m_batch;
Firebird::RefPtr<Firebird::IMessageMetadata> m_meta;
Firebird::IMessageMetadata* m_meta;
class DataCache : public Firebird::PermanentStorage
{

View File

@ -7722,10 +7722,10 @@ void DerivedFieldNode::setParameterName(dsql_par* parameter) const
while (drvField)
{
if (fieldNode = nodeAs<FieldNode>(drvField->value))
if ((fieldNode = nodeAs<FieldNode>(drvField->value)))
break;
if (dbKeyNode = nodeAs<RecordKeyNode>(drvField->value))
if ((dbKeyNode = nodeAs<RecordKeyNode>(drvField->value)))
break;
drvField = nodeAs<DerivedFieldNode>(drvField->value);

View File

@ -303,7 +303,7 @@ public:
return this;
}
virtual void execute(thread_db* tdbb, dsql_req* request) const = 0;
virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** traHandle) const = 0;
};

View File

@ -1543,7 +1543,7 @@ DeclareSubFuncNode* DeclareSubFuncNode::dsqlPass(DsqlCompilerScratch* dsqlScratc
dsqlFunction->udf_scale = returnType->scale;
dsqlFunction->udf_sub_type = returnType->subType;
dsqlFunction->udf_length = returnType->length;
dsqlFunction->udf_character_set_id = returnType->charSetId;
dsqlFunction->udf_character_set_id = returnType->charSetId.value;
if (dsqlDeterministic)
dsqlSignature.flags |= Signature::FLAG_DETERMINISTIC;
@ -3826,18 +3826,24 @@ const StmtNode* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* r
TRA_attach_request(transaction, request);
tdbb->setTransaction(transaction);
try
{
// run ON TRANSACTION START triggers
JRD_run_trans_start_triggers(tdbb, transaction);
}
catch (Exception&)
{
TRA_attach_request(org_transaction, request);
tdbb->setTransaction(org_transaction);
throw;
}
request->req_auto_trans.push(org_transaction);
impure->traNumber = transaction->tra_number;
const Savepoint* const savepoint = transaction->startSavepoint();
impure->savNumber = savepoint->getNumber();
if (!(attachment->att_flags & ATT_no_db_triggers))
{
// run ON TRANSACTION START triggers
EXE_execute_db_triggers(tdbb, transaction, TRIGGER_TRANS_START);
}
return action;
}
@ -6535,7 +6541,7 @@ const StmtNode* ReceiveNode::execute(thread_db* /*tdbb*/, jrd_req* request, ExeS
switch (request->req_operation)
{
case jrd_req::req_return:
if (!(request->req_batch && batchFlag))
if (!(request->req_batch_mode && batchFlag))
break;
// fall into
@ -8094,18 +8100,18 @@ void SetTransactionNode::genTableLock(DsqlCompilerScratch* dsqlScratch,
//--------------------
void SessionResetNode::execute(thread_db* tdbb, dsql_req* request) const
void SessionResetNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** traHandle) const
{
SET_TDBB(tdbb);
Attachment* const attachment = tdbb->getAttachment();
attachment->resetSession(tdbb);
attachment->resetSession(tdbb, traHandle);
}
//--------------------
void SetRoleNode::execute(thread_db* tdbb, dsql_req* request) const
void SetRoleNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** /*traHandle*/) const
{
SET_TDBB(tdbb);
Attachment* const attachment = tdbb->getAttachment();
@ -8201,7 +8207,7 @@ SetRoundNode::SetRoundNode(MemoryPool& pool, Firebird::MetaName* name)
rndMode = mode->val;
}
void SetRoundNode::execute(thread_db* tdbb, dsql_req* /*request*/) const
void SetRoundNode::execute(thread_db* tdbb, dsql_req* /*request*/, jrd_tra** /*traHandle*/) const
{
SET_TDBB(tdbb);
Attachment* const attachment = tdbb->getAttachment();
@ -8221,7 +8227,7 @@ void SetTrapsNode::trap(Firebird::MetaName* name)
traps |= trap->val;
}
void SetTrapsNode::execute(thread_db* tdbb, dsql_req* /*request*/) const
void SetTrapsNode::execute(thread_db* tdbb, dsql_req* /*request*/, jrd_tra** /*traHandle*/) const
{
SET_TDBB(tdbb);
Attachment* const attachment = tdbb->getAttachment();
@ -8232,7 +8238,7 @@ void SetTrapsNode::execute(thread_db* tdbb, dsql_req* /*request*/) const
//--------------------
void SetBindNode::execute(thread_db* tdbb, dsql_req* /*request*/) const
void SetBindNode::execute(thread_db* tdbb, dsql_req* /*request*/, jrd_tra** /*traHandle*/) const
{
SET_TDBB(tdbb);
Attachment* const attachment = tdbb->getAttachment();
@ -8291,7 +8297,7 @@ string SetSessionNode::internalPrint(NodePrinter& printer) const
return "SetSessionNode";
}
void SetSessionNode::execute(thread_db* tdbb, dsql_req* request) const
void SetSessionNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** /*traHandle*/) const
{
Attachment* att = tdbb->getAttachment();
@ -9622,8 +9628,7 @@ static void preprocessAssignments(thread_db* tdbb, CompilerScratch* csb,
while (true)
{
if (assignToField->fieldStream == stream &&
relation->rel_fields &&
(fld = (*relation->rel_fields)[fieldId]))
(fld = MET_get_field(relation, fieldId)))
{
if (insertOverride && fld->fld_identity_type.specified)
{

View File

@ -1586,7 +1586,7 @@ public:
return "SessionResetNode";
}
virtual void execute(thread_db* tdbb, dsql_req* request) const;
virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** traHandle) const;
};
@ -1618,7 +1618,7 @@ public:
return "SetRoleNode";
}
virtual void execute(thread_db* tdbb, dsql_req* request) const;
virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** traHandle) const;
public:
bool trusted;
@ -1635,7 +1635,7 @@ public:
public:
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual void execute(thread_db* tdbb, dsql_req* request) const;
virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** traHandle) const;
private:
Type m_type;
@ -1658,7 +1658,7 @@ public:
return "SetRoundNode";
}
virtual void execute(thread_db* tdbb, dsql_req* request) const;
virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** traHandle) const;
public:
USHORT rndMode;
@ -1684,7 +1684,7 @@ public:
return "SetTrapsNode";
}
virtual void execute(thread_db* tdbb, dsql_req* request) const;
virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** traHandle) const;
void trap(Firebird::MetaName* name);
@ -1712,7 +1712,7 @@ public:
return "SetBindNode";
}
virtual void execute(thread_db* tdbb, dsql_req* request) const;
virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** traHandle) const;
public:
Firebird::DecimalBinding bind;

View File

@ -211,7 +211,7 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field,
if (field->dtype <= dtype_any_text ||
(field->dtype == dtype_blob && field->subType == isc_blob_text))
{
field->charSet = METD_get_charset_name(dsqlScratch->getTransaction(), field->charSetId);
field->charSet = METD_get_charset_name(dsqlScratch->getTransaction(), field->charSetId.value);
}
}
@ -269,7 +269,7 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field,
return;
}
if (field->charSetId != 0 && collation_name.isEmpty())
if (field->charSetId.specified && collation_name.isEmpty())
{
// This field has already been resolved once, and the collation
// hasn't changed. Therefore, no need to do it again.
@ -296,7 +296,7 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field,
if (afield)
{
field->charSetId = afield->charSetId;
bpc = METD_get_charset_bpc(dsqlScratch->getTransaction(), field->charSetId);
bpc = METD_get_charset_bpc(dsqlScratch->getTransaction(), field->charSetId.value);
field->collationId = afield->collationId;
field->textType = afield->textType;
@ -310,7 +310,7 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field,
}
}
if (!(field->charSet.hasData() || field->charSetId || // set if a domain
if (!(field->charSet.hasData() || field->charSetId.specified || // set if a domain
(field->flags & FLD_national)))
{
// Attach the database default character set, if not otherwise specified
@ -371,7 +371,7 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field,
if (collation_name.hasData())
{
const dsql_intlsym* resolved_collation = METD_get_collation(dsqlScratch->getTransaction(),
collation_name, field->charSetId);
collation_name, field->charSetId.value);
if (!resolved_collation)
{
@ -382,7 +382,7 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field,
else
{
charSetName = METD_get_charset_name(dsqlScratch->getTransaction(),
field->charSetId);
field->charSetId.value);
}
// Specified collation not found
@ -396,8 +396,8 @@ void DDL_resolve_intl_type(DsqlCompilerScratch* dsqlScratch, dsql_fld* field,
resolved_type = resolved_collation;
if ((field->charSetId != resolved_type->intlsym_charset_id) &&
(field->charSetId != ttype_dynamic))
if ((field->charSetId.value != resolved_type->intlsym_charset_id) &&
(field->charSetId.value != ttype_dynamic))
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) <<
Arg::Gds(isc_dsql_datatype_err) <<

View File

@ -948,7 +948,7 @@ void DsqlSessionManagementRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
Firebird::IMessageMetadata* outMetadata, UCHAR* outMsg,
bool singleton)
{
node->execute(tdbb, this);
node->execute(tdbb, this, traHandle);
}
@ -1654,11 +1654,11 @@ void dsql_req::setTimeout(unsigned int timeOut)
TimeoutTimer* dsql_req::setupTimer(thread_db* tdbb)
{
if (statement->getFlags() & JrdStatement::FLAG_INTERNAL)
return req_timer;
if (req_request)
{
if (req_request->getStatement()->flags & JrdStatement::FLAG_INTERNAL)
return req_timer;
req_request->req_timeout = this->req_timeout;
fb_assert(!req_request->req_caller);

View File

@ -213,7 +213,6 @@ public:
segLength(0),
precision(0),
charLength(0),
charSetId(0),
collationId(0),
textType(0),
fullDomain(false),
@ -274,7 +273,7 @@ public:
USHORT segLength; // Segment length for blobs
USHORT precision; // Precision for exact numeric types
USHORT charLength; // Length of field in characters
SSHORT charSetId;
Nullable<SSHORT> charSetId;
SSHORT collationId;
SSHORT textType;
bool fullDomain; // Domain name without TYPE OF prefix

View File

@ -204,11 +204,8 @@ static void internal_post(const Arg::StatusVector& v)
final << v;
}
// keep existing warnings
final << Arg::StatusVector(status_vector->getWarnings());
// save & punt
final.copyTo(status_vector);
status_vector->setErrors2(final.length(), final.value());
ERRD_punt();
}

View File

@ -264,7 +264,7 @@ void MAKE_desc_from_field(dsc* desc, const dsql_fld* field)
desc->dsc_flags = (field->flags & FLD_nullable) ? DSC_nullable : 0;
if (desc->isText() || desc->isBlob())
desc->setTextType(INTL_CS_COLL_TO_TTYPE(field->charSetId, field->collationId));
desc->setTextType(INTL_CS_COLL_TO_TTYPE(field->charSetId.value, field->collationId));
}

View File

@ -568,7 +568,7 @@ bool METD_get_domain(jrd_tra* transaction, TypeClause* field, const MetaName& na
field->subType = FLX.RDB$FIELD_SUB_TYPE;
field->dimensions = FLX.RDB$DIMENSIONS.NULL ? 0 : FLX.RDB$DIMENSIONS;
field->charSetId = 0;
field->charSetId = Nullable<SSHORT>::empty();
if (!FLX.RDB$CHARACTER_SET_ID.NULL)
field->charSetId = FLX.RDB$CHARACTER_SET_ID;
field->collationId = 0;

View File

@ -631,6 +631,13 @@ using namespace Firebird;
%token <metaNamePtr> WINDOW
%token <metaNamePtr> CONSISTENCY
// external connections pool management
%token <metaNamePtr> CONNECTIONS
%token <metaNamePtr> POOL
%token <metaNamePtr> LIFETIME
%token <metaNamePtr> CLEAR
%token <metaNamePtr> OLDEST
// precedence declarations for expression evaluation
%left OR
@ -1973,6 +1980,29 @@ alter_charset_clause
{ $$ = newNode<AlterCharSetNode>(*$1, *$5); }
;
//
%type <ddlNode> alter_eds_conn_pool_clause
alter_eds_conn_pool_clause
: SET SIZE unsigned_short_integer
{ $$ = newNode<AlterEDSPoolSetNode>(AlterEDSPoolSetNode::POOL_SIZE, $3); }
| SET LIFETIME unsigned_short_integer eds_pool_lifetime_mult
{ $$ = newNode<AlterEDSPoolSetNode>(AlterEDSPoolSetNode::POOL_LIFETIME, $3 * $4); }
| CLEAR sql_string
{ $$ = newNode<AlterEDSPoolClearNode>(AlterEDSPoolClearNode::POOL_DB, $2->getString()); }
| CLEAR ALL
{ $$ = newNode<AlterEDSPoolClearNode>(AlterEDSPoolClearNode::POOL_ALL); }
| CLEAR OLDEST
{ $$ = newNode<AlterEDSPoolClearNode>(AlterEDSPoolClearNode::POOL_OLDEST); }
;
%type <intVal> eds_pool_lifetime_mult
eds_pool_lifetime_mult :
HOUR { $$ = 3600; }
| MINUTE { $$ = 60; }
| SECOND { $$ = 1; }
;
// CREATE DATABASE
// ASF: CREATE DATABASE command is divided in three pieces: name, initial options and
// remote options.
@ -3874,6 +3904,7 @@ alter_clause
| SEQUENCE alter_sequence_clause { $$ = $2; }
| MAPPING alter_map_clause(false) { $$ = $2; }
| GLOBAL MAPPING alter_map_clause(true) { $$ = $3; }
| EXTERNAL CONNECTIONS POOL alter_eds_conn_pool_clause { $$ = $4; }
;
%type <alterDomainNode> alter_domain
@ -8528,6 +8559,11 @@ non_reserved_word
| TIES
| TOTALORDER
| TRAPS
| CONNECTIONS // external connections pool management
| POOL
| LIFETIME
| CLEAR
| OLDEST
| CONSISTENCY
;

View File

@ -243,6 +243,9 @@ void C_CXX_action(const act* action, int column)
case ACT_update:
case ACT_statistics:
begin(column);
default:
break;
}
switch (action->act_type)
@ -658,7 +661,7 @@ static void asgn_to( const act* action, ref* reference, int column)
// Pick up NULL value if one is there
if (reference = reference->ref_null)
if ((reference = reference->ref_null))
{
align(column);
fprintf(gpreGlob.out_file, "%s = %s;", reference->ref_value,
@ -687,7 +690,7 @@ static void asgn_to( const act* action, ref* reference, int column)
// Pick up NULL value if one is there
if (reference = reference->ref_null)
if ((reference = reference->ref_null))
{
align(column);
fprintf(gpreGlob.out_file, "%s = %s;", reference->ref_value, gen_name(s, reference, true));
@ -1049,7 +1052,7 @@ static void gen_blob_open( const act* action, USHORT column)
fprintf(gpreGlob.out_file, "%s = %s;", s, reference->ref_value);
}
if (args.pat_value1 = blob->blb_bpb_length)
if ((args.pat_value1 = blob->blb_bpb_length))
PATTERN_expand(column, pattern1, &args);
else
PATTERN_expand(column, pattern2, &args);

View File

@ -440,6 +440,9 @@ void CME_expr(gpre_nod* node, gpre_req* request)
request->add_long(1);
CME_expr(node->nod_arg[2], request);
return;
default:
break;
}
const op_table* nod2blr_operator;
@ -485,6 +488,9 @@ void CME_expr(gpre_nod* node, gpre_req* request)
CME_rse(node->nod_arg[0], request);
CME_expr(node->nod_arg[1], request);
CME_expr(node->nod_arg[2], request);
default:
break;
}
}
@ -1154,7 +1160,7 @@ void CME_relation(gpre_ctx* context, gpre_req* request)
}
request->add_byte(context->ctx_internal);
}
else if (procedure = context->ctx_procedure)
else if ((procedure = context->ctx_procedure))
{
if (gpreGlob.sw_ids)
{
@ -1217,7 +1223,7 @@ void CME_rse(gpre_rse* selection, gpre_req* request)
cmp_map(sub_rse->rse_map, request);
}
}
else if (sub_rse = selection->rse_aggregate)
else if ((sub_rse = selection->rse_aggregate))
{
request->add_byte(1);
request->add_byte(blr_aggregate);
@ -1286,7 +1292,7 @@ void CME_rse(gpre_rse* selection, gpre_req* request)
}
}
if (temp = selection->rse_reduced)
if ((temp = selection->rse_reduced))
{
request->add_byte(blr_project);
request->add_byte(temp->nod_count);
@ -1295,7 +1301,7 @@ void CME_rse(gpre_rse* selection, gpre_req* request)
CME_expr(*ptr++, request);
}
if (temp = selection->rse_plan)
if ((temp = selection->rse_plan))
{
request->add_byte(blr_plan);
cmp_plan(temp, request);
@ -1762,6 +1768,9 @@ static void cmp_plan(const gpre_nod* plan_expression, gpre_req* request)
}
break;
}
default:
break;
}
}
}
@ -2147,6 +2156,9 @@ static void get_dtype_of_case(const gpre_nod* node, gpre_fld* f)
get_dtype_of_list(args, f);
MSC_free(args);
break;
default:
break;
}
}

View File

@ -388,7 +388,8 @@ int main(int argc, char* argv[])
TEXT spare_file_name[MAXPATHLEN];
if (gpreGlob.sw_language == lang_undef)
for (const ext_table_t* ext_tab = dml_ext_table;
gpreGlob.sw_language = ext_tab->ext_language; ext_tab++)
(gpreGlob.sw_language = ext_tab->ext_language);
ext_tab++)
{
strcpy(spare_file_name, file_name);
if (!file_rename(spare_file_name, ext_tab->in, NULL))
@ -400,7 +401,8 @@ int main(int argc, char* argv[])
if (gpreGlob.sw_language == lang_undef)
for (const ext_table_t* ext_tab = dml_ext_table;
gpreGlob.sw_language = ext_tab->ext_language; ext_tab++)
(gpreGlob.sw_language = ext_tab->ext_language);
ext_tab++)
{
strcpy(spare_file_name, file_name);
if (file_rename(spare_file_name, ext_tab->in, NULL) &&
@ -799,7 +801,7 @@ int main(int argc, char* argv[])
{
out_file_name = spare_out_file_name;
strcpy(spare_out_file_name, file_name);
if (renamed = file_rename(spare_out_file_name, out_src_ext_tab->in, out_src_ext_tab->out))
if ((renamed = file_rename(spare_out_file_name, out_src_ext_tab->in, out_src_ext_tab->out)))
{
explicitt = false;
}
@ -842,7 +844,7 @@ int main(int argc, char* argv[])
try {
SLONG end_position = 0;
while (end_position = compile_module(end_position, filename_array[3]))
while ((end_position = compile_module(end_position, filename_array[3])))
; // empty loop body
} // try
catch (const Firebird::Exception&) {} // fall through to the cleanup code

View File

@ -103,6 +103,8 @@ void INT_CXX_action( const act* action, int column)
case ACT_s_start:
begin(column);
align(column);
default:
break;
}
switch (action->act_type)

View File

@ -264,7 +264,7 @@ void MSC_init()
free_lls = NULL;
gpre_space* stuff;
while (stuff = space)
while ((stuff = space))
{
space = space->spc_next;
gds__free(stuff);

View File

@ -907,6 +907,10 @@ static const struct {
{"vld_plugins", 335545203},
{"db_crypt_key", 335545204},
{"no_keyholder_plugin", 335545205},
{"ses_reset_err", 335545206},
{"ses_reset_open_trans", 335545207},
{"ses_reset_warn", 335545208},
{"ses_reset_tran_rollback", 335545209},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},

View File

@ -941,6 +941,10 @@ const ISC_STATUS isc_hdr_overflow = 335545202L;
const ISC_STATUS isc_vld_plugins = 335545203L;
const ISC_STATUS isc_db_crypt_key = 335545204L;
const ISC_STATUS isc_no_keyholder_plugin = 335545205L;
const ISC_STATUS isc_ses_reset_err = 335545206L;
const ISC_STATUS isc_ses_reset_open_trans = 335545207L;
const ISC_STATUS isc_ses_reset_warn = 335545208L;
const ISC_STATUS isc_ses_reset_tran_rollback = 335545209L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@ -1415,7 +1419,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
const ISC_STATUS isc_err_max = 1359;
const ISC_STATUS isc_err_max = 1363;
#else /* c definitions */
@ -2326,6 +2330,10 @@ const ISC_STATUS isc_err_max = 1359;
#define isc_vld_plugins 335545203L
#define isc_db_crypt_key 335545204L
#define isc_no_keyholder_plugin 335545205L
#define isc_ses_reset_err 335545206L
#define isc_ses_reset_open_trans 335545207L
#define isc_ses_reset_warn 335545208L
#define isc_ses_reset_tran_rollback 335545209L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
@ -2800,7 +2808,7 @@ const ISC_STATUS isc_err_max = 1359;
#define isc_trace_switch_param_miss 337182758L
#define isc_trace_param_act_notcompat 337182759L
#define isc_trace_mandatory_switch_miss 337182760L
#define isc_err_max 1359
#define isc_err_max 1363
#endif

View File

@ -910,6 +910,10 @@ Data source : @4"}, /* eds_statement */
{335545203, "No matching client/server authentication plugins configured for execute statement in embedded datasource"}, /* vld_plugins */
{335545204, "Missing database encryption key for your attachment"}, /* db_crypt_key */
{335545205, "Key holder plugin @1 failed to load"}, /* no_keyholder_plugin */
{335545206, "Cannot reset user session"}, /* ses_reset_err */
{335545207, "There are open transactions (@1 active)"}, /* ses_reset_open_trans */
{335545208, "Session was reset with warning(s)"}, /* ses_reset_warn */
{335545209, "Transaction is rolled back due to session reset, all changes are lost"}, /* ses_reset_tran_rollback */
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */

View File

@ -906,6 +906,10 @@ static const struct {
{335545203, -901}, /* 883 vld_plugins */
{335545204, -902}, /* 884 db_crypt_key */
{335545205, -104}, /* 885 no_keyholder_plugin */
{335545206, -901}, /* 886 ses_reset_err */
{335545207, -901}, /* 887 ses_reset_open_trans */
{335545208, -901}, /* 888 ses_reset_warn */
{335545209, -901}, /* 889 ses_reset_tran_rollback */
{335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */

View File

@ -906,6 +906,10 @@ static const struct {
{335545203, "28000"}, // 883 vld_plugins
{335545204, "08004"}, // 884 db_crypt_key
{335545205, "HY024"}, // 885 no_keyholder_plugin
{335545206, "01002"}, // 886 ses_reset_err
{335545207, "25S02"}, // 887 ses_reset_open_trans
{335545208, "01000"}, // 888 ses_reset_warn
{335545209, "01102"}, // 889 ses_reset_tran_rollback
{335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw

View File

@ -633,8 +633,8 @@ static bool extract_rel_constraints(const char* relation_name)
isqlGlob.printf("UNIQUE (%s)", collist);
// Yes, the same RDB$... naming convention is used for both domains and indices.
const bool explicit_index = (isPK && !fb_utils::implicit_pk(IDX.RDB$INDEX_NAME) ||
!isPK && !fb_utils::implicit_domain(IDX.RDB$INDEX_NAME)) &&
const bool explicit_index = ((isPK && !fb_utils::implicit_pk(IDX.RDB$INDEX_NAME)) ||
(!isPK && !fb_utils::implicit_domain(IDX.RDB$INDEX_NAME))) &&
strcmp(RELC.RDB$CONSTRAINT_NAME, IDX.RDB$INDEX_NAME);
const bool descending_index = !IDX.RDB$INDEX_TYPE.NULL && IDX.RDB$INDEX_TYPE == 1;
if (explicit_index || descending_index)

View File

@ -3529,7 +3529,7 @@ static bool check_date(const tm& times)
return false;
if (m < 1 || m > 12)
return false;
const bool leap = y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
const bool leap = (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
const int days[] = {0, 31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (d < 1 || d > days[m])
return false;
@ -5267,7 +5267,7 @@ static processing_state get_statement(Firebird::string& statement,
TEXT con_prompt[MSG_LENGTH];
IUTILS_msg_get(CON_PROMPT, con_prompt);
if (Interactive && !Input_file || setValues.Echo) {
if ((Interactive && !Input_file) || setValues.Echo) {
ISQL_prompt(statement_prompt);
}
@ -5334,7 +5334,7 @@ static processing_state get_statement(Firebird::string& statement,
Filelist->removeIntoIfp();
if (Interactive && !Input_file || setValues.Echo)
if ((Interactive && !Input_file) || setValues.Echo)
ISQL_prompt(statement_prompt);
// CVC: Let's detect if we went back to the first level.
@ -5365,7 +5365,7 @@ static processing_state get_statement(Firebird::string& statement,
}
// If in a comment, keep reading
if (Interactive && !Input_file || setValues.Echo)
if ((Interactive && !Input_file) || setValues.Echo)
{
if (state == in_block_comment)
{
@ -6221,15 +6221,15 @@ static processing_state newdb(TEXT* dbname,
}
FB_SIZE_T l;
if (l = fb_strlen(local_usr)) {
if ((l = fb_strlen(local_usr))) {
dpb.insertString(isc_dpb_user_name, local_usr, l);
}
if (l = fb_strlen(local_psw)) {
if ((l = fb_strlen(local_psw))) {
dpb.insertString(isc_dpb_password, local_psw, l);
}
if (l = fb_strlen(local_sql_role))
if ((l = fb_strlen(local_sql_role)))
{
dpb.insertInt(isc_dpb_sql_dialect, isqlGlob.SQL_dialect);
dpb.insertString(isc_dpb_sql_role_name, local_sql_role, l);
@ -6861,6 +6861,8 @@ static processing_state parse_arg(int argc, SCHAR** argv, SCHAR* tabname)
IUTILS_msg_get(EMPTY_PASS, errbuf, SafeArg() << swarg_str);
// empty password file @1
break;
default:
break;
}
STDERROUT(errbuf);
ret = ps_ERR;
@ -8564,8 +8566,8 @@ static processing_state process_statement(const TEXT* str2)
// command-line ISQL only.
if (printHead &&
(Pagelength && (lines % Pagelength == 0) ||
!Pagelength && !lines) )
((Pagelength && (lines % Pagelength == 0)) ||
(!Pagelength && !lines)))
{
isqlGlob.printf("%s%s%s%s%s",
NEWLINE,

View File

@ -136,9 +136,9 @@ public:
} // anonymous namespace
static int ISQL_vax_integer(const UCHAR* bytes, USHORT length)
static SINT64 ISQL_vax_integer(const UCHAR* bytes, USHORT length)
{
return isc_vax_integer((const char*)bytes, length);
return isc_portable_integer(bytes, length);
}
@ -403,7 +403,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle,
SCHAR* info = info_buf;
for (const UCHAR* d = buffer; *d != isc_info_end;)
{
SLONG value_out = 0;
SINT64 value_out = 0;
const UCHAR item = *d++;
const int length = ISQL_vax_integer(d, 2);
d += 2;
@ -420,7 +420,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle,
case isc_info_page_size:
value_out = ISQL_vax_integer(d, length);
sprintf(info, "PAGE_SIZE %" SLONGFORMAT"%s", value_out, separator);
sprintf(info, "PAGE_SIZE %" SQUADFORMAT"%s", value_out, separator);
break;
case isc_info_db_size_in_pages:
@ -431,7 +431,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle,
sprintf(info, "%s%s", msg, separator);
}
else
sprintf(info, "Number of DB pages allocated = %" SLONGFORMAT"%s", value_out, separator);
sprintf(info, "Number of DB pages allocated = %" SQUADFORMAT"%s", value_out, separator);
break;
case fb_info_pages_used:
@ -442,7 +442,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle,
sprintf(info, "%s%s", msg, separator);
}
else
sprintf(info, "Number of DB pages used = %" SLONGFORMAT"%s", value_out, separator);
sprintf(info, "Number of DB pages used = %" SQUADFORMAT"%s", value_out, separator);
break;
case fb_info_pages_free:
@ -453,7 +453,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle,
sprintf(info, "%s%s", msg, separator);
}
else
sprintf(info, "Number of DB pages free = %" SLONGFORMAT"%s", value_out, separator);
sprintf(info, "Number of DB pages free = %" SQUADFORMAT"%s", value_out, separator);
break;
case fb_info_crypt_state:
@ -495,7 +495,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle,
sprintf(info, "%s%s", msg, separator);
}
else
sprintf(info, "Sweep interval = %" SLONGFORMAT"%s", value_out, separator);
sprintf(info, "Sweep interval = %" SQUADFORMAT"%s", value_out, separator);
break;
case isc_info_forced_writes:
@ -505,22 +505,22 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle,
case isc_info_oldest_transaction :
value_out = ISQL_vax_integer (d, length);
sprintf(info, "Transaction - oldest = %" SLONGFORMAT"%s", value_out, separator);
sprintf(info, "Transaction - oldest = %" SQUADFORMAT"%s", value_out, separator);
break;
case isc_info_oldest_active :
value_out = ISQL_vax_integer (d, length);
sprintf(info, "Transaction - oldest active = %" SLONGFORMAT"%s", value_out, separator);
sprintf(info, "Transaction - oldest active = %" SQUADFORMAT"%s", value_out, separator);
break;
case isc_info_oldest_snapshot :
value_out = ISQL_vax_integer (d, length);
sprintf(info, "Transaction - oldest snapshot = %" SLONGFORMAT"%s", value_out, separator);
sprintf(info, "Transaction - oldest snapshot = %" SQUADFORMAT"%s", value_out, separator);
break;
case isc_info_next_transaction :
value_out = ISQL_vax_integer (d, length);
sprintf (info, "Transaction - Next = %" SLONGFORMAT"%s", value_out, separator);
sprintf (info, "Transaction - Next = %" SQUADFORMAT"%s", value_out, separator);
break;
case isc_info_base_level:
@ -531,7 +531,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle,
sprintf(info, "%s%s", msg, separator);
}
else
sprintf(info, "Base level = %" SLONGFORMAT"%s", value_out, separator);
sprintf(info, "Base level = %" SQUADFORMAT"%s", value_out, separator);
break;
case isc_info_limbo:
@ -542,7 +542,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle,
sprintf(info, "%s%s", msg, separator);
}
else
sprintf(info, "Transaction in limbo = %" SLONGFORMAT"%s", value_out, separator);
sprintf(info, "Transaction in limbo = %" SQUADFORMAT"%s", value_out, separator);
break;
case isc_info_ods_version:
@ -550,7 +550,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle,
break;
case isc_info_ods_minor_version:
value_out = ISQL_vax_integer(d, length);
sprintf(info, "ODS = %" SLONGFORMAT".%" SLONGFORMAT"%s",
sprintf(info, "ODS = %" SLONGFORMAT".%" SQUADFORMAT"%s",
(SLONG) isqlGlob.major_ods, value_out, separator);
break;
@ -2951,8 +2951,8 @@ static processing_state show_collations(const SCHAR* object, SSHORT sys_flag, co
fb_utils::exact_name(CL.RDB$COLLATION_NAME);
if ((!*object &&
(!CL.RDB$SYSTEM_FLAG.NULL && CL.RDB$SYSTEM_FLAG != 0 && sys_flag != 0 ||
!(!CL.RDB$SYSTEM_FLAG.NULL && CL.RDB$SYSTEM_FLAG != 0) && sys_flag != 1)) ||
((!CL.RDB$SYSTEM_FLAG.NULL && CL.RDB$SYSTEM_FLAG != 0 && sys_flag != 0) ||
(!(!CL.RDB$SYSTEM_FLAG.NULL && CL.RDB$SYSTEM_FLAG != 0) && sys_flag != 1))) ||
strcmp(CL.RDB$COLLATION_NAME, object) == 0)
{
if (!found)
@ -3676,7 +3676,7 @@ static processing_state show_dependencies(const char* object, int obj_type)
END_ERROR;
bool missing3 = true;
if (obj_type == obj_relation && is_table || obj_type == obj_view && !is_table)
if ((obj_type == obj_relation && is_table) || (obj_type == obj_view && !is_table))
{
FOR RFR IN RDB$RELATION_FIELDS
CROSS FLD IN RDB$FIELDS
@ -5722,7 +5722,7 @@ static processing_state show_table(const SCHAR* relation_name, bool isView)
isqlGlob.printf("External file: %s%s", REL.RDB$EXTERNAL_FILE, NEWLINE);
}
first = false;
if (isView && REL.RDB$VIEW_BLR.NULL || !isView && !REL.RDB$VIEW_BLR.NULL)
if ((isView && REL.RDB$VIEW_BLR.NULL) || (!isView && !REL.RDB$VIEW_BLR.NULL))
first = true;
END_FOR
ON_ERROR
@ -5962,8 +5962,8 @@ static processing_state show_table(const SCHAR* relation_name, bool isView)
WITH IDX.RDB$INDEX_NAME = RELC1.RDB$INDEX_NAME
// Yes, the same RDB$... naming convention is used for both domains and indices.
const bool explicit_index =
(isPK && !fb_utils::implicit_pk(IDX.RDB$INDEX_NAME) ||
isUK && !fb_utils::implicit_domain(RELC1.RDB$INDEX_NAME)) &&
((isPK && !fb_utils::implicit_pk(IDX.RDB$INDEX_NAME)) ||
(isUK && !fb_utils::implicit_domain(RELC1.RDB$INDEX_NAME))) &&
strcmp(RELC1.RDB$CONSTRAINT_NAME, RELC1.RDB$INDEX_NAME);
const bool descending_index = !IDX.RDB$INDEX_TYPE.NULL && IDX.RDB$INDEX_TYPE == 1;
if (explicit_index || descending_index)

View File

@ -197,6 +197,7 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb)
att_dsql_cache(*pool),
att_udf_pointers(*pool),
att_ext_connection(NULL),
att_ext_parent(NULL),
att_ext_call_depth(0),
att_trace_manager(FB_NEW_POOL(*att_pool) TraceManager(this)),
att_utility(UTIL_NONE),
@ -210,7 +211,8 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb)
att_charset_ids(*pool),
att_pools(*pool),
att_idle_timeout(0),
att_stmt_timeout(0)
att_stmt_timeout(0),
att_batches(*pool)
{
att_internal.grow(irq_MAX);
att_dyn_req.grow(drq_MAX);
@ -221,6 +223,9 @@ Jrd::Attachment::~Attachment()
{
delete att_trace_manager;
for (unsigned n = 0; n < att_batches.getCount(); ++n)
att_batches[n]->resetHandle();
while (att_pools.hasData())
deletePool(att_pools.pop());
@ -381,8 +386,61 @@ void Jrd::Attachment::releaseGTTs(thread_db* tdbb)
}
}
void Jrd::Attachment::resetSession(thread_db* tdbb)
void Jrd::Attachment::resetSession(thread_db* tdbb, jrd_tra** traHandle)
{
jrd_tra* oldTran = traHandle ? *traHandle : nullptr;
if (att_transactions)
{
int n = 0;
bool err = false;
for (const jrd_tra* tra = att_transactions; tra; tra = tra->tra_next)
{
n++;
if (tra != oldTran && !(tra->tra_flags & TRA_prepared))
err = true;
}
// Cannot reset user session
// There are open transactions (@1 active)
if (err)
{
ERR_post(Arg::Gds(isc_ses_reset_err) <<
Arg::Gds(isc_ses_reset_open_trans) << Arg::Num(n));
}
}
// TODO: trigger before reset
ULONG oldFlags = 0;
SSHORT oldTimeout = 0;
if (oldTran)
{
oldFlags = oldTran->tra_flags;
oldTimeout = oldTran->tra_lock_timeout;
try
{
// It will also run run ON TRANSACTION ROLLBACK triggers
JRD_rollback_transaction(tdbb, oldTran);
*traHandle = nullptr;
}
catch (const Exception& ex)
{
Arg::StatusVector error;
error.assign(ex);
error.prepend(Arg::Gds(isc_ses_reset_err));
error.raise();
}
// Session was reset with warning(s)
// Transaction is rolled back due to session reset, all changes are lost
if (oldFlags & TRA_write)
{
ERR_post_warning(Arg::Warning(isc_ses_reset_warn) <<
Arg::Gds(isc_ses_reset_tran_rollback));
}
}
// reset DecFloat
att_dec_status = DecimalStatus::DEFAULT;
att_dec_binding = DecimalBinding::DEFAULT;
@ -400,6 +458,29 @@ void Jrd::Attachment::resetSession(thread_db* tdbb)
// reset GTT's
releaseGTTs(tdbb);
if (oldTran)
{
try
{
jrd_tra* newTran = TRA_start(tdbb, oldFlags, oldTimeout);
// run ON TRANSACTION START triggers
JRD_run_trans_start_triggers(tdbb, newTran);
tdbb->setTransaction(newTran);
*traHandle = newTran;
}
catch (const Exception& ex)
{
Arg::StatusVector error;
error.assign(ex);
error.prepend(Arg::Gds(isc_ses_reset_err));
error.raise();
}
}
// TODO: trigger after reset
}

View File

@ -332,6 +332,7 @@ public:
ThreadId att_purge_tid; // ID of thread running purge_attachment()
EDS::Connection* att_ext_connection; // external connection executed by this attachment
EDS::Connection* att_ext_parent; // external connection, parent of this attachment
ULONG att_ext_call_depth; // external connection call depth, 0 for user attachment
TraceManager* att_trace_manager; // Trace API manager
@ -408,7 +409,7 @@ public:
void releaseGTTs(thread_db* tdbb);
void resetSession(thread_db* tdbb);
void resetSession(thread_db* tdbb, jrd_tra** traHandle);
void signalCancel();
void signalShutdown(ISC_STATUS code);
@ -460,6 +461,16 @@ public:
// returns time when idle timer will be expired, if set
bool getIdleTimerTimestamp(Firebird::TimeStamp& ts) const;
// batches control
void registerBatch(JBatch* b)
{
att_batches.add(b);
}
void deregisterBatch(JBatch* b)
{
att_batches.findAndRemove(b);
}
private:
Attachment(MemoryPool* pool, Database* dbb);
~Attachment();
@ -495,6 +506,8 @@ private:
unsigned int att_idle_timeout; // seconds
unsigned int att_stmt_timeout; // milliseconds
Firebird::RefPtr<IdleTimer> att_idle_timer;
Firebird::Array<JBatch*> att_batches;
};

View File

@ -201,7 +201,7 @@ public:
void setDefaultBpb(Firebird::CheckStatusWrapper* status, unsigned parLength, const unsigned char* par);
public:
JBatch(DsqlBatch* handle, JStatement* aStatement);
JBatch(DsqlBatch* handle, JStatement* aStatement, Firebird::IMessageMetadata* aMetadata);
StableAttachmentPart* getAttachment();
@ -218,6 +218,9 @@ public:
private:
DsqlBatch* batch;
Firebird::RefPtr<JStatement> statement;
Firebird::RefPtr<Firebird::IMessageMetadata> m_meta;
void freeEngineData(Firebird::CheckStatusWrapper* status);
};
class JStatement FB_FINAL :

View File

@ -94,7 +94,8 @@ RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, TraNumber tran, bool a
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"jrd_rel::getPages inst %" ULONGFORMAT", ppp %" SLONGFORMAT", irp %" SLONGFORMAT", addr 0x%x\n",
"jrd_rel::getPages rel_id %u, inst %" SQUADFORMAT", ppp %" SLONGFORMAT", irp %" SLONGFORMAT", addr 0x%x\n",
rel_id,
newPages->rel_instance_id,
newPages->rel_pages ? (*newPages->rel_pages)[0] : 0,
newPages->rel_index_root,
@ -129,7 +130,8 @@ RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, TraNumber tran, bool a
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"jrd_rel::getPages inst %" SQUADFORMAT", irp %" SLONGFORMAT", idx %u, idx_root %" SLONGFORMAT", addr 0x%x\n",
"jrd_rel::getPages rel_id %u, inst %" SQUADFORMAT", irp %" SLONGFORMAT", idx %u, idx_root %" SLONGFORMAT", addr 0x%x\n",
rel_id,
newPages->rel_instance_id,
newPages->rel_index_root,
idx->idx_id,
@ -167,7 +169,8 @@ bool jrd_rel::delPages(thread_db* tdbb, TraNumber tran, RelationPages* aPages)
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"jrd_rel::delPages inst %" ULONGFORMAT", ppp %" SLONGFORMAT", irp %" SLONGFORMAT", addr 0x%x\n",
"jrd_rel::delPages rel_id %u, inst %" SQUADFORMAT", ppp %" SLONGFORMAT", irp %" SLONGFORMAT", addr 0x%x\n",
rel_id,
pages->rel_instance_id,
pages->rel_pages ? (*pages->rel_pages)[0] : 0,
pages->rel_index_root,

View File

@ -1672,6 +1672,9 @@ bool SimilarToMatcher<CharType, StrConverter>::Evaluator::match()
case msReturningTrue:
scopeStack.pop();
break;
default:
break;
}
}

View File

@ -53,6 +53,7 @@
#include "../jrd/trace/TraceObjects.h"
#include "../jrd/Collation.h"
#include "../common/classes/FpeControl.h"
#include "../jrd/extds/ExtDS.h"
#include <math.h>
using namespace Firebird;
@ -275,6 +276,10 @@ const char
// SYSTEM namespace: global and database wise items
ENGINE_VERSION[] = "ENGINE_VERSION",
DATABASE_NAME[] = "DB_NAME",
EXT_CONN_POOL_SIZE[] = "EXT_CONN_POOL_SIZE",
EXT_CONN_POOL_IDLE[] = "EXT_CONN_POOL_IDLE_COUNT",
EXT_CONN_POOL_ACTIVE[] = "EXT_CONN_POOL_ACTIVE_COUNT",
EXT_CONN_POOL_LIFETIME[] = "EXT_CONN_POOL_LIFETIME",
// SYSTEM namespace: connection wise items
SESSION_ID_NAME[] = "SESSION_ID",
NETWORK_PROTOCOL_NAME[] = "NETWORK_PROTOCOL",
@ -2664,6 +2669,17 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar
resultStr.printf("%" SLONGFORMAT, transaction->tra_lock_timeout);
else if (nameStr == READ_ONLY_NAME)
resultStr = (transaction->tra_flags & TRA_readonly) ? TRUE_VALUE : FALSE_VALUE;
else if (nameStr == EXT_CONN_POOL_SIZE)
resultStr.printf("%d", EDS::Manager::getConnPool()->getMaxCount());
else if (nameStr == EXT_CONN_POOL_IDLE)
resultStr.printf("%d", EDS::Manager::getConnPool()->getIdleCount());
else if (nameStr == EXT_CONN_POOL_ACTIVE)
{
EDS::ConnectionsPool* connPool = EDS::Manager::getConnPool();
resultStr.printf("%d", connPool->getAllCount() - connPool->getIdleCount());
}
else if (nameStr == EXT_CONN_POOL_LIFETIME)
resultStr.printf("%d", EDS::Manager::getConnPool()->getLifeTime());
else
{
// "Context variable %s is not found in namespace %s"
@ -4443,7 +4459,8 @@ dsc* evlRoleInUse(thread_db* tdbb, const SysFunction*, const NestValueArray& arg
return NULL;
string roleStr(MOV_make_string2(tdbb, value, ttype_none));
roleStr.upper();
//roleStr.upper(); // sorry - but this breaks role names containing lower case letters
// roles to be entered as returned by CURRENT_ROLE
impure->vlu_misc.vlu_uchar = (attachment->att_user &&
attachment->att_user->roleInUse(tdbb, roleStr.c_str())) ? FB_TRUE : FB_FALSE;

View File

@ -63,6 +63,7 @@ SYSTEM_PRIVILEGE(GRANT_REVOKE_ON_ANY_OBJECT)
SYSTEM_PRIVILEGE(GRANT_REVOKE_ANY_DDL_RIGHT)
SYSTEM_PRIVILEGE(CREATE_PRIVILEGED_ROLES)
SYSTEM_PRIVILEGE(GET_DBCRYPT_INFO)
SYSTEM_PRIVILEGE(MODIFY_EXT_CONN_POOL)
#ifdef FB_JRD_SYSTEM_PRIVILEGES_TMP
maxSystemPrivilege

View File

@ -5948,7 +5948,7 @@ string print_key(thread_db* tdbb, jrd_rel* relation, index_desc* idx, Record* re
MET_scan_relation(tdbb, relation);
}
const int MAX_KEY_STRING_LEN = 250;
const FB_SIZE_T MAX_KEY_STRING_LEN = 250;
string key, value;
try

View File

@ -3,16 +3,16 @@
*** DO NOT EDIT ***
TO CHANGE ANY INFORMATION IN HERE PLEASE
EDIT src/misc/writeBuildNum.sh
FORMAL BUILD NUMBER:993
FORMAL BUILD NUMBER:1057
*/
#define PRODUCT_VER_STRING "4.0.0.993"
#define FILE_VER_STRING "WI-T4.0.0.993"
#define LICENSE_VER_STRING "WI-T4.0.0.993"
#define FILE_VER_NUMBER 4, 0, 0, 993
#define PRODUCT_VER_STRING "4.0.0.1057"
#define FILE_VER_STRING "WI-T4.0.0.1057"
#define LICENSE_VER_STRING "WI-T4.0.0.1057"
#define FILE_VER_NUMBER 4, 0, 0, 1057
#define FB_MAJOR_VER "4"
#define FB_MINOR_VER "0"
#define FB_REV_NO "0"
#define FB_BUILD_NO "993"
#define FB_BUILD_NO "1057"
#define FB_BUILD_TYPE "T"
#define FB_BUILD_SUFFIX "Firebird 4.0 Alpha 1"

View File

@ -268,12 +268,38 @@ int CCH_down_grade_dbb(void* ast_object)
SyncLockGuard bcbSync(&bcb->bcb_syncObject, SYNC_EXCLUSIVE, "CCH_down_grade_dbb");
bcb->bcb_flags &= ~BCB_exclusive;
if (bcb->bcb_count)
bool done = (bcb->bcb_count == 0);
while (!done)
{
done = true;
const bcb_repeat* const head = bcb->bcb_rpt;
const bcb_repeat* tail = bcb->bcb_rpt;
fb_assert(tail); // once I've got here with NULL. AP.
for (const bcb_repeat* const end = tail + bcb->bcb_count; tail < end; ++tail)
PAGE_LOCK_ASSERT(tdbb, bcb, tail->bcb_bdb->bdb_lock);
{
BufferDesc* bdb = tail->bcb_bdb;
// Acquire EX latch to avoid races with LCK_release (called by CCH_release)
// or LCK_lock (by lock_buffer) in main thread. Take extra care to avoid
// deadlock with CCH_handoff. See CORE-5436.
Sync sync(&bdb->bdb_syncPage, FB_FUNCTION);
while (!sync.lockConditional(SYNC_EXCLUSIVE))
{
SyncUnlockGuard bcbUnlock(bcbSync);
Thread::sleep(1);
}
if (head != bcb->bcb_rpt)
{
// expand_buffers or CCH_fini was called, consider to start all over again
done = (bcb->bcb_count == 0);
break;
}
PAGE_LOCK_ASSERT(tdbb, bcb, bdb->bdb_lock);
}
}
}

View File

@ -149,8 +149,10 @@ void DPM_backout( thread_db* tdbb, record_param* rpb)
CHECK_DBB(dbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"DPM_backout (record_param %" QUADFORMAT"d)\n", rpb->rpb_number.getValue());
"DPM_backout (rel_id %u, record_param %" QUADFORMAT"d)\n",
relation->rel_id, rpb->rpb_number.getValue());
VIO_trace(DEBUG_WRITES_INFO,
" record %" ULONGFORMAT":%d transaction %" ULONGFORMAT" back %"
@ -339,9 +341,10 @@ bool DPM_chain( thread_db* tdbb, record_param* org_rpb, record_param* new_rpb)
CHECK_DBB(dbb);
#ifdef VIO_DEBUG
jrd_rel* relation = org_rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"DPM_chain (org_rpb %" QUADFORMAT"d, new_rpb %"
QUADFORMAT"d)\n", org_rpb->rpb_number.getValue(),
"DPM_chain (rel_id %u, org_rpb %" QUADFORMAT"d, new_rpb %" QUADFORMAT"d)\n",
relation->rel_id, org_rpb->rpb_number.getValue(),
new_rpb ? new_rpb->rpb_number.getValue() : 0);
VIO_trace(DEBUG_WRITES_INFO,
@ -509,6 +512,15 @@ bool DPM_chain( thread_db* tdbb, record_param* org_rpb, record_param* new_rpb)
if (fill)
memset(data + size, 0, fill);
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES_INFO,
" new record %" ULONGFORMAT":%d transaction %" ULONGFORMAT
" back %" ULONGFORMAT":%d fragment %" ULONGFORMAT":%d flags %d\n",
new_rpb->rpb_page, new_rpb->rpb_line, new_rpb->rpb_transaction_nr,
new_rpb->rpb_b_page, new_rpb->rpb_b_line, new_rpb->rpb_f_page,
new_rpb->rpb_f_line, new_rpb->rpb_flags);
#endif
if (page->dpg_header.pag_flags & dpg_swept)
{
page->dpg_header.pag_flags &= ~dpg_swept;
@ -687,6 +699,7 @@ void DPM_delete( thread_db* tdbb, record_param* rpb, ULONG prior_page)
CHECK_DBB(dbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"DPM_delete (record_param %" QUADFORMAT", prior_page %" ULONGFORMAT")\n",
rpb->rpb_number.getValue(), prior_page);
@ -937,10 +950,18 @@ void DPM_delete( thread_db* tdbb, record_param* rpb, ULONG prior_page)
CCH_MARK(tdbb, &pwindow);
const ULONG dpSequence = ppage->ppg_sequence * dbb->dbb_dp_per_pp;
s = extent ? firstSlot : slot;
for (i = 0; i < pages.getCount(); i++, s++)
{
ppage->ppg_page[s] = 0;
if (relPages->rel_last_free_pri_dp == pages[i])
relPages->rel_last_free_pri_dp = 0;
relPages->setDPNumber(dpSequence + s, 0);
}
if (relPages->rel_data_pages)
relPages->rel_data_pages -= pages.getCount();
@ -1015,7 +1036,8 @@ void DPM_delete_relation_pages(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation,
#ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL,
"DPM_delete_relation (relation %d)\n", relation->rel_id);
"DPM_delete_relation_pages (relation %d, instance %" SQUADFORMAT")\n",
relation->rel_id, relPages->rel_instance_id);
#endif
// Delete all data and pointer pages
@ -1107,9 +1129,10 @@ bool DPM_fetch(thread_db* tdbb, record_param* rpb, USHORT lock)
SET_TDBB(tdbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"DPM_fetch (record_param %" QUADFORMAT"d, lock %d)\n",
rpb->rpb_number.getValue(), lock);
"DPM_fetch (rel_id %u, record_param %" QUADFORMAT"d, lock %d)\n",
relation->rel_id, rpb->rpb_number.getValue(), lock);
VIO_trace(DEBUG_READS_INFO,
" record %" ULONGFORMAT":%d\n", rpb->rpb_page, rpb->rpb_line);
@ -1169,9 +1192,10 @@ bool DPM_fetch_back(thread_db* tdbb, record_param* rpb, USHORT lock, SSHORT latc
SET_TDBB(tdbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"DPM_fetch_back (record_param %" QUADFORMAT"d, lock %d)\n",
rpb->rpb_number.getValue(), lock);
"DPM_fetch_back (rel_id %u, record_param %" QUADFORMAT"d, lock %d)\n",
relation->rel_id, rpb->rpb_number.getValue(), lock);
VIO_trace(DEBUG_READS_INFO,
" record %" ULONGFORMAT":%d transaction %" ULONGFORMAT
@ -1233,9 +1257,10 @@ void DPM_fetch_fragment( thread_db* tdbb, record_param* rpb, USHORT lock)
SET_TDBB(tdbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"DPM_fetch_fragment (record_param %" QUADFORMAT"d, lock %d)\n",
rpb->rpb_number.getValue(), lock);
"DPM_fetch_fragment (rel_id %u, record_param %" QUADFORMAT"d, lock %d)\n",
relation->rel_id, rpb->rpb_number.getValue(), lock);
VIO_trace(DEBUG_READS_INFO,
" record %" ULONGFORMAT":%d transaction %" ULONGFORMAT
@ -1394,9 +1419,10 @@ bool DPM_get(thread_db* tdbb, record_param* rpb, SSHORT lock_type)
CHECK_DBB(dbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"DPM_get (record_param %" QUADFORMAT"d, lock type %d)\n",
rpb->rpb_number.getValue(), lock_type);
"DPM_get (rel_id %u, record_param %" QUADFORMAT"d, lock type %d)\n",
relation->rel_id, rpb->rpb_number.getValue(), lock_type);
#endif
WIN* window = &rpb->getWindow(tdbb);
@ -1500,10 +1526,11 @@ ULONG DPM_get_blob(thread_db* tdbb,
rpb.getWindow(tdbb).win_flags = WIN_secondary;
#ifdef VIO_DEBUG
jrd_rel* relation = blob->blb_relation;
VIO_trace(DEBUG_READS,
"DPM_get_blob (blob, record_number %" QUADFORMAT
"DPM_get_blob (rel_id %u, blob, record_number %" QUADFORMAT
"d, delete_flag %d, prior_page %" ULONGFORMAT")\n",
record_number.getValue(), (int) delete_flag, prior_page);
relation->rel_id, record_number.getValue(), (int)delete_flag, prior_page);
#endif
// Find starting point
@ -1619,8 +1646,10 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage
CHECK_DBB(dbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"DPM_next (record_param %" QUADFORMAT"d)\n", rpb->rpb_number.getValue());
"DPM_next (rel_id %u, record_param %" QUADFORMAT"d)\n",
relation->rel_id, rpb->rpb_number.getValue());
#endif
WIN* window = &rpb->getWindow(tdbb);
@ -1647,7 +1676,7 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage
#ifdef VIO_DEBUG
VIO_trace(DEBUG_READS_INFO,
" pointer, slot, and line %d:%d%d\n", pp_sequence, slot, line);
" sequence, slot, and line %" ULONGFORMAT" %" ULONGFORMAT":%d\n", pp_sequence, slot, line);
#endif
// If I'm a sweeper I don't need to look at swept pages. Also I should
@ -2037,9 +2066,10 @@ void DPM_store( thread_db* tdbb, record_param* rpb, PageStack& stack, const Jrd:
CHECK_DBB(dbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"DPM_store (record_param %" QUADFORMAT"d, stack, type %d)\n",
rpb->rpb_number.getValue(), type);
"DPM_store (rel_id %u, record_param %" QUADFORMAT"d, stack, type %d)\n",
relation->rel_id, rpb->rpb_number.getValue(), type);
VIO_trace(DEBUG_WRITES_INFO,
" record to store %" ULONGFORMAT":%d transaction %" ULONGFORMAT
@ -2122,8 +2152,10 @@ RecordNumber DPM_store_blob(thread_db* tdbb, blb* blob, Record* record)
CHECK_DBB(dbb);
#ifdef VIO_DEBUG
jrd_rel* relation = blob->blb_relation;
VIO_trace(DEBUG_WRITES,
"DPM_store_blob (blob, record)\n");
"DPM_store_blob (rel_id %u, blob, record)\n",
relation->rel_id);
#endif
// Figure out length of blob on page. Remember that blob can either
@ -2190,8 +2222,10 @@ void DPM_rewrite_header( thread_db* tdbb, record_param* rpb)
CHECK_DBB(dbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"DPM_rewrite_header (record_param %" QUADFORMAT"d)\n", rpb->rpb_number.getValue());
"DPM_rewrite_header (rel_id %u, record_param %" QUADFORMAT"d)\n",
relation->rel_id, rpb->rpb_number.getValue());
VIO_trace(DEBUG_WRITES_INFO,
" record %" ULONGFORMAT":%d\n", rpb->rpb_page, rpb->rpb_line);
@ -2243,9 +2277,10 @@ void DPM_update( thread_db* tdbb, record_param* rpb, PageStack* stack, const jrd
CHECK_DBB(dbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"DPM_update (record_param %" QUADFORMAT"d, stack, transaction %" ULONGFORMAT")\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
"DPM_update (rel_id %u, record_param %" QUADFORMAT"d, stack, transaction %" ULONGFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
VIO_trace(DEBUG_WRITES_INFO,
" record %" ULONGFORMAT":%d transaction %" ULONGFORMAT" back %"
@ -2614,10 +2649,11 @@ static void fragment(thread_db* tdbb,
CHECK_DBB(dbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"fragment (record_param %" QUADFORMAT
"fragment (rel_id %u, record_param %" QUADFORMAT
"d, available_space %d, dcc, length %d, transaction %" ULONGFORMAT")\n",
rpb->rpb_number.getValue(), available_space, length,
relation->rel_id, rpb->rpb_number.getValue(), available_space, length,
transaction ? transaction->tra_number : 0);
VIO_trace(DEBUG_WRITES_INFO,
@ -2789,7 +2825,8 @@ static void extend_relation(thread_db* tdbb, jrd_rel* relation, WIN* window, con
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES_INFO,
" extend_relation (relation %d, window)\n", relation->rel_id);
" extend_relation (relation %d, instance %" SQUADFORMAT", window)\n",
relation->rel_id, relPages->rel_instance_id);
#endif
// Search pointer pages for an empty slot.
@ -3436,9 +3473,10 @@ static void mark_full(thread_db* tdbb, record_param* rpb)
Database* dbb = tdbb->getDatabase();
CHECK_DBB(dbb);
jrd_rel* relation = rpb->rpb_relation;
#ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL,
"mark_full ()\n");
"mark_full (rel_id %u)\n", relation->rel_id);
#endif
// We need to access the pointer page for write. To avoid deadlocks,
@ -3450,7 +3488,6 @@ static void mark_full(thread_db* tdbb, record_param* rpb)
const ULONG sequence = dpage->dpg_sequence;
CCH_RELEASE(tdbb, &rpb->getWindow(tdbb));
jrd_rel* relation = rpb->rpb_relation;
RelationPages* relPages = relation->getPages(tdbb);
WIN pp_window(relPages->rel_pg_space_id, -1);
@ -3596,8 +3633,10 @@ static void store_big_record(thread_db* tdbb,
CHECK_DBB(dbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE_ALL,
"store_big_record ()\n");
"store_big_record (rel_id %u, record %" SQUADFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue());
#endif
// Start compression from the end.
@ -3673,7 +3712,7 @@ static void store_big_record(thread_db* tdbb,
" back portion\n");
VIO_trace(DEBUG_WRITES_INFO,
" getWindow(tdbb) page %" ULONGFORMAT
" window page %" ULONGFORMAT
", max_data %d, \n\trhdf_flags %d, prior %" ULONGFORMAT"\n",
rpb->getWindow(tdbb).win_page.getPageNum(), max_data, header->rhdf_flags,
prior.getPageNum());

View File

@ -235,6 +235,14 @@ enum drq_type_t
drq_l_grant_option, // lookup grant option for privilege
drq_l_granted_roles, // lookup granted roles
drq_l_grant_object, // check grantor can grant object
drq_proc_exist, // check if procedure exists
drq_udf_exist, // check if udf exists
drq_package_exist, // check if package exists
drq_trigger_exist, // check if trigger exists
drq_rel_exist, // check if relation or view exists
drq_exception_exist, // check if exception exists
drq_generator_exist, // check if generator exists
drq_rel_field_exist, // check if a field of relation or view exists
drq_MAX
};

View File

@ -339,6 +339,8 @@ LikeEvaluator<CharType>::LikeEvaluator(
case piEscapedString:
item->str.length++;
break;
default:
break;
}
continue;
}
@ -359,6 +361,8 @@ LikeEvaluator<CharType>::LikeEvaluator(
case piNone:
item->type = piSkipMore;
break;
default:
break;
}
continue;
}
@ -380,6 +384,8 @@ LikeEvaluator<CharType>::LikeEvaluator(
case piSkipMore:
item->skipCount++;
break;
default:
break;
}
continue;
}
@ -400,6 +406,8 @@ LikeEvaluator<CharType>::LikeEvaluator(
case piEscapedString:
item->str.length++;
break;
default:
break;
}
}
@ -461,6 +469,8 @@ LikeEvaluator<CharType>::LikeEvaluator(
itemL->match_any = true;
}
break;
default:
break;
}
i++;
}
@ -585,6 +595,8 @@ bool LikeEvaluator<CharType>::processNextChunk(const CharType* data, SLONG data_
}
}
break;
default:
break;
}
branch_number++;
}

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,7 @@ namespace EDS {
class Manager;
class Provider;
class Connection;
class ConnectionsPool;
class Transaction;
class Statement;
class Blob;
@ -67,19 +68,22 @@ public:
const Firebird::string& dataSource, const Firebird::string& user,
const Firebird::string& pwd, const Firebird::string& role, TraScope tra_scope);
// Notify providers when some jrd attachment is about to be released
static void jrdAttachmentEnd(Jrd::thread_db* tdbb, Jrd::Attachment* att);
static int shutdown();
static ConnectionsPool* getConnPool() { return m_connPool; }
// Release bound external connections when some jrd attachment is about to be released
static void jrdAttachmentEnd(Jrd::thread_db* tdbb, Jrd::Attachment* att, bool forced);
static int shutdown();
private:
static Firebird::GlobalPtr<Manager> manager;
static Firebird::Mutex m_mutex;
static Provider* m_providers;
static volatile bool m_initialized;
static ConnectionsPool* m_connPool;
};
// manages connections\connection pool
// manages connections
class Provider : public Firebird::GlobalStorage
{
@ -89,16 +93,24 @@ class Provider : public Firebird::GlobalStorage
public:
explicit Provider(const char* prvName);
// return existing or create new Connection
virtual Connection* getConnection(Jrd::thread_db* tdbb, const Firebird::PathName& dbName,
const Firebird::string& user, const Firebird::string& pwd, const Firebird::string& role,
// create new Connection
virtual Connection* createConnection(Jrd::thread_db* tdbb,
const Firebird::PathName& dbName, Firebird::ClumpletReader& dpb,
TraScope tra_scope);
// Connection gets unused, release it into pool or delete it completely
// bind connection to the current attachment
void bindConnection(Jrd::thread_db* tdbb, Connection* conn);
// get available connection already bound to the current attachment
Connection* getBoundConnection(Jrd::thread_db* tdbb,
const Firebird::PathName& dbName, Firebird::ClumpletReader& dpb,
TraScope tra_scope);
// Connection gets unused, release it into pool or delete it immediately
virtual void releaseConnection(Jrd::thread_db* tdbb, Connection& conn, bool inPool = true);
// Notify provider when some jrd attachment is about to be released
virtual void jrdAttachmentEnd(Jrd::thread_db* tdbb, Jrd::Attachment* att) = 0;
// release connections bound to the attachment
virtual void jrdAttachmentEnd(Jrd::thread_db* tdbb, Jrd::Attachment* att, bool forced);
// cancel execution of every connection
void cancelConnections();
@ -123,6 +135,10 @@ protected:
void clearConnections(Jrd::thread_db* tdbb);
virtual Connection* doCreateConnection() = 0;
void generateDPB(Jrd::thread_db* tdbb, Firebird::ClumpletWriter& dpb,
const Firebird::string& user, const Firebird::string& pwd,
const Firebird::string& role) const;
// Protection against simultaneous attach database calls. Not sure we still
// need it, but i believe it will not harm
Firebird::Mutex m_mutex;
@ -130,7 +146,39 @@ protected:
Firebird::string m_name;
Provider* m_next;
Firebird::Array<Connection*> m_connections;
class AttToConn
{
public:
Jrd::Attachment* m_att;
Connection* m_conn;
AttToConn() :
m_att(NULL),
m_conn(NULL)
{}
AttToConn(Jrd::Attachment* att, Connection* conn) :
m_att(att),
m_conn(conn)
{}
static const AttToConn& generate(const void*, const AttToConn& item)
{
return item;
}
static bool greaterThan(const AttToConn& i1, const AttToConn& i2)
{
return (i1.m_att > i2.m_att) ||
(i1.m_att == i2.m_att && i1.m_conn > i2.m_conn);
}
};
typedef Firebird::BePlusTree<AttToConn, AttToConn, Firebird::MemoryPool,
AttToConn, AttToConn>
AttToConnMap;
AttToConnMap m_connections;
int m_flags;
};
@ -141,26 +189,238 @@ const int prvNamedParams = 0x0004; // supports named parameters
const int prvTrustedAuth = 0x0008; // supports trusted authentication
class ConnectionsPool
{
public:
ConnectionsPool(Firebird::MemoryPool& pool);
~ConnectionsPool();
// find and return cached connection or NULL
Connection* getConnection(Jrd::thread_db* tdbb, Provider* prv, ULONG hash, const Firebird::PathName& dbName,
Firebird::ClumpletReader& dpb);
// put unused connection into pool or destroy it
void putConnection(Jrd::thread_db* tdbb, Connection* conn);
// assotiate new active connection with pool
void addConnection(Jrd::thread_db* tdbb, Connection* conn, ULONG hash);
// clear connection relation with pool
void delConnection(Jrd::thread_db* tdbb, Connection* conn, bool destroy);
ULONG getIdleCount() const { return m_idleArray.getCount(); }
ULONG getAllCount() const { return m_allCount; } ;
ULONG getMaxCount() const { return m_maxCount; }
void setMaxCount(ULONG val);
ULONG getLifeTime() const { return m_lifeTime; }
void setLifeTime(ULONG val);
// delete idle connections: all or older than lifetime
void clearIdle(Jrd::thread_db* tdbb, bool all);
// delete all idle connections, remove from pool all active connections
void clear(Jrd::thread_db* tdbb);
// return time when oldest idle connection should be released, or zero
time_t getIdleExpireTime();
// verify bound connection internals
static bool checkBoundConnection(Jrd::thread_db* tdbb, Connection* conn);
public:
// this class is embedded into Connection but managed by ConnectionsPool
class Data
{
public:
// constructor for embedded into Connection instance
explicit Data(Connection* conn)
{
clear();
m_conn = conn;
}
ConnectionsPool* getConnPool() const { return m_connPool; }
static const Data& generate(const Data* item)
{
return *item;
}
static bool greaterThan(const Data& i1, const Data& i2)
{
if (i1.m_hash == i2.m_hash)
{
if (i1.m_lastUsed == i2.m_lastUsed)
return &i1 > &i2;
return (i1.m_lastUsed < i2.m_lastUsed);
}
return (i1.m_hash > i2.m_hash);
}
private:
friend class ConnectionsPool;
ConnectionsPool* m_connPool;
Connection* m_conn;
ULONG m_hash;
time_t m_lastUsed;
// placement in connections list
Data* m_next;
Data* m_prev;
Data(const Data&);
Data& operator=(const Data&);
// create instance used to search for recently used connection by hash
explicit Data(ULONG hash)
{
clear();
m_conn = NULL;
m_hash = hash;
m_lastUsed = MAX_SINT64;
}
void clear()
{
m_connPool = NULL;
// m_conn = NULL;
m_hash = 0;
m_lastUsed = 0;
m_next = m_prev = NULL;
}
void setConnPool(ConnectionsPool *connPool)
{
fb_assert(!connPool || !m_connPool);
m_connPool = connPool;
}
Firebird::string print();
int verify(ConnectionsPool *connPool, bool active);
};
private:
class IdleTimer FB_FINAL :
public Firebird::RefCntIface<Firebird::ITimerImpl<IdleTimer, Firebird::CheckStatusWrapper> >
{
public:
explicit IdleTimer(ConnectionsPool& connPool) :
m_connPool(connPool),
m_time(0)
{}
// ITimer implementation
void handler();
int release();
void start();
void stop();
private:
ConnectionsPool& m_connPool;
Firebird::Mutex m_mutex;
time_t m_time; // time when timer should fire, or zero
};
void addToList(Data** head, Data* item)
{
fb_assert(item->m_next == NULL);
fb_assert(item->m_prev == NULL);
fb_assert(head == (item->m_lastUsed ? &m_idleList : &m_activeList));
if (*head)
{
item->m_next = (*head);
item->m_prev = (*head)->m_prev;
item->m_next->m_prev = item;
item->m_prev->m_next = item;
}
else
{
item->m_next = item;
item->m_prev = item;
}
*head = item;
}
void removeFromList(Data** head, Data* item)
{
if (!item->m_next)
return;
fb_assert(head == (item->m_lastUsed ? &m_idleList : &m_activeList));
if (item->m_next != item)
{
item->m_next->m_prev = item->m_prev;
item->m_prev->m_next = item->m_next;
if (*head == item)
*head = item->m_next;
}
else
{
fb_assert((*head) == item);
*head = NULL;
}
item->m_next = item->m_prev = NULL;
}
void removeFromPool(Data* item, FB_SIZE_T pos);
Data* removeOldest();
void printPool(Firebird::string& s);
bool verifyPool();
// Array of Data*, sorted by [hash, lastUsed desc]
typedef Firebird::SortedArray<Data*, Firebird::EmptyStorage<Data*>, Data, Data, Data>
IdleArray;
Firebird::MemoryPool& m_pool;
Firebird::Mutex m_mutex;
IdleArray m_idleArray;
Data* m_idleList;
Data* m_activeList;
ULONG m_allCount;
ULONG m_maxCount;
ULONG m_lifeTime; // How long idle connection should wait before destroyng, seconds
Firebird::RefPtr<IdleTimer> m_timer;
};
class Connection : public Firebird::PermanentStorage
{
protected:
friend class EngineCallbackGuard;
friend class Provider;
// only Provider could create, setup and delete Connections
explicit Connection(Provider& prov);
virtual ~Connection();
public:
static void deleteConnection(Jrd::thread_db* tdbb, Connection* conn);
void setup(const Firebird::PathName& dbName, const Firebird::ClumpletReader& dpb);
void setBoundAtt(Jrd::Attachment* att) { m_boundAtt = att; }
public:
Provider* getProvider() { return &m_provider; }
virtual void attach(Jrd::thread_db* tdbb, const Firebird::PathName& dbName,
const Firebird::MetaName& user, const Firebird::string& pwd,
const Firebird::MetaName& role) = 0;
Jrd::Attachment* getBoundAtt() const { return m_boundAtt; }
ConnectionsPool* getConnPool() { return m_poolData.getConnPool(); }
ConnectionsPool::Data* getPoolData() { return &m_poolData; }
virtual void attach(Jrd::thread_db* tdbb) = 0;
virtual void detach(Jrd::thread_db* tdbb);
virtual bool cancelExecution(bool forced) = 0;
virtual bool resetSession() = 0;
int getSqlDialect() const { return m_sqlDialect; }
@ -171,10 +431,13 @@ public:
virtual bool isAvailable(Jrd::thread_db* tdbb, TraScope traScope) const = 0;
virtual bool isConnected() const = 0;
virtual bool validate(Jrd::thread_db* tdbb) = 0;
virtual bool isSameDatabase(Jrd::thread_db* tdbb, const Firebird::PathName& dbName,
const Firebird::MetaName& user, const Firebird::string& pwd,
const Firebird::MetaName& role) const;
virtual bool isSameDatabase(const Firebird::PathName& dbName,
Firebird::ClumpletReader& dpb) const;
// only Internal provider is able to create "current" connections
virtual bool isCurrent() const { return false; }
bool isBroken() const
{
@ -213,10 +476,6 @@ public:
virtual Blob* createBlob() = 0;
protected:
void generateDPB(Jrd::thread_db* tdbb, Firebird::ClumpletWriter& dpb,
const Firebird::MetaName& user, const Firebird::string& pwd,
const Firebird::MetaName& role) const;
virtual Transaction* doCreateTransaction() = 0;
virtual Statement* doCreateStatement() = 0;
@ -230,13 +489,14 @@ protected:
Provider& m_provider;
Firebird::PathName m_dbName;
Firebird::ClumpletWriter m_dpb;
Firebird::UCharBuffer m_dpb;
Jrd::Attachment* m_boundAtt;
Firebird::Array<Transaction*> m_transactions;
Firebird::Array<Statement*> m_statements;
Statement* m_freeStatements;
const Jrd::Attachment* m_boundAtt;
ConnectionsPool::Data m_poolData;
static const int MAX_CACHED_STMTS = 16;
int m_used_stmts;

View File

@ -64,26 +64,35 @@ static GlobalPtr<RegisterInternalProvider> reg;
// InternalProvider
void InternalProvider::jrdAttachmentEnd(thread_db* tdbb, Jrd::Attachment* att)
void InternalProvider::jrdAttachmentEnd(thread_db* tdbb, Attachment* att, bool forced)
{
/***
hvlad: this inactive code could be useful in the future, for example when EDS
connection pool will be implemented - it allows to remove closed connections
from the pool.
Provider::jrdAttachmentEnd(tdbb, att, forced);
if (m_connections.getCount() == 0)
Connection* conn = att->att_ext_parent;
if (!conn)
return;
Connection** ptr = m_connections.end();
Connection** begin = m_connections.begin();
for (ptr--; ptr >= begin; ptr--)
{
InternalConnection* conn = (InternalConnection*) *ptr;
if (conn->getJrdAtt() == att->getInterface())
releaseConnection(tdbb, *conn, false);
Database* dbb = tdbb->getDatabase();
MutexLockGuard guard(m_mutex, FB_FUNCTION);
AttToConnMap::Accessor acc(&m_connections);
if (acc.locate(AttToConn(conn->getBoundAtt(), conn)))
{
InternalConnection* intConn = (InternalConnection*) acc.current().m_conn;
if (!intConn->getJrdAtt() || intConn->getJrdAtt()->getHandle() != att)
{
fb_assert(intConn->getJrdAtt() == NULL);
return;
}
fb_assert(intConn == conn);
}
else
return;
}
***/
if (conn)
releaseConnection(tdbb, *conn, false);
}
void InternalProvider::getRemoteError(const FbStatusVector* status, string& err) const
@ -135,22 +144,17 @@ private:
FbStatusVector *v;
};
void InternalConnection::attach(thread_db* tdbb, const PathName& dbName,
const MetaName& user, const string& pwd,
const MetaName& role)
void InternalConnection::attach(thread_db* tdbb)
{
fb_assert(!m_attachment);
Database* dbb = tdbb->getDatabase();
fb_assert(dbName.isEmpty() || dbName == dbb->dbb_database_name.c_str());
Attachment* attachment = tdbb->getAttachment();
fb_assert(m_dbName.isEmpty() || m_dbName == dbb->dbb_database_name.c_str());
// Don't wrap raised errors. This is needed for backward compatibility.
setWrapErrors(false);
Jrd::Attachment* attachment = tdbb->getAttachment();
if (attachment->att_user &&
(user.isEmpty() || user == attachment->att_user->getUserName()) &&
pwd.isEmpty() &&
(role.isEmpty() || role == attachment->att_user->getSqlRole()))
if (m_dpb.isEmpty())
{
m_isCurrent = true;
m_attachment = attachment->getInterface();
@ -159,11 +163,11 @@ void InternalConnection::attach(thread_db* tdbb, const PathName& dbName,
{
m_isCurrent = false;
m_dbName = dbb->dbb_database_name.c_str();
generateDPB(tdbb, m_dpb, user, pwd, role);
// Avoid change of m_dpb by validatePassword() below
ClumpletWriter newDpb(m_dpb);
ClumpletWriter newDpb(ClumpletReader::Tagged, MAX_DPB_SIZE, m_dpb.begin(), m_dpb.getCount(), 0);
validatePassword(tdbb, m_dbName, newDpb);
newDpb.insertInt(isc_dpb_ext_call_depth, attachment->att_ext_call_depth + 1);
FbLocalStatus status;
{
@ -176,9 +180,11 @@ void InternalConnection::attach(thread_db* tdbb, const PathName& dbName,
if (status->getState() & IStatus::STATE_ERRORS)
raise(&status, tdbb, "JProvider::attach");
m_attachment->getHandle()->att_ext_parent = this;
}
m_sqlDialect = (m_attachment->getHandle()->att_database->dbb_flags & DBB_DB_SQL_dialect_3) ?
m_sqlDialect = (attachment->att_database->dbb_flags & DBB_DB_SQL_dialect_3) ?
SQL_DIALECT_V6 : SQL_DIALECT_V5;
}
@ -204,7 +210,7 @@ void InternalConnection::doDetach(thread_db* tdbb)
att->detach(&status);
}
if (status->getErrors()[1] == isc_att_shutdown)
if (status->getErrors()[1] == isc_att_shutdown || status->getErrors()[1] == isc_shutdown)
{
status->init();
}
@ -233,6 +239,20 @@ bool InternalConnection::cancelExecution(bool /*forced*/)
return !(status->getState() & IStatus::STATE_ERRORS);
}
bool InternalConnection::resetSession()
{
fb_assert(!m_isCurrent);
if (m_isCurrent)
return true;
FbLocalStatus status;
m_attachment->execute(&status, NULL, 0, "ALTER SESSION RESET",
m_sqlDialect, NULL, NULL, NULL, NULL);
return !(status->getState() & IStatus::STATE_ERRORS);
}
// this internal connection instance is available for the current execution context if it
// a) is current connection and current thread's attachment is equal to
// this attachment, or
@ -243,20 +263,46 @@ bool InternalConnection::isAvailable(thread_db* tdbb, TraScope /*traScope*/) con
(m_isCurrent && (tdbb->getAttachment() == m_attachment->getHandle()));
}
bool InternalConnection::isSameDatabase(thread_db* tdbb, const PathName& dbName,
const MetaName& user, const string& pwd,
const MetaName& role) const
bool InternalConnection::validate(thread_db* tdbb)
{
if (m_isCurrent)
return true;
if (!m_attachment)
return false;
EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);
FbLocalStatus status;
m_attachment->ping(&status);
return status.isSuccess();
}
bool InternalConnection::isSameDatabase(const PathName& dbName, ClumpletReader& dpb) const
{
if (m_isCurrent)
{
const UserId* attUser = m_attachment->getHandle()->att_user;
return (attUser &&
(user.isEmpty() || user == attUser->getUserName()) &&
pwd.isEmpty() &&
(role.isEmpty() || role == attUser->getSqlRole()));
const Attachment* att = m_attachment->getHandle();
const MetaName& attUser = att->att_user->getUserName();
const MetaName& attRole = att->att_user->getSqlRole();
MetaName str;
if (dpb.find(isc_dpb_user_name))
{
dpb.getString(str);
if (str != attUser)
return false;
}
if (dpb.find(isc_dpb_sql_role_name))
{
dpb.getString(str);
if (str != attRole)
return false;
}
}
return Connection::isSameDatabase(tdbb, dbName, user, pwd, role);
return Connection::isSameDatabase(dbName, dpb);
}
Transaction* InternalConnection::doCreateTransaction()
@ -358,7 +404,7 @@ void InternalTransaction::doRollback(FbStatusVector* status, thread_db* tdbb, bo
m_transaction->rollback(&s);
}
if (status->getErrors()[1] == isc_att_shutdown && !retain)
if ((status->getErrors()[1] == isc_att_shutdown || status->getErrors()[1] == isc_shutdown) && !retain)
{
m_transaction = NULL;
status->init();

View File

@ -40,8 +40,9 @@ public:
~InternalProvider()
{}
virtual void jrdAttachmentEnd(Jrd::thread_db* tdbb, Jrd::Attachment* att, bool forced);
virtual void initialize() {}
virtual void jrdAttachmentEnd(Jrd::thread_db* tdbb, Jrd::Attachment* att);
virtual void getRemoteError(const Jrd::FbStatusVector* status, Firebird::string& err) const;
protected:
@ -63,21 +64,20 @@ protected:
virtual ~InternalConnection();
public:
virtual void attach(Jrd::thread_db* tdbb, const Firebird::PathName& dbName,
const Firebird::MetaName& user, const Firebird::string& pwd,
const Firebird::MetaName& role);
virtual void attach(Jrd::thread_db* tdbb);
virtual bool cancelExecution(bool forced);
virtual bool resetSession();
virtual bool isAvailable(Jrd::thread_db* tdbb, TraScope traScope) const;
virtual bool isConnected() const { return (m_attachment != 0); }
virtual bool validate(Jrd::thread_db* tdbb);
virtual bool isSameDatabase(Jrd::thread_db* tdbb, const Firebird::PathName& dbName,
const Firebird::MetaName& user, const Firebird::string& pwd,
const Firebird::MetaName& role) const;
virtual bool isSameDatabase(const Firebird::PathName& dbName,
Firebird::ClumpletReader& dpb) const;
bool isCurrent() const { return m_isCurrent; }
virtual bool isCurrent() const { return m_isCurrent; }
Jrd::JAttachment* getJrdAtt() { return m_attachment; }

View File

@ -110,15 +110,14 @@ IscConnection::~IscConnection()
{
}
void IscConnection::attach(thread_db* tdbb, const PathName& dbName, const MetaName& user,
const string& pwd, const MetaName& role)
void IscConnection::attach(thread_db* tdbb)
{
m_dbName = dbName;
generateDPB(tdbb, m_dpb, user, pwd, role);
Attachment* attachment = tdbb->getAttachment();
// Avoid change of m_dpb by validatePassword() below
ClumpletWriter newDpb(m_dpb);
ClumpletWriter newDpb(ClumpletReader::Tagged, MAX_DPB_SIZE, m_dpb.begin(), m_dpb.getCount(), 0);
validatePassword(tdbb, m_dbName, newDpb);
newDpb.insertInt(isc_dpb_ext_call_depth, attachment->att_ext_call_depth + 1);
FbLocalStatus status;
{
@ -240,6 +239,21 @@ bool IscConnection::cancelExecution(bool forced)
return !(status->getState() & IStatus::STATE_ERRORS);
}
bool IscConnection::resetSession()
{
if (!m_handle)
return false;
FbLocalStatus status;
m_iscProvider.isc_dsql_execute_immediate(&status, &m_handle,
NULL, 0, "ALTER SESSION RESET", m_sqlDialect, NULL);
if (!(status->getState() & IStatus::STATE_ERRORS))
return true;
return false; // (status->getErrors()[1] == isc_dsql_error);
}
// this ISC connection instance is available for the current execution context if it
// a) has no active statements or supports many active statements
// and
@ -260,6 +274,22 @@ bool IscConnection::isAvailable(thread_db* tdbb, TraScope traScope) const
return true;
}
bool IscConnection::validate(Jrd::thread_db* tdbb)
{
if (!m_handle)
return false;
FbLocalStatus status;
EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);
char info[] = {isc_info_attachment_id, isc_info_end};
char buff[32];
return m_iscProvider.isc_database_info(&status, &m_handle,
sizeof(info), info, sizeof(buff), buff) == 0;
}
Blob* IscConnection::createBlob()
{
return FB_NEW IscBlob(*this);
@ -1096,14 +1126,14 @@ ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_execute2(FbStatusVector* user_status
}
ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_execute_immediate(FbStatusVector* user_status,
isc_db_handle *,
isc_tr_handle *,
unsigned short,
const char*,
unsigned short,
const XSQLDA *)
isc_db_handle* db_handle, isc_tr_handle* tra_handle, unsigned short length,
const char* str, unsigned short dialect, const XSQLDA* sqlda)
{
return notImplemented(user_status);
if (!m_api.isc_dsql_execute_immediate)
return notImplemented(user_status);
return (*m_api.isc_dsql_execute_immediate) (IscStatus(user_status),
db_handle, tra_handle, length, str, dialect, sqlda);
}
ISC_STATUS ISC_EXPORT IscProvider::isc_dsql_fetch(FbStatusVector* user_status,
@ -1641,8 +1671,17 @@ void FBProvider::loadAPI()
static bool isConnectionBrokenError(FbStatusVector* status)
{
ISC_STATUS code = status->getErrors()[1];
return (fb_utils::isNetworkError(code) || code == isc_att_shutdown);
const ISC_STATUS code = status->getErrors()[1];
switch (code)
{
case isc_shutdown:
case isc_att_shutdown:
case isc_bad_db_handle:
return true;
default:
return fb_utils::isNetworkError(code);
}
}

View File

@ -49,7 +49,6 @@ public:
loadAPI();
}
virtual void jrdAttachmentEnd(Jrd::thread_db* /*tdbb*/, Jrd::Attachment* /*att*/) {}
virtual void getRemoteError(const Jrd::FbStatusVector* status, Firebird::string& err) const;
protected:
@ -517,15 +516,14 @@ protected:
public:
FB_API_HANDLE& getAPIHandle() { return m_handle; }
virtual void attach(Jrd::thread_db* tdbb, const Firebird::PathName& dbName,
const Firebird::MetaName& user, const Firebird::string& pwd,
const Firebird::MetaName& role);
virtual void attach(Jrd::thread_db* tdbb);
virtual bool cancelExecution(bool forced);
virtual bool resetSession();
virtual bool isAvailable(Jrd::thread_db* tdbb, TraScope traScope) const;
virtual bool isConnected() const { return (m_handle != 0); }
virtual bool validate(Jrd::thread_db* tdbb);
virtual Blob* createBlob();

View File

@ -1087,10 +1087,10 @@ static void invoke(thread_db* tdbb,
if (function->fun_return_arg)
{
CALL_UDF<void>(tdbb, function->fun_entrypoint, args);
result_is_null = return_ptr->prm_fun_mechanism == FUN_descriptor &&
(value->vlu_desc.dsc_flags & DSC_null) ||
return_ptr->prm_fun_mechanism == FUN_blob_struct && return_blob_struct &&
!return_blob_struct->blob_handle;
result_is_null =
(return_ptr->prm_fun_mechanism == FUN_descriptor && (value->vlu_desc.dsc_flags & DSC_null)) ||
(return_ptr->prm_fun_mechanism == FUN_blob_struct && return_blob_struct &&
!return_blob_struct->blob_handle);
}
else if (return_ptr->prm_fun_mechanism == FUN_value)
{

View File

@ -810,7 +810,7 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database)
}
if (DTYPE_IS_TEXT(gfield->gfld_dtype))
get_charset_by_text_type(field->charSetId, gfield->gfld_sub_type);
get_charset_by_text_type(field->charSetId.value, gfield->gfld_sub_type);
if (gfield->gfld_nullable)
field->flags |= FLD_nullable;

View File

@ -4188,6 +4188,8 @@ void JProvider::shutdown(CheckStatusWrapper* status, unsigned int timeout, const
ThreadContextHolder tdbb;
EDS::Manager::shutdown();
ULONG attach_count, database_count, svc_count;
JRD_enum_attachments(NULL, attach_count, database_count, svc_count);
@ -5542,9 +5544,10 @@ JBatch* JStatement::createBatch(Firebird::CheckStatusWrapper* status, Firebird::
DsqlBatch* const b = DsqlBatch::open(tdbb, getHandle(), inMetadata, parLength, par);
batch = FB_NEW JBatch(b, this);
batch = FB_NEW JBatch(b, this, inMetadata);
batch->addRef();
b->setInterfacePtr(batch);
tdbb->getAttachment()->registerBatch(batch);
}
catch (const Exception& ex)
{
@ -5565,9 +5568,10 @@ JBatch* JStatement::createBatch(Firebird::CheckStatusWrapper* status, Firebird::
}
JBatch::JBatch(DsqlBatch* handle, JStatement* aStatement)
JBatch::JBatch(DsqlBatch* handle, JStatement* aStatement, IMessageMetadata* aMetadata)
: batch(handle),
statement(aStatement)
statement(aStatement),
m_meta(aMetadata)
{ }
@ -5583,12 +5587,46 @@ int JBatch::release()
return 1;
if (batch)
delete batch;
{
LocalStatus status;
CheckStatusWrapper statusWrapper(&status);
freeEngineData(&statusWrapper);
}
delete this;
return 0;
}
void JBatch::freeEngineData(Firebird::CheckStatusWrapper* user_status)
{
try
{
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
check_database(tdbb);
try
{
Attachment* att = getAttachment()->getHandle();
if (att)
att->deregisterBatch(this);
delete batch;
}
catch (const Exception& ex)
{
transliterateException(tdbb, ex, user_status, FB_FUNCTION);
return;
}
}
catch (const Exception& ex)
{
ex.stuffException(user_status);
return;
}
successful_completion(user_status);
}
void JBatch::add(CheckStatusWrapper* status, unsigned count, const void* inBuffer)
{
@ -7599,7 +7637,7 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
try
{
// allow to free resources used by dynamic statements
EDS::Manager::jrdAttachmentEnd(tdbb, attachment);
EDS::Manager::jrdAttachmentEnd(tdbb, attachment, forcedPurge);
if (!(dbb->dbb_flags & DBB_bugcheck))
{
@ -8020,9 +8058,6 @@ static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM arg)
try
{
// Shutdown external datasets manager
EDS::Manager::shutdown();
{ // scope
MutexLockGuard guard(databases_mutex, FB_FUNCTION);
@ -8631,6 +8666,38 @@ void JRD_start_and_send(thread_db* tdbb, jrd_req* request, jrd_tra* transaction,
}
void JRD_run_trans_start_triggers(thread_db* tdbb, jrd_tra* transaction)
{
/**************************************
*
* Run TRIGGER_TRANS_START, rollback transaction on failure.
* Handle rollback error, re-throw trigger error
*
**************************************/
try
{
EXE_execute_db_triggers(tdbb, transaction, TRIGGER_TRANS_START);
}
catch (const Exception&)
{
try
{
TRA_rollback(tdbb, transaction, false, false);
}
catch (const Exception& ex2)
{
if (tdbb->getDatabase()->dbb_flags & DBB_bugcheck)
throw;
iscLogException("Error rolling back new transaction", ex2);
}
throw;
}
}
static void start_transaction(thread_db* tdbb, bool transliterate, jrd_tra** tra_handle,
Jrd::Attachment* attachment, unsigned int tpb_length, const UCHAR* tpb)
{
@ -8659,10 +8726,10 @@ static void start_transaction(thread_db* tdbb, bool transliterate, jrd_tra** tra
jrd_tra* transaction = TRA_start(tdbb, tpb_length, tpb);
*tra_handle = transaction;
// run ON TRANSACTION START triggers
EXE_execute_db_triggers(tdbb, transaction, TRIGGER_TRANS_START);
JRD_run_trans_start_triggers(tdbb, transaction);
*tra_handle = transaction;
}
catch (const Exception& ex)
{

View File

@ -66,6 +66,7 @@ void JRD_commit_transaction(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction);
void JRD_commit_retaining(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction);
void JRD_rollback_transaction(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction);
void JRD_rollback_retaining(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction);
void JRD_run_trans_start_triggers(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction);
void JRD_send(Jrd::thread_db* tdbb, Jrd::jrd_req* request, USHORT msg_type, ULONG msg_length,
const void* msg);
void JRD_start_and_send(Jrd::thread_db* tdbb, Jrd::jrd_req* request, Jrd::jrd_tra* transaction,

View File

@ -491,7 +491,7 @@ DecimalFixed MOV_get_dec_fixed(Jrd::thread_db* tdbb, const dsc* desc, SSHORT sca
namespace Jrd
{
DescPrinter::DescPrinter(thread_db* tdbb, const dsc* desc, int mLen)
DescPrinter::DescPrinter(thread_db* tdbb, const dsc* desc, FB_SIZE_T mLen)
: maxLen(mLen)
{
const char* const NULL_KEY_STRING = "NULL";
@ -504,9 +504,9 @@ DescPrinter::DescPrinter(thread_db* tdbb, const dsc* desc, int mLen)
fb_assert(!desc->isBlob());
value = MOV_make_string2(tdbb, desc, ttype_dynamic);
const bool isBinary = (desc->isText() && desc->getTextType() == ttype_binary);
value = MOV_make_string2(tdbb, desc, isBinary ? ttype_binary : ttype_dynamic);
const int len = (int) value.length();
const char* const str = value.c_str();
if (desc->isText() || desc->isDateTime())
@ -517,18 +517,23 @@ DescPrinter::DescPrinter(thread_db* tdbb, const dsc* desc, int mLen)
value.rtrim(pad);
}
if (desc->isText() && desc->getTextType() == ttype_binary)
if (isBinary)
{
Firebird::string hex;
string hex;
FB_SIZE_T len = value.length();
const bool cut = (len > (maxLen - 3) / 2);
if (cut)
len = (maxLen - 5) / 2;
char* s = hex.getBuffer(2 * len);
for (int i = 0; i < len; i++)
for (FB_SIZE_T i = 0; i < len; i++)
{
sprintf(s, "%02X", (int)(unsigned char) str[i]);
s += 2;
}
value = "x'" + hex + "'";
value = "x'" + hex + (cut ? "..." : "'");
}
else
value = "'" + value + "'";

View File

@ -61,7 +61,7 @@ namespace Jrd
class DescPrinter
{
public:
DescPrinter(thread_db* tdbb, const dsc* desc, int mLen);
DescPrinter(thread_db* tdbb, const dsc* desc, FB_SIZE_T mLen);
const Firebird::string& get() const
{
@ -70,7 +70,7 @@ public:
private:
Firebird::string value;
int maxLen;
FB_SIZE_T maxLen;
};
} // namespace Jrd

View File

@ -644,8 +644,8 @@ PAG PAG_allocate_pages(thread_db* tdbb, WIN* window, int cntAlloc, bool aligned)
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES_INFO,
"\tPAG_allocate: allocated page %" SLONGFORMAT"\n",
i + sequence * pageMgr.pagesPerPIP);
"PAG_allocate: allocated page %" SLONGFORMAT"\n",
i + sequence * pageMgr.pagesPerPIP);
#endif
}
@ -715,8 +715,8 @@ PAG PAG_allocate_pages(thread_db* tdbb, WIN* window, int cntAlloc, bool aligned)
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES_INFO,
"\tPAG_allocate: allocated page %" SLONGFORMAT"\n",
bit + sequence * pageMgr.pagesPerPIP);
"PAG_allocate: allocated page %" SLONGFORMAT"\n",
bit + sequence * pageMgr.pagesPerPIP);
#endif
}
@ -1554,11 +1554,19 @@ void PAG_release_pages(thread_db* tdbb, USHORT pageSpaceID, int cntRelease,
page_inv_page* pages = NULL;
ULONG sequence = 0;
#ifdef VIO_DEBUG
string dbg = "PAG_release_pages: about to release pages: ";
#endif
for (int i = 0; i < cntRelease; i++)
{
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES_INFO,
"\tPAG_release_pages: about to release page %" SLONGFORMAT"\n", pgNums[i]);
if (i > 0)
dbg.append(", ");
char num[16];
_ltoa_s(pgNums[i], num, sizeof(num), 10);
dbg.append(num);
#endif
const ULONG seq = pgNums[i] / pageMgr.pagesPerPIP;
@ -1593,6 +1601,10 @@ void PAG_release_pages(thread_db* tdbb, USHORT pageSpaceID, int cntRelease,
pages->pip_min = MIN(pages->pip_min, relative_bit);
}
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES_INFO, "%s\n", dbg.c_str());
#endif
pageSpace->pipHighWater.exchangeLower(sequence);
if (pages->pip_extent < pageMgr.pagesPerPIP)

View File

@ -305,7 +305,7 @@ public:
} req_operation; // operation for next node
StatusXcp req_last_xcp; // last known exception
bool req_batch;
bool req_batch_mode;
template <typename T> T* getImpure(unsigned offset)
{

View File

@ -221,7 +221,12 @@ void SCL_check_access(thread_db* tdbb,
**************************************/
SET_TDBB(tdbb);
if (tdbb->tdbb_flags & TDBB_trusted_ddl)
// RS: SCL_references must be checked for DDL operation of index creation
// and we need to ignore TDBB_trusted_ddl flag in this case.
// More general solution is to remove TDBB_trusted_dll flag since its purpose to
// allow system table modification due DDL operations. It requires removing SCL_checks
// from VIO_{store,erase,motify}. It's quite possible but not so trivial as at fist look.
if ((tdbb->tdbb_flags & TDBB_trusted_ddl) && (mask != SCL_references))
return;
if (s_class && (s_class->scl_flags & SCL_corrupt))

View File

@ -929,13 +929,13 @@ void TRA_update_counters(thread_db* tdbb, Database* dbb)
{
CCH_MARK_MUST_WRITE(tdbb, &window);
if (dbb->dbb_oldest_active > header->hdr_oldest_active)
if (dbb->dbb_oldest_active > oldest_active)
Ods::writeOAT(header, dbb->dbb_oldest_active);
if (dbb->dbb_oldest_transaction > header->hdr_oldest_transaction)
if (dbb->dbb_oldest_transaction > oldest_transaction)
Ods::writeOIT(header, dbb->dbb_oldest_transaction);
if (dbb->dbb_oldest_snapshot > header->hdr_oldest_snapshot)
if (dbb->dbb_oldest_snapshot > oldest_snapshot)
Ods::writeOST(header, dbb->dbb_oldest_snapshot);
if (dbb->dbb_next_transaction > next_transaction)

File diff suppressed because it is too large Load Diff

View File

@ -824,7 +824,7 @@ const Validation::MSG_ENTRY Validation::vdr_msg_table[VAL_MAX_ERROR] =
{true, isc_info_ppage_errors, "Pointer page {sequence %" ULONGFORMAT"} lost"},
{true, isc_info_ppage_errors, "Pointer page %" ULONGFORMAT" {sequence %" ULONGFORMAT"} inconsistent"},
{true, isc_info_record_errors, "Record %" SQUADFORMAT" is marked as damaged"},
{true, isc_info_record_errors, "Record %" SQUADFORMAT" has bad transaction %" ULONGFORMAT}, // 15
{true, isc_info_record_errors, "Record %" SQUADFORMAT" has bad transaction %" SQUADFORMAT}, // 15
{true, isc_info_record_errors, "Fragmented record %" SQUADFORMAT" is corrupt"},
{true, isc_info_record_errors, "Record %" SQUADFORMAT" is wrong length"},
{true, isc_info_ipage_errors, "Missing index root page"},
@ -1618,7 +1618,7 @@ void Validation::walk_database()
WIN window(DB_PAGE_SPACE, -1);
header_page* page = 0;
fetch_page(true, HEADER_PAGE, pag_header, &window, &page);
vdr_max_transaction = page->hdr_next_transaction;
TraNumber next = vdr_max_transaction = Ods::getNT(page);
if (vdr_flags & VDR_online) {
release_page(&window);
@ -1629,7 +1629,7 @@ void Validation::walk_database()
walk_header(page->hdr_next_page);
walk_pip();
walk_scns();
walk_tip(page->hdr_next_transaction);
walk_tip(next);
walk_generators();
}
@ -2716,6 +2716,11 @@ Validation::RTN Validation::walk_record(jrd_rel* relation, const rhd* header, US
p = (SCHAR*) fragment->rhdf_data;
end = p + length - offsetof(rhdf, rhdf_data[0]);
}
else if (header->rhd_flags & rhd_long_tranum)
{
p = (SCHAR*) ((rhde*)header)->rhde_data;
end = p + length - offsetof(rhde, rhde_data[0]);
}
else
{
p = (SCHAR*) header->rhd_data;
@ -2773,6 +2778,11 @@ Validation::RTN Validation::walk_record(jrd_rel* relation, const rhd* header, US
p = (SCHAR*) fragment->rhdf_data;
end = p + line->dpg_length - offsetof(rhdf, rhdf_data[0]);
}
else if (fragment->rhdf_flags & rhd_long_tranum)
{
p = (SCHAR*) ((rhde*)fragment)->rhde_data;
end = p + line->dpg_length - offsetof(rhde, rhde_data[0]);
}
else
{
p = (SCHAR*) ((rhd*) fragment)->rhd_data;
@ -3013,7 +3023,7 @@ Validation::RTN Validation::walk_relation(jrd_rel* relation)
WIN window(DB_PAGE_SPACE, -1);
header_page* page = NULL;
fetch_page(false, (SLONG) HEADER_PAGE, pag_header, &window, &page);
vdr_max_transaction = page->hdr_next_transaction;
vdr_max_transaction = Ods::getNT(page);
release_page(&window);
}

View File

@ -112,7 +112,7 @@ static void garbage_collect(thread_db*, record_param*, ULONG, RecordStack&);
#include <stdio.h>
#include <stdarg.h>
int vio_debug_flag = 0;
int vio_debug_flag = DEBUG_TRACE_ALL_INFO;
void VIO_trace(int level, const char* format, ...)
{
@ -390,14 +390,14 @@ void VIO_backout(thread_db* tdbb, record_param* rpb, const jrd_tra* transaction)
fb_assert(assert_gc_enabled(transaction, rpb->rpb_relation));
jrd_rel* const relation = rpb->rpb_relation;
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"VIO_backout (record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT")\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
"VIO_backout (rel_id %u, record_param %" SQUADFORMAT", transaction %" SQUADFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
#endif
jrd_rel* const relation = rpb->rpb_relation;
// If there is data in the record, fetch it now. If the old version
// is a differences record, we will need it sooner. In any case, we
// will need it eventually to clean up blobs and indices. If the record
@ -516,7 +516,7 @@ void VIO_backout(thread_db* tdbb, record_param* rpb, const jrd_tra* transaction)
#ifdef VIO_DEBUG
if (temp2.rpb_b_page != rpb->rpb_b_page || temp.rpb_b_line != rpb->rpb_b_line ||
temp.rpb_transaction_nr != rpb->rpb_transaction_nr)
temp.rpb_transaction_nr != rpb->rpb_transaction_nr)
{
VIO_trace(DEBUG_WRITES_INFO,
" record changed!)\n");
@ -704,8 +704,9 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb,
#ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL,
"VIO_chase_record_version (record_param %" QUADFORMAT"d, transaction %"
"VIO_chase_record_version (rel_id %u, record_param %" QUADFORMAT"d, transaction %"
SQUADFORMAT", pool %p)\n",
relation->rel_id,
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
(void*) pool);
@ -1302,10 +1303,12 @@ void VIO_data(thread_db* tdbb, record_param* rpb, MemoryPool* pool)
**************************************/
SET_TDBB(tdbb);
jrd_rel* const relation = rpb->rpb_relation;
#ifdef VIO_DEBUG
VIO_trace(DEBUG_READS,
"VIO_data (record_param %" QUADFORMAT"d, pool %p)\n",
rpb->rpb_number.getValue(), (void*) pool);
"VIO_data (rel_id %u, record_param %" QUADFORMAT"d, pool %p)\n",
relation->rel_id, rpb->rpb_number.getValue(), (void*)pool);
VIO_trace(DEBUG_READS_INFO,
@ -1321,7 +1324,6 @@ void VIO_data(thread_db* tdbb, record_param* rpb, MemoryPool* pool)
// the format block and set up the record block. This is a performance
// optimization.
jrd_rel* const relation = rpb->rpb_relation;
Record* const record = VIO_record(tdbb, rpb, NULL, pool);
const Format* const format = record->getFormat();
@ -1432,11 +1434,12 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
SET_TDBB(tdbb);
jrd_req* request = tdbb->getRequest();
jrd_rel* relation = rpb->rpb_relation;
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"VIO_erase (record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT")\n",
rpb->rpb_number.getValue(), transaction->tra_number);
"VIO_erase (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction->tra_number);
VIO_trace(DEBUG_WRITES_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -1458,8 +1461,6 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
}
// deleting tx has updated/inserted this record before
jrd_rel* relation = rpb->rpb_relation;
tdbb->bumpRelStats(RuntimeStatistics::RECORD_DELETES, relation->rel_id);
// Special case system transaction
@ -2263,10 +2264,11 @@ bool VIO_garbage_collect(thread_db* tdbb, record_param* rpb, jrd_tra* transactio
Jrd::Attachment* attachment = transaction->tra_attachment;
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE,
"VIO_garbage_collect (record_param %" QUADFORMAT"d, transaction %"
"VIO_garbage_collect (rel_id %u, record_param %" QUADFORMAT"d, transaction %"
SQUADFORMAT")\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
VIO_trace(DEBUG_TRACE_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -2398,9 +2400,10 @@ bool VIO_get(thread_db* tdbb, record_param* rpb, jrd_tra* transaction, MemoryPoo
SET_TDBB(tdbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"VIO_get (record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT", pool %p)\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
"VIO_get (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT", pool %p)\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
(void*) pool);
#endif
@ -2477,9 +2480,10 @@ bool VIO_get_current(thread_db* tdbb,
Attachment* const attachment = tdbb->getAttachment();
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE,
"VIO_get_current (record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT", pool %p)\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
"VIO_get_current (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT", pool %p)\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
(void*) pool);
#endif
@ -2742,12 +2746,13 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
SET_TDBB(tdbb);
MetaName object_name, package_name;
jrd_rel* relation = org_rpb->rpb_relation;
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"VIO_modify (org_rpb %" QUADFORMAT"d, new_rpb %" QUADFORMAT"d, "
"VIO_modify (rel_id %u, org_rpb %" QUADFORMAT"d, new_rpb %" QUADFORMAT"d, "
"transaction %" SQUADFORMAT")\n",
org_rpb->rpb_number.getValue(), new_rpb->rpb_number.getValue(),
relation->rel_id, org_rpb->rpb_number.getValue(), new_rpb->rpb_number.getValue(),
transaction ? transaction->tra_number : 0);
VIO_trace(DEBUG_WRITES_INFO,
@ -2758,7 +2763,6 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
org_rpb->rpb_f_page, org_rpb->rpb_f_line);
#endif
jrd_rel* relation = org_rpb->rpb_relation;
transaction->tra_flags |= TRA_write;
new_rpb->rpb_transaction_nr = transaction->tra_number;
new_rpb->rpb_flags = 0;
@ -3241,9 +3245,10 @@ bool VIO_next_record(thread_db* tdbb,
const USHORT lock_type = (rpb->rpb_stream_flags & RPB_s_update) ? LCK_write : LCK_read;
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE,
"VIO_next_record (record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT", pool %p)\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
"VIO_next_record (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT", pool %p)\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
(void*) pool);
VIO_trace(DEBUG_TRACE_INFO,
@ -3308,9 +3313,10 @@ Record* VIO_record(thread_db* tdbb, record_param* rpb, const Format* format, Mem
SET_TDBB(tdbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE,
"VIO_record (record_param %" QUADFORMAT"d, format %d, pool %p)\n",
rpb->rpb_number.getValue(), format ? format->fmt_version : 0,
"VIO_record (rel_id %u, record_param %" QUADFORMAT"d, format %d, pool %p)\n",
relation->rel_id, rpb->rpb_number.getValue(), format ? format->fmt_version : 0,
(void*) pool);
#endif
@ -3350,9 +3356,10 @@ bool VIO_refetch_record(thread_db* tdbb, record_param* rpb, jrd_tra* transaction
*
**************************************/
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"VIO_refetch_record (record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT")\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
"VIO_refetch_record (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
#endif
const TraNumber tid_fetch = rpb->rpb_transaction_nr;
@ -3418,6 +3425,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
**************************************/
SET_TDBB(tdbb);
jrd_req* const request = tdbb->getRequest();
jrd_rel* relation = rpb->rpb_relation;
DeferredWork* work = NULL;
MetaName package_name;
@ -3426,13 +3434,12 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"VIO_store (record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT
")\n", rpb->rpb_number.getValue(),
"VIO_store (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT
")\n", relation->rel_id, rpb->rpb_number.getValue(),
transaction ? transaction->tra_number : 0);
#endif
transaction->tra_flags |= TRA_write;
jrd_rel* relation = rpb->rpb_relation;
DSC desc, desc2;
check_gbak_cheating_insupd(tdbb, relation, "INSERT");
@ -3785,11 +3792,11 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d\n",
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr,
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line,
rpb->rpb_f_page, rpb->rpb_f_line);
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d\n",
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr,
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line,
rpb->rpb_f_page, rpb->rpb_f_line);
#endif
if (!(transaction->tra_flags & TRA_system) &&
@ -3932,10 +3939,11 @@ bool VIO_writelock(thread_db* tdbb, record_param* org_rpb, jrd_tra* transaction)
**************************************/
SET_TDBB(tdbb);
jrd_rel* const relation = org_rpb->rpb_relation;
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"VIO_writelock (org_rpb %" QUADFORMAT"d, transaction %" SQUADFORMAT")\n",
org_rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
"VIO_writelock (rel_id %u, org_rpb %" QUADFORMAT"d, transaction %" SQUADFORMAT")\n",
relation->rel_id, org_rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
VIO_trace(DEBUG_WRITES_INFO,
" old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -3977,8 +3985,6 @@ bool VIO_writelock(thread_db* tdbb, record_param* org_rpb, jrd_tra* transaction)
org_rpb->rpb_format_number = org_format->fmt_version;
}
jrd_rel* const relation = org_rpb->rpb_relation;
// Set up the descriptor for the new record version. Initially,
// it points to the same record data as the original one.
record_param new_rpb = *org_rpb;
@ -4302,9 +4308,10 @@ static void delete_record(thread_db* tdbb, record_param* rpb, ULONG prior_page,
SET_TDBB(tdbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"delete_record (record_param %" QUADFORMAT"d, prior_page %" SLONGFORMAT", pool %p)\n",
rpb->rpb_number.getValue(), prior_page, (void*) pool);
"delete_record (rel_id %u, record_param %" QUADFORMAT"d, prior_page %" SLONGFORMAT", pool %p)\n",
relation->rel_id, rpb->rpb_number.getValue(), prior_page, (void*)pool);
VIO_trace(DEBUG_WRITES_INFO,
" delete_record record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -4379,9 +4386,10 @@ static UCHAR* delete_tail(thread_db* tdbb,
SET_TDBB(tdbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"delete_tail (record_param %" QUADFORMAT"d, prior_page %" SLONGFORMAT", tail %p, tail_end %p)\n",
rpb->rpb_number.getValue(), prior_page, tail, tail_end);
"delete_tail (rel_id %u, record_param %" QUADFORMAT"d, prior_page %" SLONGFORMAT", tail %p, tail_end %p)\n",
relation->rel_id, rpb->rpb_number.getValue(), prior_page, tail, tail_end);
VIO_trace(DEBUG_WRITES_INFO,
" tail of record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -4467,10 +4475,11 @@ static void expunge(thread_db* tdbb, record_param* rpb, const jrd_tra* transacti
fb_assert(assert_gc_enabled(transaction, rpb->rpb_relation));
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"expunge (record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT
"expunge (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT
", prior_page %" SLONGFORMAT")\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
prior_page);
#endif
@ -4552,9 +4561,10 @@ static void garbage_collect(thread_db* tdbb, record_param* rpb, ULONG prior_page
SET_TDBB(tdbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"garbage_collect (record_param %" QUADFORMAT"d, prior_page %" SLONGFORMAT", staying)\n",
rpb->rpb_number.getValue(), prior_page);
"garbage_collect (rel_id %u, record_param %" QUADFORMAT"d, prior_page %" SLONGFORMAT", staying)\n",
relation->rel_id, rpb->rpb_number.getValue(), prior_page);
VIO_trace(DEBUG_WRITES_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -5429,12 +5439,13 @@ static int prepare_update( thread_db* tdbb,
SET_TDBB(tdbb);
Attachment* const attachment = tdbb->getAttachment();
jrd_rel* const relation = rpb->rpb_relation;
#ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL,
"prepare_update (transaction %" SQUADFORMAT
"prepare_update (rel_id %u, transaction %" SQUADFORMAT
", commit_tid read %" SQUADFORMAT", record_param %" QUADFORMAT"d, ",
transaction ? transaction->tra_number : 0, commit_tid_read,
relation->rel_id, transaction ? transaction->tra_number : 0, commit_tid_read,
rpb ? rpb->rpb_number.getValue() : 0);
VIO_trace(DEBUG_TRACE_ALL,
@ -5468,8 +5479,6 @@ static int prepare_update( thread_db* tdbb,
the record and committed, then an update error will be returned.
*/
jrd_rel* const relation = rpb->rpb_relation;
*temp = *rpb;
Record* const record = rpb->rpb_record;
@ -5845,9 +5854,11 @@ static void purge(thread_db* tdbb, record_param* rpb)
fb_assert(assert_gc_enabled(tdbb->getTransaction(), rpb->rpb_relation));
jrd_rel* const relation = rpb->rpb_relation;
#ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL,
"purge (record_param %" QUADFORMAT"d)\n", rpb->rpb_number.getValue());
"purge (rel_id %u, record_param %" QUADFORMAT"d)\n",
relation->rel_id, rpb->rpb_number.getValue());
VIO_trace(DEBUG_TRACE_ALL_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -5862,7 +5873,6 @@ static void purge(thread_db* tdbb, record_param* rpb)
// the record.
record_param temp = *rpb;
jrd_rel* const relation = rpb->rpb_relation;
AutoGCRecord gc_rec(VIO_gc_record(tdbb, relation));
Record* record = rpb->rpb_record = gc_rec;
@ -5924,9 +5934,10 @@ static void replace_record(thread_db* tdbb,
SET_TDBB(tdbb);
#ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE_ALL,
"replace_record (record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT")\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
"replace_record (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
VIO_trace(DEBUG_TRACE_ALL_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -6018,7 +6029,7 @@ static void refresh_fk_fields(thread_db* tdbb, Record* old_rec, record_param* cu
// If field was not changed by user - pick up possible modification by
// system cascade trigger
if (flag_old == flag_new &&
(!flag_old || flag_old && MOV_compare(tdbb, &desc1, &desc2) == 0))
(!flag_old || (flag_old && MOV_compare(tdbb, &desc1, &desc2) == 0)))
{
const bool flag_tmp = EVL_field(relation, cur_rpb->rpb_record, fld, &desc1);
if (flag_tmp)
@ -6161,11 +6172,12 @@ void VIO_update_in_place(thread_db* tdbb,
Database* dbb = tdbb->getDatabase();
CHECK_DBB(dbb);
jrd_rel* const relation = org_rpb->rpb_relation;
#ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL,
"update_in_place (transaction %" SQUADFORMAT", org_rpb %" QUADFORMAT"d, "
"update_in_place (rel_id %u, transaction %" SQUADFORMAT", org_rpb %" QUADFORMAT"d, "
"new_rpb %" QUADFORMAT"d)\n",
transaction ? transaction->tra_number : 0, org_rpb->rpb_number.getValue(),
relation->rel_id, transaction ? transaction->tra_number : 0, org_rpb->rpb_number.getValue(),
new_rpb ? new_rpb->rpb_number.getValue() : 0);
VIO_trace(DEBUG_TRACE_ALL_INFO,
@ -6186,7 +6198,6 @@ void VIO_update_in_place(thread_db* tdbb,
stack = &org_rpb->rpb_record->getPrecedence();
}
jrd_rel* const relation = org_rpb->rpb_relation;
Record* const old_data = org_rpb->rpb_record;
// If the old version has been stored as a delta, things get complicated. Clearly,

View File

@ -408,7 +408,7 @@ int CLIB_ROUTINE main( int argc, char *argv[])
break;
case 'i':
while (c = *p++)
while ((c = *p++))
switch (c)
{
case 'a':

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