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

Merged changes from master branch

This commit is contained in:
AlexPeshkoff 2017-02-16 17:56:23 +03:00
commit 028248b194
185 changed files with 6920 additions and 4484 deletions

2
.gitignore vendored
View File

@ -16,3 +16,5 @@ libtool
*.bak
*.tmp
src/dsql/parse.cpp
.vscode/.browse.VC.db
extern/decNumber/libdecFloat.a

41
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,41 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "isql - launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceRoot}/gen/Debug/firebird/bin/isql",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceRoot}",
"environment": [],
"externalConsole": true,
"linux": {
"MIMode": "gdb"
},
"osx": {
"MIMode": "lldb"
},
"windows": {
"MIMode": "gdb"
}
},
{
"name": "isql - attach",
"type": "cppdbg",
"request": "attach",
"program": "${workspaceRoot}/gen/Debug/firebird/bin/isql",
"processId": "${command.pickProcess}",
"linux": {
"MIMode": "gdb"
},
"osx": {
"MIMode": "lldb"
},
"windows": {
"MIMode": "gdb"
}
}
]
}

14
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,14 @@
// Place your settings in this file to overwrite default and user settings.
{
"editor.tabSize": 4,
"editor.insertSpaces": false,
"editor.rulers": [120],
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"files.exclude": {
"temp": true,
"gen": true
}
}

13
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,13 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "0.1.0",
"command": "make",
"isShellCommand": true,
"args": [
"TARGET=Debug",
"engine",
"-j9"
],
"showOutput": "always"
}

View File

@ -2,6 +2,9 @@
## Bugfixes
* [CORE-5408](http://tracker.firebirdsql.org/browse/CORE-5408): Result of boolean expression can not be concatenated with string literal
Contributor(s): Adriano dos Santos Fernandes
* [CORE-5237](http://tracker.firebirdsql.org/browse/CORE-5237): Invalid handling of dot (.) and asterisk (*) in config file name and path for include clause
Contributor(s): Dimitry Sibiryakov
@ -25,15 +28,30 @@
## Improvements
* [CORE-5431](http://tracker.firebirdsql.org/browse/CORE-5431): Support for DROP IDENTITY clause
Contributor(s): Adriano dos Santos Fernandes
* [CORE-5430](http://tracker.firebirdsql.org/browse/CORE-5430): Support for INCREMENT option in identity columns
Contributor(s): Adriano dos Santos Fernandes
* [CORE-5119](http://tracker.firebirdsql.org/browse/CORE-5119): Support autocommit mode in SET TRANSACTION statement
Contributor(s): Dmitry Yemanov
* [CORE-2557](http://tracker.firebirdsql.org/browse/CORE-2557): Grants on MON$ tables
Contributor(s): Alex Peshkoff
* [CORE-2216](http://tracker.firebirdsql.org/browse/CORE-2216): NBackup as online dump
Contributor(s): Roman Simakov, Vlad Khorsun
* [CORE-2192](http://tracker.firebirdsql.org/browse/CORE-2192): Extend maximum database page size to 32KB
Contributor(s): Dmitry Yemanov
* [CORE-2040](http://tracker.firebirdsql.org/browse/CORE-2040): Allow exception name and possibly exception text to be determined within a "WHEN ANY" error handling block
Contributor(s): Dmitry Yemanov
* [CORE-1132](http://tracker.firebirdsql.org/browse/CORE-1132): Exception context in PSQL exception handlers
Contributor(s): Dmitry Yemanov
* [CORE-749](http://tracker.firebirdsql.org/browse/CORE-749): Increase maximum length of object names to 63 characters
Contributor(s): Adriano dos Santos Fernandes
@ -48,6 +66,9 @@
* [CORE-3647](http://tracker.firebirdsql.org/browse/CORE-3647): Frames for window functions
Contributor(s): Adriano dos Santos Fernandes
* [CORE-2990](http://tracker.firebirdsql.org/browse/CORE-2990): Physical (page-level) standby replication / page shipping
Contributor(s): Roman Simakov, Vlad Khorsun
* [CORE-2762](http://tracker.firebirdsql.org/browse/CORE-2762): New built-in function to check whether some role is implicitly active
Contributor(s): Roman Simakov

View File

@ -370,7 +370,7 @@ EOF
chown root:root $initScript
chmod u=rwx,g=rx,o=r $initScript
if [ "${fb_install_prefix}" == "${default_prefix}" ]
if [ "${fb_install_prefix}" = "${default_prefix}" ]
then
# RedHat and Mandrake specific
if [ -x /sbin/chkconfig ]

View File

@ -466,6 +466,37 @@
#
#KeyHolderPlugin =
# ----------------------------
#
# Ability to use encrypted security database
#
# If one relies on network encryption feature with crypt key generated
# by authentication plugin (like SRP does) to transfer database crypt
# keys over the wire then use of encrypted security databases is a kind of
# vicious circle. In order to send DB crypt key over the wire in secure way
# wire transfers should be already encrypted but this requires wire crypt key
# from authentication plugin which needs to open security database for hash
# validation which in turn requires DB crypt key. Luckily in most cases there
# is no big need to encrypt security database - it protects itself quite well
# if you use high quality passwords. But in some cases it's desired to have
# security database encrypted, for example if one wants to use self security
# database feature for encrypted database. In that case special care should be
# taken to encrypt that key before passing it to server using callback. Make
# sure your keys are well encrypted before enabling this parameter. Take into
# account that with CryptSecurityDatabase=TRUE unencrypted by firebird protocol
# key transfer may take place even with not encrypted security database.
# This feature is not supported by legacy authentication plugin - if you care
# about security please never use legacy authentication.
#
# Type: boolean
#
# Per-database configurable.
#
#########################################################################
# Please understand what are you doing before enabling this feature !!! #
#########################################################################
#
#CryptSecurityDatabase = false
# ----------------------------
#

View File

@ -546,26 +546,38 @@ buildUninstallFile() {
then
cp $Manifest $MANIFEST_TXT
else
rm -f $MANIFEST_TXT
oldPath=".${default_prefix}"
for line in `grep "^${oldPath}" $Manifest | colrm 1 ${#oldPath}`
do
echo ".${fb_install_prefix}${line}" >>$MANIFEST_TXT
done
newPath=`dirname "${fb_install_prefix}"`
while [ ${#newPath} -gt 1 ]
do
echo ".${newPath}" >>$MANIFEST_TXT
newPath=`dirname $newPath`
done
newManifest $Manifest $MANIFEST_TXT
fi
[ -f @FB_SBINDIR@/$UninstallScript ] && chmod u=rx,go= @FB_SBINDIR@/$UninstallScript
}
#------------------------------------------------------------------------
# newManifest
# Create new manifest replacing default_prefix with fb_install_prefix
# in existing manifest
newManifest() {
ExistingManifestFile=${1}
CreateManifestFile=${2}
rm -f $CreateManifestFile
oldPath=".${default_prefix}"
for line in `grep "^${oldPath}" $ExistingManifestFile | colrm 1 ${#oldPath}`
do
echo ".${fb_install_prefix}${line}" >>$CreateManifestFile
done
newPath=`dirname "${fb_install_prefix}"`
while [ ${#newPath} -gt 1 ]
do
echo ".${newPath}" >>$CreateManifestFile
newPath=`dirname $newPath`
done
}
#------------------------------------------------------------------------
# Remove if only a link
@ -715,14 +727,25 @@ archivePriorInstallSystemFiles() {
fi
tarArc=${ArchiveMainFile}.$tarExt
oldPWD=`pwd`
distManifest=${oldPWD}/manifest.txt
archiveFileList=""
archiveDelTemp=""
if [ "${fb_install_prefix}" != "${default_prefix}" ]
then
TmpFile=""
MakeTemp
newManifest $distManifest $TmpFile
distManifest=$TmpFile
archiveDelTemp=$TmpFile
fi
cd /
if [ -f ${oldPWD}/manifest.txt ]; then
manifest=`cat ${oldPWD}/manifest.txt`
if [ -f ${distManifest} ]; then
manifest=`cat ${distManifest}`
for i in $manifest; do
if [ -f $i ]; then
i=${i#/} # strip off leading /
@ -731,6 +754,8 @@ archivePriorInstallSystemFiles() {
done
fi
rm -f "$archiveDelTemp"
DestFile=@FB_CONFDIR@
if [ -e "$DestFile" ]
then
@ -754,7 +779,8 @@ archivePriorInstallSystemFiles() {
fi
fi
if [ "${fb_install_prefix}" = "${default_prefix}" ]
then
for i in ibase.h ib_util.h
do
DestFile=usr/include/$i
@ -786,6 +812,7 @@ archivePriorInstallSystemFiles() {
fi
fi
done
fi
if [ ! -z "$archiveFileList" ]
then
@ -1148,7 +1175,7 @@ extractBuildroot() {
# depending upon presence of startup script starts super or classic server
startFirebird() {
if [ "${fb_install_prefix}" == "${default_prefix}" ]
if [ "${fb_install_prefix}" = "${default_prefix}" ]
then
if standaloneServerInstalled; then
startService

View File

@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2011-11-20.07; # UTC
scriptversion=2013-12-25.23; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@ -41,19 +41,15 @@ scriptversion=2011-11-20.07; # UTC
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" "" $nl"
IFS=" $tab$nl"
# set DOITPROG to echo to test this script
# Set DOITPROG to "echo" to test this script.
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
@ -68,17 +64,6 @@ mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_glob='?'
initialize_posix_glob='
test "$posix_glob" != "?" || {
if (set -f) 2>/dev/null; then
posix_glob=
else
posix_glob=:
fi
}
'
posix_mkdir=
# Desired mode of installed file.
@ -97,7 +82,7 @@ dir_arg=
dst_arg=
copy_on_change=false
no_target_directory=
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
@ -143,8 +128,7 @@ while test $# -ne 0; do
-m) mode=$2
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
@ -155,14 +139,16 @@ while test $# -ne 0; do
-s) stripcmd=$stripprog;;
-t) dst_arg=$2
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) no_target_directory=true;;
-T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
@ -177,6 +163,16 @@ while test $# -ne 0; do
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
@ -207,6 +203,15 @@ if test $# -eq 0; then
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
@ -269,7 +274,7 @@ do
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
@ -277,33 +282,7 @@ do
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
dstdir=`dirname "$dst"`
test -d "$dstdir"
dstdir_status=$?
fi
@ -396,14 +375,12 @@ do
*) prefix='';;
esac
eval "$initialize_posix_glob"
oIFS=$IFS
IFS=/
$posix_glob set -f
set -f
set fnord $dstdir
shift
$posix_glob set +f
set +f
IFS=$oIFS
prefixes=
@ -474,13 +451,10 @@ do
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
eval "$initialize_posix_glob" &&
$posix_glob set -f &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
$posix_glob set +f &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then

View File

@ -321,7 +321,7 @@ LINK_IB_UTIL = $(LIB_LINK) $(LINK_IBUTIL_SYMBOLS) $(LIB_LINK_OPTIONS) $(UNDEF_FL
LINK_IB_UTIL_LIBS = $(THR_LIBS)
LINK_INTL = $(LIB_LINK) $(LINK_FBINTL_SYMBOLS) $(LIB_LINK_OPTIONS) $(UNDEF_FLAGS)\
$(call LIB_LINK_SONAME,libintl.$(SHRLIB_EXT).1) $(call LIB_LINK_RPATH,lib)
$(call LIB_LINK_SONAME,libfbintl.$(SHRLIB_EXT).1) $(call LIB_LINK_RPATH,lib)
LINK_INTL_LIBS = -L$(LIB) $(SO_LINK_LIBS) $(FIREBIRD_LIBRARY_LINK)
LINK_TRACE = $(LIB_LINK) $(LINK_PLUGIN_SYMBOLS) $(LIB_LINK_OPTIONS) $(UNDEF_FLAGS)\

View File

@ -48,10 +48,11 @@ $(OBJ)/dsql/parse.cpp $(SRC_ROOT)/include/gen/parse.h: $(SRC_ROOT)/dsql/parse.y
($(BTYACC) -l -d -S $(SRC_ROOT)/dsql/btyacc_fb.ske $(GEN_ROOT)/y.y; echo $$? > $(GEN_ROOT)/y.status) 2>&1 | tee $(GEN_ROOT)/y.txt
(exit `cat $(GEN_ROOT)/y.status`)
sed -n -e "s/.*btyacc: \(.*conflicts.*\)/\1/p" $(GEN_ROOT)/y.txt > $(SRC_ROOT)/dsql/parse-conflicts.txt
$(MV) $(GEN_ROOT)/y_tab.c $(OBJ)/dsql/parse.cpp
sed -i 's/#define \([A-Z].*\)/#define TOK_\1/' $(GEN_ROOT)/y_tab.h
sed -i 's/#define TOK_YY\(.*\)/#define YY\1/' $(GEN_ROOT)/y_tab.h
$(MV) $(GEN_ROOT)/y_tab.h $(SRC_ROOT)/include/gen/parse.h
$(MV) $(GEN_ROOT)/y_tab.c $(OBJ)/dsql/parse.cpp
touch $(OBJ)/dsql/parse.cpp
# gpre_meta needs a special boot build since there is no database.

View File

@ -27,5 +27,6 @@
@del types.y
@del y_tab.h
@del y_tab.c
@del sed*
:END

File diff suppressed because it is too large Load Diff

View File

@ -170,20 +170,30 @@ SQLSTATE (FB 2.5)
1. SQLSTATE always evaluates to NULL outside the exception handling block.
EXCEPTION (FB 4.0)
RDB$ERROR (FB 4.0)
------------------
Function:
Returns name of the active user-defined exception.
Returns specific context of the active exception.
Author:
Dmitry Yemanov <dimitr@firebirdsql.org>
Syntax rules:
EXCEPTION
RDB$ERROR ( context )
context ::= { GDSCODE | SQLCODE | SQLSTATE | EXCEPTION | MESSAGE }
GDSCODE, SQLCODE, SQLSTATE - see above
EXCEPTION : VARCHAR(63) CHARACTER SET UTF8
Returns name of the active user-defined exception
or NULL if active exception is a system one
MESSAGE : VARCHAR(1024) CHARACTER SET UTF8
Returns interpreted text for the active exception
Type:
VARCHAR(63) CHARACTER SET UTF8
Depends on context
Scope:
PSQL, context of the exception handling block.
@ -192,41 +202,8 @@ EXCEPTION (FB 4.0)
BEGIN
...
WHEN ANY DO
IF (EXCEPTION IS NOT NULL)
EXECUTE PROCEDURE P_USR_EXCEPTION(EXCEPTION);
ELSE
EXECUTE PROCEDURE P_SYS_EXCEPTION;
EXECUTE PROCEDURE P_LOG_EXCEPTION(RDB$ERROR(MESSAGE));
END
Note(s):
1. EXCEPTION always contains NULL outside the exception handling block.
2. If system exception is thrown, EXCEPTION also contains NULL.
ERROR_MESSAGE (FB 4.0)
----------------------
Function:
Returns interpreted text for the active exception.
Author:
Dmitry Yemanov <dimitr@firebirdsql.org>
Syntax rules:
ERROR_MESSAGE
Type:
VARCHAR(1024) CHARACTER SET UTF8
Scope:
PSQL, context of the exception handling block.
Example(s):
BEGIN
...
WHEN ANY DO
EXECUTE PROCEDURE P_LOG_EXCEPTION(ERROR_MESSAGE);
END
Note(s):
1. ERROR_MESSAGE always contains NULL outside the exception handling block.
RDB$ERROR always contains NULL outside the exception handling block.

View File

@ -74,3 +74,30 @@ BOOLEAN (FB 3.0)
5. It's allowed to test booleans without compare with TRUE or FALSE. For example,
"field1 OR field2" and "NOT field1" are valid expressions. It's also allowed to compare with
others operators, including the new IS operator: "field1 IS FALSE".
BINARY, VARBINARY, BINARY VARYING (FB 4.0)
------------------------------------------
Function:
Alias for CHAR, VARCHAR, VARYING CHAR with CHARACTER SET OCTETS.
Author:
Dimitry Sibiryakov
Syntax rules:
BINARY[(length)]
VARBINARY(length)
BINARY VARYING(length)
Example(s):
1. DECLARE VARIABLE VAR1 VARBINARY(10);
2. CREATE TABLE TABLE1 (FIELD1 BINARY(16),
FIELD2 VARBINARY(100),
FIELD3 BINARY VARYING(1000));
Note(s):
1. If length is omitted for type BINARY, it is considered to be 1.
2. Can be distinguished from text types by value 1 in RDB$FIELD_SUB_TYPE.
3. Character set is set to OCTETS for backward compatibility.
4. In API are similar to corresponding text types, getSubType() returns 0.

View File

@ -11,10 +11,19 @@ Description:
Syntax:
<column definition> ::=
<name> <type> GENERATED BY DEFAULT AS IDENTITY [ (START WITH <value>) ] <constraints>
<name> <type> GENERATED BY DEFAULT AS IDENTITY [ ( <identity column option>... ) ] <constraints>
<identity column option> ::=
START WITH <value> |
INCREMENT [ BY ] <value>
<alter column definition> ::=
<name> RESTART [ WITH <value> ]
<name> <alter identity column option>... |
<name> DROP IDENTITY
<alter identity column option> ::=
RESTART [ WITH <value> ] |
SET INCREMENT [ BY ] <value>
Syntax rules:
- The type of an identity column must be an exact number type with zero scale. That includes:
@ -25,6 +34,7 @@ Notes:
- You cannot alter a identity column to normal column and vice versa.
- Identity columns are implicitly NOT NULL.
- Identity columns don't enforce uniqueness automatically. Use UNIQUE or PRIMARY key for that.
- Increment value cannot be 0.
Implementation:
Two columns have been inserted in RDB$RELATION_FIELDS: RDB$GENERATOR_NAME and RDB$IDENTITY_TYPE.
@ -68,3 +78,9 @@ select * from objects order by id;
2 Book
10 Computer
15 Pencil
alter table objects
alter id set increment by 2;
alter table objects
alter id drop identity;

View File

@ -294,6 +294,8 @@ Firebird 4.0
UNBOUNDED
WINDOW
BINARY
VARBINARY
Added as non-reserved words:

View File

@ -25,6 +25,7 @@
*/
#include "../interfaces/ifaceExamples.h"
#include <firebird/Message.h>
using namespace Firebird;
@ -79,7 +80,13 @@ public:
status->dispose();
}
enum Action {NONE, ENC, DEC};
enum Action {NONE, ENC, DEC, EX_LCL, EX_RMT};
// Switches/actions have the following meanings:
// ENC(-e) - encrypt database
// DEC(-d) - decrypt database
// EX_LCL(-l) - execute some predefined select command (demonstrates that database can respond to select request)
// EX_RMT(-r) - execute select using execute statement in remote datasource (demonstrates that dbcrypt key is
// passed to target database when using execute statement)
void execute(const char* dbName, const Action a)
{
@ -104,18 +111,55 @@ public:
throw "startTransaction";
}
if (a == ENC)
switch(a)
{
case ENC:
att->execute(status, tra, 0,
"ALTER DATABASE ENCRYPT WITH \"DbCrypt_example\"", 3, NULL, NULL, NULL, NULL);
if (status->getState() & IStatus::STATE_ERRORS)
throw "execute";
}
if (a == DEC)
{
break;
case DEC:
att->execute(status, tra, 0, "ALTER DATABASE DECRYPT", 3, NULL, NULL, NULL, NULL);
if (status->getState() & IStatus::STATE_ERRORS)
throw "execute";
break;
case EX_LCL:
case EX_RMT:
{
FB_MESSAGE(Output, CheckStatusWrapper,
(FB_VARCHAR(31), logon)
) output(status, master);
const char* sqlL = "select current_user from rdb$database";
const char* sqlR = "execute block returns(logon varchar(31)) as begin "
"execute statement 'select current_user from rdb$database' "
"on external 'localhost:employee' as user 'test' password 'test' into :logon; "
"suspend; end";
const char* sql = a == EX_LCL ? sqlL : sqlR;
curs = att->openCursor(status, tra, 0, sql, 3, NULL, NULL, output.getMetadata(), NULL, 0);
if (status->getState() & IStatus::STATE_ERRORS)
throw "openCursor";
printf("\nExec SQL: %s\nReturns:\n", sql);
while (curs->fetchNext(status, output.getData()) == IStatus::RESULT_OK)
{
unsigned l = output->logonNull ? 0 : output->logon.length;
printf("%*.*s\n", l, l, output->logon.str);
}
printf("done.\n");
if (status->getState() & IStatus::STATE_ERRORS)
throw "fetchNext";
curs->close(status);
if (status->getState() & IStatus::STATE_ERRORS)
throw "close";
curs = NULL;
break;
}
}
if (tra)
@ -126,7 +170,7 @@ public:
tra = NULL;
}
printf("Providing key for crypt plugin - press enter to continue ...");
printf("\nProviding key for crypt plugin - press enter to continue ...");
getchar();
att->detach(status);
@ -151,13 +195,14 @@ private:
IProvider* p;
IAttachment* att;
ITransaction* tra;
IResultSet* curs;
CryptKey key;
};
int usage()
{
fprintf(stderr, "Usage: CryptApplication [ -e | -d ] { db-name }\n");
fprintf(stderr, "Usage: cryptAppSample [ -e | -d | -l | -r ] { db-name }\n");
return 2;
}
@ -181,6 +226,12 @@ int main(int ac, char** av)
case 'd':
act = App::DEC;
break;
case 'l':
act = App::EX_LCL;
break;
case 'r':
act = App::EX_RMT;
break;
default:
return usage();
}

View File

@ -77,6 +77,7 @@ public:
// IKeyHolderPlugin implementation
int keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback);
ICryptKeyCallback* keyHandle(CheckStatusWrapper* status, const char* keyName);
ICryptKeyCallback* chainHandle(CheckStatusWrapper* status);
int release()
{
@ -108,6 +109,17 @@ public:
return key;
}
FB_BOOLEAN useOnlyOwnKeys(CheckStatusWrapper* status)
{
IConfigEntry* e = getEntry(status, "OnlyOwnKey");
if (!e)
return FB_TRUE; // safe default
FB_BOOLEAN rc = e->getBoolValue();
e->release();
return rc;
}
private:
class CallbackInterface : public ICryptKeyCallbackImpl<CallbackInterface, CheckStatusWrapper>
{
@ -189,8 +201,6 @@ IConfigEntry* CryptKeyHolder::getEntry(CheckStatusWrapper* status, const char* e
int CryptKeyHolder::keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback)
{
status->init();
if (key != 0)
return 1;
@ -247,6 +257,12 @@ ICryptKeyCallback* CryptKeyHolder::keyHandle(CheckStatusWrapper* status, const c
return NULL;
}
ICryptKeyCallback* CryptKeyHolder::chainHandle(CheckStatusWrapper* status)
{
return &callbackInterface;
}
class Factory : public IPluginFactoryImpl<Factory, CheckStatusWrapper>
{
public:

View File

@ -81,7 +81,8 @@ public:
void decrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to);
void setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolderPlugin** sources,
const char* keyName);
// One if free to ignore passed info when not needed
// One is free to ignore passed info when not needed
void setInfo(CheckStatusWrapper* status, IDbCryptInfo* info)
{
// You may uncomment next line in a case of embedded connection
@ -235,8 +236,10 @@ void DbCrypt::setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolder
return;
if (callback && callback->callback(0, NULL, 1, &key) == 1)
{
return;
}
}
key = 0;
noKeyError(status);

View File

@ -1,2 +1,39 @@
All files in this directory are trivial samples.
They do not perform any real data encryption and should not be used in production!
**************************************************************************************
* All files in this directory are trivial samples. *
* They do not perform any real data encryption and should not be used in production! *
**************************************************************************************
Brief description of the sample.
Sample contains 3 components - DbCrypt plugin, KeyHolder plugin and application, which can pass
crypt key to server. Plugins do not perform any real encryption (XOR with single byte hardly can
be treated as encryption though makes database useless without crypt plugin), key is sent between
components in plain form - they just demonstrate what calls in plugins should be done and what
methods should be implemented in order for plugin to start to work.
Depending upon settings in configuration file plugins may use different ways to manage encryption
key. DbCrypt's configuration file may contain following parameters:
Auto - boolean value, when FALSE plugin queries KeyHolder plugin for key value (this is default),
when TRUE get key value from "Value" configuration parameter.
Value - integer value (lower byte is actually used), used in "Auto" mode as key value (default 90).
CryptKeyHolder's configuration file may contain following parameters:
Auto - boolean value, when FALSE plugin queries client application for key value (this is default),
when TRUE get key value from configuration file by name or use default (90) for unnamed key.
Key{Name} - integer value, a key with name "Name" (i.e. when one issues "ALTER DATABASE ENCRYPT ...
KEY Doggy" configuration parameter KeyDoggy should be present).
OnlyOwnKey - boolean value, enables/disables use of a key from another key holder in SuperServer.
Default value is TRUE (i.e. only key, owned by this KeyHolder, can be used by related
attachment).
Crypt application has a few parameters making it possible to demonstrate different operations.
-e - Encrypt database (use gstat to monitor crypt progress).
-d - Decrypt database.
-l - Locally execute SELECT statement returning name of currently attached user.
-r - Execute same statement using remote datasource 'localhost:employee'. To make it work
user "test" with password "test" should be created in employee database. If employee was
encrypted in advance this demonstrates passing database crypt key through the chain of
key holders.
cryptDb.pas is a minimum (XOR using fixed key hardcoded in plugin body) sample of database crypt
plugin written on Pascal. Was tested with both FreePascal and Delphi.

View File

@ -1798,6 +1798,8 @@ C --
PARAMETER (GDS__dsql_wrong_param_num = 336003111)
INTEGER*4 GDS__dsql_invalid_drop_ss_clause
PARAMETER (GDS__dsql_invalid_drop_ss_clause = 336003112)
INTEGER*4 GDS__upd_ins_cannot_default
PARAMETER (GDS__upd_ins_cannot_default = 336003113)
INTEGER*4 GDS__dyn_filter_not_found
PARAMETER (GDS__dyn_filter_not_found = 336068645)
INTEGER*4 GDS__dyn_func_not_found
@ -1950,6 +1952,8 @@ C --
PARAMETER (GDS__dyn_cant_use_in_foreignkey = 336068897)
INTEGER*4 GDS__dyn_defvaldecl_package_func
PARAMETER (GDS__dyn_defvaldecl_package_func = 336068898)
INTEGER*4 GDS__dyn_cant_use_zero_inc_ident
PARAMETER (GDS__dyn_cant_use_zero_inc_ident = 336068904)
INTEGER*4 GDS__gbak_unknown_switch
PARAMETER (GDS__gbak_unknown_switch = 336330753)
INTEGER*4 GDS__gbak_page_size_missing

View File

@ -1793,6 +1793,8 @@ const
gds_dsql_wrong_param_num = 336003111;
isc_dsql_invalid_drop_ss_clause = 336003112;
gds_dsql_invalid_drop_ss_clause = 336003112;
isc_upd_ins_cannot_default = 336003113;
gds_upd_ins_cannot_default = 336003113;
isc_dyn_filter_not_found = 336068645;
gds_dyn_filter_not_found = 336068645;
isc_dyn_func_not_found = 336068649;
@ -1945,6 +1947,8 @@ const
gds_dyn_cant_use_in_foreignkey = 336068897;
isc_dyn_defvaldecl_package_func = 336068898;
gds_dyn_defvaldecl_package_func = 336068898;
isc_dyn_cant_use_zero_inc_ident = 336068904;
gds_dyn_cant_use_zero_inc_ident = 336068904;
isc_gbak_unknown_switch = 336330753;
gds_gbak_unknown_switch = 336330753;
isc_gbak_page_size_missing = 336330754;

View File

@ -30,7 +30,6 @@
#include "firebird.h"
#include <stdio.h>
#include "../jrd/ibase.h"
//#include "../jrd/license.h"
#include "../alice/alice.h"
#include "../alice/alice_meta.h"
#include "../yvalve/gds_proto.h"

View File

@ -123,6 +123,9 @@ int DebugServer::authenticate(Firebird::CheckStatusWrapper* status, Firebird::IS
return AUTH_FAILED;
}
void DebugServer::setDbCryptCallback(Firebird::CheckStatusWrapper*, Firebird::ICryptKeyCallback*)
{ /* ignore it */ }
int DebugServer::release()
{
if (--refCounter == 0)

View File

@ -54,6 +54,7 @@ public:
int authenticate(Firebird::CheckStatusWrapper* status, Firebird::IServerBlock* sBlock,
Firebird::IWriter* writerInterface);
void setDbCryptCallback(Firebird::CheckStatusWrapper*, Firebird::ICryptKeyCallback*);
int release();
private:

View File

@ -55,7 +55,7 @@ public:
: server(NULL), data(getPool()), account(getPool()),
clientPubKey(getPool()), serverPubKey(getPool()),
verifier(getPool()), salt(getPool()), sessionKey(getPool()),
secDbName(NULL)
secDbName(NULL), cryptCallback(NULL)
{
LocalStatus ls;
CheckStatusWrapper s(&ls);
@ -65,6 +65,7 @@ public:
// IServer implementation
int authenticate(CheckStatusWrapper* status, IServerBlock* sBlock, IWriter* writerInterface);
void setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback);
int release();
private:
@ -82,6 +83,7 @@ private:
UCharBuffer sessionKey;
RefPtr<IFirebirdConf> config;
const char* secDbName;
ICryptKeyCallback* cryptCallback;
};
int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWriter* writerInterface)
@ -130,6 +132,12 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite
try
{
if (cryptCallback)
{
p->setDbCryptCallback(status, cryptCallback);
status->init(); // ignore possible errors like missing call in provider
}
ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE);
dpb.insertByte(isc_dpb_sec_attach, TRUE);
dpb.insertString(isc_dpb_user_name, DBA_USER_NAME, fb_strlen(DBA_USER_NAME));
@ -287,6 +295,11 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite
return AUTH_CONTINUE;
}
void SrpServer::setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback)
{
cryptCallback = callback;
}
int SrpServer::release()
{
if (--refCounter == 0)

View File

@ -134,6 +134,7 @@ public:
// IServer implementation
int authenticate(Firebird::CheckStatusWrapper* status, Firebird::IServerBlock* sBlock,
Firebird::IWriter* writerInterface);
void setDbCryptCallback(Firebird::CheckStatusWrapper*, Firebird::ICryptKeyCallback*) { } // ignore
int release();
private:

View File

@ -107,6 +107,7 @@ public:
// IServer implementation
int authenticate(Firebird::CheckStatusWrapper* status, Firebird::IServerBlock* sBlock,
Firebird::IWriter* writerInterface);
void setDbCryptCallback(Firebird::CheckStatusWrapper* status, Firebird::ICryptKeyCallback* callback) {}; // do nothing
int release();
WinSspiServer(Firebird::IPluginConfig*);

View File

@ -779,8 +779,6 @@ struct burp_meta_obj
// I need to review if we tolerate different lengths for different OS's here.
const unsigned int MAX_FILE_NAME_SIZE = 256;
//#include "../jrd/svc.h"
#include "../burp/std_desc.h"
#ifdef WIN_NT

View File

@ -585,18 +585,33 @@ UCHAR MVOL_write(const UCHAR c, int* io_cnt, UCHAR** io_ptr)
const size_t nBytesToWrite = size_t(longBytesToWrite);
bool error = false;
bool disk_full = false;
cnt = 0;
#ifndef WIN_NT
cnt = write(tdgbl->file_desc, ptr, nBytesToWrite);
#else
ssize_t ret = write(tdgbl->file_desc, ptr, nBytesToWrite);
DWORD ret = 0;
if (ret == -1)
{
error = true;
if (errno == ENOSPC || errno == EIO || errno == ENXIO || errno == EFBIG)
disk_full = true;
}
else
cnt = ret;
#else
if (!WriteFile(tdgbl->file_desc, ptr, (DWORD) nBytesToWrite, &cnt, NULL))
{
ret = GetLastError();
error = true;
DWORD ret = GetLastError();
if (ret == ERROR_DISK_FULL || ret == ERROR_HANDLE_DISK_FULL)
disk_full = true;
}
#endif // !WIN_NT
tdgbl->mvol_io_buffer = tdgbl->mvol_io_data;
if (cnt > 0)
if (!error)
{
tdgbl->mvol_cumul_count += cnt;
file_not_empty();
@ -610,13 +625,7 @@ UCHAR MVOL_write(const UCHAR c, int* io_cnt, UCHAR** io_ptr)
}
else
{
if (!cnt ||
#ifndef WIN_NT
errno == ENOSPC || errno == EIO || errno == ENXIO ||
errno == EFBIG)
#else
ret == ERROR_DISK_FULL || ret == ERROR_HANDLE_DISK_FULL)
#endif // !WIN_NT
if (disk_full)
{
if (tdgbl->action->act_action == ACT_backup_split)
{

View File

@ -31,6 +31,7 @@
#define JRD_THREADSTART_H
#include "../common/ThreadData.h"
#include "../common/classes/semaphore.h"
#ifdef WIN_NT
#include <windows.h>
@ -89,4 +90,88 @@ inline ThreadId getThreadId()
return Thread::getId();
}
#ifndef USE_POSIX_THREADS
#define USE_FINI_SEM
#endif
template <typename TA>
class ThreadFinishSync
{
public:
typedef void ThreadRoutine(TA);
ThreadFinishSync(Firebird::MemoryPool& pool, ThreadRoutine* routine, int priority_arg)
:
#ifdef USE_FINI_SEM
fini(pool),
#else
threadHandle(0),
#endif
threadRoutine(routine),
threadPriority(priority_arg)
{ }
void run(TA arg)
{
threadArg = arg;
Thread::start(internalRun, this, threadPriority
#ifndef USE_FINI_SEM
, &threadHandle
#endif
);
}
void waitForCompletion()
{
#ifdef USE_FINI_SEM
fini.enter();
#else
Thread::waitForCompletion(threadHandle);
threadHandle = 0;
#endif
}
private:
#ifdef USE_FINI_SEM
Firebird::Semaphore fini;
#else
Thread::Handle threadHandle;
#endif
TA threadArg;
ThreadRoutine* threadRoutine;
int threadPriority;
static THREAD_ENTRY_DECLARE internalRun(THREAD_ENTRY_PARAM arg)
{
((ThreadFinishSync*) arg)->internalRun();
return 0;
}
void internalRun()
{
try
{
threadRoutine(threadArg);
}
catch (const Firebird::Exception& ex)
{
threadArg->exceptionHandler(ex, threadRoutine);
}
#ifdef USE_FINI_SEM
try
{
fini.release();
}
catch (const Firebird::Exception& ex)
{
threadArg->exceptionHandler(ex, threadRoutine);
}
#endif
}
};
#endif // JRD_THREADSTART_H

View File

@ -1,6 +1,6 @@
/*
* PROGRAM: Firebird interface.
* MODULE: ImplementHelper.h
* MODULE: GetPlugins.h
* DESCRIPTION: Tools to help access plugins.
*
* The contents of this file are subject to the Initial
@ -54,7 +54,7 @@ public:
}
GetPlugins(unsigned int interfaceType,
Config* knownConfig, const char* namesList = NULL)
const Config* knownConfig, const char* namesList = NULL)
: masterInterface(), pluginInterface(),
pluginSet(NULL), currentPlugin(NULL),
ls(*getDefaultMemoryPool()), status(&ls)
@ -82,6 +82,16 @@ public:
return currentPlugin;
}
P* makeInstance()
{
if (!hasData())
return NULL;
P* p = (P*) pluginSet->getPlugin(&status);
check(&status);
return p;
}
void next()
{
if (hasData())

View File

@ -60,6 +60,11 @@ public:
return nullable;
}
T orElse(T elseValue) const
{
return specified ? value : elseValue;
}
bool operator ==(const BaseNullable<T>& o) const
{
return (!specified && !o.specified) || (specified == o.specified && value == o.value);

View File

@ -33,12 +33,12 @@ namespace Firebird
class RefCounted
{
public:
virtual int addRef()
virtual int addRef() const
{
return ++m_refCnt;
}
virtual int release()
virtual int release() const
{
fb_assert(m_refCnt.value() > 0);
const int refCnt = --m_refCnt;
@ -56,7 +56,7 @@ namespace Firebird
}
private:
AtomicCounter m_refCnt;
mutable AtomicCounter m_refCnt;
};
// reference counted object guard

View File

@ -33,10 +33,7 @@
#define CLASSES_SYNCHRONIZE_H
#include "../common/classes/SyncObject.h"
#ifndef WIN_NT
#include "fb_pthread.h"
#endif
#include "../common/ThreadStart.h"
namespace Firebird {

View File

@ -28,7 +28,6 @@
#include "tree.h"
#include "alloc.h"
//#include "../memory/memory_pool.h"
#include <stdio.h>
#include <time.h>
#include <set>

View File

@ -69,12 +69,14 @@ public:
}
}
/* void changeDefaultConfig(Config* newConfig)
/* It was a kind of getting ready for changing config remotely...
void changeDefaultConfig(Config* newConfig)
{
defaultConfig = newConfig;
}
*/
const Firebird::RefPtr<Config>& getDefaultConfig() const
Firebird::RefPtr<const Config>& getDefaultConfig()
{
return defaultConfig;
}
@ -92,7 +94,7 @@ public:
}
private:
Firebird::RefPtr<Config> defaultConfig;
Firebird::RefPtr<const Config> defaultConfig;
ConfigImpl(const ConfigImpl&);
void operator=(const ConfigImpl&);
@ -194,7 +196,8 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] =
{TYPE_BOOLEAN, "IPv6V6Only", (ConfigValue) false},
{TYPE_BOOLEAN, "WireCompression", (ConfigValue) false},
{TYPE_INTEGER, "MaxIdentifierByteLength", (ConfigValue) -1},
{TYPE_INTEGER, "MaxIdentifierCharLength", (ConfigValue) -1}
{TYPE_INTEGER, "MaxIdentifierCharLength", (ConfigValue) -1},
{TYPE_BOOLEAN, "CryptSecurityDatabase", (ConfigValue) false}
};
/******************************************************************************
@ -256,7 +259,7 @@ Config::Config(const ConfigFile& file, const Config& base, const Firebird::PathN
notifyDatabase = notify;
}
void Config::notify()
void Config::notify() const
{
if (!notifyDatabase.hasData())
return;
@ -264,7 +267,7 @@ void Config::notify()
notifyDatabase.erase();
}
void Config::merge(Firebird::RefPtr<Config>& config, const Firebird::string* dpbConfig)
void Config::merge(Firebird::RefPtr<const Config>& config, const Firebird::string* dpbConfig)
{
if (dpbConfig && dpbConfig->hasData())
{
@ -338,7 +341,7 @@ Config::~Config()
* Public interface
*/
const Firebird::RefPtr<Config>& Config::getDefaultConfig()
const Firebird::RefPtr<const Config>& Config::getDefaultConfig()
{
return firebirdConf().getDefaultConfig();
}
@ -810,3 +813,8 @@ int Config::getMaxIdentifierCharLength() const
return MIN(MAX(rc, 1), METADATA_IDENTIFIER_CHAR_LEN);
}
bool Config::getCryptSecurityDatabase() const
{
return get<bool>(KEY_ENCRYPT_SECURITY_DATABASE);
}

View File

@ -142,6 +142,7 @@ public:
KEY_WIRE_COMPRESSION,
KEY_MAX_IDENTIFIER_BYTE_LENGTH,
KEY_MAX_IDENTIFIER_CHAR_LENGTH,
KEY_ENCRYPT_SECURITY_DATABASE,
MAX_CONFIG_KEY // keep it last
};
@ -174,7 +175,7 @@ private:
static const ConfigEntry entries[MAX_CONFIG_KEY];
ConfigValue values[MAX_CONFIG_KEY];
Firebird::PathName notifyDatabase;
mutable Firebird::PathName notifyDatabase;
public:
explicit Config(const ConfigFile& file); // use to build default config
@ -184,7 +185,7 @@ public:
// Call it when database with given config is created
void notify();
void notify() const;
// Check for missing firebird.conf
@ -199,10 +200,10 @@ public:
static const Firebird::PathName* getCommandLineRootDirectory();
// Master config - needed to provide per-database config
static const Firebird::RefPtr<Config>& getDefaultConfig();
static const Firebird::RefPtr<const Config>& getDefaultConfig();
// Merge config entries from DPB into existing config
static void merge(Firebird::RefPtr<Config>& config, const Firebird::string* dpbConfig);
static void merge(Firebird::RefPtr<const Config>& config, const Firebird::string* dpbConfig);
// reports key to be used by the following functions
static unsigned int getKeyByName(ConfigName name);
@ -349,6 +350,8 @@ public:
int getMaxIdentifierByteLength() const;
int getMaxIdentifierCharLength() const;
bool getCryptSecurityDatabase() const;
};
// Implementation of interface to access master configuration file
@ -356,7 +359,7 @@ class FirebirdConf FB_FINAL :
public Firebird::RefCntIface<Firebird::IFirebirdConfImpl<FirebirdConf, Firebird::CheckStatusWrapper> >
{
public:
FirebirdConf(Config* existingConfig)
FirebirdConf(const Config* existingConfig)
: config(existingConfig)
{ }
@ -369,7 +372,7 @@ public:
int release();
private:
Firebird::RefPtr<Config> config;
Firebird::RefPtr<const Config> config;
};
// Create default instance of IFirebirdConf interface

View File

@ -227,7 +227,7 @@ namespace
}
PathName name;
RefPtr<Config> config;
RefPtr<const Config> config;
#ifdef HAVE_ID_BY_NAME
Id* id;
#endif
@ -417,7 +417,7 @@ static inline bool hasSeparator(const PathName& name)
// Search for 'alias' in databases.conf, return its value in 'file' if found. Else set file to alias.
// Returns true if alias is found in databases.conf.
static bool resolveAlias(const PathName& alias, PathName& file, RefPtr<Config>* config)
static bool resolveAlias(const PathName& alias, PathName& file, RefPtr<const Config>* config)
{
PathName correctedAlias = alias;
replace_dir_sep(correctedAlias);
@ -492,7 +492,7 @@ static bool setPath(const PathName& filename, PathName& expandedName)
// Returns true if alias was found in databases.conf
bool expandDatabaseName(Firebird::PathName alias,
Firebird::PathName& file,
Firebird::RefPtr<Config>* config)
Firebird::RefPtr<const Config>* config)
{
try
{

View File

@ -30,7 +30,7 @@ class Config;
bool expandDatabaseName(Firebird::PathName alias,
Firebird::PathName& file,
Firebird::RefPtr<Config>* config);
Firebird::RefPtr<const Config>* config);
bool notifyDatabaseName(const Firebird::PathName& file);

View File

@ -57,6 +57,7 @@
#include "../common/classes/Aligner.h"
#include "../common/utils_proto.h"
#include "../common/os/os_utils.h"
#include "../common/os/path_utils.h"
#include <sys/types.h>
#ifdef HAVE_SYS_IPC_H
@ -84,6 +85,9 @@
#ifdef HAVE_ICONV_H
#include <iconv.h>
#endif
#ifdef LINUX
#include <sys/sysmacros.h>
#endif
#include "../common/config/config.h"
@ -228,6 +232,28 @@ bool ISC_analyze_nfs(tstring& expanded_filename, tstring& node_name)
return false;
}
#ifdef LINUX
// In order to avoid analyzing mtab in most cases check for non-device mounts first
struct stat fileStat;
unsigned m = 1; // use something that is known to be not non-device major
if (os_utils::stat(expanded_filename.c_str(), &fileStat) == 0) {
m = major(fileStat.st_dev);
}
else { // stat error - let's try with path component
tstring path, name;
PathUtils::splitLastComponent(path, name, expanded_filename);
if (path.hasData() && os_utils::stat(path.c_str(), &fileStat) == 0)
m = major(fileStat.st_dev);
}
if (m != 0 && m != 144 && m != 145 && m != 146) {
// device mount or stat for file/path is impossible - definitely not NFS
return false;
}
// proceed with deeper analysis
#endif
tstring max_node, max_path;
size_t len = 0;

View File

@ -47,7 +47,9 @@
#ifdef LINUX
// This hack fixes CORE-2896 - embedded connections fail on linux.
// Looks like a lot of linux kernels are buggy when working with PRIO_INHERIT mutexes.
//#undef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
// dimitr (10-11-2016): PRIO_INHERIT also causes undesired short-time sleeps (CPU idle 30-35%)
// during context switches under concurrent load. Proved on linux kernels up to 4.8.
#undef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
#endif

View File

@ -62,6 +62,7 @@
#include "../common/utils_proto.h"
#include "../common/StatusArg.h"
#include "../common/ThreadData.h"
#include "../common/ThreadStart.h"
#include "../common/classes/rwlock.h"
#include "../common/classes/GenericMap.h"
#include "../common/classes/RefMutex.h"

View File

@ -70,23 +70,15 @@ public:
/// Destructor
virtual ~Module() {}
#ifdef WIN_NT
const Firebird::PathName fileName;
#endif
protected:
/// The constructor is protected so normal code can't allocate instances
/// of the class, but the class itself is still able to be subclassed.
#ifdef WIN_NT
Module(MemoryPool& pool, const Firebird::PathName& aFileName)
: fileName(pool, aFileName)
{
}
#else
Module()
{
}
#endif
private:
/// Copy construction is not supported, hence the copy constructor is private

View File

@ -28,6 +28,7 @@
#include "firebird.h"
#include "../common/os/mod_loader.h"
#include "../common/os/os_utils.h"
#include "../common/os/path_utils.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@ -40,8 +41,9 @@
class DlfcnModule : public ModuleLoader::Module
{
public:
DlfcnModule(void* m)
: module(m)
DlfcnModule(MemoryPool& pool, const Firebird::PathName& aFileName, void* m)
: ModuleLoader::Module(pool, aFileName),
module(m)
{}
~DlfcnModule();
@ -109,7 +111,7 @@ ModuleLoader::Module* ModuleLoader::loadModule(const Firebird::PathName& modPath
system(command.c_str());
#endif
return FB_NEW_POOL(*getDefaultMemoryPool()) DlfcnModule(module);
return FB_NEW_POOL(*getDefaultMemoryPool()) DlfcnModule(*getDefaultMemoryPool(), modPath, module);
}
DlfcnModule::~DlfcnModule()
@ -127,6 +129,18 @@ void* DlfcnModule::findSymbol(const Firebird::string& symName)
result = dlsym(module, newSym.c_str());
}
#ifdef HAVE_DLADDR
if (!PathUtils::isRelative(fileName))
{
Dl_info info;
if (!dladdr(result, &info))
return NULL;
if (fileName != info.dli_fname)
return NULL;
}
#endif
return result;
}

View File

@ -103,6 +103,8 @@ public:
"msvcr120.dll",
#elif _MSC_VER == 1900
"vcruntime140.dll",
#elif _MSC_VER == 1910
"vcruntime140.dll",
#else
#error Specify CRT DLL name here !
#endif

View File

@ -41,7 +41,7 @@ void raise()
namespace Auth {
Get::Get(Config* firebirdConf)
Get::Get(const Config* firebirdConf)
: GetPlugins<Firebird::IManagement>(IPluginManager::TYPE_AUTH_USER_MANAGEMENT, firebirdConf)
{
if (!hasData())
@ -50,7 +50,7 @@ Get::Get(Config* firebirdConf)
}
}
Get::Get(Config* firebirdConf, const char* plugName)
Get::Get(const Config* firebirdConf, const char* plugName)
: GetPlugins<Firebird::IManagement>(IPluginManager::TYPE_AUTH_USER_MANAGEMENT, firebirdConf, plugName)
{
if (!hasData())

View File

@ -259,8 +259,8 @@ public:
class Get : public Firebird::GetPlugins<Firebird::IManagement>
{
public:
explicit Get(Config* firebirdConf);
Get(Config* firebirdConf, const char* plugName);
explicit Get(const Config* firebirdConf);
Get(const Config* firebirdConf, const char* plugName);
};
int setGsecCode(int code, unsigned int operation);

View File

@ -23,7 +23,7 @@
*/
/* Domain definitions */
CREATE DOMAIN PLG$PASSWD AS VARCHAR(64) CHARACTER SET BINARY;
CREATE DOMAIN PLG$PASSWD AS VARBINARY(64);
CREATE DOMAIN PLG$ID AS INTEGER;
COMMIT;

View File

@ -58,36 +58,6 @@ static const int TEMP_LENGTH = 128;
//--------------------
namespace
{
// Copy sub expressions (including subqueries).
class SubExprNodeCopier : public NodeCopier
{
public:
explicit SubExprNodeCopier(thread_db* tdbb, CompilerScratch* aCsb)
//: NodeCopier(aCsb, localMap)
: NodeCopier(aCsb, FB_NEW_POOL(*tdbb->getDefaultPool()) StreamType[STREAM_MAP_LENGTH])
{
// Initialize the map so all streams initially resolve to the original number. As soon as
// copy creates new streams, the map are being overwritten.
// CVC: better in the heap, because we need larger map.
localMap = remap;
for (unsigned i = 0; i < STREAM_MAP_LENGTH; ++i)
localMap[i] = i;
}
~SubExprNodeCopier()
{
delete[] localMap;
}
private:
//StreamType localMap[JrdStatement::MAP_LENGTH];
StreamType* localMap;
};
} // namespace
//--------------------
@ -1951,8 +1921,7 @@ BoolExprNode* RseBoolNode::convertNeqAllToNotAny(thread_db* tdbb, CompilerScratc
newInnerRse->rse_boolean = boolean;
SubExprNodeCopier copier(tdbb, csb);
SubExprNodeCopier copier(csb);
return copier.copy(tdbb, static_cast<BoolExprNode*>(newNode));
}

View File

@ -6214,7 +6214,7 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
ObjectsArray<CreateDropConstraint> constraints;
bool notNullFlag = false;
if (clause->identity)
if (clause->identityOptions)
notNullFlag = true; // identity columns are implicitly not null
for (ObjectsArray<AddConstraintClause>::iterator ptr = clause->constraints.begin();
@ -6277,8 +6277,15 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
if (clause->collate.hasData())
DDL_resolve_intl_type(dsqlScratch, field, clause->collate);
if (clause->identity)
if (clause->identityOptions)
{
if (clause->identityOptions->increment.orElse(1) == 0)
{
status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_inc_ident) <<
Arg::Str(field->fld_name) <<
Arg::Str(name));
}
dsc desc;
MET_get_domain(tdbb, *tdbb->getDefaultPool(), fieldDefinition.fieldSource, &desc, NULL);
@ -6291,7 +6298,9 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
DYN_UTIL_generate_generator_name(tdbb, fieldDefinition.identitySequence);
CreateAlterSequenceNode::store(tdbb, transaction, fieldDefinition.identitySequence,
fb_sysflag_identity_generator, clause->identityStart, 1);
fb_sysflag_identity_generator,
clause->identityOptions->startValue.orElse(0),
clause->identityOptions->increment.orElse(1));
}
BlrDebugWriter::BlrData defaultValue;
@ -6859,104 +6868,78 @@ void RelationNode::defineSetDefaultTrigger(DsqlCompilerScratch* dsqlScratch,
Constraint::BlrWriter& blrWriter = constraint.blrWritersHolder.add();
blrWriter.init(dsqlScratch);
generateUnnamedTriggerBeginning(constraint, onUpdate, blrWriter);
blrWriter.appendUChar(blr_begin);
const int BLOB_BUFFER_SIZE = 4096; // to read in blr blob for default values
UCHAR defaultVal[BLOB_BUFFER_SIZE];
USHORT index = 0;
for (ObjectsArray<MetaName>::const_iterator column(constraint.columns.begin());
column != constraint.columns.end();
++column)
++column, index += 2)
{
// If the FK table's column is NOT NULL without DEFAULT, we want to avoid the engine throwing a constraint
// violation on our trigger's variable, so we declare two variables, one with blr_domain_type_of (don't use
// DEFAULT and null flag) and another blr_domain_full with DEFAULT and null flag. We swallow the error when
// transfering the value from the second to the first variable.
// This could be better done with blr_default, but let's maintain backward compatible BLR for now.
blrWriter.appendUChar(blr_dcl_variable);
blrWriter.appendUShort(index);
blrWriter.appendUChar(blr_column_name);
blrWriter.appendUChar(blr_domain_type_of);
blrWriter.appendNullString(0, name.c_str());
blrWriter.appendNullString(0, column->c_str());
blrWriter.appendUChar(blr_dcl_variable);
blrWriter.appendUShort(index + 1);
blrWriter.appendUChar(blr_column_name);
blrWriter.appendUChar(blr_domain_full);
blrWriter.appendNullString(0, name.c_str());
blrWriter.appendNullString(0, column->c_str());
blrWriter.appendUChar(blr_assignment);
blrWriter.appendUChar(blr_null);
blrWriter.appendUChar(blr_variable);
blrWriter.appendUShort(index);
blrWriter.appendUChar(blr_block); // 1
blrWriter.appendUChar(blr_begin); // 2
blrWriter.appendUChar(blr_init_variable);
blrWriter.appendUShort(index + 1);
blrWriter.appendUChar(blr_assignment);
blrWriter.appendUChar(blr_variable);
blrWriter.appendUShort(index + 1);
blrWriter.appendUChar(blr_variable);
blrWriter.appendUShort(index);
blrWriter.appendUChar(blr_end); // 2
blrWriter.appendUChar(blr_error_handler);
blrWriter.appendUShort(1);
blrWriter.appendUChar(blr_default_code);
blrWriter.appendUChar(blr_begin); // 3
blrWriter.appendUChar(blr_end); // 3
blrWriter.appendUChar(blr_end); // 1
}
generateUnnamedTriggerBeginning(constraint, onUpdate, blrWriter);
index = 0;
for (ObjectsArray<MetaName>::const_iterator column(constraint.columns.begin());
column != constraint.columns.end();
++column, index += 2)
{
blrWriter.appendUChar(blr_assignment);
// ASF: This is wrong way to do the thing. See CORE-3073.
// Here stuff the default value as blr_literal .... or blr_null
// if this column does not have an applicable default.
// The default is determined in many cases:
// (1) the info. for the column is in memory. (This is because
// the column is being created in this ddl statement).
// (1-a) the table has a column level default. We get this by
// searching the dsql parse tree.
// (1-b) the table does not have a column level default, but
// has a domain default. We get the domain name from the dsql
// parse tree and call METD_get_domain_default to read the
// default from the system tables.
// (2) The default-info for this column is not in memory (This is
// because this is an alter table ddl statement). The table
// already exists; therefore we get the column and/or domain
// default value from the system tables by calling:
// METD_get_col_default().
bool foundDefault = false;
bool searchForDefault = true;
// Search the parse tree to find the column
for (NestConst<Clause>* ptr = clauses.begin(); ptr != clauses.end(); ++ptr)
{
if ((*ptr)->type != Clause::TYPE_ADD_COLUMN)
continue;
AddColumnClause* clause = static_cast<AddColumnClause*>(ptr->getObject());
if (*column != clause->field->fld_name)
continue;
// Now we have the right column in the parse tree. case (1) above
if (clause->defaultValue)
{
// case (1-a) above: There is a column level default
dsqlScratch->getBlrData().clear();
dsqlScratch->getDebugData().clear();
GEN_expr(dsqlScratch, clause->defaultValue->value);
foundDefault = true;
searchForDefault = false;
// Move the blr to the constraint blrWriter.
blrWriter.getBlrData().join(dsqlScratch->getBlrData());
}
else
{
if (!clause->field->typeOfName.hasData())
break;
// case: (1-b): Domain name is available. Column level default
// is not declared. So get the domain default.
const USHORT defaultLen = METD_get_domain_default(dsqlScratch->getTransaction(),
clause->field->typeOfName, &foundDefault, defaultVal, sizeof(defaultVal));
searchForDefault = false;
if (foundDefault)
stuffDefaultBlr(ByteChunk(defaultVal, defaultLen), blrWriter);
else
{
// Neither column level nor domain level default exists.
blrWriter.appendUChar(blr_null);
}
}
break;
}
if (searchForDefault)
{
// case 2: See if the column/domain has already been created.
const USHORT defaultLen = METD_get_col_default(dsqlScratch->getTransaction(),
name.c_str(), column->c_str(), &foundDefault, defaultVal, sizeof(defaultVal));
if (foundDefault)
stuffDefaultBlr(ByteChunk(defaultVal, defaultLen), blrWriter);
else
blrWriter.appendUChar(blr_null);
}
blrWriter.appendUChar(blr_variable);
blrWriter.appendUShort(index);
// The context for the foreign key relation.
blrWriter.appendUChar(blr_field);
@ -6969,6 +6952,8 @@ void RelationNode::defineSetDefaultTrigger(DsqlCompilerScratch* dsqlScratch,
if (onUpdate)
blrWriter.appendUCharRepeated(blr_end, 3);
blrWriter.appendUChar(blr_end);
blrWriter.appendUChar(blr_eoc); // end of the blr
TriggerDefinition& trigger = constraint.triggers.add();
@ -7838,7 +7823,22 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc
}
END_MODIFY
}
else if (clause->identityRestart)
else if (clause->dropIdentity)
{
if (RFR.RDB$GENERATOR_NAME.NULL)
{
// msg 285: "Column @1 is not an identity column"
status_exception::raise(Arg::PrivateDyn(285) << field->fld_name);
}
DropSequenceNode::deleteIdentity(tdbb, transaction, RFR.RDB$GENERATOR_NAME);
MODIFY RFR
RFR.RDB$GENERATOR_NAME.NULL = TRUE;
RFR.RDB$IDENTITY_TYPE.NULL = TRUE;
END_MODIFY
}
else if (clause->identityOptions)
{
bool found = false;
AutoRequest request2;
@ -7849,11 +7849,28 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc
{
const SLONG id = GEN.RDB$GENERATOR_ID;
const MetaName genName(RFR.RDB$GENERATOR_NAME);
const SINT64 val = clause->identityRestartValue.specified ?
clause->identityRestartValue.value :
(!GEN.RDB$INITIAL_VALUE.NULL ? GEN.RDB$INITIAL_VALUE : 0);
if (clause->identityOptions->restart)
{
const SINT64 val = clause->identityOptions->startValue
.orElse(!GEN.RDB$INITIAL_VALUE.NULL ? GEN.RDB$INITIAL_VALUE : 0);
transaction->getGenIdCache()->put(id, val);
}
if (clause->identityOptions->increment.specified)
{
if (clause->identityOptions->increment.value == 0)
{
status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_inc_ident) <<
Arg::Str(field->fld_name) <<
Arg::Str(name));
}
MET_update_generator_increment(tdbb, id,
clause->identityOptions->increment.value);
}
dsc desc;
desc.makeText((USHORT) genName.length(), ttype_metadata,
(UCHAR*) genName.c_str());

View File

@ -1304,6 +1304,18 @@ public:
NestConst<BoolSourceClause> check;
};
struct IdentityOptions
{
IdentityOptions(MemoryPool&)
: restart(false)
{
}
Nullable<SINT64> startValue;
Nullable<SLONG> increment;
bool restart; // used in ALTER
};
struct AddColumnClause : public Clause
{
explicit AddColumnClause(MemoryPool& p)
@ -1313,8 +1325,7 @@ public:
constraints(p),
collate(p),
computed(NULL),
identity(false),
identityStart(0),
identityOptions(NULL),
notNullSpecified(false)
{
}
@ -1324,8 +1335,7 @@ public:
Firebird::ObjectsArray<AddConstraintClause> constraints;
Firebird::MetaName collate;
NestConst<ValueSourceClause> computed;
bool identity;
SINT64 identityStart;
NestConst<IdentityOptions> identityOptions;
bool notNullSpecified;
};
@ -1375,7 +1385,8 @@ public:
field(NULL),
defaultValue(NULL),
dropDefault(false),
identityRestart(false),
dropIdentity(false),
identityOptions(NULL),
computed(NULL)
{
}
@ -1383,8 +1394,8 @@ public:
dsql_fld* field;
NestConst<ValueSourceClause> defaultValue;
bool dropDefault;
bool identityRestart;
Nullable<SINT64> identityRestartValue;
bool dropIdentity;
NestConst<IdentityOptions> identityOptions;
NestConst<ValueSourceClause> computed;
};

View File

@ -4318,6 +4318,155 @@ dsc* DecodeNode::execute(thread_db* tdbb, jrd_req* request) const
//--------------------
static RegisterNode<DefaultNode> regDefaultNode(blr_default);
DefaultNode::DefaultNode(MemoryPool& pool, const Firebird::MetaName& aRelationName,
const Firebird::MetaName& aFieldName)
: DsqlNode<DefaultNode, ExprNode::TYPE_DEFAULT>(pool),
relationName(aRelationName),
fieldName(aFieldName),
field(NULL)
{
}
DmlNode* DefaultNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/)
{
MetaName relationName, fieldName;
csb->csb_blr_reader.getMetaName(relationName);
csb->csb_blr_reader.getMetaName(fieldName);
CompilerScratch::Dependency dependency(obj_relation);
dependency.relation = MET_lookup_relation(tdbb, relationName);
dependency.subName = FB_NEW_POOL(pool) MetaName(fieldName);
csb->csb_dependencies.push(dependency);
jrd_fld* fld = NULL;
while (true)
{
jrd_rel* relation = MET_lookup_relation(tdbb, relationName);
if (relation && relation->rel_fields)
{
int fieldId = MET_lookup_field(tdbb, relation, fieldName);
if (fieldId >= 0)
{
fld = (*relation->rel_fields)[fieldId];
if (fld)
{
if (fld->fld_source_rel_field.first.hasData())
{
relationName = fld->fld_source_rel_field.first;
fieldName = fld->fld_source_rel_field.second;
continue;
}
else
{
DefaultNode* node = FB_NEW_POOL(pool) DefaultNode(pool, relationName, fieldName);
node->field = fld;
return node;
}
}
}
}
return FB_NEW_POOL(pool) NullNode(pool);
}
}
ValueExprNode* DefaultNode::createFromField(thread_db* tdbb, CompilerScratch* csb,
StreamType* map, jrd_fld* fld)
{
if (fld->fld_generator_name.hasData())
{
// Make a (next value for <generator name>) expression.
GenIdNode* const genNode = FB_NEW_POOL(csb->csb_pool) GenIdNode(
csb->csb_pool, (csb->blrVersion == 4), fld->fld_generator_name, NULL, true, true);
bool sysGen = false;
if (!MET_load_generator(tdbb, genNode->generator, &sysGen, &genNode->step))
PAR_error(csb, Arg::Gds(isc_gennotdef) << Arg::Str(fld->fld_generator_name));
if (sysGen)
PAR_error(csb, Arg::Gds(isc_cant_modify_sysobj) << "generator" << fld->fld_generator_name);
return genNode;
}
else if (fld->fld_default_value)
{
StreamMap localMap;
if (!map)
map = localMap.getBuffer(STREAM_MAP_LENGTH);
return NodeCopier(csb, map).copy(tdbb, fld->fld_default_value);
}
else
return FB_NEW_POOL(csb->csb_pool) NullNode(csb->csb_pool);
}
string DefaultNode::internalPrint(NodePrinter& printer) const
{
ValueExprNode::internalPrint(printer);
NODE_PRINT(printer, relationName);
NODE_PRINT(printer, fieldName);
return "DefaultNode";
}
ValueExprNode* DefaultNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
DefaultNode* node = FB_NEW_POOL(getPool()) DefaultNode(getPool(),
relationName, fieldName);
return node;
}
void DefaultNode::setParameterName(dsql_par* parameter) const
{
parameter->par_name = parameter->par_alias = "DEFAULT";
}
bool DefaultNode::setParameterType(DsqlCompilerScratch* /*dsqlScratch*/, const dsc* /*desc*/, bool /*forceVarChar*/)
{
return false;
}
void DefaultNode::genBlr(DsqlCompilerScratch* dsqlScratch)
{
dsqlScratch->appendUChar(blr_default);
dsqlScratch->appendMetaString(relationName.c_str());
dsqlScratch->appendMetaString(fieldName.c_str());
}
void DefaultNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* /*desc*/)
{
}
bool DefaultNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const
{
if (!ExprNode::dsqlMatch(other, ignoreMapCast))
return false;
const DefaultNode* o = other->as<DefaultNode>();
fb_assert(o);
return relationName == o->relationName && fieldName == o->fieldName;
}
ValueExprNode* DefaultNode::pass1(thread_db* tdbb, CompilerScratch* csb)
{
ValueExprNode* node = createFromField(tdbb, csb, NULL, field);
doPass1(tdbb, csb, &node);
return node;
}
//--------------------
static RegisterNode<DerivedExprNode> regDerivedExprNode(blr_derived_expr);
DmlNode* DerivedExprNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/)
@ -5895,16 +6044,14 @@ ValueExprNode* FieldNode::pass1(thread_db* tdbb, CompilerScratch* csb)
return ValueExprNode::pass1(tdbb, csb);
}
//StreamType local_map[JrdStatement::MAP_LENGTH];
AutoPtr<StreamType, ArrayDelete<StreamType> > localMap;
StreamMap localMap;
StreamType* map = tail->csb_map;
if (!map)
{
localMap = FB_NEW_POOL(*tdbb->getDefaultPool()) StreamType[STREAM_MAP_LENGTH];
map = localMap;
map = localMap.getBuffer(STREAM_MAP_LENGTH);
fb_assert(stream + 2u <= MAX_STREAMS);
localMap[0] = stream;
map[0] = stream;
map[1] = stream + 1;
map[2] = stream + 2;
}
@ -6073,11 +6220,8 @@ dsc* FieldNode::execute(thread_db* tdbb, jrd_req* request) const
MOV_move(tdbb, &desc, &impure->vlu_desc);
}
if (!relation || !(relation->rel_flags & REL_system))
{
if (impure->vlu_desc.dsc_dtype == dtype_text)
INTL_adjust_text_descriptor(tdbb, &impure->vlu_desc);
}
return &impure->vlu_desc;
}
@ -6325,7 +6469,9 @@ const InternalInfoNode::InfoAttr InternalInfoNode::INFO_TYPE_ATTRIBUTES[MAX_INFO
{"SQLCODE", DsqlCompilerScratch::FLAG_BLOCK},
{"ROW_COUNT", DsqlCompilerScratch::FLAG_BLOCK},
{"INSERTING/UPDATING/DELETING", DsqlCompilerScratch::FLAG_TRIGGER},
{"SQLSTATE", DsqlCompilerScratch::FLAG_BLOCK}
{"SQLSTATE", DsqlCompilerScratch::FLAG_BLOCK},
{"EXCEPTION", DsqlCompilerScratch::FLAG_BLOCK},
{"MESSAGE", DsqlCompilerScratch::FLAG_BLOCK}
};
InternalInfoNode::InternalInfoNode(MemoryPool& pool, ValueExprNode* aArg)

View File

@ -476,6 +476,36 @@ public:
};
class DefaultNode : public DsqlNode<DefaultNode, ExprNode::TYPE_DEFAULT>
{
public:
explicit DefaultNode(MemoryPool& pool, const Firebird::MetaName& aRelationName,
const Firebird::MetaName& aFieldName);
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
static ValueExprNode* createFromField(thread_db* tdbb, CompilerScratch* csb, StreamType* map, jrd_fld* fld);
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
virtual void setParameterName(dsql_par* parameter) const;
virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch,
const dsc* desc, bool forceVarChar);
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc);
virtual bool dsqlMatch(const ExprNode* other, bool ignoreMapCast) const;
virtual ValueExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
public:
const Firebird::MetaName relationName;
const Firebird::MetaName fieldName;
private:
jrd_fld* field;
};
class DerivedExprNode : public TypedNode<ValueExprNode, ExprNode::TYPE_DERIVED_EXPR>
{
public:
@ -698,9 +728,9 @@ public:
const bool dialect1;
GeneratorItem generator;
NestConst<ValueExprNode> arg;
SLONG step;
private:
SLONG step;
bool sysGen;
const bool implicit;
const bool identity;

View File

@ -408,6 +408,7 @@ public:
TYPE_CURRENT_USER,
TYPE_DERIVED_EXPR,
TYPE_DECODE,
TYPE_DEFAULT,
TYPE_DERIVED_FIELD,
TYPE_DOMAIN_VALIDATION,
TYPE_EXTRACT,
@ -854,13 +855,13 @@ public:
fb_assert(false);
}
virtual DsqlNode* pass1(thread_db* /*tdbb*/, CompilerScratch* /*csb*/)
virtual ValueExprNode* pass1(thread_db* /*tdbb*/, CompilerScratch* /*csb*/)
{
fb_assert(false);
return NULL;
}
virtual DsqlNode* pass2(thread_db* /*tdbb*/, CompilerScratch* /*csb*/)
virtual ValueExprNode* pass2(thread_db* /*tdbb*/, CompilerScratch* /*csb*/)
{
fb_assert(false);
return NULL;
@ -1661,6 +1662,22 @@ public:
Firebird::MetaName secName;
};
typedef Firebird::Array<StreamType> StreamMap;
// Copy sub expressions (including subqueries).
class SubExprNodeCopier : private StreamMap, public NodeCopier
{
public:
SubExprNodeCopier(CompilerScratch* aCsb)
: NodeCopier(aCsb, getBuffer(STREAM_MAP_LENGTH))
{
// Initialize the map so all streams initially resolve to the original number.
// As soon as copy creates new streams, the map is being overwritten.
for (unsigned i = 0; i < STREAM_MAP_LENGTH; ++i)
remap[i] = i;
}
};
} // namespace

View File

@ -591,7 +591,6 @@ bool CreateAlterPackageNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch*
PKG.RDB$SQL_SECURITY.NULL = FALSE;
PKG.RDB$SQL_SECURITY = ssDefiner.value ? FB_TRUE : FB_FALSE;
}
END_MODIFY
owner = PKG.RDB$OWNER_NAME;

View File

@ -97,7 +97,7 @@ Parser::Parser(thread_db* tdbb, MemoryPool& pool, DsqlCompilerScratch* aScratch,
yylexemes = 0;
lex.start = string;
lex.line_start = lex.ptr = string;
lex.line_start = lex.last_token = lex.ptr = string;
lex.end = string + length;
lex.lines = 1;
lex.att_charset = characterSet;
@ -437,7 +437,7 @@ int Parser::yylexAux()
check_bound(p, string);
if (p > string + maxByteLength || p > string + maxCharLength)
yyabandon(-104, isc_dyn_name_longer);
yyabandon(yyposn, -104, isc_dyn_name_longer);
*p = 0;
@ -519,7 +519,7 @@ int Parser::yylexAux()
{
if (buffer != string)
gds__free (buffer);
yyabandon (-104, isc_invalid_string_constant);
yyabandon(yyposn, -104, isc_invalid_string_constant);
}
else if (client_dialect >= SQL_DIALECT_V6)
{
@ -527,19 +527,19 @@ int Parser::yylexAux()
{
if (buffer != string)
gds__free (buffer);
yyabandon(-104, isc_token_too_long);
yyabandon(yyposn, -104, isc_token_too_long);
}
else if (p > &buffer[MAX_SQL_IDENTIFIER_LEN])
{
if (buffer != string)
gds__free (buffer);
yyabandon(-104, isc_dyn_name_longer);
yyabandon(yyposn, -104, isc_dyn_name_longer);
}
else if (p - buffer == 0)
{
if (buffer != string)
gds__free (buffer);
yyabandon(-104, isc_dyn_zero_len_id);
yyabandon(yyposn, -104, isc_dyn_zero_len_id);
}
Attachment* const attachment = tdbb->getAttachment();
@ -548,7 +548,7 @@ int Parser::yylexAux()
name.length(), (const UCHAR*) name.c_str(), true);
if (name.length() > maxByteLength || charLength > maxCharLength)
yyabandon(-104, isc_dyn_name_longer);
yyabandon(yyposn, -104, isc_dyn_name_longer);
yylval.metaNamePtr = FB_NEW_POOL(pool) MetaName(pool, name);
@ -1103,7 +1103,7 @@ int Parser::yylexAux()
*p = 0;
if (p > &string[maxByteLength] || p > &string[maxCharLength])
yyabandon(-104, isc_dyn_name_longer);
yyabandon(yyposn, -104, isc_dyn_name_longer);
const MetaName str(string, p - string);
const Keyword* const keyVer = keywordsMap->get(str);
@ -1206,7 +1206,7 @@ void Parser::yyerrorIncompleteCmd()
void Parser::check_bound(const char* const to, const char* const string)
{
if ((to - string) >= Parser::MAX_TOKEN_LEN)
yyabandon(-104, isc_token_too_long);
yyabandon(yyposn, -104, isc_token_too_long);
}
void Parser::check_copy_incr(char*& to, const char ch, const char* const string)
@ -1216,7 +1216,7 @@ void Parser::check_copy_incr(char*& to, const char ch, const char* const string)
}
void Parser::yyabandon(SLONG sql_code, ISC_STATUS error_symbol)
void Parser::yyabandon(const Position& position, SLONG sql_code, ISC_STATUS error_symbol)
{
/**************************************
*
@ -1229,6 +1229,8 @@ void Parser::yyabandon(SLONG sql_code, ISC_STATUS error_symbol)
*
**************************************/
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(sql_code) <<
Arg::Gds(error_symbol));
ERRD_post(
Arg::Gds(isc_sqlerr) << Arg::Num(sql_code) << Arg::Gds(error_symbol) <<
Arg::Gds(isc_dsql_line_col_error) <<
Arg::Num(position.firstLine) << Arg::Num(position.firstColumn));
}

View File

@ -234,7 +234,7 @@ private:
void check_bound(const char* const to, const char* const string);
void check_copy_incr(char*& to, const char ch, const char* const string);
void yyabandon(SLONG, ISC_STATUS);
void yyabandon(const Position& position, SLONG, ISC_STATUS);
Firebird::MetaName optName(Firebird::MetaName* name)
{

View File

@ -87,12 +87,12 @@ static void makeValidation(thread_db* tdbb, CompilerScratch* csb, StreamType str
static StmtNode* pass1ExpandView(thread_db* tdbb, CompilerScratch* csb, StreamType orgStream,
StreamType newStream, bool remap);
static RelationSourceNode* pass1Update(thread_db* tdbb, CompilerScratch* csb, jrd_rel* relation,
const trig_vec* trigger, StreamType stream, StreamType updateStream, SecurityClass::flags_t priv,
const TrigVector* trigger, StreamType stream, StreamType updateStream, SecurityClass::flags_t priv,
jrd_rel* view, StreamType viewStream, StreamType viewUpdateStream);
static void pass1Validations(thread_db* tdbb, CompilerScratch* csb, Array<ValidateInfo>& validations);
static void postTriggerAccess(CompilerScratch* csb, jrd_rel* ownerRelation,
ExternalAccess::exa_act operation, jrd_rel* view);
static void preModifyEraseTriggers(thread_db* tdbb, trig_vec** trigs,
static void preModifyEraseTriggers(thread_db* tdbb, TrigVector** trigs,
StmtNode::WhichTrigger whichTrig, record_param* rpb, record_param* rec, TriggerAction op);
static void validateExpressions(thread_db* tdbb, const Array<ValidateInfo>& validations);
@ -1401,7 +1401,7 @@ DmlNode* DeclareSubFuncNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerSc
{ // scope
CompilerScratch* const subCsb = node->subCsb =
FB_NEW_POOL(csb->csb_pool) CompilerScratch(csb->csb_pool);
subCsb->csb_g_flags |= csb_subroutine;
subCsb->csb_g_flags |= csb_subroutine | (csb->csb_g_flags & csb_get_dependencies);
subCsb->csb_blr_reader = csb->csb_blr_reader;
BlrReader& reader = subCsb->csb_blr_reader;
@ -1676,7 +1676,7 @@ DmlNode* DeclareSubProcNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerSc
{ // scope
CompilerScratch* const subCsb = node->subCsb =
FB_NEW_POOL(csb->csb_pool) CompilerScratch(csb->csb_pool);
subCsb->csb_g_flags |= csb_subroutine;
subCsb->csb_g_flags |= csb_subroutine | (csb->csb_g_flags & csb_get_dependencies);
subCsb->csb_blr_reader = csb->csb_blr_reader;
BlrReader& reader = subCsb->csb_blr_reader;
@ -2243,8 +2243,8 @@ void EraseNode::pass1Erase(thread_db* tdbb, CompilerScratch* csb, EraseNode* nod
if (parent)
priv |= SCL_select;
const trig_vec* trigger = relation->rel_pre_erase ?
relation->rel_pre_erase : relation->rel_post_erase;
RefPtr<const TrigVector> trigger(relation->rel_pre_erase ?
relation->rel_pre_erase : relation->rel_post_erase);
// If we have a view with triggers, let's expand it.
@ -5877,6 +5877,51 @@ void ModifyNode::genBlr(DsqlCompilerScratch* dsqlScratch)
ModifyNode* ModifyNode::pass1(thread_db* tdbb, CompilerScratch* csb)
{
CompoundStmtNode* compoundNode = statement->as<CompoundStmtNode>();
// Remove assignments of DEFAULT to computed fields.
if (compoundNode)
{
for (size_t i = compoundNode->statements.getCount(); i--; )
{
const AssignmentNode* assign = compoundNode->statements[i]->as<AssignmentNode>();
fb_assert(assign);
if (!assign)
continue;
const ExprNode* assignFrom = assign->asgnFrom;
const FieldNode* assignToField = assign->asgnTo->as<FieldNode>();
if (assignToField && assignFrom->is<DefaultNode>())
{
jrd_rel* relation = csb->csb_rpt[newStream].csb_relation;
int fieldId = assignToField->fieldId;
while (true)
{
jrd_fld* fld;
if (assignToField->fieldStream == newStream &&
relation &&
relation->rel_fields &&
(fld = (*relation->rel_fields)[fieldId]))
{
if (fld->fld_computation)
compoundNode->statements.remove(i);
else if (relation->rel_view_rse && fld->fld_source_rel_field.first.hasData())
{
relation = MET_lookup_relation(tdbb, fld->fld_source_rel_field.first);
if ((fieldId = MET_lookup_field(tdbb, relation, fld->fld_source_rel_field.second)) >= 0)
continue;
}
}
break;
}
}
}
}
pass1Modify(tdbb, csb, this);
doPass1(tdbb, csb, statement.getAddress());
@ -5936,8 +5981,8 @@ void ModifyNode::pass1Modify(thread_db* tdbb, CompilerScratch* csb, ModifyNode*
if (parent)
priv |= SCL_select;
const trig_vec* trigger = (relation->rel_pre_modify) ?
relation->rel_pre_modify : relation->rel_post_modify;
RefPtr<const TrigVector> trigger(relation->rel_pre_modify ?
relation->rel_pre_modify : relation->rel_post_modify);
// If we have a view with triggers, let's expand it.
@ -6556,6 +6601,8 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch,
NestConst<ValueExprNode>* ptr = fields.begin();
NestConst<ValueExprNode>* ptr2 = values->items.begin();
for (const NestConst<ValueExprNode>* end = fields.end(); ptr != end; ++ptr, ++ptr2)
{
if (*ptr2) // it's NULL for DEFAULT
{
AssignmentNode* temp = FB_NEW_POOL(getPool()) AssignmentNode(getPool());
temp->asgnFrom = *ptr2;
@ -6565,6 +6612,7 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch,
PASS1_set_parameter_type(dsqlScratch, *ptr2, temp->asgnTo, false);
}
}
}
if (updateOrInsert)
{
@ -6697,8 +6745,8 @@ bool StoreNode::pass1Store(thread_db* tdbb, CompilerScratch* csb, StoreNode* nod
postTriggerAccess(csb, relation, ExternalAccess::exa_insert, view);
const trig_vec* trigger = relation->rel_pre_store ?
relation->rel_pre_store : relation->rel_post_store;
RefPtr<const TrigVector> trigger(relation->rel_pre_store ?
relation->rel_pre_store : relation->rel_post_store);
// Check out insert. If this is an insert thru a view, verify the view by checking for read
// access on the base table. If field-level select privileges are implemented, this needs
@ -6774,15 +6822,13 @@ void StoreNode::makeDefaults(thread_db* tdbb, CompilerScratch* csb)
if (!vector)
return;
//StreamType localMap[JrdStatement::MAP_LENGTH];
AutoPtr<StreamType, ArrayDelete<StreamType> > localMap;
StreamMap localMap;
StreamType* map = csb->csb_rpt[stream].csb_map;
if (!map)
{
localMap = FB_NEW_POOL(*tdbb->getDefaultPool()) StreamType[STREAM_MAP_LENGTH];
map = localMap;
fb_assert(stream <= MAX_STREAMS); // CVC: MAX_UCHAR relevant, too?
map = localMap.getBuffer(STREAM_MAP_LENGTH);
fb_assert(stream <= MAX_STREAMS);
map[0] = stream;
map[1] = 1;
map[2] = 2;
@ -6832,36 +6878,9 @@ void StoreNode::makeDefaults(thread_db* tdbb, CompilerScratch* csb)
AssignmentNode* assign = FB_NEW_POOL(*tdbb->getDefaultPool()) AssignmentNode(
*tdbb->getDefaultPool());
assign->asgnTo = PAR_gen_field(tdbb, stream, fieldId);
assign->asgnFrom = DefaultNode::createFromField(tdbb, csb, map, *ptr1);
stack.push(assign);
const MetaName& generatorName = (*ptr1)->fld_generator_name;
if (generatorName.hasData())
{
// Make a gen_id(<generator name>, 1) expression.
LiteralNode* literal = FB_NEW_POOL(csb->csb_pool) LiteralNode(csb->csb_pool);
SLONG* increment = FB_NEW_POOL(csb->csb_pool) SLONG(1);
literal->litDesc.makeLong(0, increment);
GenIdNode* const genNode = FB_NEW_POOL(csb->csb_pool)
GenIdNode(csb->csb_pool, (csb->blrVersion == 4), generatorName, literal, false, true);
bool sysGen = false;
if (!MET_load_generator(tdbb, genNode->generator, &sysGen))
PAR_error(csb, Arg::Gds(isc_gennotdef) << Arg::Str(generatorName));
if (sysGen)
PAR_error(csb, Arg::Gds(isc_cant_modify_sysobj) << "generator" << generatorName);
assign->asgnFrom = genNode;
}
else //if (value)
{
// Clone the field default value.
assign->asgnFrom = RemapFieldNodeCopier(csb, map, fieldId).copy(tdbb, value);
}
}
}
@ -8053,7 +8072,10 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
for (; fieldPtr != fieldsCopy.end(); ++fieldPtr, ++valuePtr)
{
AssignmentNode* assign = FB_NEW_POOL(pool) AssignmentNode(pool);
assign->asgnFrom = *valuePtr;
if (!(assign->asgnFrom = *valuePtr)) // it's NULL for DEFAULT
assign->asgnFrom = FB_NEW_POOL(pool) DefaultNode(pool, relation_name, (*fieldPtr)->dsqlName);
assign->asgnTo = *fieldPtr;
assignments->statements.add(assign);
@ -8077,6 +8099,9 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
if (testField == fieldName)
{
if (!*valuePtr) // it's NULL for DEFAULT
ERRD_post(Arg::Gds(isc_upd_ins_cannot_default) << fieldName);
++matchCount;
const FB_SIZE_T fieldPos = fieldPtr - fieldsCopy.begin();
@ -8194,7 +8219,8 @@ static void dsqlExplodeFields(dsql_rel* relation, Array<NestConst<T> >& fields)
for (dsql_fld* field = relation->rel_fields; field; field = field->fld_next)
{
// CVC: Ann Harrison requested to skip COMPUTED fields in INSERT w/o field list.
if (field->flags & FLD_computed)
// ASF: But not for views - CORE-5454
if (!(relation->rel_flags & REL_view) && (field->flags & FLD_computed))
continue;
FieldNode* fieldNode = FB_NEW_POOL(pool) FieldNode(pool);
@ -8967,14 +8993,13 @@ static void makeValidation(thread_db* tdbb, CompilerScratch* csb, StreamType str
if (!vector)
return;
//StreamType local_map[JrdStatement::MAP_LENGTH];
AutoPtr<StreamType, ArrayDelete<StreamType> > localMap;
StreamMap localMap;
StreamType* map = csb->csb_rpt[stream].csb_map;
if (!map)
{
localMap = FB_NEW_POOL(*tdbb->getDefaultPool()) StreamType[STREAM_MAP_LENGTH];
map = localMap;
fb_assert(stream <= MAX_STREAMS); // CVC: MAX_UCHAR still relevant for the bitmap?
map = localMap.getBuffer(STREAM_MAP_LENGTH);
fb_assert(stream <= MAX_STREAMS);
map[0] = stream;
}
@ -9069,7 +9094,7 @@ static StmtNode* pass1ExpandView(thread_db* tdbb, CompilerScratch* csb, StreamTy
// If it's a view update, make sure the view is updatable, and return the view source for redirection.
// If it's a simple relation, return NULL.
static RelationSourceNode* pass1Update(thread_db* tdbb, CompilerScratch* csb, jrd_rel* relation,
const trig_vec* trigger, StreamType stream, StreamType updateStream, SecurityClass::flags_t priv,
const TrigVector* trigger, StreamType stream, StreamType updateStream, SecurityClass::flags_t priv,
jrd_rel* view, StreamType viewStream, StreamType viewUpdateStream)
{
SET_TDBB(tdbb);
@ -9196,7 +9221,7 @@ static void postTriggerAccess(CompilerScratch* csb, jrd_rel* ownerRelation,
}
// Perform operation's pre-triggers, storing active rpb in chain.
static void preModifyEraseTriggers(thread_db* tdbb, trig_vec** trigs,
static void preModifyEraseTriggers(thread_db* tdbb, TrigVector** trigs,
StmtNode::WhichTrigger whichTrig, record_param* rpb, record_param* rec, TriggerAction op)
{
if (!tdbb->getTransaction()->tra_rpblist)

View File

@ -343,118 +343,6 @@ dsql_intlsym* METD_get_collation(jrd_tra* transaction, const MetaName& name, USH
}
USHORT METD_get_col_default(jrd_tra* transaction, const char* for_rel_name,
const char* for_col_name, bool* has_default, UCHAR* buffer, USHORT buff_length)
{
/*************************************************************
*
* M E T D _ g e t _ c o l _ d e f a u l t
*
**************************************************************
*
* Function:
* Gets the default value for a column of an existing table.
* Will check the default for the column of the table, if that is
* not present, will check for the default of the relevant domain
*
* The default blr is returned in buffer. The blr is of the form
* blr_version4 blr_literal ..... blr_eoc
*
* Reads the system tables RDB$FIELDS and RDB$RELATION_FIELDS.
*
**************************************************************/
thread_db* tdbb = JRD_get_thread_data();
validateTransaction(transaction);
dsql_dbb* dbb = transaction->getDsqlAttachment();
bid* blob_id;
USHORT result = 0;
blb* blob_handle = 0;
*has_default = false;
AutoCacheRequest handle(tdbb, irq_col_default, IRQ_REQUESTS);
FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction)
RFL IN RDB$RELATION_FIELDS CROSS
FLD IN RDB$FIELDS WITH
RFL.RDB$RELATION_NAME EQ for_rel_name AND
RFL.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME AND
RFL.RDB$FIELD_NAME EQ for_col_name
{
if (!RFL.RDB$DEFAULT_VALUE.NULL)
{
blob_id = &RFL.RDB$DEFAULT_VALUE;
*has_default = true;
}
else if (!FLD.RDB$DEFAULT_VALUE.NULL)
{
blob_id = &FLD.RDB$DEFAULT_VALUE;
*has_default = true;
}
else
*has_default = false;
if (*has_default)
{
blob_handle = blb::open2(tdbb, transaction, blob_id, sizeof(blr_bpb), blr_bpb, true);
// fetch segments. Assuming here that the buffer is big enough.
UCHAR* ptr_in_buffer = buffer;
while (true)
{
const USHORT length = blob_handle->BLB_get_segment(tdbb, ptr_in_buffer, buff_length);
ptr_in_buffer += length;
buff_length -= length;
result += length;
if (blob_handle->blb_flags & BLB_eof)
{
// null terminate the buffer
*ptr_in_buffer = 0;
break;
}
if (blob_handle->getFragmentSize())
status_exception::raise(Arg::Gds(isc_segment));
else
continue;
}
try
{
ThreadStatusGuard status_vector(tdbb);
blob_handle->BLB_close(tdbb);
blob_handle = NULL;
}
catch (Exception&)
{
}
// the default string must be of the form:
// blr_version4 blr_literal ..... blr_eoc
fb_assert((buffer[0] == blr_version4) || (buffer[0] == blr_version5));
fb_assert(buffer[1] == blr_literal);
}
else
{
if (dbb->dbb_db_SQL_dialect > SQL_DIALECT_V5)
buffer[0] = blr_version5;
else
buffer[0] = blr_version4;
buffer[1] = blr_eoc;
result = 2;
}
}
END_FOR
return result;
}
dsql_intlsym* METD_get_charset(jrd_tra* transaction, USHORT length, const char* name) // UTF-8
{
/**************************************
@ -711,100 +599,6 @@ bool METD_get_domain(jrd_tra* transaction, TypeClause* field, const MetaName& na
}
USHORT METD_get_domain_default(jrd_tra* transaction, const MetaName& domain_name, bool* has_default,
UCHAR* buffer, USHORT buff_length)
{
/*************************************************************
*
* M E T D _ g e t _ d o m a i n _ d e f a u l t
*
**************************************************************
*
* Function:
* Gets the default value for a domain of an existing table.
*
**************************************************************/
thread_db* tdbb = JRD_get_thread_data();
validateTransaction(transaction);
*has_default = false;
dsql_dbb* dbb = transaction->getDsqlAttachment();
USHORT result = 0;
AutoCacheRequest handle(tdbb, irq_domain_2, IRQ_REQUESTS);
FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction)
FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME EQ domain_name.c_str()
{
bid* blob_id;
if (!FLD.RDB$DEFAULT_VALUE.NULL)
{
blob_id = &FLD.RDB$DEFAULT_VALUE;
*has_default = true;
}
else
*has_default = false;
if (*has_default)
{
blb* blob_handle = blb::open2(tdbb, transaction, blob_id, sizeof(blr_bpb), blr_bpb, true);
// fetch segments. Assume buffer is big enough.
UCHAR* ptr_in_buffer = buffer;
while (true)
{
const USHORT length = blob_handle->BLB_get_segment(tdbb, ptr_in_buffer, buff_length);
ptr_in_buffer += length;
buff_length -= length;
result += length;
if (blob_handle->blb_flags & BLB_eof)
{
// null terminate the buffer
*ptr_in_buffer = 0;
break;
}
if (blob_handle->getFragmentSize())
status_exception::raise(Arg::Gds(isc_segment));
else
continue;
}
try
{
ThreadStatusGuard status_vector(tdbb);
blob_handle->BLB_close(tdbb);
blob_handle = NULL;
}
catch (Exception&)
{
}
// the default string must be of the form:
// blr_version4 blr_literal ..... blr_eoc
fb_assert((buffer[0] == blr_version4) || (buffer[0] == blr_version5));
fb_assert(buffer[1] == blr_literal);
}
else
{
if (dbb->dbb_db_SQL_dialect > SQL_DIALECT_V5)
buffer[0] = blr_version5;
else
buffer[0] = blr_version4;
buffer[1] = blr_eoc;
result = 2;
}
}
END_FOR
return result;
}
dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScratch,
const QualifiedName& name)
{

View File

@ -55,10 +55,8 @@ Jrd::dsql_intlsym* METD_get_charset(Jrd::jrd_tra*, USHORT, const char* name);
USHORT METD_get_charset_bpc(Jrd::jrd_tra*, SSHORT);
Firebird::MetaName METD_get_charset_name(Jrd::jrd_tra*, SSHORT);
Jrd::dsql_intlsym* METD_get_collation(Jrd::jrd_tra*, const Firebird::MetaName&, USHORT charset_id);
USHORT METD_get_col_default(Jrd::jrd_tra*, const char*, const char*, bool*, UCHAR*, USHORT);
Firebird::MetaName METD_get_default_charset(Jrd::jrd_tra*);
bool METD_get_domain(Jrd::jrd_tra*, class Jrd::TypeClause*, const Firebird::MetaName& name);
USHORT METD_get_domain_default(Jrd::jrd_tra*, const Firebird::MetaName&, bool*, UCHAR*, USHORT);
Jrd::dsql_udf* METD_get_function(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*,
const Firebird::QualifiedName&);
void METD_get_primary_key(Jrd::jrd_tra*, const Firebird::MetaName&,

View File

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

View File

@ -591,18 +591,20 @@ using namespace Firebird;
// tokens added for Firebird 4.0
%token <metaNamePtr> BINARY
%token <metaNamePtr> CUME_DIST
%token <metaNamePtr> DEFINER
%token <metaNamePtr> ERROR_MESSAGE
%token <metaNamePtr> EXCLUDE
%token <metaNamePtr> FOLLOWING
%token <metaNamePtr> INVOKER
%token <metaNamePtr> MESSAGE
%token <metaNamePtr> NTILE
%token <metaNamePtr> OTHERS
%token <metaNamePtr> PERCENT_RANK
%token <metaNamePtr> PRECEDING
%token <metaNamePtr> PRIVILEGE
%token <metaNamePtr> RANGE
%token <metaNamePtr> RDB_ERROR
%token <metaNamePtr> RDB_ROLE_IN_USE
%token <metaNamePtr> RDB_SYSTEM_PRIVILEGE
%token <metaNamePtr> SECURITY
@ -610,6 +612,7 @@ using namespace Firebird;
%token <metaNamePtr> SYSTEM
%token <metaNamePtr> TIES
%token <metaNamePtr> UNBOUNDED
%token <metaNamePtr> VARBINARY
%token <metaNamePtr> WINDOW
%token <metaNamePtr> DECFLOAT
@ -722,6 +725,7 @@ using namespace Firebird;
Jrd::RelationNode::AddColumnClause* addColumnClause;
Jrd::RelationNode::RefActionClause* refActionClause;
Jrd::RelationNode::IndexConstraintClause* indexConstraintClause;
Jrd::RelationNode::IdentityOptions* identityOptions;
Jrd::CreateRelationNode* createRelationNode;
Jrd::CreateAlterViewNode* createAlterViewNode;
Jrd::CreateIndexNode* createIndexNode;
@ -2097,9 +2101,12 @@ gtt_ops($createRelationNode)
%type gtt_op(<createRelationNode>)
gtt_op($createRelationNode)
: // nothing by default. Will be set "on commit delete rows" in dsqlPass
| sql_security_clause { $createRelationNode->ssDefiner = $1; }
| ON COMMIT DELETE ROWS { setClause($createRelationNode->relationType, "ON COMMIT DELETE ROWS", rel_global_temp_delete); }
| ON COMMIT PRESERVE ROWS { setClause($createRelationNode->relationType, "ON COMMIT PRESERVE ROWS", rel_global_temp_preserve); }
| sql_security_clause
{ setClause(static_cast<BaseNullable<bool>&>($createRelationNode->ssDefiner), "SQL SECURITY", $1); }
| ON COMMIT DELETE ROWS
{ setClause($createRelationNode->relationType, "ON COMMIT DELETE ROWS", rel_global_temp_delete); }
| ON COMMIT PRESERVE ROWS
{ setClause($createRelationNode->relationType, "ON COMMIT PRESERVE ROWS", rel_global_temp_preserve); }
;
%type <stringPtr> external_file
@ -2145,8 +2152,7 @@ column_def($relationNode)
newNode<RelationNode::AddColumnClause>();
clause->field = $2;
clause->field->fld_name = *$1;
clause->identity = true;
clause->identityStart = $3;
clause->identityOptions = $3;
$relationNode->clauses.add(clause);
}
column_constraint_clause(NOTRIAL($<addColumnClause>4)) collate_clause
@ -2174,15 +2180,32 @@ column_def($relationNode)
}
;
%type <int64Val> identity_clause
%type <identityOptions> identity_clause
identity_clause
: GENERATED BY DEFAULT AS IDENTITY identity_clause_options { $$ = $6; }
: GENERATED BY DEFAULT AS IDENTITY
{ $$ = newNode<RelationNode::IdentityOptions>(); }
identity_clause_options_opt($6)
{ $$ = $6; }
;
%type <int64Val> identity_clause_options
identity_clause_options
: /* nothing */ { $$ = 0; }
| '(' START WITH sequence_value ')' { $$ = $4; }
%type identity_clause_options_opt(<identityOptions>)
identity_clause_options_opt($identityOptions)
: // nothing
| '(' identity_clause_options($identityOptions) ')'
;
%type identity_clause_options(<identityOptions>)
identity_clause_options($identityOptions)
: identity_clause_options identity_clause_option($identityOptions)
| identity_clause_option($identityOptions)
;
%type identity_clause_option(<identityOptions>)
identity_clause_option($identityOptions)
: START WITH sequence_value
{ setClause($identityOptions->startValue, "START WITH", $3); }
| INCREMENT by_noise signed_long_integer
{ setClause($identityOptions->increment, "INCREMENT BY", $3); }
;
// value does allow parens around it, but there is a problem getting the source text.
@ -3907,13 +3930,22 @@ alter_op($relationNode)
clause->dropDefault = true;
$relationNode->clauses.add(clause);
}
| col_opt symbol_column_name RESTART with_opt
| col_opt symbol_column_name
{ $<identityOptions>$ = newNode<RelationNode::IdentityOptions>(); }
alter_identity_clause_options($<identityOptions>3)
{
RelationNode::AlterColTypeClause* clause = newNode<RelationNode::AlterColTypeClause>();
clause->field = newNode<dsql_fld>();
clause->field->fld_name = *$2;
clause->identityRestart = true;
clause->identityRestartValue = $4;
clause->identityOptions = $<identityOptions>3;
$relationNode->clauses.add(clause);
}
| col_opt symbol_column_name DROP IDENTITY
{
RelationNode::AlterColTypeClause* clause = newNode<RelationNode::AlterColTypeClause>();
clause->field = newNode<dsql_fld>();
clause->field->fld_name = *$2;
clause->dropIdentity = true;
$relationNode->clauses.add(clause);
}
| ALTER SQL SECURITY DEFINER
@ -4017,7 +4049,6 @@ keyword_or_column
| REGR_SXY
| REGR_SYY
| RETURN
| RDB_RECORD_VERSION
| ROW
| SCROLL
| SQLSTATE
@ -4048,6 +4079,23 @@ alter_data_type_or_domain
}
;
%type alter_identity_clause_options(<identityOptions>)
alter_identity_clause_options($identityOptions)
: alter_identity_clause_options alter_identity_clause_option($identityOptions)
| alter_identity_clause_option($identityOptions)
;
%type alter_identity_clause_option(<identityOptions>)
alter_identity_clause_option($identityOptions)
: RESTART with_opt
{
setClause($identityOptions->restart, "RESTART");
$identityOptions->startValue = $2;
}
| SET INCREMENT by_noise signed_long_integer
{ setClause($identityOptions->increment, "SET INCREMENT BY", $4); }
;
%type <boolVal> drop_behaviour
drop_behaviour
: { $$ = false; }
@ -4385,6 +4433,7 @@ simple_type
%type <legacyField> non_charset_simple_type
non_charset_simple_type
: national_character_type
| binary_character_type
| numeric_type
| float_type
| decfloat_type
@ -4435,7 +4484,7 @@ non_charset_simple_type
$$->length = sizeof(GDS_TIMESTAMP);
}
else if (client_dialect == SQL_DIALECT_V6_TRANSITION)
yyabandon(-104, isc_transitional_date);
yyabandon(YYPOSNARG(1), -104, isc_transitional_date);
else
{
$$->dtype = dtype_sql_date;
@ -4571,6 +4620,40 @@ national_character_type
}
;
%type <legacyField> binary_character_type
binary_character_type
: binary_character_keyword '(' pos_short_integer ')'
{
$$ = newNode<dsql_fld>();
$$->dtype = dtype_text;
$$->charLength = (USHORT) $3;
$$->length = (USHORT) $3;
$$->textType = ttype_binary;
$$->charSetId = CS_BINARY;
$$->subType = fb_text_subtype_binary;
}
| binary_character_keyword
{
$$ = newNode<dsql_fld>();
$$->dtype = dtype_text;
$$->charLength = 1;
$$->length = 1;
$$->textType = ttype_binary;
$$->charSetId = CS_BINARY;
$$->subType = fb_text_subtype_binary;
}
| varbinary_character_keyword '(' pos_short_integer ')'
{
$$ = newNode<dsql_fld>();
$$->dtype = dtype_varying;
$$->charLength = (USHORT) $3;
$$->length = (USHORT) $3 + sizeof(USHORT);
$$->textType = ttype_binary;
$$->charSetId = CS_BINARY;
$$->subType = fb_text_subtype_binary;
}
;
%type <legacyField> character_type
character_type
: character_keyword '(' pos_short_integer ')'
@ -4610,6 +4693,14 @@ national_character_keyword
| NATIONAL CHAR
;
binary_character_keyword
: BINARY
;
varbinary_character_keyword
: VARBINARY
| BINARY VARYING
;
// numeric type
@ -4625,7 +4716,7 @@ decfloat_type
| DECFLOAT '(' signed_long_integer ')'
{
if ($3 != 16 && $3 != 34)
yyabandon(-842, isc_decprecision_err); // DecFloat precision must be 16 or 34.
yyabandon(YYPOSNARG(3), -842, isc_decprecision_err); // DecFloat precision must be 16 or 34.
$$ = newNode<dsql_fld>();
$$->precision = $3;
@ -4668,7 +4759,7 @@ prec_scale
$$ = newNode<dsql_fld>();
if ($2 < 1 || $2 > 18)
yyabandon(-842, isc_precision_err); // Precision must be between 1 and 18.
yyabandon(YYPOSNARG(2), -842, isc_precision_err); // Precision must be between 1 and 18.
if ($2 > 9)
{
@ -4718,10 +4809,10 @@ prec_scale
$$ = newNode<dsql_fld>();
if ($2 < 1 || $2 > 18)
yyabandon (-842, isc_precision_err); // Precision should be between 1 and 18
yyabandon(YYPOSNARG(2), -842, isc_precision_err); // Precision should be between 1 and 18
if ($4 > $2 || $4 < 0)
yyabandon (-842, isc_scale_nogt); // Scale must be between 0 and precision
yyabandon(YYPOSNARG(4), -842, isc_scale_nogt); // Scale must be between 0 and precision
if ($2 > 9)
{
@ -5846,7 +5937,7 @@ fetch_first_clause
// IBO hack: replace column_parens_opt by ins_column_parens_opt.
%type <storeNode> insert
insert
: insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) VALUES '(' value_list ')'
: insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) VALUES '(' value_or_default_list ')'
returning_clause
{
StoreNode* node = $$ = $1;
@ -5878,6 +5969,18 @@ insert_start
}
;
%type <valueListNode> value_or_default_list
value_or_default_list
: value_or_default { $$ = newNode<ValueListNode>($1); }
| value_or_default_list ',' value_or_default { $$ = $1->add($3); }
;
%type <valueExprNode> value_or_default
value_or_default
: value
| DEFAULT { $$ = NULL; }
;
// MERGE statement
%type <mergeNode> merge
@ -5908,7 +6011,7 @@ merge_when_clause($mergeNode)
merge_when_matched_clause($mergeNode)
: WHEN MATCHED
{ $<mergeMatchedClause>$ = &$mergeNode->whenMatched.add(); }
merge_update_specification(NOTRIAL($<mergeMatchedClause>3))
merge_update_specification(NOTRIAL($<mergeMatchedClause>3), NOTRIAL(&$mergeNode->relation->dsqlName))
;
%type merge_when_not_matched_clause(<mergeNode>)
@ -5918,11 +6021,11 @@ merge_when_not_matched_clause($mergeNode)
merge_insert_specification(NOTRIAL($<mergeNotMatchedClause>4))
;
%type merge_update_specification(<mergeMatchedClause>)
merge_update_specification($mergeMatchedClause)
: THEN UPDATE SET assignments
%type merge_update_specification(<mergeMatchedClause>, <metaNamePtr>)
merge_update_specification($mergeMatchedClause, $relationName)
: THEN UPDATE SET update_assignments(NOTRIAL($relationName))
{ $mergeMatchedClause->assignments = $4; }
| AND search_condition THEN UPDATE SET assignments
| AND search_condition THEN UPDATE SET update_assignments(NOTRIAL($relationName))
{
$mergeMatchedClause->condition = $2;
$mergeMatchedClause->assignments = $6;
@ -5935,10 +6038,10 @@ merge_update_specification($mergeMatchedClause)
%type merge_insert_specification(<mergeNotMatchedClause>)
merge_insert_specification($mergeNotMatchedClause)
: THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields))
VALUES '(' value_list ')'
VALUES '(' value_or_default_list ')'
{ $mergeNotMatchedClause->values = $6; }
| AND search_condition THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields))
VALUES '(' value_list ')'
VALUES '(' value_or_default_list ')'
{
$mergeNotMatchedClause->values = $8;
$mergeNotMatchedClause->condition = $2;
@ -5992,7 +6095,7 @@ update
%type <stmtNode> update_searched
update_searched
: UPDATE table_name SET assignments where_clause plan_clause
: UPDATE table_name SET update_assignments(NOTRIAL(&$2->dsqlName)) where_clause plan_clause
order_clause_opt rows_clause_optional returning_clause
{
ModifyNode* node = newNode<ModifyNode>();
@ -6009,7 +6112,7 @@ update_searched
%type <stmtNode> update_positioned
update_positioned
: UPDATE table_name SET assignments cursor_clause returning_clause
: UPDATE table_name SET update_assignments(NOTRIAL(&$2->dsqlName)) cursor_clause returning_clause
{
ModifyNode* node = newNode<ModifyNode>();
node->dsqlRelation = $2;
@ -6030,7 +6133,7 @@ update_or_insert
UpdateOrInsertNode* node = $$ = newNode<UpdateOrInsertNode>();
node->relation = $5;
}
ins_column_parens_opt(NOTRIAL(&$6->fields)) VALUES '(' value_list ')'
ins_column_parens_opt(NOTRIAL(&$6->fields)) VALUES '(' value_or_default_list ')'
update_or_insert_matching_opt(NOTRIAL(&$6->matching)) returning_clause
{
UpdateOrInsertNode* node = $$ = $6;
@ -6102,6 +6205,38 @@ assignment
}
;
%type <compoundStmtNode> update_assignments(<metaNamePtr>)
update_assignments($relationName)
: update_assignment($relationName)
{
$$ = newNode<CompoundStmtNode>();
$$->statements.add($1);
}
| update_assignments ',' update_assignment($relationName)
{
$1->statements.add($3);
$$ = $1;
}
;
%type <stmtNode> update_assignment(<metaNamePtr>)
update_assignment($relationName)
: update_column_name '=' value
{
AssignmentNode* node = newNode<AssignmentNode>();
node->asgnTo = $1;
node->asgnFrom = $3;
$$ = node;
}
| update_column_name '=' DEFAULT
{
AssignmentNode* node = newNode<AssignmentNode>();
node->asgnTo = $1;
node->asgnFrom = newNode<DefaultNode>(*$relationName, $1->dsqlName);
$$ = node;
}
;
%type <stmtNode> exec_function
exec_function
: udf
@ -6306,22 +6441,17 @@ distinct_predicate
%type <boolExprNode> between_predicate
between_predicate
: value BETWEEN value_between AND value_between %prec BETWEEN
{ $$ = newNode<ComparativeBoolNode>(blr_between, $1, $3, $5); }
| value NOT BETWEEN value_between AND value_between %prec BETWEEN
: value BETWEEN value_special AND value_special %prec BETWEEN
{
$$ = newNode<ComparativeBoolNode>(blr_between, $1, $3, $5);
}
| value NOT BETWEEN value_special AND value_special %prec BETWEEN
{
ComparativeBoolNode* node = newNode<ComparativeBoolNode>(blr_between, $1, $4, $6);
$$ = newNode<NotBoolNode>(node);
}
;
// Special value for BETWEEN, to avoid conflicts with boolean expressions.
%type <valueExprNode> value_between
value_between
: value_primary
| '(' boolean_value_expression ')' { $$ = newNode<BoolAsValueNode>($2); }
;
%type <boolExprNode> binary_pattern_predicate
binary_pattern_predicate
: value binary_pattern_operator value %prec CONTAINING
@ -6721,6 +6851,13 @@ value
{ $$ = newNode<BoolAsValueNode>($1); }
;
// Used in situations that is not possible to use non-parenthesized boolean expressions.
%type <valueExprNode> value_special
value_special
: value_primary
| '(' boolean_value_expression ')' { $$ = newNode<BoolAsValueNode>($2); }
;
%type <valueExprNode> value_primary
value_primary
: nonparenthesized_value
@ -6752,21 +6889,21 @@ nonparenthesized_value
{ $$ = $1; }
| udf
{ $$ = $1; }
| '-' value_primary %prec UMINUS
| '-' value_special %prec UMINUS
{ $$ = newNode<NegateNode>($2); }
| '+' value_primary %prec UPLUS
| '+' value_special %prec UPLUS
{ $$ = $2; }
| value_primary '+' value_primary
| value_special '+' value_special
{ $$ = newNode<ArithmeticNode>(blr_add, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); }
| value_primary CONCATENATE value_primary
| value_special CONCATENATE value_special
{ $$ = newNode<ConcatenateNode>($1, $3); }
| value_primary COLLATE symbol_collation_name
| value_special COLLATE symbol_collation_name
{ $$ = newNode<CollateNode>($1, *$3); }
| value_primary '-' value_primary
| value_special '-' value_special
{ $$ = newNode<ArithmeticNode>(blr_subtract, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); }
| value_primary '*' value_primary
| value_special '*' value_special
{ $$ = newNode<ArithmeticNode>(blr_multiply, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); }
| value_primary '/' value_primary
| value_special '/' value_special
{ $$ = newNode<ArithmeticNode>(blr_divide, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); }
| '(' column_singleton ')'
{ $$ = $2; }
@ -6973,12 +7110,20 @@ internal_info
{ $$ = newNode<InternalInfoNode>(MAKE_const_slong(INFO_TYPE_SQLSTATE)); }
| ROW_COUNT
{ $$ = newNode<InternalInfoNode>(MAKE_const_slong(INFO_TYPE_ROWS_AFFECTED)); }
| EXCEPTION
{ $$ = newNode<InternalInfoNode>(MAKE_const_slong(INFO_TYPE_EXCEPTION)); }
| ERROR_MESSAGE
{ $$ = newNode<InternalInfoNode>(MAKE_const_slong(INFO_TYPE_ERROR_MSG)); }
| RDB_ERROR '(' error_context ')'
{ $$ = newNode<InternalInfoNode>(MAKE_const_slong($3)); }
;
%type <int32Val> error_context
error_context
: GDSCODE { $$ = INFO_TYPE_GDSCODE; }
| SQLCODE { $$ = INFO_TYPE_SQLCODE; }
| SQLSTATE { $$ = INFO_TYPE_SQLSTATE; }
| EXCEPTION { $$ = INFO_TYPE_EXCEPTION; }
| MESSAGE { $$ = INFO_TYPE_ERROR_MSG; }
;
%type <intlStringPtr> sql_string
sql_string
: STRING // string in current charset
@ -7012,7 +7157,7 @@ nonneg_short_integer
: NUMBER
{
if ($1 > SHRT_POS_MAX)
yyabandon(-842, isc_expec_short); // Short integer expected
yyabandon(YYPOSNARG(1), -842, isc_expec_short); // Short integer expected
$$ = $1;
}
@ -7023,7 +7168,7 @@ neg_short_integer
: NUMBER
{
if ($1 > SHRT_NEG_MAX)
yyabandon(-842, isc_expec_short); // Short integer expected
yyabandon(YYPOSNARG(1), -842, isc_expec_short); // Short integer expected
$$ = $1;
}
@ -7034,7 +7179,7 @@ pos_short_integer
: nonneg_short_integer
{
if ($1 == 0)
yyabandon(-842, isc_expec_positive); // Positive number expected
yyabandon(YYPOSNARG(1), -842, isc_expec_positive); // Positive number expected
$$ = $1;
}
@ -7045,7 +7190,7 @@ unsigned_short_integer
: NUMBER
{
if ($1 > SHRT_UNSIGNED_MAX)
yyabandon(-842, isc_expec_ushort); // Unsigned short integer expected
yyabandon(YYPOSNARG(1), -842, isc_expec_ushort); // Unsigned short integer expected
$$ = $1;
}
@ -7760,6 +7905,7 @@ symbol_blob_subtype_name
%type <metaNamePtr> symbol_character_set_name
symbol_character_set_name
: valid_symbol_name
| BINARY
;
%type <metaNamePtr> symbol_collation_name
@ -7986,7 +8132,6 @@ non_reserved_word
| TANH
| TEMPORARY
| TRUNC
| WEEK
| AUTONOMOUS // added in FB 2.5
| CHAR_TO_UUID
| FIRSTNAME
@ -8014,7 +8159,6 @@ non_reserved_word
| CONTAINING
| CSTRING
| DATABASE
// | DB_KEY
| DESC
| DO
| DOMAIN
@ -8070,7 +8214,7 @@ non_reserved_word
// | VARIABLE
// | VIEW
| WAIT
// | WEEK
| WEEK
// | WHILE
| WORK
| WRITE // end of old keywords, that were reserved pre-Firebird.2.5
@ -8089,8 +8233,6 @@ non_reserved_word
| PACKAGE
| PARTITION
| PRIOR
| RDB_GET_CONTEXT
| RDB_SET_CONTEXT
| RELATIVE
| DENSE_RANK
| FIRST_VALUE
@ -8109,18 +8251,16 @@ non_reserved_word
| TRUSTED
| CUME_DIST // added in FB 4.0
| DEFINER
| ERROR_MESSAGE
| EXCLUDE
| FOLLOWING
| INVOKER
| MESSAGE
| NTILE
| OTHERS
| PERCENT_RANK
| PRECEDING
| PRIVILEGE
| RANGE
| RDB_ROLE_IN_USE
| RDB_SYSTEM_PRIVILEGE
| SECURITY
| SQL
| SYSTEM

View File

@ -32,7 +32,6 @@
#include <string.h>
#include "../jrd/ibase.h"
#include "../gpre/gpre.h"
//#include "../jrd/license.h"
#include "../jrd/intl.h"
#include "../gpre/gpre_proto.h"
#include "../gpre/hsh_proto.h"

View File

@ -32,7 +32,6 @@
#include <string.h>
#include "../jrd/ibase.h"
#include "../gpre/gpre.h"
//#include "../jrd/license.h"
#include "../jrd/intl.h"
#include "../gpre/gpre_proto.h"
#include "../gpre/hsh_proto.h"

View File

@ -650,6 +650,13 @@
//#define isc_blob_dbase_ole 23
//#define isc_blob_typed_binary 24
/*****************/
/* Text Subtypes */
/*****************/
#define fb_text_subtype_text 0
#define fb_text_subtype_binary 1
/* Deprecated definitions maintained for compatibility only */
//#define isc_info_db_SQL_dialect 62

View File

@ -439,6 +439,9 @@ typedef ISC_STATUS API_ROUTINE prototype_fb_cancel_operation(ISC_STATUS *,
isc_db_handle *,
USHORT);
typedef ISC_STATUS API_ROUTINE prototype_fb_database_crypt_callback(ISC_STATUS *,
void *);
struct FirebirdApiPointers
{
prototype_isc_attach_database *isc_attach_database;
@ -519,6 +522,7 @@ struct FirebirdApiPointers
prototype_isc_service_query *isc_service_query;
prototype_isc_service_start *isc_service_start;
prototype_fb_cancel_operation *fb_cancel_operation;
prototype_fb_database_crypt_callback *fb_database_crypt_callback;
};
#endif

View File

@ -43,7 +43,6 @@
#include "fb_types.h"
#include "firebird/Interface.h"
#include "../common/ThreadStart.h"
namespace Firebird
{

View File

@ -68,7 +68,6 @@
#ifdef __cplusplus
#include "../common/common.h"
//#include "fb_exception.h"
#endif
#ifdef NULL

View File

@ -599,6 +599,8 @@ interface Server : Auth
{
[notImplemented(Auth::AUTH_FAILED)]
int authenticate(Status status, ServerBlock sBlock, Writer writerInterface);
version: // 3.0.1 => 4.0
void setDbCryptCallback(Status status, CryptKeyCallback cryptCallback);
}
// .. and corresponding client
@ -732,6 +734,13 @@ interface KeyHolderPlugin : PluginBase
// Missing key with given name is not an error condition for keyHandle().
// It should just return NULL in this case
CryptKeyCallback keyHandle(Status status, const string keyName);
version: // 3.0.1 => 4.0
// With returning true here KeyHolder attachment can use only keys, provided by this KeyHolder.
// Use of keys, got by database crypt plugin from other attachments, is prohibited.
boolean useOnlyOwnKeys(Status status);
// Communication in a chain of key holders - get callback interface for chaining holders
CryptKeyCallback chainHandle(Status status);
}

View File

@ -2402,6 +2402,7 @@ namespace Firebird
struct VTable : public IAuth::VTable
{
int (CLOOP_CARG *authenticate)(IServer* self, IStatus* status, IServerBlock* sBlock, IWriter* writerInterface) throw();
void (CLOOP_CARG *setDbCryptCallback)(IServer* self, IStatus* status, ICryptKeyCallback* cryptCallback) throw();
};
protected:
@ -2415,7 +2416,7 @@ namespace Firebird
}
public:
static const unsigned VERSION = 5;
static const unsigned VERSION = 6;
template <typename StatusType> int authenticate(StatusType* status, IServerBlock* sBlock, IWriter* writerInterface)
{
@ -2424,6 +2425,19 @@ namespace Firebird
StatusType::checkException(status);
return ret;
}
template <typename StatusType> void setDbCryptCallback(StatusType* status, ICryptKeyCallback* cryptCallback)
{
if (cloopVTable->version < 6)
{
StatusType::setVersionError(status, "IServer", cloopVTable->version, 6);
StatusType::checkException(status);
return;
}
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->setDbCryptCallback(this, status, cryptCallback);
StatusType::checkException(status);
}
};
class IClient : public IAuth
@ -2905,6 +2919,8 @@ namespace Firebird
{
int (CLOOP_CARG *keyCallback)(IKeyHolderPlugin* self, IStatus* status, ICryptKeyCallback* callback) throw();
ICryptKeyCallback* (CLOOP_CARG *keyHandle)(IKeyHolderPlugin* self, IStatus* status, const char* keyName) throw();
FB_BOOLEAN (CLOOP_CARG *useOnlyOwnKeys)(IKeyHolderPlugin* self, IStatus* status) throw();
ICryptKeyCallback* (CLOOP_CARG *chainHandle)(IKeyHolderPlugin* self, IStatus* status) throw();
};
protected:
@ -2918,7 +2934,7 @@ namespace Firebird
}
public:
static const unsigned VERSION = 4;
static const unsigned VERSION = 5;
template <typename StatusType> int keyCallback(StatusType* status, ICryptKeyCallback* callback)
{
@ -2935,6 +2951,34 @@ namespace Firebird
StatusType::checkException(status);
return ret;
}
template <typename StatusType> FB_BOOLEAN useOnlyOwnKeys(StatusType* status)
{
if (cloopVTable->version < 5)
{
StatusType::setVersionError(status, "IKeyHolderPlugin", cloopVTable->version, 5);
StatusType::checkException(status);
return 0;
}
StatusType::clearException(status);
FB_BOOLEAN ret = static_cast<VTable*>(this->cloopVTable)->useOnlyOwnKeys(this, status);
StatusType::checkException(status);
return ret;
}
template <typename StatusType> ICryptKeyCallback* chainHandle(StatusType* status)
{
if (cloopVTable->version < 5)
{
StatusType::setVersionError(status, "IKeyHolderPlugin", cloopVTable->version, 5);
StatusType::checkException(status);
return 0;
}
StatusType::clearException(status);
ICryptKeyCallback* ret = static_cast<VTable*>(this->cloopVTable)->chainHandle(this, status);
StatusType::checkException(status);
return ret;
}
};
class IDbCryptInfo : public IReferenceCounted
@ -9998,6 +10042,7 @@ namespace Firebird
this->setOwner = &Name::cloopsetOwnerDispatcher;
this->getOwner = &Name::cloopgetOwnerDispatcher;
this->authenticate = &Name::cloopauthenticateDispatcher;
this->setDbCryptCallback = &Name::cloopsetDbCryptCallbackDispatcher;
}
} vTable;
@ -10019,6 +10064,20 @@ namespace Firebird
}
}
static void CLOOP_CARG cloopsetDbCryptCallbackDispatcher(IServer* self, IStatus* status, ICryptKeyCallback* cryptCallback) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::setDbCryptCallback(&status2, cryptCallback);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static void CLOOP_CARG cloopsetOwnerDispatcher(IPluginBase* self, IReferenceCounted* r) throw()
{
try
@ -10084,6 +10143,7 @@ namespace Firebird
}
virtual int authenticate(StatusType* status, IServerBlock* sBlock, IWriter* writerInterface) = 0;
virtual void setDbCryptCallback(StatusType* status, ICryptKeyCallback* cryptCallback) = 0;
};
template <typename Name, typename StatusType, typename Base>
@ -11230,6 +11290,8 @@ namespace Firebird
this->getOwner = &Name::cloopgetOwnerDispatcher;
this->keyCallback = &Name::cloopkeyCallbackDispatcher;
this->keyHandle = &Name::cloopkeyHandleDispatcher;
this->useOnlyOwnKeys = &Name::cloopuseOnlyOwnKeysDispatcher;
this->chainHandle = &Name::cloopchainHandleDispatcher;
}
} vTable;
@ -11266,6 +11328,36 @@ namespace Firebird
}
}
static FB_BOOLEAN CLOOP_CARG cloopuseOnlyOwnKeysDispatcher(IKeyHolderPlugin* self, IStatus* status) throw()
{
StatusType status2(status);
try
{
return static_cast<Name*>(self)->Name::useOnlyOwnKeys(&status2);
}
catch (...)
{
StatusType::catchException(&status2);
return static_cast<FB_BOOLEAN>(0);
}
}
static ICryptKeyCallback* CLOOP_CARG cloopchainHandleDispatcher(IKeyHolderPlugin* self, IStatus* status) throw()
{
StatusType status2(status);
try
{
return static_cast<Name*>(self)->Name::chainHandle(&status2);
}
catch (...)
{
StatusType::catchException(&status2);
return static_cast<ICryptKeyCallback*>(0);
}
}
static void CLOOP_CARG cloopsetOwnerDispatcher(IPluginBase* self, IReferenceCounted* r) throw()
{
try
@ -11332,6 +11424,8 @@ namespace Firebird
virtual int keyCallback(StatusType* status, ICryptKeyCallback* callback) = 0;
virtual ICryptKeyCallback* keyHandle(StatusType* status, const char* keyName) = 0;
virtual FB_BOOLEAN useOnlyOwnKeys(StatusType* status) = 0;
virtual ICryptKeyCallback* chainHandle(StatusType* status) = 0;
};
template <typename Name, typename StatusType, typename Base>

View File

@ -895,6 +895,7 @@ static const struct {
{"dsql_no_output_sqlda", 336003110},
{"dsql_wrong_param_num", 336003111},
{"dsql_invalid_drop_ss_clause", 336003112},
{"upd_ins_cannot_default", 336003113},
{"dyn_filter_not_found", 336068645},
{"dyn_func_not_found", 336068649},
{"dyn_index_not_found", 336068656},
@ -971,6 +972,7 @@ static const struct {
{"dyn_cant_use_zero_increment", 336068896},
{"dyn_cant_use_in_foreignkey", 336068897},
{"dyn_defvaldecl_package_func", 336068898},
{"dyn_cant_use_zero_inc_ident", 336068904},
{"gbak_unknown_switch", 336330753},
{"gbak_page_size_missing", 336330754},
{"gbak_page_size_toobig", 336330755},

View File

@ -929,6 +929,7 @@ const ISC_STATUS isc_dsql_no_input_sqlda = 336003109L;
const ISC_STATUS isc_dsql_no_output_sqlda = 336003110L;
const ISC_STATUS isc_dsql_wrong_param_num = 336003111L;
const ISC_STATUS isc_dsql_invalid_drop_ss_clause = 336003112L;
const ISC_STATUS isc_upd_ins_cannot_default = 336003113L;
const ISC_STATUS isc_dyn_filter_not_found = 336068645L;
const ISC_STATUS isc_dyn_func_not_found = 336068649L;
const ISC_STATUS isc_dyn_index_not_found = 336068656L;
@ -1005,6 +1006,7 @@ const ISC_STATUS isc_dyn_cant_modify_sysobj = 336068895L;
const ISC_STATUS isc_dyn_cant_use_zero_increment = 336068896L;
const ISC_STATUS isc_dyn_cant_use_in_foreignkey = 336068897L;
const ISC_STATUS isc_dyn_defvaldecl_package_func = 336068898L;
const ISC_STATUS isc_dyn_cant_use_zero_inc_ident = 336068904L;
const ISC_STATUS isc_gbak_unknown_switch = 336330753L;
const ISC_STATUS isc_gbak_page_size_missing = 336330754L;
const ISC_STATUS isc_gbak_page_size_toobig = 336330755L;
@ -1335,7 +1337,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 = 1279;
const ISC_STATUS isc_err_max = 1281;
#else /* c definitions */
@ -2234,6 +2236,7 @@ const ISC_STATUS isc_err_max = 1279;
#define isc_dsql_no_output_sqlda 336003110L
#define isc_dsql_wrong_param_num 336003111L
#define isc_dsql_invalid_drop_ss_clause 336003112L
#define isc_upd_ins_cannot_default 336003113L
#define isc_dyn_filter_not_found 336068645L
#define isc_dyn_func_not_found 336068649L
#define isc_dyn_index_not_found 336068656L
@ -2310,6 +2313,7 @@ const ISC_STATUS isc_err_max = 1279;
#define isc_dyn_cant_use_zero_increment 336068896L
#define isc_dyn_cant_use_in_foreignkey 336068897L
#define isc_dyn_defvaldecl_package_func 336068898L
#define isc_dyn_cant_use_zero_inc_ident 336068904L
#define isc_gbak_unknown_switch 336330753L
#define isc_gbak_page_size_missing 336330754L
#define isc_gbak_page_size_toobig 336330755L
@ -2640,7 +2644,7 @@ const ISC_STATUS isc_err_max = 1279;
#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 1279
#define isc_err_max 1281
#endif

View File

@ -898,6 +898,7 @@ Data source : @4"}, /* eds_statement */
{336003110, "No SQLDA for output values provided"}, /* dsql_no_output_sqlda */
{336003111, "Wrong number of parameters (expected @1, got @2)"}, /* dsql_wrong_param_num */
{336003112, "Invalid DROP SQL SECURITY clause"}, /* dsql_invalid_drop_ss_clause */
{336003113, "UPDATE OR INSERT value for field @1, part of the implicit or explicit MATCHING clause, cannot be DEFAULT"}, /* upd_ins_cannot_default */
{336068645, "BLOB Filter @1 not found"}, /* dyn_filter_not_found */
{336068649, "Function @1 not found"}, /* dyn_func_not_found */
{336068656, "Index not found"}, /* dyn_index_not_found */
@ -974,6 +975,7 @@ Data source : @4"}, /* eds_statement */
{336068896, "INCREMENT BY 0 is an illegal option for sequence @1"}, /* dyn_cant_use_zero_increment */
{336068897, "Can't use @1 in FOREIGN KEY constraint"}, /* dyn_cant_use_in_foreignkey */
{336068898, "Default values for parameters are allowed only in declaration of packaged function @1.@2"}, /* dyn_defvaldecl_package_func */
{336068904, "INCREMENT BY 0 is an illegal option for identity column @1 of table @2"}, /* dyn_cant_use_zero_inc_ident */
{336330753, "found unknown switch"}, /* gbak_unknown_switch */
{336330754, "page size parameter missing"}, /* gbak_page_size_missing */
{336330755, "Page size specified (@1) greater than limit (32768 bytes)"}, /* gbak_page_size_toobig */

View File

@ -894,6 +894,7 @@ static const struct {
{336003110, -802}, /* 38 dsql_no_output_sqlda */
{336003111, -313}, /* 39 dsql_wrong_param_num */
{336003112, -817}, /* 40 dsql_invalid_drop_ss_clause */
{336003113, -313}, /* 41 upd_ins_cannot_default */
{336068645, -901}, /* 37 dyn_filter_not_found */
{336068649, -901}, /* 41 dyn_func_not_found */
{336068656, -901}, /* 48 dyn_index_not_found */
@ -970,6 +971,7 @@ static const struct {
{336068896, -901}, /* 288 dyn_cant_use_zero_increment */
{336068897, -901}, /* 289 dyn_cant_use_in_foreignkey */
{336068898, -901}, /* 290 dyn_defvaldecl_package_func */
{336068904, -901}, /* 296 dyn_cant_use_zero_inc_ident */
{336330753, -901}, /* 1 gbak_unknown_switch */
{336330754, -901}, /* 2 gbak_page_size_missing */
{336330755, -901}, /* 3 gbak_page_size_toobig */

View File

@ -894,6 +894,7 @@ static const struct {
{336003110, "07002"}, // 38 dsql_no_output_sqlda
{336003111, "07001"}, // 39 dsql_wrong_param_num
{336003112, "42000"}, // 40 dsql_invalid_drop_ss_clause
{336003113, "42000"}, // 41 upd_ins_cannot_default
{336068645, "42000"}, // 37 dyn_filter_not_found
{336068649, "42000"}, // 41 dyn_func_not_found
{336068656, "42000"}, // 48 dyn_index_not_found
@ -970,6 +971,7 @@ static const struct {
{336068896, "42000"}, // 288 dyn_cant_use_zero_increment
{336068897, "42000"}, // 289 dyn_cant_use_in_foreignkey
{336068898, "42000"}, // 290 dyn_defvaldecl_package_func
{336068904, "42000"}, // 296 dyn_cant_use_zero_inc_ident
{336330753, "00000"}, // 1 gbak_unknown_switch
{336330754, "00000"}, // 2 gbak_page_size_missing
{336330755, "00000"}, // 3 gbak_page_size_toobig

View File

@ -24,7 +24,6 @@
#include "firebird.h"
#include "OptionsBase.h"
//#include "../common/utils_proto.h" // strnicmp
#include "../common/gdsassert.h"

View File

@ -59,7 +59,6 @@
#include "../jrd/ods.h"
#include "../common/utils_proto.h"
#include "../jrd/constants.h"
//#include "../common/classes/ImplementHelper.h"
using MsgFormat::SafeArg;
@ -410,8 +409,11 @@ int EXTRACT_list_table(const SCHAR* relation_name,
}
else
{
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE))
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE,
FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE))
{
return FINI_ERROR;
}
if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR))
{
@ -440,7 +442,8 @@ int EXTRACT_list_table(const SCHAR* relation_name,
}
// International character sets
if ((FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR ||
if ((((FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR) &&
FLD.RDB$FIELD_SUB_TYPE == fb_text_subtype_text) ||
FLD.RDB$FIELD_TYPE == BLOB) &&
!FLD.RDB$CHARACTER_SET_ID.NULL)
{
@ -801,8 +804,11 @@ static void get_procedure_args(const char* proc_name)
}
else
{
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE))
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE,
FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE))
{
return; // ps_ERR;
}
// Changed this to return RDB$CHARACTER_LENGTH if available
// Fix for Bug #122563
@ -816,7 +822,9 @@ static void get_procedure_args(const char* proc_name)
}
// Show international character sets and collations
if (!FLD.RDB$COLLATION_ID.NULL || !FLD.RDB$CHARACTER_SET_ID.NULL)
if ((!FLD.RDB$COLLATION_ID.NULL || !FLD.RDB$CHARACTER_SET_ID.NULL) &&
!(((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) &&
FLD.RDB$FIELD_SUB_TYPE != fb_text_subtype_text))
{
char_sets[0] = 0;
@ -1017,8 +1025,11 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg)
}
else
{
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE))
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE,
FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE))
{
return; // ps_ERR;
}
// Changed this to return RDB$CHARACTER_LENGTH if available
// Fix for Bug #122563
@ -1032,7 +1043,9 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg)
}
// Show international character sets and collations
if (!FLD.RDB$COLLATION_ID.NULL || !FLD.RDB$CHARACTER_SET_ID.NULL)
if ((!FLD.RDB$COLLATION_ID.NULL || !FLD.RDB$CHARACTER_SET_ID.NULL) &&
!(((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) &&
FLD.RDB$FIELD_SUB_TYPE != fb_text_subtype_text))
{
char_sets[0] = 0;
@ -2235,8 +2248,11 @@ static void list_domain_table(const SCHAR* table_name, SSHORT default_char_set_i
isqlGlob.printf("CREATE DOMAIN %s AS ", FLD.RDB$FIELD_NAME);
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE))
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE,
FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE))
{
return; // ps_ERR;
}
if (FLD.RDB$FIELD_TYPE == BLOB)
{
@ -2265,7 +2281,9 @@ static void list_domain_table(const SCHAR* table_name, SSHORT default_char_set_i
// do, then the domain syntax when printed is not correct.
// Since the character set is part of the field type, display that information now.
if (!FLD.RDB$CHARACTER_SET_ID.NULL)
if (!FLD.RDB$CHARACTER_SET_ID.NULL &&
!(((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) &&
FLD.RDB$FIELD_SUB_TYPE != fb_text_subtype_text))
{
char_sets[0] = 0;
@ -2357,8 +2375,11 @@ static void list_domains(SSHORT default_char_set_id)
else
isqlGlob.printf("CREATE DOMAIN %s AS ", FLD.RDB$FIELD_NAME);
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE))
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE,
FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE))
{
return; // ps_ERR;
}
if (FLD.RDB$FIELD_TYPE == BLOB)
{
@ -2388,7 +2409,9 @@ static void list_domains(SSHORT default_char_set_id)
// do, then the domain syntax when printed is not correct.
// Since the character set is part of the field type, display that information now.
if (!FLD.RDB$CHARACTER_SET_ID.NULL)
if (!FLD.RDB$CHARACTER_SET_ID.NULL &&
!(((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) &&
FLD.RDB$FIELD_SUB_TYPE != fb_text_subtype_text))
{
char_sets[0] = 0;
if ((FLD.RDB$CHARACTER_SET_ID != default_char_set_id) ||
@ -2575,8 +2598,11 @@ static void listRelationComputed(LegacyTables flag, SSHORT default_char_set_id)
}
else
{
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE))
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE,
FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE))
{
return;
}
if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR))
{
@ -2605,7 +2631,8 @@ static void listRelationComputed(LegacyTables flag, SSHORT default_char_set_id)
}
// International character sets
if ((FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR ||
if ((((FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR) &&
FLD.RDB$FIELD_SUB_TYPE == fb_text_subtype_text) ||
FLD.RDB$FIELD_TYPE == BLOB) &&
!FLD.RDB$CHARACTER_SET_ID.NULL)
{

View File

@ -46,7 +46,6 @@
#include "firebird.h"
#include <stdio.h>
#include "../yvalve/keywords.h"
//#include "../yvalve/gds_proto.h"
#include "../jrd/intl.h"
#include <stdlib.h>
#include <stdarg.h>
@ -80,10 +79,6 @@
#include <locale.h>
#endif
//#ifdef HAVE_IO_H
//#include <io.h> // mktemp
//#endif
#ifdef HAVE_EDITLINE_H
// This is a local file included in our distribution - but not always
// compiled into the system
@ -1808,7 +1803,8 @@ bool ISQL_is_domain(const TEXT* field_name)
// Print the numeric type as accurately as possible, depending on the ODS.
// If it isn't numeric/decimal or is another non-numeric data type, print only the type.
bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int fieldScale)
bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int fieldSubType,
const int fieldPrecision, const int fieldScale)
{
// Look through types array
int i = 0;
@ -1822,34 +1818,24 @@ bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int
return false;
}
bool precision_known = false;
if (isqlGlob.major_ods >= ODS_VERSION10 &&
(fieldType == SMALLINT || fieldType == INTEGER || fieldType == BIGINT))
switch (fieldType)
{
case SMALLINT:
case INTEGER:
case BIGINT:
// Handle Integral subtypes NUMERIC and DECIMAL
// We are ODS >= 10 and could be any Dialect
FOR FLD1 IN RDB$FIELDS WITH
FLD1.RDB$FIELD_NAME EQ fieldName
AND NOT FLD1.RDB$FIELD_PRECISION EQ 0
// We are Dialect >=3 since FIELD_PRECISION is non-NULL
if (FLD1.RDB$FIELD_SUB_TYPE > 0 && FLD1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES)
if (isqlGlob.major_ods >= ODS_VERSION10 && fieldPrecision != 0 &&
fieldSubType > 0 && fieldSubType <= MAX_INTSUBTYPES)
{
isqlGlob.printf("%s(%d, %d)",
Integral_subtypes[FLD1.RDB$FIELD_SUB_TYPE],
FLD1.RDB$FIELD_PRECISION,
-FLD1.RDB$FIELD_SCALE);
precision_known = true;
Integral_subtypes[fieldSubType],
fieldPrecision,
-fieldScale);
}
END_FOR
ON_ERROR
ISQL_errmsg (fbStatus);
return false;
END_ERROR;
}
if (!precision_known)
else
{
if (fieldScale < 0)
{
@ -1868,16 +1854,32 @@ bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int
case DOUBLE_PRECISION:
isqlGlob.printf("NUMERIC(15, %d)", -fieldScale);
break;
default:
isqlGlob.printf("%s", Column_types[i].type_name);
}
}
else
{
// This is a non-numeric data type
break;
}
}
return true;
case T_CHAR:
if (fieldSubType >= 0 && fieldSubType <= MAX_TEXTSUBTYPES)
{
isqlGlob.printf("%s", Text_subtypes[fieldSubType]);
return true;
}
break;
case VARCHAR:
if (fieldSubType >= 0 && fieldSubType <= MAX_VARYINGSUBTYPES)
{
isqlGlob.printf("%s", Varying_subtypes[fieldSubType]);
return true;
}
break;
}
// Field type without recognizable subtypes
isqlGlob.printf("%s", Column_types[i].type_name);
}
}
return true;
}

View File

@ -329,6 +329,24 @@ static const SCHAR* Integral_subtypes[] = {
"DECIMAL" // DECIMAL, keyword
};
// Text subtypes
const int MAX_TEXTSUBTYPES = 1;
static const SCHAR* Text_subtypes[] = {
"CHAR",
"BINARY"
};
// Varying subtypes
const int MAX_VARYINGSUBTYPES = 1;
static const SCHAR* Varying_subtypes[] = {
"VARCHAR",
"VARBINARY"
};
// Blob subtypes
const int MAX_BLOBSUBTYPES = 8;

View File

@ -53,7 +53,8 @@ SSHORT ISQL_init(FILE*, FILE*);
bool ISQL_is_domain(const TEXT*);
#endif
int ISQL_main(int, char**);
bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int fieldScale);
bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int fieldSubType,
const int fieldPrecision, const int fieldScale);
void ISQL_print_validation(FILE*, ISC_QUAD*, bool, Firebird::ITransaction*);
//void ISQL_query_database(SSHORT*, FILE*, FILE*, FILE*);
//void ISQL_reset_settings();

View File

@ -3855,8 +3855,11 @@ static processing_state show_domains(const SCHAR* domain_name)
isqlGlob.printf("%s ", NEWLINE);
}
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE))
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE,
FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE))
{
return ps_ERR;
}
// Length for CHARs
if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) {
@ -3877,8 +3880,8 @@ static processing_state show_domains(const SCHAR* domain_name)
}
// Show international character sets
if (FLD.RDB$FIELD_TYPE == T_CHAR ||
FLD.RDB$FIELD_TYPE == VARCHAR ||
if (((FLD.RDB$FIELD_TYPE == T_CHAR ||
FLD.RDB$FIELD_TYPE == VARCHAR) && FLD.RDB$FIELD_SUB_TYPE == fb_text_subtype_text) ||
FLD.RDB$FIELD_TYPE == BLOB)
{
show_charsets(NULL, FLD.RDB$FIELD_NAME, true, false, false, false);
@ -4351,8 +4354,11 @@ static processing_state show_func(const SCHAR* funcname)
}
}
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE))
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE,
FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE))
{
return ps_ERR;
}
// Use RDB$CHARACTER_LENGTH instead of RDB$FIELD_LENGTH
// FSG 19.Nov.2000
@ -4364,8 +4370,8 @@ static processing_state show_func(const SCHAR* funcname)
// Show international character sets and collations
if (FLD.RDB$FIELD_TYPE == T_CHAR ||
FLD.RDB$FIELD_TYPE == VARCHAR ||
if (((FLD.RDB$FIELD_TYPE == T_CHAR ||
FLD.RDB$FIELD_TYPE == VARCHAR) && FLD.RDB$FIELD_SUB_TYPE == fb_text_subtype_text) ||
FLD.RDB$FIELD_TYPE == BLOB)
{
SSHORT charset = 0, collation = 0;
@ -5244,8 +5250,11 @@ static processing_state show_proc(const SCHAR* procname)
}
}
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE))
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE,
FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE))
{
return ps_ERR;
}
// Use RDB$CHARACTER_LENGTH instead of RDB$FIELD_LENGTH
// FSG 19.Nov.2000
@ -5257,8 +5266,8 @@ static processing_state show_proc(const SCHAR* procname)
// Show international character sets and collations
if (FLD.RDB$FIELD_TYPE == T_CHAR ||
FLD.RDB$FIELD_TYPE == VARCHAR ||
if (((FLD.RDB$FIELD_TYPE == T_CHAR ||
FLD.RDB$FIELD_TYPE == VARCHAR) && FLD.RDB$FIELD_SUB_TYPE == fb_text_subtype_text) ||
FLD.RDB$FIELD_TYPE == BLOB)
{
SSHORT charset = 0;
@ -5775,15 +5784,21 @@ static processing_state show_table(const SCHAR* relation_name, bool isView)
continue;
}
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE))
if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE,
FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE))
{
return ps_ERR;
}
if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) {
isqlGlob.printf("(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME));
if (FLD.RDB$FIELD_SUB_TYPE == fb_text_subtype_text)
{
// Show international character sets and collations
show_charsets(relation_name, RFR.RDB$FIELD_NAME, true, false, false, false);
}
}
if (FLD.RDB$FIELD_TYPE == BLOB)
{

View File

@ -725,12 +725,21 @@ void AttachmentsRefHolder::debugHelper(const char* from)
RefDeb(DEB_RLS_JATT, from);
}
void StableAttachmentPart::manualLock(ULONG& flags)
void StableAttachmentPart::manualLock(ULONG& flags, const ULONG whatLock)
{
fb_assert(!(flags & whatLock));
if (whatLock & ATT_async_manual_lock)
{
fb_assert(!(flags & ATT_manual_lock));
asyncMutex.enter(FB_FUNCTION);
flags |= ATT_async_manual_lock;
}
if (whatLock & ATT_manual_lock)
{
mainMutex.enter(FB_FUNCTION);
flags |= (ATT_manual_lock | ATT_async_manual_lock);
flags |= ATT_manual_lock;
}
}
void StableAttachmentPart::manualUnlock(ULONG& flags)
@ -756,3 +765,4 @@ JAttachment* Attachment::getInterface() throw()
{
return att_stable->getInterface();
}

View File

@ -39,6 +39,7 @@
#include "../common/classes/array.h"
#include "../common/classes/stack.h"
#include "../common/classes/timestamp.h"
#include "../common/ThreadStart.h"
#include "../jrd/EngineInterface.h"
@ -77,7 +78,7 @@ namespace Jrd
class jrd_rel;
class jrd_prc;
class Trigger;
typedef Firebird::ObjectsArray<Trigger> trig_vec;
class TrigVector;
class Function;
class JrdStatement;
class Validation;
@ -114,9 +115,35 @@ struct DdlTriggerContext
};
struct bid;
// Attachment flags
const ULONG ATT_no_cleanup = 0x00001L; // Don't expunge, purge, or garbage collect
const ULONG ATT_shutdown = 0x00002L; // attachment has been shutdown
const ULONG ATT_shutdown_manager = 0x00004L; // attachment requesting shutdown
const ULONG ATT_exclusive = 0x00008L; // attachment wants exclusive database access
const ULONG ATT_attach_pending = 0x00010L; // Indicate attachment is only pending
const ULONG ATT_exclusive_pending = 0x00020L; // Indicate exclusive attachment pending
const ULONG ATT_notify_gc = 0x00040L; // Notify garbage collector to expunge, purge ..
const ULONG ATT_garbage_collector = 0x00080L; // I'm a garbage collector
const ULONG ATT_cancel_raise = 0x00100L; // Cancel currently running operation
const ULONG ATT_cancel_disable = 0x00200L; // Disable cancel operations
const ULONG ATT_no_db_triggers = 0x00400L; // Don't execute database triggers
const ULONG ATT_manual_lock = 0x00800L; // Was locked manually
const ULONG ATT_async_manual_lock = 0x01000L; // Async mutex was locked manually
//const ULONG ATT_purge_started = 0x02000L; // Purge already started - avoid 2 purges at once
const ULONG ATT_overwrite_check = 0x02000L; // Attachment checks is it possible to overwrite DB
const ULONG ATT_system = 0x04000L; // Special system attachment
const ULONG ATT_creator = 0x08000L; // This attachment created the DB
const ULONG ATT_monitor_done = 0x10000L; // Monitoring data is refreshed
const ULONG ATT_security_db = 0x20000L; // Attachment used for security purposes
const ULONG ATT_mapping = 0x40000L; // Attachment used for mapping auth block
const ULONG ATT_crypt_thread = 0x80000L; // Attachment from crypt thread
const ULONG ATT_NO_CLEANUP = (ATT_no_cleanup | ATT_notify_gc);
class Attachment;
struct bid;
//
// RefCounted part of Attachment object, placed into permanent pool
@ -155,6 +182,11 @@ public:
return useAsync ? &asyncMutex : &mainMutex;
}
Firebird::Mutex* getBlockingMutex()
{
return &blockingMutex;
}
void cancel()
{
fb_assert(asyncMutex.locked());
@ -172,7 +204,7 @@ public:
return getInterface()->getTransactionInterface(status, tra);
}
void manualLock(ULONG& flags);
void manualLock(ULONG& flags, const ULONG whatLock = ATT_manual_lock | ATT_async_manual_lock);
void manualUnlock(ULONG& flags);
void manualAsyncUnlock(ULONG& flags);
@ -183,6 +215,8 @@ private:
// These mutexes guarantee attachment existence. After releasing both of them with possibly
// zero att_use_count one should check does attachment still exists calling getHandle().
Firebird::Mutex mainMutex, asyncMutex;
// This mutex guarantees attachment is not accessed by more than single external thread.
Firebird::Mutex blockingMutex;
};
//
@ -295,8 +329,8 @@ public:
vec<jrd_rel*>* att_relations; // relation vector
Firebird::Array<jrd_prc*> att_procedures; // scanned procedures
trig_vec* att_triggers[DB_TRIGGER_MAX];
trig_vec* att_ddl_triggers;
TrigVector* att_triggers[DB_TRIGGER_MAX];
TrigVector* att_ddl_triggers;
Firebird::Array<Function*> att_functions; // User defined functions
Firebird::Array<JrdStatement*> att_internal; // internal statements
@ -385,33 +419,6 @@ private:
};
// Attachment flags
const ULONG ATT_no_cleanup = 0x00001L; // Don't expunge, purge, or garbage collect
const ULONG ATT_shutdown = 0x00002L; // attachment has been shutdown
const ULONG ATT_shutdown_manager = 0x00004L; // attachment requesting shutdown
const ULONG ATT_exclusive = 0x00008L; // attachment wants exclusive database access
const ULONG ATT_attach_pending = 0x00010L; // Indicate attachment is only pending
const ULONG ATT_exclusive_pending = 0x00020L; // Indicate exclusive attachment pending
const ULONG ATT_notify_gc = 0x00040L; // Notify garbage collector to expunge, purge ..
const ULONG ATT_garbage_collector = 0x00080L; // I'm a garbage collector
const ULONG ATT_cancel_raise = 0x00100L; // Cancel currently running operation
const ULONG ATT_cancel_disable = 0x00200L; // Disable cancel operations
const ULONG ATT_no_db_triggers = 0x00400L; // Don't execute database triggers
const ULONG ATT_manual_lock = 0x00800L; // Was locked manually
const ULONG ATT_async_manual_lock = 0x01000L; // Async mutex was locked manually
//const ULONG ATT_purge_started = 0x02000L; // Purge already started - avoid 2 purges at once
const ULONG ATT_overwrite_check = 0x02000L; // Attachment checks is it possible to overwrite DB
const ULONG ATT_system = 0x04000L; // Special system attachment
const ULONG ATT_creator = 0x08000L; // This attachment created the DB
const ULONG ATT_monitor_done = 0x10000L; // Monitoring data is refreshed
const ULONG ATT_security_db = 0x20000L; // Attachment used for security purposes
const ULONG ATT_mapping = 0x40000L; // Attachment used for mapping auth block
const ULONG ATT_crypt_thread = 0x80000L; // Attachment from crypt thread
const ULONG ATT_NO_CLEANUP = (ATT_no_cleanup | ATT_notify_gc);
inline bool Attachment::locksmith(thread_db* tdbb, SystemPrivilege sp) const
{
return att_user && att_user->locksmith(tdbb, sp);
@ -563,7 +570,6 @@ private:
Firebird::RefPtr<JAttachment> m_JAttachment;
};
} // namespace Jrd
#endif // JRD_ATTACHMENT_H

View File

@ -47,7 +47,7 @@
#include "../jrd/Monitoring.h"
#include "../jrd/os/pio_proto.h"
#include "../common/isc_proto.h"
#include "../common/classes/GetPlugins.h"
#include "../common/classes/auto.h"
#include "../common/classes/RefMutex.h"
#include "../common/classes/ClumpletWriter.h"
#include "../common/sha.h"
@ -69,6 +69,19 @@ namespace {
const UCHAR CRYPT_INIT = LCK_EX;
const int MAX_PLUGIN_NAME_LEN = 31;
class ReleasePlugin
{
public:
static void clear(IPluginBase* ptr)
{
if (ptr)
{
PluginManagerInterfacePtr()->releasePlugin(ptr);
}
}
};
}
@ -265,10 +278,12 @@ namespace Jrd {
: PermanentStorage(*tdbb->getDatabase()->dbb_permanent),
sync(this),
keyName(getPool()),
keyHolderPlugins(getPool()),
keyHolderPlugins(getPool(), this),
hash(getPool()),
dbInfo(FB_NEW DbInfo(this)),
cryptThreadId(0),
cryptPlugin(NULL),
checkFactory(NULL),
dbb(*tdbb->getDatabase()),
cryptAtt(NULL),
slowIO(0),
@ -289,6 +304,7 @@ namespace Jrd {
delete stateLock;
delete threadLock;
delete checkFactory;
dbInfo->destroy();
}
@ -361,24 +377,25 @@ namespace Jrd {
else
keyName = "";
loadPlugin(hdr->hdr_crypt_plugin);
loadPlugin(tdbb, hdr->hdr_crypt_plugin);
string valid;
calcValidation(valid);
calcValidation(valid, cryptPlugin);
if (hc.find(Ods::HDR_crypt_hash))
{
string hash;
hc.getString(hash);
if (hash != valid)
(Arg::Gds(isc_bad_crypt_key) << keyName).raise();
}
else
hash = valid;
}
if (flags & CRYPT_HDR_INIT)
checkDigitalSignature(hdr);
checkDigitalSignature(tdbb, hdr);
}
void CryptoManager::loadPlugin(const char* pluginName)
void CryptoManager::loadPlugin(thread_db* tdbb, const char* pluginName)
{
if (cryptPlugin)
{
@ -391,14 +408,14 @@ namespace Jrd {
return;
}
GetPlugins<IDbCryptPlugin> cryptControl(IPluginManager::TYPE_DB_CRYPT, dbb.dbb_config, pluginName);
if (!cryptControl.hasData())
AutoPtr<Factory> cryptControl(FB_NEW Factory(IPluginManager::TYPE_DB_CRYPT, dbb.dbb_config, pluginName));
if (!cryptControl->hasData())
{
(Arg::Gds(isc_no_crypt_plugin) << pluginName).raise();
}
// do not assign cryptPlugin directly before key init complete
IDbCryptPlugin* p = cryptControl.plugin();
IDbCryptPlugin* p = cryptControl->plugin();
FbLocalStatus status;
p->setInfo(&status, dbInfo);
@ -409,9 +426,20 @@ namespace Jrd {
status_exception::raise(&status);
}
keyHolderPlugins.init(p, keyName.c_str());
keyHolderPlugins.init(p, keyName);
cryptPlugin = p;
cryptPlugin->addRef();
// remove old factory if present
delete checkFactory;
checkFactory = NULL;
// store new one
if (dbb.dbb_config->getServerMode() == MODE_SUPER)
{
checkFactory = cryptControl.release();
keyHolderPlugins.validateNewAttachment(tdbb->getAttachment(), keyName);
}
}
void CryptoManager::prepareChangeCryptState(thread_db* tdbb, const MetaName& plugName,
@ -467,18 +495,18 @@ namespace Jrd {
}
keyName = key;
loadPlugin(plugName.c_str());
loadPlugin(tdbb, plugName.c_str());
}
}
}
void CryptoManager::calcValidation(string& valid)
void CryptoManager::calcValidation(string& valid, IDbCryptPlugin* plugin)
{
// crypt verifier
const char* sample = "0123456789ABCDEF";
char result[16];
FbLocalStatus sv;
cryptPlugin->encrypt(&sv, sizeof(result), sample, result);
plugin->encrypt(&sv, sizeof(result), sample, result);
if (sv->getState() & IStatus::STATE_ERRORS)
Arg::StatusVector(&sv).raise();
@ -487,6 +515,13 @@ namespace Jrd {
Sha1::hashBased64(valid, verifier);
}
bool CryptoManager::checkValidation(IDbCryptPlugin* plugin)
{
string valid;
calcValidation(valid, plugin);
return valid == hash;
}
void CryptoManager::changeCryptState(thread_db* tdbb, const string& plugName)
{
if (plugName.length() > 31)
@ -537,7 +572,7 @@ namespace Jrd {
// Load plugin
if (newCryptState)
{
loadPlugin(plugName.c_str());
loadPlugin(tdbb, plugName.c_str());
}
crypt = newCryptState;
@ -550,14 +585,16 @@ namespace Jrd {
{
header->hdr_flags |= Ods::hdr_encrypted;
plugName.copyTo(header->hdr_crypt_plugin, sizeof(header->hdr_crypt_plugin));
string hash;
calcValidation(hash);
calcValidation(hash, cryptPlugin);
hc.deleteWithTag(Ods::HDR_crypt_hash);
hc.insertString(Ods::HDR_crypt_hash, hash);
hc.deleteWithTag(Ods::HDR_crypt_key);
if (keyName.hasData())
hc.insertString(Ods::HDR_crypt_key, keyName);
if (checkFactory)
keyHolderPlugins.validateExistingAttachments(keyName);
}
else
header->hdr_flags &= ~Ods::hdr_encrypted;
@ -569,7 +606,7 @@ namespace Jrd {
header->hdr_flags |= Ods::hdr_crypt_process;
process = true;
digitalySignDatabase(hdr);
digitalySignDatabase(tdbb, hdr);
hdr.flush();
}
catch (const Exception&)
@ -619,7 +656,15 @@ namespace Jrd {
{
keyHolderPlugins.attach(att, dbb.dbb_config);
Factory* f = checkFactory;
lockAndReadHeader(tdbb, CRYPT_HDR_INIT);
if (f && f == checkFactory)
{
if (!keyHolderPlugins.validateNewAttachment(att, keyName))
(Arg::Gds(isc_bad_crypt_key) << keyName).raise();
}
}
void CryptoManager::terminateCryptThread(thread_db*, bool wait)
@ -683,7 +728,7 @@ namespace Jrd {
crypt = hdr->hdr_flags & Ods::hdr_encrypted ? true : false;
// If we are going to start crypt thread, we need plugin to be loaded
loadPlugin(hdr->hdr_crypt_plugin);
loadPlugin(tdbb, hdr->hdr_crypt_plugin);
releasingLock = true;
LCK_release(tdbb, threadLock);
@ -926,7 +971,7 @@ namespace Jrd {
}
}
digitalySignDatabase(hdr);
digitalySignDatabase(tdbb, hdr);
hdr.flush();
}
@ -1132,50 +1177,7 @@ namespace Jrd {
return (crypt ? fb_info_crypt_encrypted : 0) | (process ? fb_info_crypt_process : 0);
}
CryptoManager::HolderAttachments::HolderAttachments(MemoryPool& p)
: keyHolder(NULL), attachments(p)
{ }
void CryptoManager::HolderAttachments::setPlugin(IKeyHolderPlugin* kh)
{
keyHolder = kh;
keyHolder->addRef();
}
CryptoManager::HolderAttachments::~HolderAttachments()
{
if (keyHolder)
{
PluginManagerInterfacePtr()->releasePlugin(keyHolder);
}
}
void CryptoManager::HolderAttachments::registerAttachment(Attachment* att)
{
attachments.add(att);
}
bool CryptoManager::HolderAttachments::unregisterAttachment(Attachment* att)
{
unsigned i = attachments.getCount();
while (i--)
{
if (attachments[i] == att)
{
attachments.remove(i);
break;
}
}
return attachments.getCount() == 0;
}
bool CryptoManager::HolderAttachments::operator==(IKeyHolderPlugin* kh) const
{
// ASF: I think there should be a better way to do this.
return keyHolder->cloopVTable == kh->cloopVTable;
}
void CryptoManager::KeyHolderPlugins::attach(Attachment* att, Config* config)
void CryptoManager::KeyHolderPlugins::attach(Attachment* att, const Config* config)
{
MutexLockGuard g(holdersMutex, FB_FUNCTION);
@ -1184,31 +1186,43 @@ namespace Jrd {
{
IKeyHolderPlugin* keyPlugin = keyControl.plugin();
FbLocalStatus st;
if (keyPlugin->keyCallback(&st, att->att_crypt_callback) > 0)
bool flProvide = false;
if (keyPlugin->keyCallback(&st, att->att_crypt_callback))
flProvide = true;
else
{
// holder accepted attachment's key
HolderAttachments* ha = NULL;
st.check();
flProvide = !keyPlugin->useOnlyOwnKeys(&st);
// Ignore error condition to support old plugins
}
if (flProvide)
{
// holder is going to provide a key
PerAttHolders* pa = NULL;
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
{
if (knownHolders[i] == keyPlugin)
if (knownHolders[i].first == att)
{
ha = &knownHolders[i];
pa = &knownHolders[i];
break;
}
}
if (!ha)
if (!pa)
{
ha = &(knownHolders.add());
ha->setPlugin(keyPlugin);
pa = &(knownHolders.add());
pa->first = att;
}
ha->registerAttachment(att);
break; // Do not need >1 key from attachment to single DB
if (pa)
{
pa->second.add(keyPlugin);
keyPlugin->addRef();
}
}
else
st.check();
}
}
@ -1216,33 +1230,149 @@ namespace Jrd {
{
MutexLockGuard g(holdersMutex, FB_FUNCTION);
unsigned i = knownHolders.getCount();
while (i--)
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
{
if (knownHolders[i].unregisterAttachment(att))
if (knownHolders[i].first == att)
{
releaseHolders(knownHolders[i]);
knownHolders.remove(i);
break;
}
}
}
void CryptoManager::KeyHolderPlugins::init(IDbCryptPlugin* crypt, const char* keyName)
void CryptoManager::KeyHolderPlugins::releaseHolders(PerAttHolders& pa)
{
unsigned j = 0;
for (; j < pa.second.getCount(); ++j)
PluginManagerInterfacePtr()->releasePlugin(pa.second[j]);
pa.second.removeCount(0, j);
}
void CryptoManager::KeyHolderPlugins::init(IDbCryptPlugin* crypt, const MetaName& keyName)
{
MutexLockGuard g(holdersMutex, FB_FUNCTION);
Firebird::HalfStaticArray<Firebird::IKeyHolderPlugin*, 64> holdersVector;
unsigned int length = knownHolders.getCount();
IKeyHolderPlugin** vector = holdersVector.getBuffer(length);
for (unsigned i = 0; i < length; ++i)
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
{
vector[i] = knownHolders[i].getPlugin();
PerAttHolders pa = knownHolders[i];
for (unsigned j = 0; j < pa.second.getCount(); ++j)
holdersVector.push(pa.second[j]);
}
FbLocalStatus st;
crypt->setKey(&st, length, vector, keyName);
crypt->setKey(&st, holdersVector.getCount(), holdersVector.begin(), keyName.c_str());
st.check();
}
bool CryptoManager::KeyHolderPlugins::validateHoldersGroup(PerAttHolders& pa, const MetaName& keyName)
{
FbLocalStatus st;
fb_assert(holdersMutex.locked());
for (unsigned j = 0; j < pa.second.getCount(); ++j)
{
IKeyHolderPlugin* keyHolder = pa.second[j];
if (!keyHolder->useOnlyOwnKeys(&st))
return true;
if (validateHolder(keyHolder, keyName))
return true;
}
return false;
}
bool CryptoManager::KeyHolderPlugins::validateNewAttachment(Attachment* att, const MetaName& keyName)
{
FbLocalStatus st;
MutexLockGuard g(holdersMutex, FB_FUNCTION);
// Check for current attachment
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
{
PerAttHolders& pa = knownHolders[i];
if (pa.first == att)
{
bool empty = (pa.second.getCount() == 0);
bool result = empty ? false : validateHoldersGroup(pa, keyName);
if (empty)
break;
return result;
}
}
// Special case - holders not needed at all
return validateHolder(NULL, keyName);
}
bool CryptoManager::KeyHolderPlugins::validateHolder(IKeyHolderPlugin* keyHolder, const MetaName& keyName)
{
fb_assert(mgr->checkFactory);
if (!mgr->checkFactory)
return false;
FbLocalStatus st;
AutoPtr<IDbCryptPlugin, ReleasePlugin> crypt(mgr->checkFactory->makeInstance());
crypt->setKey(&st, keyHolder ? 1 : 0, &keyHolder, keyName.c_str());
if (st.isSuccess())
{
try
{
if (mgr->checkValidation(crypt))
return true;
}
catch (const Exception&)
{ } // Ignore possible errors, continue analysis
}
return false;
}
void CryptoManager::KeyHolderPlugins::validateExistingAttachments(const MetaName& keyName)
{
FbLocalStatus st;
// Special case - holders not needed at all
if (validateHolder(NULL, keyName))
return;
// Loop through whole attachments list of DBB, shutdown attachments missing any holders
fb_assert(!mgr->dbb.dbb_sync.isLocked());
MutexLockGuard g(holdersMutex, FB_FUNCTION);
SyncLockGuard dsGuard(&mgr->dbb.dbb_sync, SYNC_EXCLUSIVE, FB_FUNCTION);
for (Attachment* att = mgr->dbb.dbb_attachments; att; att = att->att_next)
{
bool found = false;
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
{
if (knownHolders[i].first == att)
{
found = true;
break;
}
}
if (!found)
att->signalShutdown();
}
// Loop through internal attachments list closing one missing valid holders
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
{
if (!validateHoldersGroup(knownHolders[i], keyName))
knownHolders[i].first->signalShutdown();
}
}
void CryptoManager::addClumplet(string& signature, ClumpletReader& block, UCHAR tag)
{
if (block.find(tag))
@ -1254,7 +1384,7 @@ namespace Jrd {
}
}
void CryptoManager::calcDigitalSignature(string& signature, const Header& hdr)
void CryptoManager::calcDigitalSignature(thread_db* tdbb, string& signature, const Header& hdr)
{
/*
We use the following items to calculate digital signature (hash of encrypted string)
@ -1283,7 +1413,7 @@ namespace Jrd {
unsigned len = signature.length();
len &= ~(QUANTUM - 1);
loadPlugin(hdr->hdr_crypt_plugin);
loadPlugin(tdbb, hdr->hdr_crypt_plugin);
string enc;
FbLocalStatus sv;
@ -1295,7 +1425,7 @@ namespace Jrd {
}
void CryptoManager::digitalySignDatabase(CchHdr& hdr)
void CryptoManager::digitalySignDatabase(thread_db* tdbb, CchHdr& hdr)
{
ClumpletWriter hc(ClumpletWriter::UnTagged, hdr->hdr_page_size);
hdr.getClumplets(hc);
@ -1307,7 +1437,7 @@ namespace Jrd {
{
wf = true;
string signature;
calcDigitalSignature(signature, hdr);
calcDigitalSignature(tdbb, signature, hdr);
hc.insertString(Ods::HDR_crypt_checksum, signature);
}
@ -1315,7 +1445,7 @@ namespace Jrd {
hdr.setClumplets(hc);
}
void CryptoManager::checkDigitalSignature(const Header& hdr)
void CryptoManager::checkDigitalSignature(thread_db* tdbb, const Header& hdr)
{
if (hdr->hdr_flags & (Ods::hdr_crypt_process | Ods::hdr_encrypted))
{
@ -1326,7 +1456,7 @@ namespace Jrd {
string sig1, sig2;
hc.getString(sig1);
calcDigitalSignature(sig2, hdr);
calcDigitalSignature(tdbb, sig2, hdr);
if (sig1 != sig2)
Arg::Gds(isc_crypt_checksum).raise();
}

View File

@ -36,6 +36,7 @@
#include "../common/classes/objects_array.h"
#include "../common/classes/condition.h"
#include "../common/classes/MetaName.h"
#include "../common/classes/GetPlugins.h"
#include "../common/ThreadStart.h"
#include "../jrd/ods.h"
#include "../jrd/status.h"
@ -268,6 +269,8 @@ private:
class CryptoManager FB_FINAL : public Firebird::PermanentStorage, public BarSync::IBar
{
public:
typedef Firebird::GetPlugins<Firebird::IDbCryptPlugin> Factory;
explicit CryptoManager(thread_db* tdbb);
~CryptoManager();
@ -294,6 +297,8 @@ public:
void cryptThread();
bool checkValidation(Firebird::IDbCryptPlugin* crypt);
ULONG getCurrentPage() const;
UCHAR getCurrentState() const;
@ -319,42 +324,31 @@ private:
char buf[MAX_PAGE_SIZE + PAGE_ALIGNMENT - 1];
};
class HolderAttachments
{
public:
explicit HolderAttachments(Firebird::MemoryPool& p);
~HolderAttachments();
void registerAttachment(Attachment* att);
bool unregisterAttachment(Attachment* att);
void setPlugin(Firebird::IKeyHolderPlugin* kh);
Firebird::IKeyHolderPlugin* getPlugin() const
{
return keyHolder;
}
bool operator==(Firebird::IKeyHolderPlugin* kh) const;
private:
Firebird::IKeyHolderPlugin* keyHolder;
Firebird::HalfStaticArray<Attachment*, 32> attachments;
};
class KeyHolderPlugins
{
public:
explicit KeyHolderPlugins(Firebird::MemoryPool& p)
: knownHolders(p)
typedef CryptoManager::Factory Factory;
explicit KeyHolderPlugins(Firebird::MemoryPool& p, CryptoManager* m)
: knownHolders(p), mgr(m)
{ }
void attach(Attachment* att, Config* config);
void attach(Attachment* att, const Config* config);
void init(Firebird::IDbCryptPlugin* crypt, const Firebird::MetaName& keyName);
bool validateNewAttachment(Attachment*, const Firebird::MetaName& keyName);
void validateExistingAttachments(const Firebird::MetaName& keyName);
void detach(Attachment* att);
void init(Firebird::IDbCryptPlugin* crypt, const char* keyName);
private:
Firebird::Mutex holdersMutex;
Firebird::ObjectsArray<HolderAttachments> knownHolders;
typedef Firebird::Pair<Firebird::Right<Attachment*,
Firebird::HalfStaticArray<Firebird::IKeyHolderPlugin*, 4> > > PerAttHolders;
Firebird::ObjectsArray<PerAttHolders> knownHolders;
CryptoManager* mgr;
bool validateHoldersGroup(PerAttHolders& pa, const Firebird::MetaName& keyName);
bool validateHolder(Firebird::IKeyHolderPlugin* keyHolder, const Firebird::MetaName& keyName);
void releaseHolders(PerAttHolders& pa);
};
class DbInfo;
@ -395,28 +389,31 @@ private:
void doOnTakenWriteSync(thread_db* tdbb);
void doOnAst(thread_db* tdbb);
void loadPlugin(const char* pluginName);
void loadPlugin(thread_db* tdbb, const char* pluginName);
ULONG getLastPage(thread_db* tdbb);
void writeDbHeader(thread_db* tdbb, ULONG runpage);
void calcValidation(Firebird::string& valid);
void calcValidation(Firebird::string& valid, Firebird::IDbCryptPlugin* plugin);
void checkValidation();
void lockAndReadHeader(thread_db* tdbb, unsigned flags = 0);
static const unsigned CRYPT_HDR_INIT = 0x01;
static const unsigned CRYPT_HDR_NOWAIT = 0x02;
void addClumplet(Firebird::string& value, Firebird::ClumpletReader& block, UCHAR tag);
void calcDigitalSignature(Firebird::string& signature, const class Header& hdr);
void digitalySignDatabase(class CchHdr& hdr);
void checkDigitalSignature(const class Header& hdr);
void calcDigitalSignature(thread_db* tdbb, Firebird::string& signature, const class Header& hdr);
void digitalySignDatabase(thread_db* tdbb, class CchHdr& hdr);
void checkDigitalSignature(thread_db* tdbb, const class Header& hdr);
BarSync sync;
Firebird::MetaName keyName;
ULONG currentPage;
Firebird::Mutex pluginLoadMtx, cryptThreadMtx;
KeyHolderPlugins keyHolderPlugins;
Firebird::string hash;
Firebird::RefPtr<DbInfo> dbInfo;
Thread::Handle cryptThreadId;
Firebird::IDbCryptPlugin* cryptPlugin;
Factory* checkFactory;
Database& dbb;
Lock* stateLock;
Lock* threadLock;

View File

@ -122,6 +122,8 @@ namespace Jrd
}
int Database::blocking_ast_sweep(void* ast_object)
{
try
{
Database* dbb = static_cast<Database*>(ast_object);
AsyncContextHolder tdbb(dbb, FB_FUNCTION);
@ -131,6 +133,9 @@ namespace Jrd
dbb->dbb_flags &= ~DBB_sweep_starting;
LCK_release(tdbb, dbb->dbb_sweep_lock);
}
}
catch (const Exception&)
{} // no-op
return 0;
}

View File

@ -440,7 +440,7 @@ public:
GarbageCollector* dbb_garbage_collector; // GarbageCollector class
Firebird::Semaphore dbb_gc_sem; // Event to wake up garbage collector
Firebird::Semaphore dbb_gc_init; // Event for initialization garbage collector
Firebird::Semaphore dbb_gc_fini; // Event for finalization garbage collector
ThreadFinishSync<Database*> dbb_gc_fini; // Sync for finalization garbage collector
Firebird::MemoryStats dbb_memory_stats;
RuntimeStatistics dbb_stats;
@ -461,7 +461,7 @@ public:
BackupManager* dbb_backup_manager; // physical backup manager
Firebird::TimeStamp dbb_creation_date; // creation date
ExternalFileDirectoryList* dbb_external_file_directory_list;
Firebird::RefPtr<Config> dbb_config;
Firebird::RefPtr<const Config> dbb_config;
SharedCounter dbb_shared_counter;
CryptoManager* dbb_crypto_manager;
@ -512,6 +512,7 @@ private:
dbb_owner(*p),
dbb_pools(*p, 4),
dbb_sort_buffers(*p),
dbb_gc_fini(*p, garbage_collector, THREAD_medium),
dbb_stats(*p),
dbb_lock_owner_id(getLockOwnerId()),
dbb_tip_cache(NULL),
@ -561,6 +562,9 @@ public:
// reset sweep flags and release sweep lock
void clearSweepFlags(thread_db* tdbb);
static void garbage_collector(Database* dbb);
void exceptionHandler(const Firebird::Exception& ex, ThreadFinishSync<Database*>::ThreadRoutine* routine);
private:
//static int blockingAstSharedCounter(void*);
static int blocking_ast_sweep(void* ast_object);

View File

@ -433,7 +433,7 @@ public:
int release();
private:
JAttachment* internalAttach(Firebird::CheckStatusWrapper* status, const char* fileName,
JAttachment* internalAttach(Firebird::CheckStatusWrapper* status, const char* const fileName,
unsigned int dpbLength, const unsigned char* dpb, const UserId* existingId);
Firebird::ICryptKeyCallback* cryptCallback;
Firebird::IPluginConfig* pluginConfig;

View File

@ -662,7 +662,7 @@ Firebird::ITransaction* ExtEngineManager::ExternalContextImpl::getTransaction(
const char* ExtEngineManager::ExternalContextImpl::getUserName()
{
return internalAttachment->att_user->getUserName().c_str();
return internalAttachment->att_user ? internalAttachment->att_user->getUserName().c_str() : "";
}
const char* ExtEngineManager::ExternalContextImpl::getDatabaseName()

View File

@ -203,9 +203,9 @@ JrdStatement* JrdStatement::makeStatement(thread_db* tdbb, CompilerScratch* csb,
DmlNode::doPass1(tdbb, csb, &csb->csb_node);
// CVC: I'm going to allocate the map before the loop to avoid alloc/dealloc calls.
AutoPtr<StreamType, ArrayDelete<StreamType> > localMap(FB_NEW_POOL(*tdbb->getDefaultPool())
StreamType[STREAM_MAP_LENGTH]);
// CVC: I'm going to preallocate the map before the loop to avoid alloc/dealloc calls.
StreamMap localMap;
StreamType* const map = localMap.getBuffer(STREAM_MAP_LENGTH);
// Copy and compile (pass1) domains DEFAULT and constraints.
MapFieldInfo::Accessor accessor(&csb->csb_map_field_info);
@ -213,18 +213,17 @@ JrdStatement* JrdStatement::makeStatement(thread_db* tdbb, CompilerScratch* csb,
for (bool found = accessor.getFirst(); found; found = accessor.getNext())
{
FieldInfo& fieldInfo = accessor.current()->second;
//StreamType local_map[MAP_LENGTH];
AutoSetRestore<USHORT> autoRemapVariable(&csb->csb_remap_variable,
(csb->csb_variables ? csb->csb_variables->count() : 0) + 1);
fieldInfo.defaultValue = NodeCopier::copy(tdbb, csb, fieldInfo.defaultValue, localMap);
fieldInfo.defaultValue = NodeCopier::copy(tdbb, csb, fieldInfo.defaultValue, map);
csb->csb_remap_variable = (csb->csb_variables ? csb->csb_variables->count() : 0) + 1;
if (fieldInfo.validationExpr)
{
NodeCopier copier(csb, localMap);
NodeCopier copier(csb, map);
fieldInfo.validationExpr = copier.copy(tdbb, fieldInfo.validationExpr);
}
@ -616,7 +615,7 @@ void JrdStatement::release(thread_db* tdbb)
// Check that we have enough rights to access all resources this list of triggers touches.
void JrdStatement::verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation,
trig_vec* triggers, MetaName userName)
TrigVector* triggers, MetaName userName)
{
if (!triggers)
return;
@ -676,7 +675,7 @@ void JrdStatement::verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation,
// Invoke buildExternalAccess for triggers in vector
inline void JrdStatement::triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list,
trig_vec* tvec)
TrigVector* tvec)
{
if (!tvec)
return;
@ -723,7 +722,7 @@ void JrdStatement::buildExternalAccess(thread_db* tdbb, ExternalAccessList& list
if (!relation)
continue;
trig_vec *vec1, *vec2;
RefPtr<TrigVector> vec1, vec2;
switch (item->exa_action)
{

View File

@ -57,9 +57,9 @@ public:
void release(thread_db* tdbb);
private:
static void verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation, trig_vec* triggers,
static void verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation, TrigVector* triggers,
Firebird::MetaName userName);
static void triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list, trig_vec* tvec);
static void triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list, TrigVector* tvec);
void buildExternalAccess(thread_db* tdbb, ExternalAccessList& list);

View File

@ -329,12 +329,25 @@ public:
dataFlag = true;
downFlag = false;
}
catch (const Exception&)
catch (const Exception& ex)
{
if (curs)
curs->release();
if (tra)
tra->release();
// If database is shutdown it's not a reason to fail mapping
StaticStatusVector status;
ex.stuffException(status);
const ISC_STATUS* s = status.begin();
if (fb_utils::containsErrorCode(s, isc_shutdown))
{
downFlag = true;
return;
}
throw;
}
}
@ -584,29 +597,38 @@ class MappingIpc FB_FINAL : public Firebird::IpcObject
public:
explicit MappingIpc(MemoryPool&)
: processId(getpid())
: processId(getpid()),
cleanupSync(*getDefaultMemoryPool(), clearDelivery, THREAD_high)
{ }
~MappingIpc()
{
shutdown();
}
void shutdown()
{
if (!sharedMemory)
return;
{ // scope
Guard gShared(this);
MappingHeader* sMem = sharedMemory->getHeader();
startupSemaphore.tryEnter(5);
sMem->process[process].flags &= ~MappingHeader::FLAG_ACTIVE;
(void) // Ignore errors in cleanup
sharedMemory->eventPost(&sMem->process[process].notifyEvent);
cleanupSemaphore.tryEnter(5);
cleanupSync.waitForCompletion();
// Ignore errors in cleanup
sharedMemory->eventFini(&sMem->process[process].notifyEvent);
sharedMemory->eventFini(&sMem->process[process].callbackEvent);
bool found = false;
for (unsigned n = 0; n < sMem->processes; ++n)
{
if (sMem->process[n].flags & MappingHeader::FLAG_ACTIVE)
@ -620,6 +642,9 @@ public:
sharedMemory->removeMapFile();
}
sharedMemory = NULL;
}
void clearCache(const char* dbName, USHORT index)
{
PathName target;
@ -752,7 +777,7 @@ public:
try
{
Thread::start(clearDelivery, this, THREAD_high);
cleanupSync.run(this);
}
catch (const Exception&)
{
@ -761,6 +786,12 @@ public:
}
}
void exceptionHandler(const Exception& ex, ThreadFinishSync<MappingIpc*>::ThreadRoutine*)
{
iscLogException("Fatal error in clearDeliveryThread", ex);
fb_utils::logAndDie("Fatal error in clearDeliveryThread");
}
private:
void clearDeliveryThread()
{
@ -798,13 +829,10 @@ private:
}
if (startup)
startupSemaphore.release();
cleanupSemaphore.release();
}
catch (const Exception& ex)
{
iscLogException("Fatal error in clearDeliveryThread", ex);
fb_utils::logAndDie("Fatal error in clearDeliveryThread");
exceptionHandler(ex, NULL);
}
}
@ -859,11 +887,9 @@ private:
MappingIpc* const data;
};
static THREAD_ENTRY_DECLARE clearDelivery(THREAD_ENTRY_PARAM par)
static void clearDelivery(MappingIpc* mapping)
{
MappingIpc* m = (MappingIpc*)par;
m->clearDeliveryThread();
return 0;
mapping->clearDeliveryThread();
}
AutoPtr<SharedMemory<MappingHeader> > sharedMemory;
@ -871,7 +897,7 @@ private:
const SLONG processId;
unsigned process;
Semaphore startupSemaphore;
Semaphore cleanupSemaphore;
ThreadFinishSync<MappingIpc*> cleanupSync;
};
GlobalPtr<MappingIpc, InstanceControl::PRIORITY_DELETE_FIRST> mappingIpc;
@ -892,15 +918,21 @@ public:
: AutoPtr(att)
{
if (att)
{
MAP_DEBUG(fprintf(stderr, "Using existing db handle %p\n", att));
att->addRef();
}
}
bool attach(FbLocalStatus& st, const char* aliasDb, ICryptKeyCallback* cryptCb)
{
bool down = false; // true if on attach db is shutdown
if (hasData())
{
MAP_DEBUG(fprintf(stderr, "Already attached %s\n", aliasDb));
return down;
}
DispatcherPtr prov;
if (cryptCb)
@ -915,12 +947,14 @@ public:
embeddedSysdba.insertByte(isc_dpb_map_attach, TRUE);
embeddedSysdba.insertByte(isc_dpb_no_db_triggers, TRUE);
MAP_DEBUG(fprintf(stderr, "Attach %s\n", aliasDb));
IAttachment* att = prov->attachDatabase(&st, aliasDb,
embeddedSysdba.getBufferLength(), embeddedSysdba.getBuffer());
if (st->getState() & IStatus::STATE_ERRORS)
{
const ISC_STATUS* s = st->getErrors();
MAP_DEBUG(isc_print_status(s));
bool missing = fb_utils::containsErrorCode(s, isc_io_error);
down = fb_utils::containsErrorCode(s, isc_shutdown);
if (!(missing || down))
@ -930,6 +964,7 @@ public:
}
else
reset(att);
MAP_DEBUG(fprintf(stderr, "Att=%p\n", att));
return down;
}
@ -1326,7 +1361,13 @@ ULONG mapUser(const bool throwNotFoundError,
}
if (cDb)
{
MAP_DEBUG(fprintf(stderr, "Populate cache for main DB %p\n", iDb.get()));
cDb->populate(iDb, dbDown);
}
MAP_DEBUG(fprintf(stderr, "Populate cache for sec DB %p\n", iSec.get()));
cSec->populate(iSec, secDown);
sSec.downgrade(SYNC_SHARED);
@ -1659,4 +1700,9 @@ RecordBuffer* MappingList::getList(thread_db* tdbb, jrd_rel* relation)
return getData(relation);
}
void shutdownMappingIpc()
{
mappingIpc->shutdown();
}
} // namespace Jrd

View File

@ -53,6 +53,8 @@ void clearMappingCache(const char* dbName, USHORT index);
const USHORT MAPPING_CACHE = 0;
const USHORT SYSTEM_PRIVILEGES_CACHE = 1;
void shutdownMappingIpc();
class GlobalMappingScan: public VirtualTableScan
{
public:

View File

@ -391,9 +391,9 @@ MonitoringSnapshot::MonitoringSnapshot(thread_db* tdbb, MemoryPool& pool)
// Enumerate active sessions
const MetaName& user_name = attachment->att_user->getUserName();
const bool locksmith = attachment->locksmith(tdbb, MONITOR_ANY_ATTACHMENT);
const char* user_name_ptr = locksmith ? NULL : user_name.c_str();
const char* user_name_ptr = locksmith ? NULL : attachment->att_user ?
attachment->att_user->getUserName().c_str() : "";
MonitoringData::SessionList sessions(pool);
@ -856,7 +856,9 @@ void Monitoring::putDatabase(thread_db* tdbb, SnapshotData::DumpRecord& record)
void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Attachment* attachment)
{
fb_assert(attachment && attachment->att_user);
fb_assert(attachment);
if (!attachment->att_user)
return;
record.reset(rel_mon_attachments);
@ -1309,10 +1311,10 @@ void Monitoring::publishAttachment(thread_db* tdbb)
if (!dbb->dbb_monitoring_data)
dbb->dbb_monitoring_data = FB_NEW_POOL(*dbb->dbb_permanent) MonitoringData(dbb);
const MetaName& user_name = attachment->att_user->getUserName();
const char* user_name = attachment->att_user ? attachment->att_user->getUserName().c_str() : "";
MonitoringData::Guard guard(dbb->dbb_monitoring_data);
dbb->dbb_monitoring_data->setup(attachment->att_attachment_id, user_name.c_str());
dbb->dbb_monitoring_data->setup(attachment->att_attachment_id, user_name);
}
void Monitoring::cleanupAttachment(thread_db* tdbb)

View File

@ -1273,6 +1273,16 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
matches.add(segment->matches[j]);
}
}
// If the navigational candidate includes any matching segments,
// reset the selectivity/cost prerequisites to account these matches
if (matchedSegments)
{
totalSelectivity = navigationCandidate->selectivity;
totalIndexCost = DEFAULT_INDEX_COST + totalSelectivity * navigationCandidate->cardinality;
previousTotalCost = totalIndexCost + totalSelectivity * streamCardinality;
firstCandidate = false;
}
}
for (i = 0; i < inversions->getCount(); i++)

View File

@ -260,7 +260,7 @@ public:
bool isFiltered() const
{
return (baseSelectivity < MAXIMUM_SELECTIVITY);
return (baseIndexes || baseSelectivity < MAXIMUM_SELECTIVITY);
}
IndexedRelationships indexedRelationships;

View File

@ -614,6 +614,12 @@ RelationSourceNode* RelationSourceNode::copy(thread_db* tdbb, NodeCopier& copier
element->csb_view = newSource->view;
element->csb_view_stream = copier.remap[0];
if (alias.hasData())
{
element->csb_alias = FB_NEW_POOL(*tdbb->getDefaultPool())
string(*tdbb->getDefaultPool(), alias);
}
/** If there was a parent stream no., then copy the flags
from that stream to its children streams. (Bug 10164/10166)
For e.g.
@ -1102,17 +1108,27 @@ ProcedureSourceNode* ProcedureSourceNode::copy(thread_db* tdbb, NodeCopier& copi
newSource->targetList = copier.copy(tdbb, targetList);
}
jrd_prc* const new_procedure =
MET_lookup_procedure_id(tdbb, procedure->getId(), false, false, 0);
newSource->stream = copier.csb->nextStream();
copier.remap[stream] = newSource->stream;
newSource->context = context;
newSource->procedure = procedure;
newSource->procedure = new_procedure;
newSource->view = view;
CompilerScratch::csb_repeat* element = CMP_csb_element(copier.csb, newSource->stream);
element->csb_procedure = newSource->procedure;
element->csb_procedure = new_procedure;
element->csb_view = newSource->view;
element->csb_view_stream = copier.remap[0];
copier.csb->csb_rpt[newSource->stream].csb_flags |= copier.csb->csb_rpt[stream].csb_flags & csb_no_dbkey;
if (alias.hasData())
{
element->csb_alias = FB_NEW_POOL(*tdbb->getDefaultPool())
string(*tdbb->getDefaultPool(), alias);
}
copier.csb->csb_rpt[newSource->stream].csb_flags |=
copier.csb->csb_rpt[stream].csb_flags & csb_no_dbkey;
return newSource;
}

View File

@ -73,16 +73,8 @@ RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, TraNumber tran, bool a
return 0;
RelationPages* newPages = rel_pages_free;
if (!newPages)
{
const size_t BULK_ALLOC = 8;
RelationPages* allocatedPages = newPages =
FB_NEW_POOL(*rel_pool) RelationPages[BULK_ALLOC];
rel_pages_free = ++allocatedPages;
for (size_t i = 1; i < BULK_ALLOC - 1; i++, allocatedPages++)
allocatedPages->rel_next_free = allocatedPages + 1;
if (!newPages) {
newPages = FB_NEW_POOL(*rel_pool) RelationPages(*rel_pool);
}
else
{
@ -281,7 +273,7 @@ void jrd_rel::RelPagesSnapshot::clear()
bool jrd_rel::hasTriggers() const
{
typedef const trig_vec* ctv;
typedef const TrigVector* ctv;
ctv trigs[6] = // non-const array, don't want optimization tricks by the compiler.
{
rel_pre_erase,
@ -527,5 +519,9 @@ void RelationPages::free(RelationPages*& nextFree)
rel_index_root = rel_data_pages = 0;
rel_slot_space = rel_pri_data_space = rel_sec_data_space = 0;
rel_last_free_pri_dp = 0;
rel_instance_id = 0;
dpMap.clear();
dpMapMark = 0;
}

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