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:
commit
028248b194
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
41
.vscode/launch.json
vendored
Normal 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
14
.vscode/settings.json
vendored
Normal 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
13
.vscode/tasks.json
vendored
Normal 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"
|
||||
}
|
21
CHANGELOG.md
21
CHANGELOG.md
@ -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
|
||||
|
||||
|
@ -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 ]
|
||||
|
@ -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
|
||||
|
||||
# ----------------------------
|
||||
#
|
||||
|
@ -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,38 +779,40 @@ archivePriorInstallSystemFiles() {
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
for i in ibase.h ib_util.h
|
||||
do
|
||||
DestFile=usr/include/$i
|
||||
if [ -e $DestFile ]; then
|
||||
if [ ! "`echo $archiveFileList | grep $DestFile`" ]; then
|
||||
archiveFileList="$archiveFileList $DestFile"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
for i in libib_util.@SHRLIB_EXT@ libfbclient.@SHRLIB_EXT@*
|
||||
do
|
||||
for DestFile in usr/lib/$i
|
||||
do
|
||||
if [ -e $DestFile ]; then
|
||||
if [ "${fb_install_prefix}" = "${default_prefix}" ]
|
||||
then
|
||||
for i in ibase.h ib_util.h
|
||||
do
|
||||
DestFile=usr/include/$i
|
||||
if [ -e $DestFile ]; then
|
||||
if [ ! "`echo $archiveFileList | grep $DestFile`" ]; then
|
||||
archiveFileList="$archiveFileList $DestFile"
|
||||
archiveFileList="$archiveFileList $DestFile"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
for i in usr/sbin/rcfirebird etc/init.d/firebird etc/rc.d/init.d/firebird
|
||||
do
|
||||
DestFile=./$i
|
||||
if [ -e $DestFile ]; then
|
||||
if [ ! "`echo $archiveFileList | grep $DestFile`" ]; then
|
||||
archiveFileList="$archiveFileList $DestFile"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
for i in libib_util.@SHRLIB_EXT@ libfbclient.@SHRLIB_EXT@*
|
||||
do
|
||||
for DestFile in usr/lib/$i
|
||||
do
|
||||
if [ -e $DestFile ]; then
|
||||
if [ ! "`echo $archiveFileList | grep $DestFile`" ]; then
|
||||
archiveFileList="$archiveFileList $DestFile"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
for i in usr/sbin/rcfirebird etc/init.d/firebird etc/rc.d/init.d/firebird
|
||||
do
|
||||
DestFile=./$i
|
||||
if [ -e $DestFile ]; then
|
||||
if [ ! "`echo $archiveFileList | grep $DestFile`" ]; then
|
||||
archiveFileList="$archiveFileList $DestFile"
|
||||
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
|
||||
|
@ -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
|
||||
@ -137,46 +122,57 @@ while test $# -ne 0; do
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *' '* | *'
|
||||
'* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t) dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
-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 $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
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
|
||||
@ -223,16 +228,16 @@ if test -z "$dir_arg"; then
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
@ -269,41 +274,15 @@ 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
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
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
|
||||
@ -314,74 +293,74 @@ do
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
@ -391,53 +370,51 @@ do
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) 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=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@ -472,15 +449,12 @@ do
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
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 &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
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
|
||||
@ -493,24 +467,24 @@ do
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
|
@ -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)\
|
||||
|
@ -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.
|
||||
|
@ -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
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -294,6 +294,8 @@ Firebird 4.0
|
||||
|
||||
UNBOUNDED
|
||||
WINDOW
|
||||
BINARY
|
||||
VARBINARY
|
||||
|
||||
Added as non-reserved words:
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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,7 +236,9 @@ void DbCrypt::setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolder
|
||||
return;
|
||||
|
||||
if (callback && callback->callback(0, NULL, 1, &key) == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
key = 0;
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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*);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -131,7 +131,7 @@ const UCHAR backwardTable[FB_NELEM(hardware) * FB_NELEM(operatingSystem)] =
|
||||
const UCHAR backEndianess[FB_NELEM(hardware)] =
|
||||
{
|
||||
// Intel AMD Sparc PPC PPC64 MIPSEL MIPS ARM IA64 s390 s390x SH SHEB HPPA Alpha ARM64 PowerPC64el M68k
|
||||
0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1
|
||||
0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
@ -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())
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -28,7 +28,6 @@
|
||||
|
||||
#include "tree.h"
|
||||
#include "alloc.h"
|
||||
//#include "../memory/memory_pool.h"
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <set>
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
transaction->getGenIdCache()->put(id, val);
|
||||
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());
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
||||
@ -6557,12 +6602,15 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch,
|
||||
NestConst<ValueExprNode>* ptr2 = values->items.begin();
|
||||
for (const NestConst<ValueExprNode>* end = fields.end(); ptr != end; ++ptr, ++ptr2)
|
||||
{
|
||||
AssignmentNode* temp = FB_NEW_POOL(getPool()) AssignmentNode(getPool());
|
||||
temp->asgnFrom = *ptr2;
|
||||
temp->asgnTo = *ptr;
|
||||
assignStatements->statements.add(temp);
|
||||
if (*ptr2) // it's NULL for DEFAULT
|
||||
{
|
||||
AssignmentNode* temp = FB_NEW_POOL(getPool()) AssignmentNode(getPool());
|
||||
temp->asgnFrom = *ptr2;
|
||||
temp->asgnTo = *ptr;
|
||||
assignStatements->statements.add(temp);
|
||||
|
||||
PASS1_set_parameter_type(dsqlScratch, *ptr2, temp->asgnTo, false);
|
||||
PASS1_set_parameter_type(dsqlScratch, *ptr2, temp->asgnTo, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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&,
|
||||
|
@ -1 +1 @@
|
||||
44 shift/reduce conflicts, 583 reduce/reduce conflicts.
|
||||
45 shift/reduce conflicts, 17 reduce/reduce conflicts.
|
||||
|
272
src/dsql/parse.y
272
src/dsql/parse.y
@ -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->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->identityRestart = true;
|
||||
clause->identityRestartValue = $4;
|
||||
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
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -43,7 +43,6 @@
|
||||
|
||||
#include "fb_types.h"
|
||||
#include "firebird/Interface.h"
|
||||
#include "../common/ThreadStart.h"
|
||||
|
||||
namespace Firebird
|
||||
{
|
||||
|
@ -68,7 +68,6 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "../common/common.h"
|
||||
//#include "fb_exception.h"
|
||||
#endif
|
||||
|
||||
#ifdef NULL
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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},
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -24,7 +24,6 @@
|
||||
|
||||
#include "firebird.h"
|
||||
#include "OptionsBase.h"
|
||||
//#include "../common/utils_proto.h" // strnicmp
|
||||
#include "../common/gdsassert.h"
|
||||
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,63 +1818,69 @@ 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)
|
||||
{
|
||||
isqlGlob.printf("%s(%d, %d)",
|
||||
Integral_subtypes[FLD1.RDB$FIELD_SUB_TYPE],
|
||||
FLD1.RDB$FIELD_PRECISION,
|
||||
-FLD1.RDB$FIELD_SCALE);
|
||||
precision_known = true;
|
||||
}
|
||||
END_FOR
|
||||
ON_ERROR
|
||||
ISQL_errmsg (fbStatus);
|
||||
return false;
|
||||
END_ERROR;
|
||||
}
|
||||
|
||||
if (!precision_known)
|
||||
{
|
||||
if (fieldScale < 0)
|
||||
// We are Dialect >=3 since FIELD_PRECISION is non-NULL
|
||||
if (isqlGlob.major_ods >= ODS_VERSION10 && fieldPrecision != 0 &&
|
||||
fieldSubType > 0 && fieldSubType <= MAX_INTSUBTYPES)
|
||||
{
|
||||
// Take a stab at numerics and decimals
|
||||
switch (fieldType)
|
||||
{
|
||||
case SMALLINT:
|
||||
isqlGlob.printf("NUMERIC(4, %d)", -fieldScale);
|
||||
break;
|
||||
case INTEGER:
|
||||
isqlGlob.printf("NUMERIC(9, %d)", -fieldScale);
|
||||
break;
|
||||
case BIGINT:
|
||||
isqlGlob.printf("NUMERIC(18, %d)", -fieldScale);
|
||||
break;
|
||||
case DOUBLE_PRECISION:
|
||||
isqlGlob.printf("NUMERIC(15, %d)", -fieldScale);
|
||||
break;
|
||||
default:
|
||||
isqlGlob.printf("%s", Column_types[i].type_name);
|
||||
}
|
||||
isqlGlob.printf("%s(%d, %d)",
|
||||
Integral_subtypes[fieldSubType],
|
||||
fieldPrecision,
|
||||
-fieldScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a non-numeric data type
|
||||
isqlGlob.printf("%s", Column_types[i].type_name);
|
||||
if (fieldScale < 0)
|
||||
{
|
||||
// Take a stab at numerics and decimals
|
||||
switch (fieldType)
|
||||
{
|
||||
case SMALLINT:
|
||||
isqlGlob.printf("NUMERIC(4, %d)", -fieldScale);
|
||||
break;
|
||||
case INTEGER:
|
||||
isqlGlob.printf("NUMERIC(9, %d)", -fieldScale);
|
||||
break;
|
||||
case BIGINT:
|
||||
isqlGlob.printf("NUMERIC(18, %d)", -fieldScale);
|
||||
break;
|
||||
case DOUBLE_PRECISION:
|
||||
isqlGlob.printf("NUMERIC(15, %d)", -fieldScale);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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,14 +5784,20 @@ 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));
|
||||
|
||||
// Show international character sets and collations
|
||||
show_charsets(relation_name, RFR.RDB$FIELD_NAME, true, false, false, false);
|
||||
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)
|
||||
|
@ -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 & ATT_manual_lock));
|
||||
asyncMutex.enter(FB_FUNCTION);
|
||||
mainMutex.enter(FB_FUNCTION);
|
||||
flags |= (ATT_manual_lock | ATT_async_manual_lock);
|
||||
fb_assert(!(flags & whatLock));
|
||||
|
||||
if (whatLock & ATT_async_manual_lock)
|
||||
{
|
||||
asyncMutex.enter(FB_FUNCTION);
|
||||
flags |= ATT_async_manual_lock;
|
||||
}
|
||||
|
||||
if (whatLock & ATT_manual_lock)
|
||||
{
|
||||
mainMutex.enter(FB_FUNCTION);
|
||||
flags |= ATT_manual_lock;
|
||||
}
|
||||
}
|
||||
|
||||
void StableAttachmentPart::manualUnlock(ULONG& flags)
|
||||
@ -756,3 +765,4 @@ JAttachment* Attachment::getInterface() throw()
|
||||
{
|
||||
return att_stable->getInterface();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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,48 +324,37 @@ 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;
|
||||
friend class DbInfo;
|
||||
|
||||
class DbInfo FB_FINAL : public Firebird::RefCntIface<Firebird::IDbCryptInfoImpl<DbInfo, Firebird::CheckStatusWrapper>>
|
||||
class DbInfo FB_FINAL : public Firebird::RefCntIface<Firebird::IDbCryptInfoImpl<DbInfo, Firebird::CheckStatusWrapper> >
|
||||
{
|
||||
public:
|
||||
DbInfo(CryptoManager* cm)
|
||||
@ -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;
|
||||
|
@ -123,14 +123,19 @@ namespace Jrd
|
||||
|
||||
int Database::blocking_ast_sweep(void* ast_object)
|
||||
{
|
||||
Database* dbb = static_cast<Database*>(ast_object);
|
||||
AsyncContextHolder tdbb(dbb, FB_FUNCTION);
|
||||
|
||||
if ((dbb->dbb_flags & DBB_sweep_starting) && !(dbb->dbb_flags & DBB_sweep_in_progress))
|
||||
try
|
||||
{
|
||||
dbb->dbb_flags &= ~DBB_sweep_starting;
|
||||
LCK_release(tdbb, dbb->dbb_sweep_lock);
|
||||
Database* dbb = static_cast<Database*>(ast_object);
|
||||
AsyncContextHolder tdbb(dbb, FB_FUNCTION);
|
||||
|
||||
if ((dbb->dbb_flags & DBB_sweep_starting) && !(dbb->dbb_flags & DBB_sweep_in_progress))
|
||||
{
|
||||
dbb->dbb_flags &= ~DBB_sweep_starting;
|
||||
LCK_release(tdbb, dbb->dbb_sweep_lock);
|
||||
}
|
||||
}
|
||||
catch (const Exception&)
|
||||
{} // no-op
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,40 +597,52 @@ 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;
|
||||
|
||||
Guard gShared(this);
|
||||
{ // scope
|
||||
Guard gShared(this);
|
||||
MappingHeader* sMem = sharedMemory->getHeader();
|
||||
|
||||
MappingHeader* sMem = sharedMemory->getHeader();
|
||||
startupSemaphore.tryEnter(5);
|
||||
sMem->process[process].flags &= ~MappingHeader::FLAG_ACTIVE;
|
||||
|
||||
startupSemaphore.tryEnter(5);
|
||||
sMem->process[process].flags &= ~MappingHeader::FLAG_ACTIVE;
|
||||
(void) // Ignore errors in cleanup
|
||||
sharedMemory->eventPost(&sMem->process[process].notifyEvent);
|
||||
cleanupSemaphore.tryEnter(5);
|
||||
(void) // Ignore errors in cleanup
|
||||
sharedMemory->eventPost(&sMem->process[process].notifyEvent);
|
||||
|
||||
// Ignore errors in cleanup
|
||||
sharedMemory->eventFini(&sMem->process[process].notifyEvent);
|
||||
sharedMemory->eventFini(&sMem->process[process].callbackEvent);
|
||||
cleanupSync.waitForCompletion();
|
||||
|
||||
bool found = false;
|
||||
for (unsigned n = 0; n < sMem->processes; ++n)
|
||||
{
|
||||
if (sMem->process[n].flags & MappingHeader::FLAG_ACTIVE)
|
||||
// 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)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
if (sMem->process[n].flags & MappingHeader::FLAG_ACTIVE)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
sharedMemory->removeMapFile();
|
||||
}
|
||||
|
||||
if (!found)
|
||||
sharedMemory->removeMapFile();
|
||||
sharedMemory = NULL;
|
||||
}
|
||||
|
||||
void clearCache(const char* dbName, USHORT index)
|
||||
@ -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,7 +918,10 @@ 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)
|
||||
@ -900,7 +929,10 @@ public:
|
||||
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
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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++)
|
||||
|
@ -260,7 +260,7 @@ public:
|
||||
|
||||
bool isFiltered() const
|
||||
{
|
||||
return (baseSelectivity < MAXIMUM_SELECTIVITY);
|
||||
return (baseIndexes || baseSelectivity < MAXIMUM_SELECTIVITY);
|
||||
}
|
||||
|
||||
IndexedRelationships indexedRelationships;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user