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

Merge branch 'master' into read_consistency

# Conflicts:
#	src/include/fb_types.h
#	src/jrd/Database.cpp
#	src/jrd/tpc.cpp
#	src/jrd/tra.cpp
#	src/jrd/vio_proto.h
This commit is contained in:
hvlad 2016-05-21 21:17:31 +03:00
commit 8f311f3c27
193 changed files with 6081 additions and 3972 deletions

5
.editorconfig Normal file
View File

@ -0,0 +1,5 @@
root = true
[*]
indent_style = tab
indent_size = 4

View File

@ -11,6 +11,9 @@
* [CORE-4701](http://tracker.firebirdsql.org/browse/CORE-4701): Index and blob garbage collection don't take into accout data in undo log
Contributor(s): Dimitry Sibiryakov
* [CORE-4483](http://tracker.firebirdsql.org/browse/CORE-4483):Changed data not visible in WHEN-section if exception occured inside SP that has been called from this code
Contributor(s): Dimitry Sibiryakov
* [CORE-4424](http://tracker.firebirdsql.org/browse/CORE-4424): Rollback to wrong savepoint if several exception handlers on the same level are executed
Contributor(s): Dimitry Sibiryakov
@ -18,3 +21,14 @@
* [CORE-5119](http://tracker.firebirdsql.org/browse/CORE-5119): Support autocommit mode in SET TRANSACTION statement
Contributor(s): Dmitry Yemanov
* [CORE-2192](http://tracker.firebirdsql.org/browse/CORE-2192): Extend maximum database page size to 32KB
Contributor(s): Dmitry Yemanov
## New features
* [CORE-1815](http://tracker.firebirdsql.org/browse/CORE-1815): Ability to grant role to another role
Contributor(s): Roman Simakov
* [CORE-751](http://tracker.firebirdsql.org/browse/CORE-751): Implicitly active roles (and their permissions summarized)
Contributor(s): Roman Simakov

View File

@ -8,7 +8,6 @@ The Firebird Project is a commercially independent project of C/C++ programmers,
* http://www.firebirdsql.org/
* http://www.firebirdsql.org/en/historical-reference/
* http://www.firebirdsql.org/en/licensing/
* http://www.firebirdsql.org/en/features/
## Documentation
@ -28,6 +27,9 @@ The source code is released under variants of the Mozilla Public Licence 1.1 (MP
The source code can be found at:
https://github.com/FirebirdSQL/firebird
Build instructions are here:
http://www.firebirdsql.org/en/building-the-code/
Bugs and feature requests should be submitted at:
http://tracker.firebirdsql.org/

View File

@ -573,3 +573,10 @@ haveLibrary() {
return $?
}
#------------------------------------------------------------------------
# refresh cache of dynamic loader after add/delete files in system libdir
reconfigDynamicLoader() {
ldconfig
}

View File

@ -28,16 +28,12 @@
# This script builds an image of the installed system into
# the gen/buildroot directory.
if [ "`whoami`" != "root" ]; then
echo 'You must be root to build package'
exit 1
fi
# Making an assumption that this program is being run in the gen directory
BuildRootDir=..
BuiltFBDir=Release/firebird # Where the just build fb exists.
TargetDir=buildroot # Where we want to build the install image
SecurityDatabase=security4.fdb
TomBuild="@TOMBUILD@"
#------------------------------------------------------------------------
@ -120,6 +116,25 @@ makeDirs() {
}
#------------------------------------------------------------------------
# ReadOnlyTree
# Set correct rights to files in given subtree
ReadOnlyTree() {
Tree=$1
for i in `find ${Tree} -type d -print`
do
chmod 0755 $i
done
for i in `find ${Tree} -type f -print`
do
chmod 0644 $i
done
}
#------------------------------------------------------------------------
# copyFiles
# This function copies all the files for a distribution into a
@ -130,7 +145,8 @@ copyFiles() {
#cleanup
if [ -d $TargetDir ]
then
then
chmod -R +xw $TargetDir
rm -fr $TargetDir
fi
@ -190,18 +206,10 @@ copyFiles() {
(cd $BuiltFBDir/examples; tar cf - .) | (cd ${TargetDir}@FB_SAMPLEDIR@; tar xf -)
rm -rf ${TargetDir}@FB_SAMPLEDIR@/empbuild
for i in `find ${TargetDir}@FB_SAMPLEDIR@ -type d -print`
do
chmod 0555 $i
done
for i in `find ${TargetDir}@FB_SAMPLEDIR@ -type f -print`
do
chmod 0444 $i
done
makeDirs @FB_SAMPLEDBDIR@
cp $BuiltFBDir/examples/empbuild/*.fdb ${TargetDir}@FB_SAMPLEDBDIR@
ReadOnlyTree ${TargetDir}@FB_SAMPLEDIR@
chmod 0444 ${TargetDir}@FB_SAMPLEDBDIR@/*.fdb
fi
@ -225,12 +233,16 @@ copyFiles() {
tar -C $BuildRootDir/src/include/firebird -cf - impl | tar -C ${TargetDir}@FB_INCDIR@/firebird -x
cp $BuildRootDir/src/include/gen/Firebird.pas ${TargetDir}@FB_INCDIR@/firebird
chmod -R 0444 ${TargetDir}@FB_INCDIR@/*.h ${TargetDir}@FB_INCDIR@/firebird/*
ReadOnlyTree ${TargetDir}@FB_INCDIR@
#lib
cp -df $BuiltFBDir/lib/libfbclient.so* ${TargetDir}@FB_LIBDIR@
cp -f $BuiltFBDir/lib/libib_util.so ${TargetDir}@FB_LIBDIR@/libib_util.so
copyIfExists $BuiltFBDir/lib/libicu*.so* ${TargetDir}@FB_LIBDIR@
if [ "$TomBuild" = "Y" ]; then
makeDirs @FB_LIBDIR@/.tm
cp -df $BuildRootDir/extern/libtommath/.libs/libtommath.so* ${TargetDir}@FB_LIBDIR@/.tm
fi
chmod 0755 ${TargetDir}@FB_LIBDIR@/*.so*

View File

@ -81,4 +81,11 @@ fr.initSecurityDb=Ajouter SYSDBA à la base de sécurité.
fr.SYSDBAPasswordMismatch=Mots de passe différents. Corrigez le mot de passe SYSDBA.
fr.SYSDBAPasswordEmpty=Le mot de passe est vide. Vous devez indiquer un mot de passe pour SYSDBA.
fr.EnableLegacyClientAuth=A&utoriser les anciens clients Firebird?
fr.CreateSYSDBAPassword=Créer un mot de passe pour l'Administrateur Système
fr.ClickThroughPWCreation=Ou cliquer pour utiliser le mote de passe par défaut masterkey.
fr.PasswordNote=*** Note - avec Firebird 3 masterkey et masterke sont des mots de passe différents. ***
fr.SYSDBAPassword=Mot de passe SYSDBA:
fr.RetypeSYSDBAPassword=Confirmer le mote de passe SYSDBA:
fr.InstallingMSVC32runtimes=Installer les bibliothèques MSVC 32-bit dans le répertoire système
fr.InstallingMSVC64runtimes=Installer les bibliothèques MSVC 64-bit dans le répertoire système

View File

@ -1,12 +1,12 @@
Firebird Serveur Bases de données $MAJOR.$MINOR.$RELEASE
==================================================
========================================================
** NOTE IMPORTANTE **
Ce document est une traduction et malgré nos efforts,
il peut ne pas correspondre exactement ŕ la derničre
il peut ne pas correspondre exactement à la dernière
version, seul le texte original en anglais
(installation_readme.txt) est toujours ŕ jour.
(installation_readme.txt) est toujours à jour.
** FIN **
@ -18,7 +18,8 @@ en général.
Ce document s'adresse à des personnes connaissant déjà Firebird.
Si vous testez Firebird $MAJOR.$MINOR dans l'optique d'une migration
depuis Firebird 2.5, lisez la documentation de Firebird $MAJOR.$MINOR
afin de comprendre les modifications intervenues depuis Firebird 2.5.
afin de comprendre les modifications intervenues depuis Firebird 2.5
et $MAJOR.$MINOR.
Contenu
@ -39,10 +40,10 @@ Avant l'installation
Il est recommandé de désinstaller toutes les
précédentes versions de Firebird ou
InterBase avant de commencer l'installation.
Il est particuličrement important de vérifier que
Il est particulièrement important de vérifier que
fbclient.dll et gds32.dll ont été retirés de <system32>.
Si vous avez installé une version beta ou alpha de Firebird 3,
Si vous avez installé une version beta ou alpha de Firebird $MAJOR.$MINOR,
l'installeur va renommer firebird.conf et security3.fdb, car ces
fichiers ne sont plus compatibles avec la version actuelle.
@ -53,7 +54,7 @@ Déployement de gds32.dll
La bibliothèque gds32.dll n'est plus déployée dans les répertoires
systèmes de windows par défaut. Nous ne pouvons garantir que les
bibliothèques MSVC runtiles soit disponibles; Toutefois, au moment de
bibliothèques MSVC runtimes soit disponibles. Toutefois, au moment de
l'installation, vous pouvez choisir d'installer gds32.dll en même temps
que le déploiement de fbclient.dll dans le système.
@ -76,11 +77,11 @@ Problèmes connus d'installation
o Vous ne pouvez utiliser l'utilitaire d'installation
que pour installer l'instance par défaut de Firebird $MAJOR.$MINOR.
Si vous voulez en installer une deuxičme en plus, ou une
instance nomée, vous devez le faire ŕ partir de l'image
Si vous voulez en installer une deuxième en plus, ou une
instance nommée, vous devez le faire à partir de l'image
zip.
o Malheureusement, l'utilitaire d'installation de peux
o Malheureusement, l'utilitaire d'installation ne peux
avec certitude détecter si une version précédente de
Firebird Classic server est en fonctionnement.
@ -88,19 +89,19 @@ o Il y a des chevauchements entre les installations
32-bit et 64-bit :
- L'installateur de service (instsvc) utilise
le męme nom default instance pour les installations
le même nom default instance pour les installations
32-bit et 64-bit. Les services existent
dans le męme espace de nom.
dans le même espace de nom.
- Si les deux applets 32-bit et 64-bit du panneau de configuration
sont installées, elles pointeront sur la męme instance.
o Faites l'installation en tant qu'administrateur
Sinon, l'utilitaire d'installation ne pourra pas démarrer
le service Firebird ŕ la fin de l'installation.
le service Firebird à la fin de l'installation.
o Les bibliotèques installées par instclient peuvent ne pas se charger
les bibliotèques MSCV runtimes ne sont pas installées. Cela peut être
o Les bibliothèques installées par instclient peuvent ne pas se charger
si les bibliothèques MSCV runtimes ne sont pas installées. Cela peut être
un souci sur des anciennes versions de Windows.
@ -109,12 +110,12 @@ Désinstallation
o Il est préférable d'utiliser le programme de
désinstalation fourni.
Il peut ętre appelé depuis le panneau de
Il peut être appelé depuis le panneau de
configuration. Vous pouvez aussi utiliser directement
unins000.exe depuis le répertoire d'installation.
o Si Firebird est exécuté comme application (et non
comme service) il est recommendé d'arreter d'abord
comme service) il est recommandé d'arréter d'abord
le serveur avant de commencer la désinstalation. Ce
parce que le programme de desinstallation ne peut
arreter une application en cours. Si le serveur
@ -134,7 +135,7 @@ o La désinstallation laisse cinq fichiers dans le
Ceci est intentionnel. Ces fichiers sont tous
potentiellement modifiables par les utilisateurs et peuvent
être nécessaires si Firebird est reinstallé dans le futur. Ils
être nécessaires si Firebird est réinstallé dans le futur. Ils
peuvent être effacés si nécessaire.
o Une nouvelle fonctionnalité du desinstallateur existe

View File

@ -1,6 +1,6 @@
#########################################
#
# Firebird version 3.0 configuration file
# Firebird version 4.0 configuration file
#
# Comments
# --------

View File

@ -164,10 +164,22 @@ missingLibrary() {
}
#------------------------------------------------------------------------
# Check library presence, errorexit when missing
checkLibrary() {
libName=${1}
haveLibrary $libName || missingLibrary $libName
}
#------------------------------------------------------------------------
# Make sure we have required libraries installed
checkLibraries() {
haveLibrary tommath || missingLibrary tommath
if [ "@TOMBUILD@" != "Y" ]
then
checkLibrary tommath
fi
}
@ -583,8 +595,10 @@ createLinksForBackCompatibility() {
createLinksInSystemLib() {
LibDir=`CorrectLibDir @libdir@`
tommath=libtommath.@SHRLIB_EXT@
tomdir=@FB_LIBDIR@/.tm
origDirLinksInSystemLib=`pwd`
cd @FB_LIBDIR@
Libraries=`echo libfbclient.@SHRLIB_EXT@* libib_util.@SHRLIB_EXT@`
@ -594,7 +608,23 @@ createLinksInSystemLib() {
safeLink @FB_LIBDIR@/$l .$LibDir/$l ${MANIFEST_TXT}
done
if [ -d $tomdir ]; then
cd $tomdir
Libraries=""
if [ ! -f $LibDir/$tommath ]; then
Libraries=`echo ${tommath}*`
fi
cd /
for l in $Libraries
do
safeLink @FB_LIBDIR@/.tm/$l .$LibDir/$l ${MANIFEST_TXT}
done
fi
cd $origDirLinksInSystemLib
reconfigDynamicLoader
}
#------------------------------------------------------------------------

View File

@ -36,3 +36,5 @@ if [ -d $PidDir ]
then
rm -rf $PidDir
fi
reconfigDynamicLoader

View File

@ -4978,16 +4978,6 @@
path = par_proto.h;
refType = 4;
};
F616C67E0200B0D001EF0ADE = {
isa = PBXFileReference;
path = pcmet.epp;
refType = 4;
};
F616C67F0200B0D001EF0ADE = {
isa = PBXFileReference;
path = pcmet_proto.h;
refType = 4;
};
F616C6800200B0D001EF0ADE = {
isa = PBXFileReference;
path = pcsleep.cpp;
@ -10612,11 +10602,6 @@
path = met.cpp;
refType = 4;
};
F6B281360200CC3601EF0ADE = {
isa = PBXFileReference;
path = pcmet.cpp;
refType = 4;
};
F6B281400200CC3601EF0ADE = {
isa = PBXFileReference;
path = scl.cpp;

View File

@ -46,7 +46,7 @@ FB_FW= $(PROJ_ROOT)/build/Firebird.framework
JRD_EPP_FILES= blob_filter.cpp dyn.epp dyn_util.epp ini.epp stats.epp \
dyn_def.epp met.epp dfw.epp dyn_del.epp \
fun.epp pcmet.epp dpm.epp dyn_mod.epp grant.epp scl.epp
fun.epp dpm.epp dyn_mod.epp grant.epp scl.epp
JRD_GEN_FILES= $(JRD_EPP_FILES:%.epp=$(GEN_ROOT)/jrd/%.cpp)
DSQL_EPP_FILES= array.epp blob.epp metd.epp

View File

@ -126,6 +126,12 @@ extern:
$(MAKE) -C $(ROOT)/extern/btyacc
$(MAKE) -C $(ROOT)/extern/cloop TARGET=release WITH_FPC=0 BUILD_DIR=$(TMP_ROOT)/cloop OUT_DIR=$(GEN_ROOT)/$(TARGET)/cloop
ifeq ($(TOMBUILD_FLG),Y)
$(MAKE) -C $(ROOT)/extern/libtommath -f makefile.shared
ln -sf $(TOMMATH_SO).$(TOMMATH_VER) $(LIB)
ln -sf $(TOMMATH_SO) $(LIB)
endif
ifeq ($(STD_EDITLINE),false)
ifeq ($(EDITLINE_FLG),Y)
$(MAKE) -f $(GEN_ROOT)/Makefile.extern.editline

View File

@ -48,6 +48,7 @@ LNG_ROOT=$(ROOT)/lang_helpers
EXA_ROOT=$(ROOT)/examples
IsCross=@IS_CROSS@
TOMBUILD_FLG=@TOMBUILD@
FB_BUILD=$(GEN_ROOT)/$(TARGET)/firebird
ifeq ($(IsCross), Y)
@ -249,6 +250,12 @@ endif
IbUtilLibraryName = $(LIB_PREFIX)ib_util.$(SHRLIB_EXT)
LIBIBUTIL_SO = $(LIB)/$(IbUtilLibraryName)
# Own tommath support
TOMMATH=$(ROOT)/extern/libtommath
TOMMATH_INC=$(TOMMATH)
TOMMATH_SO=$(TOMMATH)/.libs/libtommath.so
TOMMATH_VER=0
# LINKER OPTIONS
#

View File

@ -34,6 +34,10 @@
# Please don't use compiler/platform specific flags here - nmcc 02-Nov-2002
WFLAGS =-I$(SRC_ROOT)/include/gen -I$(SRC_ROOT)/include $(CPPFLAGS)
ifeq ($(TOMBUILD_FLG),Y)
WFLAGS += -I$(TOMMATH_INC)
endif
ifeq ($(TARGET),Release)
WFLAGS += $(PROD_FLAGS)
else

View File

@ -67,7 +67,6 @@ SEGMENTS
OPT_TEXT DISCARDABLE
PAG_TEXT DISCARDABLE
PAR_TEXT DISCARDABLE
PCMET_TEXT DISCARDABLE
PCSLEEP_TEXT DISCARDABLE
PWD_TEXT DISCARDABLE
QATEST_TEXT DISCARDABLE

View File

@ -30,7 +30,6 @@
<ClCompile Include="..\..\..\gen\jrd\grant.cpp" />
<ClCompile Include="..\..\..\gen\jrd\ini.cpp" />
<ClCompile Include="..\..\..\gen\jrd\met.cpp" />
<ClCompile Include="..\..\..\gen\jrd\pcmet.cpp" />
<ClCompile Include="..\..\..\gen\jrd\scl.cpp" />
<ClCompile Include="..\..\..\gen\utilities\gstat\dba.cpp" />
<ClCompile Include="..\..\..\src\dsql\AggNodes.cpp" />
@ -135,6 +134,7 @@
<ClCompile Include="..\..\..\src\jrd\Routine.cpp" />
<ClCompile Include="..\..\..\src\jrd\rpb_chain.cpp" />
<ClCompile Include="..\..\..\src\jrd\RuntimeStatistics.cpp" />
<ClCompile Include="..\..\..\src\jrd\Savepoint.cpp" />
<ClCompile Include="..\..\..\src\jrd\sdw.cpp" />
<ClCompile Include="..\..\..\src\jrd\shut.cpp" />
<ClCompile Include="..\..\..\src\jrd\sort.cpp" />
@ -284,7 +284,6 @@
<ClInclude Include="..\..\..\src\jrd\pag.h" />
<ClInclude Include="..\..\..\src\jrd\pag_proto.h" />
<ClInclude Include="..\..\..\src\jrd\par_proto.h" />
<ClInclude Include="..\..\..\src\jrd\pcmet_proto.h" />
<ClInclude Include="..\..\..\src\jrd\PreparedStatement.h" />
<ClInclude Include="..\..\..\src\jrd\que.h" />
<ClInclude Include="..\..\..\src\jrd\RandomGenerator.h" />
@ -353,7 +352,6 @@
<None Include="..\..\..\src\jrd\grant.epp" />
<None Include="..\..\..\src\jrd\ini.epp" />
<None Include="..\..\..\src\jrd\met.epp" />
<None Include="..\..\..\src\jrd\pcmet.epp" />
<None Include="..\..\..\src\jrd\scl.epp" />
<None Include="..\..\..\src\utilities\gstat\dba.epp" />
<None Include="..\defs\plugin.def" />

View File

@ -420,9 +420,6 @@
<ClCompile Include="..\..\..\gen\jrd\met.cpp">
<Filter>JRD files\GPRE cpp</Filter>
</ClCompile>
<ClCompile Include="..\..\..\gen\jrd\pcmet.cpp">
<Filter>JRD files\GPRE cpp</Filter>
</ClCompile>
<ClCompile Include="..\..\..\gen\dsql\DdlNodes.cpp">
<Filter>DSQL\preprocesed</Filter>
</ClCompile>
@ -845,9 +842,6 @@
<ClInclude Include="..\..\..\src\jrd\par_proto.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\jrd\pcmet_proto.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\jrd\PreparedStatement.h">
<Filter>Header files</Filter>
</ClInclude>
@ -1027,9 +1021,6 @@
<None Include="..\..\..\src\jrd\met.epp">
<Filter>JRD files\GPRE files</Filter>
</None>
<None Include="..\..\..\src\jrd\pcmet.epp">
<Filter>JRD files\GPRE files</Filter>
</None>
<None Include="..\..\..\src\jrd\scl.epp">
<Filter>JRD files\GPRE files</Filter>
</None>

View File

@ -30,7 +30,6 @@
<ClCompile Include="..\..\..\gen\jrd\grant.cpp" />
<ClCompile Include="..\..\..\gen\jrd\ini.cpp" />
<ClCompile Include="..\..\..\gen\jrd\met.cpp" />
<ClCompile Include="..\..\..\gen\jrd\pcmet.cpp" />
<ClCompile Include="..\..\..\gen\jrd\scl.cpp" />
<ClCompile Include="..\..\..\gen\utilities\gstat\dba.cpp" />
<ClCompile Include="..\..\..\src\dsql\AggNodes.cpp" />
@ -135,6 +134,7 @@
<ClCompile Include="..\..\..\src\jrd\Routine.cpp" />
<ClCompile Include="..\..\..\src\jrd\rpb_chain.cpp" />
<ClCompile Include="..\..\..\src\jrd\RuntimeStatistics.cpp" />
<ClCompile Include="..\..\..\src\jrd\Savepoint.cpp" />
<ClCompile Include="..\..\..\src\jrd\sdw.cpp" />
<ClCompile Include="..\..\..\src\jrd\shut.cpp" />
<ClCompile Include="..\..\..\src\jrd\sort.cpp" />
@ -284,7 +284,6 @@
<ClInclude Include="..\..\..\src\jrd\pag.h" />
<ClInclude Include="..\..\..\src\jrd\pag_proto.h" />
<ClInclude Include="..\..\..\src\jrd\par_proto.h" />
<ClInclude Include="..\..\..\src\jrd\pcmet_proto.h" />
<ClInclude Include="..\..\..\src\jrd\PreparedStatement.h" />
<ClInclude Include="..\..\..\src\jrd\que.h" />
<ClInclude Include="..\..\..\src\jrd\RandomGenerator.h" />
@ -353,7 +352,6 @@
<None Include="..\..\..\src\jrd\grant.epp" />
<None Include="..\..\..\src\jrd\ini.epp" />
<None Include="..\..\..\src\jrd\met.epp" />
<None Include="..\..\..\src\jrd\pcmet.epp" />
<None Include="..\..\..\src\jrd\scl.epp" />
<None Include="..\..\..\src\utilities\gstat\dba.epp" />
<None Include="..\defs\plugin.def" />

View File

@ -420,9 +420,6 @@
<ClCompile Include="..\..\..\gen\jrd\met.cpp">
<Filter>JRD files\GPRE cpp</Filter>
</ClCompile>
<ClCompile Include="..\..\..\gen\jrd\pcmet.cpp">
<Filter>JRD files\GPRE cpp</Filter>
</ClCompile>
<ClCompile Include="..\..\..\gen\dsql\DdlNodes.cpp">
<Filter>DSQL\preprocesed</Filter>
</ClCompile>
@ -845,9 +842,6 @@
<ClInclude Include="..\..\..\src\jrd\par_proto.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\jrd\pcmet_proto.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\jrd\PreparedStatement.h">
<Filter>Header files</Filter>
</ClInclude>
@ -1027,9 +1021,6 @@
<None Include="..\..\..\src\jrd\met.epp">
<Filter>JRD files\GPRE files</Filter>
</None>
<None Include="..\..\..\src\jrd\pcmet.epp">
<Filter>JRD files\GPRE files</Filter>
</None>
<None Include="..\..\..\src\jrd\scl.epp">
<Filter>JRD files\GPRE files</Filter>
</None>

View File

@ -30,7 +30,6 @@
<ClCompile Include="..\..\..\gen\jrd\grant.cpp" />
<ClCompile Include="..\..\..\gen\jrd\ini.cpp" />
<ClCompile Include="..\..\..\gen\jrd\met.cpp" />
<ClCompile Include="..\..\..\gen\jrd\pcmet.cpp" />
<ClCompile Include="..\..\..\gen\jrd\scl.cpp" />
<ClCompile Include="..\..\..\gen\utilities\gstat\dba.cpp" />
<ClCompile Include="..\..\..\src\dsql\AggNodes.cpp" />
@ -135,6 +134,7 @@
<ClCompile Include="..\..\..\src\jrd\Routine.cpp" />
<ClCompile Include="..\..\..\src\jrd\rpb_chain.cpp" />
<ClCompile Include="..\..\..\src\jrd\RuntimeStatistics.cpp" />
<ClCompile Include="..\..\..\src\jrd\Savepoint.cpp" />
<ClCompile Include="..\..\..\src\jrd\sdw.cpp" />
<ClCompile Include="..\..\..\src\jrd\shut.cpp" />
<ClCompile Include="..\..\..\src\jrd\sort.cpp" />
@ -284,7 +284,6 @@
<ClInclude Include="..\..\..\src\jrd\pag.h" />
<ClInclude Include="..\..\..\src\jrd\pag_proto.h" />
<ClInclude Include="..\..\..\src\jrd\par_proto.h" />
<ClInclude Include="..\..\..\src\jrd\pcmet_proto.h" />
<ClInclude Include="..\..\..\src\jrd\PreparedStatement.h" />
<ClInclude Include="..\..\..\src\jrd\que.h" />
<ClInclude Include="..\..\..\src\jrd\RandomGenerator.h" />
@ -353,7 +352,6 @@
<None Include="..\..\..\src\jrd\grant.epp" />
<None Include="..\..\..\src\jrd\ini.epp" />
<None Include="..\..\..\src\jrd\met.epp" />
<None Include="..\..\..\src\jrd\pcmet.epp" />
<None Include="..\..\..\src\jrd\scl.epp" />
<None Include="..\..\..\src\utilities\gstat\dba.epp" />
<None Include="..\defs\plugin.def" />

View File

@ -420,9 +420,6 @@
<ClCompile Include="..\..\..\gen\jrd\met.cpp">
<Filter>JRD files\GPRE cpp</Filter>
</ClCompile>
<ClCompile Include="..\..\..\gen\jrd\pcmet.cpp">
<Filter>JRD files\GPRE cpp</Filter>
</ClCompile>
<ClCompile Include="..\..\..\gen\dsql\DdlNodes.cpp">
<Filter>DSQL\preprocesed</Filter>
</ClCompile>
@ -845,9 +842,6 @@
<ClInclude Include="..\..\..\src\jrd\par_proto.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\jrd\pcmet_proto.h">
<Filter>Header files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\jrd\PreparedStatement.h">
<Filter>Header files</Filter>
</ClInclude>
@ -1027,9 +1021,6 @@
<None Include="..\..\..\src\jrd\met.epp">
<Filter>JRD files\GPRE files</Filter>
</None>
<None Include="..\..\..\src\jrd\pcmet.epp">
<Filter>JRD files\GPRE files</Filter>
</None>
<None Include="..\..\..\src\jrd\scl.epp">
<Filter>JRD files\GPRE files</Filter>
</None>

View File

@ -539,6 +539,10 @@
RelativePath="..\..\..\src\jrd\RuntimeStatistics.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\Savepoint.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\sdw.cpp"
>
@ -754,10 +758,6 @@
RelativePath="..\..\..\gen\jrd\met.cpp"
>
</File>
<File
RelativePath="..\..\..\gen\jrd\pcmet.cpp"
>
</File>
<File
RelativePath="..\..\..\gen\jrd\scl.cpp"
>
@ -798,10 +798,6 @@
RelativePath="..\..\..\src\jrd\met.epp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\pcmet.epp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\scl.epp"
>
@ -1359,10 +1355,6 @@
RelativePath="..\..\..\src\dsql\pass1_proto.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\pcmet_proto.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\os\pio.h"
>

View File

@ -547,6 +547,10 @@
RelativePath="..\..\..\src\jrd\RuntimeStatistics.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\Savepoint.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\sdw.cpp"
>
@ -762,10 +766,6 @@
RelativePath="..\..\..\gen\jrd\met.cpp"
>
</File>
<File
RelativePath="..\..\..\gen\jrd\pcmet.cpp"
>
</File>
<File
RelativePath="..\..\..\gen\jrd\scl.cpp"
>
@ -806,10 +806,6 @@
RelativePath="..\..\..\src\jrd\met.epp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\pcmet.epp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\scl.epp"
>
@ -1367,10 +1363,6 @@
RelativePath="..\..\..\src\dsql\pass1_proto.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\pcmet_proto.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\os\pio.h"
>

View File

@ -67,7 +67,7 @@ goto :EOF
@for %%i in (array, blob) do @call :PREPROCESS yvalve %%i
@for %%i in (metd, DdlNodes, PackageNodes) do @call :PREPROCESS dsql %%i -gds_cxx
@for %%i in (gpre_meta) do @call :PREPROCESS gpre/std %%i
@for %%i in (dfw, dpm, dyn_util, fun, grant, ini, met, pcmet, scl, Function) do @call :PREPROCESS jrd %%i -gds_cxx
@for %%i in (dfw, dpm, dyn_util, fun, grant, ini, met, scl, Function) do @call :PREPROCESS jrd %%i -gds_cxx
@for %%i in (stats) do @call :PREPROCESS utilities %%i
@goto :EOF
@ -81,7 +81,7 @@ goto :EOF
@for %%i in (metd) do @call :PREPROCESS dsql %%i -gds_cxx
@for %%i in (DdlNodes, PackageNodes) do @call :PREPROCESS dsql %%i -gds_cxx
@for %%i in (gpre_meta) do @call :PREPROCESS gpre/std %%i
@for %%i in (dfw, dpm, dyn_util, fun, grant, ini, met, pcmet, scl, Function) do @call :PREPROCESS jrd %%i -gds_cxx
@for %%i in (dfw, dpm, dyn_util, fun, grant, ini, met, scl, Function) do @call :PREPROCESS jrd %%i -gds_cxx
@for %%i in (codes) do @call :PREPROCESS misc %%i
@for %%i in (build_file) do @call :PREPROCESS msgs %%i
@for %%i in (help, meta, proc, show) do @call :PREPROCESS qli %%i

View File

@ -508,6 +508,12 @@ AC_ARG_WITH(cross-build,
IS_CROSS=Y])
AC_SUBST(IS_CROSS)
TOMBUILD=N
AC_ARG_WITH(builtin-tommath,
[ --with-builtin-tommath build libtommath library from firebird tree],
[TOMBUILD=Y])
AC_SUBST(TOMBUILD)
dnl Avoid dumb '-g -O2' autoconf's default
dnl Debugging information and optimization flags should be set in prefix.$platform file
dnl Should be replaced with AC_PROG_GCC_DEFAULT_FLAGS() when available
@ -765,11 +771,17 @@ dnl setting ICU_OK here is done to only avoid default action
AC_CHECK_LIB(icuuc, main, ICU_OK=yes, AC_MSG_ERROR(ICU support not found - please install development ICU package))
dnl check for tommath presence
XE_SAVE_ENV()
LIBS=
AC_CHECK_HEADER(tommath.h,,AC_MSG_ERROR(Include file for tommath not found - please install development tommath package))
AC_CHECK_LIB(tommath, mp_init, MATHLIB=-ltommath, AC_MSG_ERROR(Library tommath not found - please install development tommath package))
XE_RESTORE_ENV()
if test "$TOMBUILD" = "Y"; then
MATHLIB=-ltommath
else
AC_CHECK_HEADER(tommath.h,,
AC_MSG_ERROR(Include file for tommath not found - please install development tommath package or use --with-builtin-tommath))
XE_SAVE_ENV()
LIBS=
AC_CHECK_LIB(tommath, mp_init, MATHLIB=-ltommath,
AC_MSG_ERROR(Library tommath not found - please install development tommath package or use --with-builtin-tommath))
XE_RESTORE_ENV()
fi
AC_SUBST(MATHLIB)
dnl Check for libraries

View File

@ -22,6 +22,19 @@ If a domain name is used in connection string, all addresses (IPv4 and IPv6)
are tried in the order returned by resolver until a connection is established.
Only if all attempts fail, the client fails to connect.
New URL-style connection string format (see README.connection_strings) allows
to restrict name lookup to only IPv4 or IPv6 addresses:
connect 'inet://server.example.org/test';
connect 'inet4://server.example.org/test';
connect 'inet6://server.example.org/test';
First example tries all addresses, second only IPv4 ones, third only IPv6
ones. This can be used to avoid connection delays on systems where name lookup
returns IPv6 addresses for some host names but attempts to connect to them
time out rather than failing immediatelly (as reported, this can happen even
for name "localhost" on some systems).
Server
------

View File

@ -107,6 +107,13 @@ Examples:
inet://myserver:fb_db/mydb
inet://localhost:fb_db/mydb
The "inet" protocol can be replaced by "inet4" or "inet6" to restrict client
to IPv4 or IPv6 addresses corresponding to supplied name ("inet" protocol
tries all addresses in the order determined by OS):
inet4://myserver/mydb
inet6://myserver/mydb
Connect via named pipes:
wnet://myserver/C:\db\mydb.fdb

View File

@ -1,202 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<TITLE></TITLE>
<META NAME="GENERATOR" CONTENT="OpenOffice 4.1.1 (Unix)">
<META NAME="AUTHOR" CONTENT="alex ">
<META NAME="CREATED" CONTENT="20130531;10003100">
<META NAME="CHANGEDBY" CONTENT="Alex Peshkoff">
<META NAME="CHANGED" CONTENT="20141113;13173600">
<META NAME="CHANGEDBY" CONTENT="Alex Peshkoff">
<STYLE TYPE="text/css">
<!--
@page { size: 8.5in 11in; margin: 0.79in }
P { margin-bottom: 0.08in }
-->
</STYLE>
</HEAD>
<BODY LANG="en-US" DIR="LTR">
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Interfaces and objects
oriented API.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Why did we decide to add a
new API in Firebird 3? There was not single reason for it. May be the
first one is limited to 16 bit size of very many integers (for
example - message size, SQL operator length, portion of BLOB data) in
existing API. This probably was enough when that API was introduced &ndash;
but puts a lot of artificial limits today. The trivial way is to add
new functions that support 32 bit variables. But this solution does
not look beautiful because we obviously need to support old API too,
i.e. have 2 sets of functions with same functionality but different
integer sizes. To make such functions differ in 'plain C' API they
should have different names, i.e. a lot of isc_some_thing() calls
will have to have isc32_some_thing() (or fb32_some_thing()) pair.
Such solution was used to support 64 bit performance counters but not
because it's good and clear, we just could not suggest better one at
that moment with at the same time great need in 64 bit counters.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>The second reason is not
so clear from the first look but it's also important. It comes from
old times when Firebird's predecessor did not support SQL &ndash;
another language was used to manage databases (you may get an idea
what it was reading QLI's help). Data was delivered between client
and server using messages with format defined at request compilation
time by BLR (binary language representation) of that request. But SQL
operator does not contain description of message format and therefore
decision was taken &ndash; surround each message with short BLR
sequence (hard to call that program) describing it's format. For a
reason they had decided to follow that rule too exactly &ndash; it
was possible to send modified BLR for each fetch of data from server,
i.e. formatting BLR was sent not only at SQL compile time. The reason
for such strange at the first glance solution was presence of one
more layer on top of that messages based API - familiar to you SQLDA
(XSQLDA). Rather obvious that manually accompanying each SQL
statement with BLR is not efficient programming style, therefore
SQLDA was invented. But it encapsulates in same object both location
of data and there format making it formally possible to change
between fetch calls not only location but format too causing need in
BLR in each message-based fetch call. And to finish with this &ndash;
changing data format between fetches was broken at network layer in
pre-Firebird times. </FONT>
</P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>So what we have with calls
processing data &ndash; hard to extend (adding something to it is far
non-trivial task) and not very clear to use SQLDA, multilayer API
moving data from layer top layer and wasting time for it and &hellip;
big desire to fix that nonsense.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>There are a lot of other
reasons to change API like enhancing status vector or optimizing
dynamic library loading, but even mentioned two are enough to move to
the new one. BTW, in README.providers you will find the information
how interfaces help to use messages API easily and comfortably.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>When making any change in
software it's always desired to avoid loose of performance. And it
was performance issues that caused the choice of interfaces not
compatible with COM. To describe them I need to say a few words about
providers architecture of Firebird. The central part of it is YValve,
which is aimed on dispatching API call to correct provider, including
old providers that potentially have older interfaces than current
one. That means that to make sure that provider really has some new
API method we must (when using COM) call IUnknown method for each
fetch call. Taken together with the fact that new API calls are
sometimes added to optimize performance COM-based solution looks bad
for future Firebird versions.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Unlike COM, Firebird
interfaces support multiple versions. Version of Firebird interface
is defined in a rather native manner &ndash; it's a total number of
virtual functions in interface. And version of interface may be
upgraded! That does not mean that one gets full new functionality:
certainly that's impossible. But after upgrade virtual table is
expanded with function defined by the caller of interface upgrade,
and that function can perform minimum reasonable action &ndash; for
example in a case of providers return an error. This may seem a very
poor kind of upgrade, but at first - this is exactly what will be
done without upgrade after working with IUnknown and next &ndash;
after checking error code one can try to use other methods to do what
he wants. Certainly, not only error return may be done. Imagine that
we added something like phone number to an interface, listing users
from security database. When upgrading old interface it's OK to add a
function returning empty string as a phone number to get reasonable
behavior of old plugin.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>As an additional reason to
use non-COM interfaces it's good to notice that use of reference
counted interfaces in all cases is often an extra overhead. Some
interfaces have by definition unlimited lifetime (like IMaster &ndash;
main interfaces calling which functions one gets access to all the
rest of Firebird API), others &ndash; API strictly defined by
lifetime of parent interface, and for not multi-threaded things like
IStatus it's better to have simpler way to destroy it, i.e. dispose()
function.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT COLOR="#ff0000"><FONT SIZE=4>Careful!</FONT></FONT>
<FONT SIZE=4>An ability to upgrade interface version places one
important limit on implementation of interfaces: it should not
contain virtual functions (including virtual destructor) except those
defined in interface definition. This is because interface upgrade
process modifies table of virtual functions, and for successful
upgrade, number of functions in interface implementation should
exactly match one in its definition. Pointer to functions, missing in
interface definition but added in its implementation, may be
</FONT><FONT COLOR="#ff0000"><FONT SIZE=4>overwritten</FONT></FONT>
<FONT SIZE=4>with a pointer to function used to upgrade interface.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Discussing in details all
functions present in all interfaces is out of this document's scope.
Here I describe only hierarchy of them in general. The base of it is
IVersioned &ndash; interface that enables version upgrade. A lot of
interfaces, that do not require additional lifetime control, are
based directly on IVersioned. A sample is already mentioned IMaster
and a number of callback interfaces which lifetime must match the
lifetime of the object from which they may be used for callback.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Two interfaces, dealing
with lifetime control &ndash; IDisposable and IRefCounted. The last
one is used specially active to create other interfaces &ndash;
IPlugin is reference counted and a lot of other interfaces, used by
plugins, are reference counted too including interfaces that describe
database attachment, transaction and SQL statement.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Each plugin has one and
only one main interface IPlugin which <SPAN LANG="en">is responsible
for basic plugin's functionality (a lot of plugins have only that
interface, but this is not a requirement). </SPAN></FONT>
</P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P LANG="en" STYLE="margin-bottom: 0in"><FONT SIZE=4>To finish with
general interfaces hierarchy is IProvider, a kind of 'main' plugin in
Firebird API. IProvider is derived from IPlugin and implemented by
any provider (i.e. if you want to write your own provider you must
implement IProvider) and also implemented by YValve. It's
implementation from YValve which is returned to the user when
getDispatcher() function from master interface is called. IProvider
contains functions making it possible to create an attachment to
database (attach and create) or attach to services manager.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Questions and answers.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P LANG="en" STYLE="margin-bottom: 0in"><FONT SIZE=4>Q. We access new
API using IMaster. But how to get access to IMaster itself?</FONT></P>
<P LANG="en" STYLE="margin-bottom: 0in"><FONT SIZE=4>A. This is done
using the only one new API function fb_get_master_interface(). It's
exported by fbclient library.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P LANG="en" STYLE="margin-bottom: 0in"><FONT SIZE=4>Q. It's said in
this document that COM-based interfaces are not used in order not to
work with IUnknown methods and that this is done due to performance
issues. But instead you have to upgrade interfaces. Why is it faster
than using IUnknown?</FONT></P>
<P LANG="en" STYLE="margin-bottom: 0in"><FONT SIZE=4>A. Upgrading
interface certainly requires some job to do. In a case when version
matches caller's requirements it's not too big &ndash; just check it,
when real upgrade is needed more CPU cycles will be spent. The main
difference with COM approach is that upgrade performed for interface
only once, after it's creation, but IUnknown methods must be called
each time we are going to call an interface with unknown version (or
that version should be stored separately and later checked). For once
upgraded Firebird interface there is absolutely no waste of time when
performing calls to it during all it's lifetime.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
</BODY>
</HTML>

View File

@ -1,12 +1,13 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8">
<TITLE></TITLE>
<META NAME="GENERATOR" CONTENT="OpenOffice 4.1.1 (Unix)">
<META NAME="GENERATOR" CONTENT="OpenOffice 4.1.2 (Unix)">
<META NAME="CREATED" CONTENT="20130417;16154700">
<META NAME="CHANGEDBY" CONTENT="Alex Peshkoff">
<META NAME="CHANGED" CONTENT="20141113;13254700">
<META NAME="CHANGED" CONTENT="20160407;19330500">
<META NAME="CHANGEDBY" CONTENT="Alex Peshkoff">
<STYLE TYPE="text/css">
<!--
@page { margin: 0.79in }
@ -29,15 +30,15 @@ parts of Firebird are implemented as plugins. </FONT>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>First of all a few words
about the term &ldquo;plugin&rdquo;. Unfortunately, it's often used
to define related but different things. Plugin is used to name:</FONT></P>
about the term “plugin”. Unfortunately, it's often used to define
related but different things. Plugin is used to name:</FONT></P>
<UL>
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>dynamic library,
containing code to be loaded as plugin (often called plugin module)
and stored in $FIREBIRD/plugins directory;</FONT></P>
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>code implementing
plugin &ndash; slightly different from the library cause single
dynamic library may contain code for more than one plugin;</FONT></P>
plugin slightly different from the library cause single dynamic
library may contain code for more than one plugin;</FONT></P>
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>plugin's factory - an
object created by that code (pure virtual C++ class), creating
plugin instances on Firebird request;</FONT></P>
@ -45,21 +46,21 @@ to define related but different things. Plugin is used to name:</FONT></P>
created by factory.</FONT></P>
</UL>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>In most cases it's clear
from context what &ldquo;plugin&rdquo; do we talk about. If not it
will be clarified explicitly.</FONT></P>
from context what “plugin” do we talk about. If not it will be
clarified explicitly.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Firebird plugin
architecture supports creation of any plugin type for any purpose &ndash;
architecture supports creation of any plugin type for any purpose
but first of all this requires changes in Firebird code. Plugin can't
be added at any desired point &ldquo;magically&rdquo;. To be able to
have plugin (for example) encrypting database on the disk, Firebird
code should be prepared for it &ndash; must have a point from which
plugin is called. I.e. each version has a fixed set of plugins which
are supported. To add one more type, first of all Firebird code
should be modified. What DOES our plugin architecture &ndash; it
helps to make both adding new types of plugins and writing plugin
code simple and as universal between plugins as possible.</FONT></P>
be added at any desired point “magically”. To be able to have
plugin (for example) encrypting database on the disk, Firebird code
should be prepared for it must have a point from which plugin is
called. I.e. each version has a fixed set of plugins which are
supported. To add one more type, first of all Firebird code should be
modified. What DOES our plugin architecture it helps to make both
adding new types of plugins and writing plugin code simple and as
universal between plugins as possible.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Firebird 3 has a following
@ -81,42 +82,41 @@ set of plugin types:</FONT></P>
plugin KeyHolder, which is used to help maintaining secret key(s)
for DbCrypt;</FONT></P>
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>and probably the most
important kind &ndash; Provider. Firebird 3 supports providers as a
kind of plugins, which has nothing outstanding compared with others.
See README.Providers for more information about providers. </FONT>
important kind Provider. Firebird 3 supports providers as a kind
of plugins, which has nothing outstanding compared with others. See
README.Providers for more information about providers. </FONT>
</P>
</UL>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Plugins are using a set of
special Firebird interfaces (see README.interfaces about interfaces
in Firebird). All plugin-specific interfaces are reference counted,
i.e. have explicitly controlled lifetime. Interfaces are declared in
Interfaces.h include file. There is a simple example of writing
plugin module &ndash; DbCrypt_example. It does not perform any actual
encryption &ndash; just a sample of how to write plugin. Complete
instruction of how to write plugins is out of this document's scope.
Here is provided a short list of plugin features:</FONT></P>
special Firebird interfaces (see Using_OO_API for details). All
plugin-specific interfaces are reference counted, i.e. have
explicitly controlled lifetime. Interfaces are declared in
Interfaces.h include file. There is an example of writing plugin
module DbCrypt_example. It does not perform any actual encryption
just a sample of how to write plugin. Complete instruction of how
to write plugins is out of this document's scope. Here is provided a
short list of plugin features:</FONT></P>
<UL>
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>plugin may be written
using any language, supporting function pointers in a
structure/record (or at least arrays of function pointers);</FONT></P>
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>currently interfaces
description is available only for C++ language, at release time
plain-C and delphi/fpc descriptions will be present (you will need
to write your interfaces declarations generator for your language if
you need something else);</FONT></P>
description is available only for C++ and Pascal(Delphi), you will
need to write your interfaces declarations generator for your
language if you need something else;</FONT></P>
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>like with UDFs you
are free to add any reasonable code to your plugin, but pay
attention to word &ldquo;reasonable&rdquo; - asking a question from
plugin at server's console is hardly good idea;</FONT></P>
attention to word “reasonable” - asking a question from plugin
at server's console is hardly good idea;</FONT></P>
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>it's OK to use
Firebird API calls in your plugin if needed (for example, default
authentication server and user manager are using Firebird database
to store accounts);</FONT></P>
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>additionally Firebird
provides a set of interfaces, helping you to configure your plugins
(certainly, you are not forced to use them &ndash; plugin is generic
(certainly, you are not forced to use them plugin is generic
code, which may use any way of providing configuration information,
but with standard tools you get common for the rest of Firebird
configuration style and sooner of all save you efforts).</FONT></P>
@ -124,13 +124,12 @@ Here is provided a short list of plugin features:</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Configuring plugins has 2
parts &ndash; first, engine should be instructed what plugins it
should load, and next plugins themselves sometimes need some
configuration. What plugins to be loaded is defined in main
configuration file &ndash; firebird.conf for each type of plugin.
Like any other value in firebird.conf the have defaults:</FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>AuthServer = Srp,
Win_Sspi</I></FONT></P>
parts first, engine should be instructed what plugins it should
load, and next plugins themselves sometimes need some configuration.
What plugins to be loaded is defined in main configuration file
firebird.conf for each type of plugin. Like any other value in
firebird.conf the have defaults:</FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>AuthServer = Srp</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>AuthClient = Srp,
Win_Sspi, Legacy_Auth</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>UserManager = Srp</I></FONT></P>
@ -140,7 +139,7 @@ Remote,Engine12,Loopback</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>WireCryptPlugin = Arc4</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>This provides normal
operation in server, client and embedded cases. If you want to add
other plugins, you must mention them in firebird.conf &ndash; except
other plugins, you must mention them in firebird.conf except
other this is security measure to avoid loading unknown code. But
what does for example fbtrace mean here? Is it a name of dynamic
library to load? In trivial case yes, but exact answer is more
@ -150,27 +149,27 @@ complicated.</FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>As it was already
mentioned, single plugin module may implement more than single
plugin. Moreover, single plugin may have at the same time more than
one configuration &ndash; and for each configuration separate
plugin's factory is created. Each of this 3 objects (module &ndash;
implementation &ndash; factory) has it's own name. Name of a module
is a file name of dynamic library. Plugin implementation's name is
one given to it by plugin developer and hard-coded inside module.
Factory's name by default equals to plugin implementation's name (and
it's factory name which is actually used in firebird.conf). Certainly
in typical trivial case, module contains one plugin, and that plugin
works with only one configuration, and all 3 names are equal, and no
more configuration is needed &ndash; for example libEngine12.so or
Engine12.dll contains implementation of provider Engine12, and
nothing else except record </FONT>
one configuration and for each configuration separate plugin's
factory is created. Each of this 3 objects (module implementation
factory) has it's own name. Name of a module is a file name of
dynamic library. Plugin implementation's name is one given to it by
plugin developer and hard-coded inside module. Factory's name by
default equals to plugin implementation's name (and it's factory name
which is actually used in firebird.conf). Certainly in typical case,
module contains one plugin, and that plugin works with only one
configuration, and all 3 names are equal, and no more configuration
is needed for example libEngine12.so or Engine12.dll contains
implementation of provider Engine12, and nothing else except record </FONT>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Providers = Engine12</FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>in firebird.conf is needed
to load it. But if you have something complex &ndash; file will help
you to have such plugin factories which you really want.</FONT></P>
to load it. But if you have something complex configuration file
plugins.conf will help you to have such plugin factories which you
really want.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>File plugins.conf has 2
types of records &ndash; config and plugin. Plugin record is a set of
types of records config and plugin. Plugin record is a set of
rules for plugin's loading and activating. Plugin record has the
following format:</FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>Plugin = PlugName ##
@ -191,10 +190,10 @@ registered with name RegName and passes it configuration from config
record ConfName or config file ConfFile (config record is used if
both are given). Each parameter in this record may be missing, in
that case the default PlugName is used. The only exception is
ConfigFile &ndash; by default, file with same name as module's
dynamic library but .conf extension is used. ConfigFile is expected
to have format Key=Value (like other Firebird configuration files),
same format is used for plugin record:</FONT></P>
ConfigFile by default, file with same name as module's dynamic
library but .conf extension is used. ConfigFile is expected to have
format Key=Value (like other Firebird configuration files), same
format is used for plugin record:</FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>Config = ConfName</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>{</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>Key1 = Value1</I></FONT></P>
@ -205,29 +204,29 @@ same format is used for plugin record:</FONT></P>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Let's have a sample.
Suppose some clients of your server trust wire encryption from one
vendor and others &ndash; from another one (and have different
licenses for appropriate client parts), but each vendor calls his
plugin BestCrypt. Certainly, first of all you have to rename
libraries to something like WC1 and WC2 &ndash; one can't have 2
files with same name in one directory. But after it, modules stop to
load automatically &ndash; they are not named BestCrypt any more. To
fix it, plugins.conf should contain something like this:</FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>Plugin = WC1</I></FONT></P>
vendor and others from another one (and have different licenses
for appropriate client parts), but each vendor calls his plugin
BestCrypt. Certainly, first of all you have to rename libraries to
something like Crypt1 and Crypt2 one can't have 2 files with same
name in one directory. But after it, modules stop to load
automatically they are not named BestCrypt any more. To fix it,
plugins.conf should contain something like this:</FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>Plugin = Crypt1</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>{</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>RegisterName =
BestCrypt</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>}</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>Plugin = WC2</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>Plugin = Crypt2</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>{</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>RegisterName =
BestCrypt</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>}</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Module names will be
automatically set to WC1 and WC2 and found. Certainly you may add
some configuration info for plugins if needed. Also don't forget to
modify firebird.conf:</FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>WireCryptPlugin = WC1,
WC2</I></FONT></P>
automatically set to Crypt1 and Crypt2 and found. Certainly you may
add some configuration info for plugins if needed. Also don't forget
to modify firebird.conf:</FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>WireCryptPlugin =
Crypt1, Crypt2</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>After it server will
automatically select appropriate plugin to talk to client.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
@ -256,16 +255,16 @@ plugins is used.</FONT></P>
and Arc4 plugins mean?</FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>A. Srp implements Secure
Remote Passwords protocol which is default way of authenticating
users in Firebird 3. It has efficient password&rsquo;s length equal
to 20 bytes, resistant to most of attacks (including man in the
middle) and does not require exchanging any keys between client and
server to work. Arc4 means Alleged RC4 - an implementation of RC4
cypher. The advantage of SRP is that it can generate unique
cryptographically strong key on both client and server and it's
impossible to guess it capturing data transferred over the wire
during password validation by SRP. That key is used after SRP
handshake by Arc4, which makes wire encryption secure without need to
exchange any keys between client and server explicitly.</FONT></P>
users in Firebird 3. It has efficient passwords length equal to 20
bytes, resistant to most of attacks (including man in the middle) and
does not require exchanging any keys between client and server to
work. Arc4 means Alleged RC4 - an implementation of RC4 cypher. The
advantage of SRP is that it can generate unique cryptographically
strong key on both client and server and it's impossible to guess it
capturing data transferred over the wire during password validation
by SRP. That key is used after SRP handshake by Arc4, which makes
wire encryption secure without need to exchange any keys between
client and server explicitly.</FONT></P>
<P STYLE="margin-bottom: 0in"><BR>
</P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>Q. And what do Win_Sspi
@ -273,11 +272,11 @@ and Legacy_Auth mean?</FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>A. Windows SSPI was used
since FB 2.1 for windows trusted authentication. Legacy_Auth is
compatibility plugin. It's enabled by default on client to let it
connect to pre-FB3 servers. (Yes &ndash; it still transfers almost
plain passwords over the wire. Compatibility...) On server it works
with security database from FB 2.5, and should be avoided except
cases when you understand well what are you doing. To use Legacy_Auth
on server you should set lower level of network traffic encryption in
connect to pre-FB3 servers. (Yes it still transfers almost plain
passwords over the wire. Compatibility...) On server it works with
security database from FB 2.5, and should be avoided except cases
when you understand well what are you doing. To use Legacy_Auth on
server you should set lower level of network traffic encryption in
firebird.conf:</FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>WireCrypt = Enabled</I></FONT></P>
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>or in the worst case:</FONT></P>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
Cumulative roles.
Implements capability to grant role to role.
Author:
Red Soft Corporation, roman.simakov(at)red-soft.biz
Syntax is:
GRANT [DEFAULT] <role name> TO [USER | ROLE] <user/role name> [WITH ADMIN OPTION];
REVOKE [DEFAULT] <role name> FROM [USER | ROLE] <user/role name> [WITH ADMIN OPTION];
Description:
Makes it possible to grant a role to user or another role.
If DEFAULT keyword is used the role will be used every time for user even if it's not specified explicitly.
While connecting user will get permissions of all roles which were granted to him with DEFAULT keyword and
permissions of all roles also granted to them with DEFAULT keyword specified.
If user specify a role in connection he will also get permissions of this role (if granted of course) and
permissions of all roles granted to it, etc.
When some user want go grant a role to another user or role ADMIN OPTION will be checked. In this case user can grant
a role cumulatively granted to him only if every role in sequence has ADMIN OPTION.
REVOKE works as usual except if DEFAULT is specified only default option will be revoked. In other words
role skill be granted but like without DEFAULT.
Let:
"->" grant without ADMIN OPTION
"=>" grant with ADMIN OPTION
Consider 3 options:
1) WORKER->MANAGER->Joe
2) WORKER->MANAGER=>Joe
3) WORKER=>MANAGER->Joe
4) WORKER=>MANAGER=>Joe
Joe can grant role MANAGER in 2 and 4 options and role WORKER only in 4 option. In 1 and 3 options Joe cannot grant
nothing even in 3 option WORKER granted to MANAGER with ADMIN OPTION.
Sample:
CREATE DATABASE 'LOCALHOST:/TMP/CUMROLES.FDB';
CREATE TABLE T(I INTEGER);
CREATE ROLE TINS;
CREATE ROLE CUMR;
GRANT INSERT ON T TO TINS;
GRANT DEFAULT TINS ROLE TO CUMR WITH ADMIN OPTION;
GRANT CUMR TO USER US WITH ADMIN OPTION;
CONNECT 'LOCALHOST:/TMP/CUMROLES.FDB' USER 'US' PASSWORD 'PAS';
INSERT INTO T VALUES (1);
GRANT TINS TO US2;

View File

@ -68,8 +68,8 @@ BOOLEAN (FB 3.0)
3. The value TRUE is greater than the value FALSE.
4. Booleans are not implicitly convertible to any other datatype. But it's convertible to/from
strings with CAST.
4. Non-booleans values are not implicitly convertible to boolean in boolean-specific expressions
like predicates and arguments for operators NOT, AND, OR and IS.
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

View File

@ -41,11 +41,6 @@ public:
}
return 1;
}
IPluginModule* getModule()
{
return NULL; // OK for application, not for plugin
}
};
class App

View File

@ -29,47 +29,37 @@
namespace
{
IMaster* master = NULL;
IPluginManager* pluginManager = NULL;
class PluginModule : public IPluginModuleImpl<PluginModule, CheckStatusWrapper>
{
public:
PluginModule()
: flag(false)
: pluginManager(NULL)
{ }
void registerMe()
{
pluginManager->registerModule(this);
flag = true;
}
~PluginModule()
{
if (flag)
if (pluginManager)
{
pluginManager->unregisterModule(this);
doClean();
}
}
IPluginModule* getModule()
void registerMe(IPluginManager* m)
{
return this;
pluginManager = m;
pluginManager->registerModule(this);
}
void doClean()
{
flag = false;
pluginManager = NULL;
}
private:
bool flag;
IPluginManager* pluginManager;
};
PluginModule module;
class CryptKeyHolder : public IKeyHolderPluginImpl<CryptKeyHolder, CheckStatusWrapper>
{
public:
@ -103,11 +93,6 @@ public:
++refCounter;
}
IPluginModule* getModule()
{
return &module;
}
void setOwner(Firebird::IReferenceCounted* o)
{
owner = o;
@ -265,38 +250,25 @@ ICryptKeyCallback* CryptKeyHolder::keyHandle(CheckStatusWrapper* status, const c
class Factory : public IPluginFactoryImpl<Factory, CheckStatusWrapper>
{
public:
IPluginModule* getModule()
{
return &module;
}
IPluginBase* createPlugin(CheckStatusWrapper* status, IPluginConfig* factoryParameter)
{
try
{
CryptKeyHolder* p = new CryptKeyHolder(factoryParameter);
p->addRef();
return p;
}
catch (...)
{
ISC_STATUS st[3] = {isc_arg_gds, isc_virmemexh, isc_arg_end};
status->setErrors(st);
}
return NULL;
CryptKeyHolder* p = new CryptKeyHolder(factoryParameter);
p->addRef();
return p;
}
};
PluginModule module;
Factory factory;
} // anonymous namespace
extern "C" void FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* m)
extern "C" void FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* master)
{
master = m;
pluginManager = master->getPluginManager();
IPluginManager* pluginManager = master->getPluginManager();
module.registerMe();
module.registerMe(pluginManager);
pluginManager->registerPluginFactory(IPluginManager::TYPE_KEY_HOLDER, "CryptKeyHolder_example",
&factory);
}

View File

@ -31,52 +31,42 @@ using namespace Firebird;
namespace
{
IMaster* master = NULL;
IPluginManager* pluginManager = NULL;
class PluginModule : public IPluginModuleImpl<PluginModule, CheckStatusWrapper>
{
public:
PluginModule()
: flag(false)
: pluginManager(NULL)
{ }
void registerMe()
{
pluginManager->registerModule(this);
flag = true;
}
~PluginModule()
{
if (flag)
if (pluginManager)
{
pluginManager->unregisterModule(this);
doClean();
}
}
IPluginModule* getModule()
void registerMe(IPluginManager* m)
{
return this;
pluginManager = m;
pluginManager->registerModule(this);
}
void doClean()
{
flag = false;
pluginManager = NULL;
}
private:
bool flag;
IPluginManager* pluginManager;
};
PluginModule module;
class DbCrypt : public IDbCryptPluginImpl<DbCrypt, CheckStatusWrapper>
{
public:
explicit DbCrypt(IPluginConfig* cnf) throw()
: config(cnf), key(0), owner(NULL)
: config(cnf), key(0), refCounter(0), owner(NULL)
{
config->addRef();
}
@ -107,11 +97,6 @@ public:
++refCounter;
}
IPluginModule* getModule()
{
return &module;
}
void setOwner(IReferenceCounted* o)
{
owner = o;
@ -254,37 +239,28 @@ void DbCrypt::setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolder
class Factory : public IPluginFactoryImpl<Factory, CheckStatusWrapper>
{
public:
IPluginModule* getModule()
{
return &module;
}
IPluginBase* createPlugin(CheckStatusWrapper* status, IPluginConfig* factoryParameter)
{
try
{
DbCrypt* p = new DbCrypt(factoryParameter);
p->addRef();
return p;
}
catch (...)
{
ISC_STATUS st[3] = {isc_arg_gds, isc_virmemexh, isc_arg_end};
status->setErrors(st);
}
return NULL;
/*
// *** Uncomment this 2 lines to see how plugin creation errors are handled
const ISC_STATUS_ARRAY vector = {isc_arg_gds, isc_virmemexh, isc_arg_end};
throw FbException(status, vector);
*/
DbCrypt* p = new DbCrypt(factoryParameter);
p->addRef();
return p;
}
};
PluginModule module;
Factory factory;
} // anonymous namespace
extern "C" void FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* m)
extern "C" void FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* master)
{
master = m;
pluginManager = master->getPluginManager();
IPluginManager* pluginManager = master->getPluginManager();
module.registerMe();
module.registerMe(pluginManager);
pluginManager->registerPluginFactory(IPluginManager::TYPE_DB_CRYPT, "DbCrypt_example", &factory);
}

View File

@ -100,8 +100,8 @@ int main()
IProvider* prov = master->getDispatcher();
IUtil* utl = master->getUtilInterface();
IService* svc = NULL;
IXpbBuilder *spb1 = NULL;
IXpbBuilder *spb2 = NULL;
IXpbBuilder* spb1 = NULL;
IXpbBuilder* spb2 = NULL;
try {
printf("** Attaching to service manager...\n");

View File

@ -1200,7 +1200,7 @@ void advance_to_start()
syntax_error(lineno, line, s_cptr); } }
c = nextc();
if (!isalpha(c) && c != '_' && c != '.' && c != '_')
if (!isalpha(c) && c != '_' && c != '.' && c != '$')
syntax_error(lineno, line, cptr);
bp = get_name();
if (goal == 0) {

View File

@ -1,2 +1,5 @@
lib/
temp/
*.o
*.l*
.libs/

View File

@ -83,7 +83,7 @@ bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin_n.o
objs: $(OBJECTS)
$(LIBNAME): $(OBJECTS)
libtool --mode=link gcc *.lo -o $(LIBNAME) -rpath $(LIBPATH) -version-info $(VERSION)
libtool --mode=link --tag=CC gcc *.lo -o $(LIBNAME) -rpath $(LIBPATH) -version-info $(VERSION)
install: $(LIBNAME)
install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(LIBPATH)

View File

@ -1630,6 +1630,8 @@ C --
PARAMETER (GDS__bad_crypt_key = 335545108)
INTEGER*4 GDS__encrypt_error
PARAMETER (GDS__encrypt_error = 335545109)
INTEGER*4 GDS__max_idx_depth
PARAMETER (GDS__max_idx_depth = 335545110)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw

View File

@ -1625,6 +1625,8 @@ const
gds_bad_crypt_key = 335545108;
isc_encrypt_error = 335545109;
gds_encrypt_error = 335545109;
isc_max_idx_depth = 335545110;
gds_max_idx_depth = 335545110;
isc_gfix_db_name = 335740929;
gds_gfix_db_name = 335740929;
isc_gfix_invalid_sw = 335740930;

View File

@ -39,6 +39,7 @@
#include "../common/classes/array.h"
#include "../common/classes/UserBlob.h"
#include "../alice/alice_proto.h"
#include "../common/utils_proto.h"
#include <string.h>
@ -411,8 +412,7 @@ static void parse_fullpath(tdr* trans)
trans->tdr_filename = q + 1;
trans->tdr_remote_site = FB_NEW_RPT(*tdgbl->getDefaultPool(), q - p + 1) alice_str;
strncpy((char*) trans->tdr_remote_site->str_data, (char*) p, q - p);
trans->tdr_remote_site->str_data[q - p] = '\0';
fb_utils::copy_terminate((char*) trans->tdr_remote_site->str_data, (char*) p, q - p + 1);
}
}
else

View File

@ -279,18 +279,18 @@ public:
switch(user->operation())
{
case MAP_DROP_OPER:
case MAP_SET_OPER:
case Firebird::IUser::OP_USER_DROP_MAP:
case Firebird::IUser::OP_USER_SET_MAP:
{
Firebird::string sql;
sql.printf("ALTER ROLE " ADMIN_ROLE " %s AUTO ADMIN MAPPING",
user->operation() == MAP_SET_OPER ? "SET" : "DROP");
user->operation() == Firebird::IUser::OP_USER_SET_MAP ? "SET" : "DROP");
att->execute(status, tra, sql.length(), sql.c_str(), SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
check(status);
}
break;
case ADD_OPER:
case Firebird::IUser::OP_USER_ADD:
{
const char* insert =
"INSERT INTO plg$srp_view(PLG$USER_NAME, PLG$VERIFIER, PLG$SALT, PLG$FIRST, PLG$MIDDLE, PLG$LAST,"
@ -378,7 +378,7 @@ public:
}
break;
case MOD_OPER:
case Firebird::IUser::OP_USER_MODIFY:
{
Firebird::string update = "UPDATE plg$srp_view SET ";
@ -482,7 +482,7 @@ public:
}
break;
case DEL_OPER:
case Firebird::IUser::OP_USER_DELETE:
{
const char* del = "DELETE FROM plg$srp_view WHERE PLG$USER_NAME=?";
Firebird::IStatement* stmt = NULL;
@ -525,8 +525,7 @@ public:
}
break;
case OLD_DIS_OPER:
case DIS_OPER:
case Firebird::IUser::OP_USER_DISPLAY:
{
Firebird::string disp = "SELECT PLG$USER_NAME, PLG$FIRST, PLG$MIDDLE, PLG$LAST, PLG$COMMENT, PLG$ATTRIBUTES, "
" CASE WHEN RDB$RELATION_NAME IS NULL THEN FALSE ELSE TRUE END, PLG$ACTIVE "

View File

@ -225,13 +225,7 @@ int SecurityDatabaseManagement::release()
return 1;
}
#define STR_STORE(to, from) strStore(to, from, sizeof(to))
static inline void strStore(char* to, const char* from, size_t len)
{
to[--len] = '\0';
strncpy(to, from, len);
}
#define STR_STORE(to, from) fb_utils::copy_terminate(to, from, sizeof(to))
int SecurityDatabaseManagement::execute(Firebird::CheckStatusWrapper* st, Firebird::IUser* user,
Firebird::IListUsers* callback)
@ -324,12 +318,12 @@ int SecurityDatabaseManagement::execute(Firebird::CheckStatusWrapper* st, Firebi
switch (user->operation())
{
case MAP_DROP_OPER:
case MAP_SET_OPER:
case Firebird::IUser::OP_USER_DROP_MAP:
case Firebird::IUser::OP_USER_SET_MAP:
{
Firebird::string sql;
sql.printf("ALTER ROLE " ADMIN_ROLE " %s AUTO ADMIN MAPPING",
user->operation() == MAP_SET_OPER ? "SET" : "DROP");
user->operation() == Firebird::IUser::OP_USER_SET_MAP ? "SET" : "DROP");
isc_dsql_execute_immediate(isc_status, &database, &transaction, sql.length(), sql.c_str(), 1, NULL);
if (isc_status[1] != 0)
{
@ -338,7 +332,7 @@ int SecurityDatabaseManagement::execute(Firebird::CheckStatusWrapper* st, Firebi
}
break;
case ADD_OPER:
case Firebird::IUser::OP_USER_ADD:
// this checks the "entered" flags for each parameter (except the name)
// and makes all non-entered parameters null valued
@ -412,7 +406,7 @@ int SecurityDatabaseManagement::execute(Firebird::CheckStatusWrapper* st, Firebi
}
break;
case MOD_OPER:
case Firebird::IUser::OP_USER_MODIFY:
// this updates an existing record, replacing all fields that are
// entered, and for those that were specified but not entered, it
// changes the current value to the null value
@ -509,7 +503,7 @@ int SecurityDatabaseManagement::execute(Firebird::CheckStatusWrapper* st, Firebi
}
break;
case DEL_OPER:
case Firebird::IUser::OP_USER_DELETE:
// looks up the specified user record and deletes it
found = false;
@ -546,8 +540,7 @@ int SecurityDatabaseManagement::execute(Firebird::CheckStatusWrapper* st, Firebi
}
break;
case DIS_OPER:
case OLD_DIS_OPER:
case Firebird::IUser::OP_USER_DISPLAY:
// gets either the desired record, or all records, and displays them
found = false;

View File

@ -229,8 +229,7 @@ bool SecurityDatabase::lookup_user(const char* user_name, char* pwd)
if (pwd)
*pwd = '\0';
strncpy(uname, user_name, sizeof uname);
uname[sizeof uname - 1] = 0;
fb_utils::copy_terminate(uname, user_name, sizeof uname);
MutexLockGuard guard(mutex, FB_FUNCTION);
@ -260,8 +259,7 @@ bool SecurityDatabase::lookup_user(const char* user_name, char* pwd)
if (pwd)
{
strncpy(pwd, user.password, MAX_LEGACY_PASSWORD_LENGTH);
pwd[MAX_LEGACY_PASSWORD_LENGTH] = 0;
fb_utils::copy_terminate(pwd, user.password, MAX_LEGACY_PASSWORD_LENGTH + 1);
}
}

View File

@ -1945,14 +1945,14 @@ int put_message( att_type attribute, att_type attribute2, const TEXT* text, cons
else if (newlen <= MAX_USHORT)
{
if (!attribute2) // In theory, this never happens, because the caller knows what it's doing.
BURP_error(314, "");
BURP_error(314, true);
put(tdgbl, attribute2);
USHORT vax_value = (USHORT) newlen;
vax_value = (USHORT) gds__vax_integer((const UCHAR*) &vax_value, sizeof(vax_value));
put_block(tdgbl, (const UCHAR*) &vax_value, sizeof(vax_value));
}
else
BURP_error(315, "");
BURP_error(315, true);
if (newlen)
put_block(tdgbl, reinterpret_cast<const UCHAR*>(text), newlen);
@ -3978,7 +3978,7 @@ void write_shadow_files()
* Write out files to use as shadows.
*
**************************************/
TEXT temp[GDS_NAME_LEN];
BASED ON RDB$FILES.RDB$FILE_NAME temp;
isc_req_handle req_handle1 = 0;
BurpGlobals* tdgbl = BurpGlobals::getSpecific();

View File

@ -65,7 +65,7 @@ static inline void BURP_free(void* block)
MISC_free_burp(block);
}
const int GDS_NAME_LEN = 32;
const int GDS_NAME_LEN = METADATA_IDENTIFIER_CHAR_LEN * 4 /* max bytes per char */ + 1;
typedef TEXT GDS_NAME[GDS_NAME_LEN];
enum redirect_vals {

View File

@ -379,6 +379,7 @@ int RESTORE_restore (const TEXT* file_name, const TEXT* database_name)
ON_ERROR
general_on_error ();
END_ERROR;
tdgbl->flag_on_line = false;
END_ERROR;
END_FOR;
ON_ERROR
@ -3084,6 +3085,9 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
// Fix for bug_no 8055:
// don't throw away the database just because an index
// could not be made
// don't bring the database on-line
tdgbl->flag_on_line = false;
ISC_STATUS error_code;
while (error_code = tdgbl->status_vector[1])
{
@ -3117,8 +3121,6 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
// msg 243 ALTER INDEX \"%s\" ACTIVE
END_MODIFY;
END_FOR;
// don't bring the database on-line
tdgbl->flag_on_line = false;
// commit one more time
COMMIT
ON_ERROR

View File

@ -208,7 +208,7 @@ public:
IStatus* clone() const
{
Final* ret = FB_NEW Final();
IStatus* ret = MasterInterfacePtr()->getStatus();
ret->setWarnings(getWarnings());
ret->setErrors(getErrors());

View File

@ -335,12 +335,14 @@ SSHORT TextType::compare(ULONG len1, const UCHAR* str1, ULONG len2, const UCHAR*
len2, Firebird::Aligner<USHORT>(str2, len2), &error_flag);
}
SSHORT cmp = memcmp(str1, str2, MIN(len1, len2));
int cmp = memcmp(str1, str2, MIN(len1, len2));
if (cmp == 0)
cmp = (len1 < len2 ? -1 : (len1 > len2 ? 1 : 0));
else
cmp = (cmp < 0 ? -1 : 1);
return cmp;
return (SSHORT) cmp;
}

View File

@ -273,12 +273,11 @@ isc_svc_handle attachRemoteServiceManager(ISC_STATUS* status,
userInfoToSpb
@brief Writes data from awful borland's struct internal_user_data
to not less awful borland's format of spb.
@brief Writes data from UserData to spb.
@param spb
@param userInfo
@param userData
**/
static void userInfoToSpb(char*& spb, Auth::UserData& userData)

View File

@ -359,6 +359,10 @@ ClumpletReader::ClumpletType ClumpletReader::getClumpletType(UCHAR tag) const
case isc_spb_rpr_rollback_trans:
case isc_spb_rpr_recover_two_phase:
return IntSpb;
case isc_spb_rpr_commit_trans_64:
case isc_spb_rpr_rollback_trans_64:
case isc_spb_rpr_recover_two_phase_64:
return BigIntSpb;
}
invalid_structure("unknown parameter for repair");
break;
@ -566,6 +570,11 @@ FB_SIZE_T ClumpletReader::getClumpletSize(bool wTag, bool wLength, bool wData) c
dataSize = 4;
break;
// Used in SPB for 8-byte integers
case BigIntSpb:
dataSize = 8;
break;
// Used in SPB for single byte
case ByteSpb:
dataSize = 1;

View File

@ -146,7 +146,7 @@ public:
}
protected:
enum ClumpletType {TraditionalDpb, SingleTpb, StringSpb, IntSpb, ByteSpb, Wide};
enum ClumpletType {TraditionalDpb, SingleTpb, StringSpb, IntSpb, BigIntSpb, ByteSpb, Wide};
ClumpletType getClumpletType(UCHAR tag) const;
FB_SIZE_T getClumpletSize(bool wTag, bool wLength, bool wData) const;
void adjustSpbState();

View File

@ -337,6 +337,12 @@ void ClumpletWriter::insertBytesLengthCheck(UCHAR tag, const void* bytes, const
m.printf("attempt to store %d bytes in a clumplet, need 4", length);
}
break;
case BigIntSpb:
if (length != 8)
{
m.printf("attempt to store %d bytes in a clumplet, need 8", length);
}
break;
case ByteSpb:
if (length != 1)
{

View File

@ -211,13 +211,19 @@ InternalMessageBuffer::InternalMessageBuffer(unsigned aBlrLength, const unsigned
unsigned aBufferLength, unsigned char* aBuffer)
{
buffer = aBuffer;
metadata = FB_NEW MetadataFromBlr(aBlrLength, aBlr, aBufferLength);
metadata->addRef();
if (aBlr)
{
metadata = FB_NEW MetadataFromBlr(aBlrLength, aBlr, aBufferLength);
metadata->addRef();
}
else
metadata = NULL;
}
InternalMessageBuffer::~InternalMessageBuffer()
{
metadata->release();
if (metadata)
metadata->release();
}
} // namespace Firebird

View File

@ -331,6 +331,17 @@ inline void operator delete[](void* mem, Firebird::MemoryPool& pool ALLOC_PARAMS
MemoryPool::globalFree(mem);
}
#if __cplusplus >= 201402L
inline void operator delete(void* mem, std::size_t s ALLOC_PARAMS) throw()
{
MemoryPool::globalFree(mem);
}
inline void operator delete[](void* mem, std::size_t s ALLOC_PARAMS) throw()
{
MemoryPool::globalFree(mem);
}
#endif
#ifdef DEBUG_GDS_ALLOC
#ifdef __clang__

View File

@ -332,6 +332,12 @@ namespace Firebird
{
}
ObjectsArray(const ObjectsArray<T, A>& o)
: A()
{
add(o);
}
ObjectsArray() :
A()
{
@ -436,6 +442,12 @@ namespace Firebird
ObjectCmp> >(p)
{ }
explicit SortedObjectsArray() :
ObjectsArray <ObjectValue, SortedArray<ObjectValue*,
ObjectStorage, const ObjectKey*, ObjectKeyOfValue,
ObjectCmp> >()
{ }
bool find(const ObjectKey& item, size_type& pos) const
{
const ObjectKey* const pItem = &item;

View File

@ -746,7 +746,7 @@ bool ConfigFile::wildCards(const char* currentFileName, const PathName& pathPref
// Any change in directory can cause config change
PathName prefix(pathPrefix);
if(!pathPrefix.hasData())
prefix = ".";
prefix = PathUtils::curr_dir_link;
bool found = false;
PathName next(components.pop());
@ -761,7 +761,7 @@ bool ConfigFile::wildCards(const char* currentFileName, const PathName& pathPref
{
PathName name;
const PathName fileName = list.getFileName();
if (fileName == ".")
if (fileName == PathUtils::curr_dir_link)
continue;
if (fileName[0] == '.' && next[0] != '.')
continue;

View File

@ -33,25 +33,44 @@ void ParsedPath::parse(const PathName& path)
{
clear();
if (path.length() == 1) {
add(path);
return;
}
PathName oldpath = path;
int toSkip = 0;
do {
PathName newpath, elem;
PathUtils::splitLastComponent(newpath, elem, oldpath);
oldpath = newpath;
if (elem.isEmpty() && !oldpath.isEmpty()) // Skip double dir separator
{
continue;
}
if (elem == PathUtils::curr_dir_link) // Skip current dir reference
{
continue;
}
if (elem == PathUtils::up_dir_link) // skip next up dir
{
toSkip++;
continue;
}
if (toSkip > 0)
{
toSkip--;
continue;
}
insert(0, elem);
} while (oldpath.length() > 0);
if (toSkip != 0)
{
// Malformed path, attempt to hack?..
// Let it be, consequent comparison will rule it out
}
}
PathName ParsedPath::subPath(FB_SIZE_T n) const
{
PathName rc = (*this)[0];
if (PathUtils::isRelative(rc + PathUtils::dir_sep))
rc = PathUtils::dir_sep + rc;
if (rc.isEmpty())
rc = PathUtils::dir_sep;
for (FB_SIZE_T i = 1; i < n; i++)
{
PathName newpath;
@ -155,42 +174,23 @@ void DirectoryList::initialize(bool simple_mode)
}
}
FB_SIZE_T last = 0;
PathName root = Config::getRootDirectory();
FB_SIZE_T i;
for (i = 0; i < val.length(); i++)
while (!val.isEmpty())
{
if (val[i] == ';')
string::size_type sep = val.find(';');
if (sep == string::npos)
sep = val.length();
PathName dir(val.c_str(), sep);
dir.alltrim(" \t\r");
val.erase(0, sep + 1);
if (PathUtils::isRelative(dir))
{
PathName dir = "";
if (i > last)
{
dir = val.substr(last, i - last);
dir.trim();
}
if (PathUtils::isRelative(dir))
{
PathName newdir;
PathUtils::concatPath(newdir, root, dir);
dir = newdir;
}
add(ParsedPath(dir));
last = i + 1;
PathName fullPath;
PathUtils::concatPath(fullPath, root, dir);
dir = fullPath;
}
add(ParsedPath(dir));
}
PathName dir = "";
if (i > last)
{
dir = val.substr(last, i - last);
dir.trim();
}
if (PathUtils::isRelative(dir))
{
PathName newdir;
PathUtils::concatPath(newdir, root, dir);
dir = newdir;
}
add(ParsedPath(dir));
}
bool DirectoryList::isPathInList(const PathName& path) const
@ -211,15 +211,6 @@ bool DirectoryList::isPathInList(const PathName& path) const
return true;
}
// Disable any up-dir(..) references - in case our path_utils
// and OS handle paths in slightly different ways,
// this is "wonderful" potential hole for hacks
// Example of IIS attack attempt:
// "GET /scripts/..%252f../winnt/system32/cmd.exe?/c+dir HTTP/1.0"
// (live from apache access.log :)
if (path.find(PathUtils::up_dir_link) != PathName::npos)
return false;
PathName varpath(path);
if (PathUtils::isRelative(path)) {
PathUtils::concatPath(varpath, PathName(Config::getRootDirectory()), path);

View File

@ -39,6 +39,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "gen/iberror.h"
#include "../common/gdsassert.h"
@ -614,7 +615,7 @@ static void string_to_datetime(const dsc* desc,
while (++p < end)
{
if (*p != ' ' && *p != '\t' && *p != 0)
if (*p != ' ' && *p != '\t' && *p != '\0')
CVT_conversion_error(desc, err);
}
@ -698,7 +699,7 @@ static void string_to_datetime(const dsc* desc,
// We won't allow random trash after the recognized string
while (p < end)
{
if (*p != ' ' && *p != '\t' && p != 0)
if (*p != ' ' && *p != '\t' && *p != '\0')
{
CVT_conversion_error(desc, err);
return;
@ -1042,11 +1043,42 @@ SLONG CVT_get_long(const dsc* desc, SSHORT scale, ErrorFunction err)
// Get the value of a boolean descriptor.
bool CVT_get_boolean(const dsc* desc, ErrorFunction err)
{
if (desc->dsc_dtype == dtype_boolean)
return *desc->dsc_address != '\0';
switch (desc->dsc_dtype)
{
case dtype_boolean:
return *desc->dsc_address != '\0';
CVT_conversion_error(desc, err);
return false; // silence warning
case dtype_varying:
case dtype_cstring:
case dtype_text:
{
VaryStr<100> buffer; // arbitrarily large
const char* p = NULL;
int len = CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), err);
// Remove heading and trailing spaces.
while (len > 0 && isspace((UCHAR) *p))
{
++p;
--len;
}
while (len > 0 && isspace((UCHAR) p[len - 1]))
--len;
if (len == 4 && fb_utils::strnicmp(p, "TRUE", len) == 0)
return true;
else if (len == 5 && fb_utils::strnicmp(p, "FALSE", len) == 0)
return false;
// fall into
}
default:
CVT_conversion_error(desc, err);
return false; // silence warning
}
}
@ -1280,7 +1312,7 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb)
{
/**************************************
*
* C V T _ m o v e
* C V T _ m o v e _ c o m m o n
*
**************************************
*
@ -1618,10 +1650,23 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb)
datetime_to_text(from, to, cb);
return;
case dtype_boolean:
{
char* text = const_cast<char*>(*(FB_BOOLEAN*) from->dsc_address ? "TRUE" : "FALSE");
dsc intermediate;
intermediate.dsc_dtype = dtype_text;
intermediate.dsc_ttype() = ttype_ascii;
intermediate.makeText(static_cast<USHORT>(strlen(text)), CS_ASCII,
reinterpret_cast<UCHAR*>(text));
CVT_move_common(&intermediate, to, cb);
return;
}
default:
fb_assert(false); // Fall into ...
case dtype_boolean:
case dtype_blob:
CVT_conversion_error(from, cb->err);
return;
@ -1632,8 +1677,8 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb)
case dtype_array:
if (from->dsc_dtype == dtype_quad)
{
((SLONG *) p)[0] = ((SLONG *) q)[0];
((SLONG *) p)[1] = ((SLONG *) q)[1];
((SLONG*) p)[0] = ((SLONG*) q)[0];
((SLONG*) p)[1] = ((SLONG*) q)[1];
return;
}
@ -1715,7 +1760,28 @@ void CVT_move_common(const dsc* from, dsc* to, Callbacks* cb)
return;
case dtype_boolean:
CVT_conversion_error(from, cb->err);
switch (from->dsc_dtype)
{
case dtype_varying:
case dtype_cstring:
case dtype_text:
*((FB_BOOLEAN*) to->dsc_address) = CVT_get_boolean(from, cb->err) ? '\1' : '\0';
return;
default:
fb_assert(false); // Fall into ...
case dtype_sql_date:
case dtype_sql_time:
case dtype_short:
case dtype_long:
case dtype_int64:
case dtype_dbkey:
case dtype_quad:
case dtype_real:
case dtype_double:
CVT_conversion_error(from, cb->err);
break;
}
break;
}

View File

@ -1116,10 +1116,7 @@ void DSC_get_dtype_name(const dsc* desc, TEXT * buffer, USHORT len)
* Convert a datatype to its textual representation
*
**************************************/
// This function didn't put a string terminator even though
// it's calling strncpy that doesn't put it if source > target.
strncpy(buffer, DSC_dtype_tostring(desc->dsc_dtype), len);
buffer[len - 1] = 0;
fb_utils::copy_terminate(buffer, DSC_dtype_tostring(desc->dsc_dtype), len);
}

View File

@ -249,10 +249,7 @@ TEXT* ISC_get_host(TEXT* string, USHORT length)
struct utsname name;
if (uname(&name) >= 0)
{
strncpy(string, name.nodename, length);
string[length - 1] = 0;
}
fb_utils::copy_terminate(string, name.nodename, length);
else
strcpy(string, "local");

View File

@ -1244,8 +1244,7 @@ static void expand_share_name(tstring& share_name)
return;
}
strncpy(workspace, p, sizeof(workspace));
workspace[sizeof(workspace) - 1] = 0;
fb_utils::copy_terminate(workspace, p, sizeof(workspace));
// We test for *q, too, to avoid buffer overrun.
TEXT* q;
for (q = workspace; *q && *p && *p != '!'; p++, q++);
@ -1460,7 +1459,7 @@ bool Mnt::get()
**************************************/
TEXT device[128], mount_point[128], mount_type[16], rw[128], foo1[16];
TEXT device[MAXPATHLEN], mount_point[MAXPATHLEN], mount_type[16], rw[512], foo1[16];
const int n = fscanf(mtab, "%s %s %s %s %s %s", device, mount_point, mount_type, rw, foo1, foo1);
if (n < 0)

View File

@ -2815,7 +2815,7 @@ static bool initializeFastMutex(FAST_MUTEX* lpMutex, LPSECURITY_ATTRIBUTES lpAtt
LPCSTR name = lpName;
if (strlen(lpName) + strlen(FAST_MUTEX_EVT_NAME) - 2 >= MAXPATHLEN)
if (lpName && strlen(lpName) + strlen(FAST_MUTEX_EVT_NAME) - 2 >= MAXPATHLEN)
{
// this is the same error which CreateEvent will return for long name
SetLastError(ERROR_FILENAME_EXCED_RANGE);
@ -2900,7 +2900,7 @@ static bool openFastMutex(FAST_MUTEX* lpMutex, DWORD DesiredAccess, LPCSTR lpNam
{
LPCSTR name = lpName;
if (strlen(lpName) + strlen(FAST_MUTEX_EVT_NAME) - 2 >= MAXPATHLEN)
if (lpName && strlen(lpName) + strlen(FAST_MUTEX_EVT_NAME) - 2 >= MAXPATHLEN)
{
SetLastError(ERROR_FILENAME_EXCED_RANGE);
return false;

View File

@ -45,6 +45,9 @@ public:
/// The directory separator for the platform.
static const char dir_sep;
/// String used to point to current directory
static const char* curr_dir_link;
/// String used to point to parent directory
static const char* up_dir_link;

View File

@ -35,6 +35,7 @@
/// The POSIX implementation of the path_utils abstraction.
const char PathUtils::dir_sep = '/';
const char* PathUtils::curr_dir_link = ".";
const char* PathUtils::up_dir_link = "..";
const char PathUtils::dir_list_sep = ':';

View File

@ -7,6 +7,7 @@
/// The Win32 implementation of the path_utils abstraction.
const char PathUtils::dir_sep = '\\';
const char* PathUtils::curr_dir_link = ".";
const char* PathUtils::up_dir_link = "..";
const char PathUtils::dir_list_sep = ';';

View File

@ -89,7 +89,7 @@ void UserData::clear(Firebird::CheckStatusWrapper*)
}
// This function sets typical gsec return code based on requested operation if it was not set by plugin
int setGsecCode(int code, int operation)
int setGsecCode(int code, unsigned int operation)
{
if (code >= 0)
{

View File

@ -164,7 +164,7 @@ public:
{ }
// IUser implementation
int operation()
unsigned int operation()
{
return op;
}
@ -217,7 +217,8 @@ public:
void clear(Firebird::CheckStatusWrapper* status);
int op, trustedAuth;
unsigned int op;
int trustedAuth;
CharField user, pass, first, last, middle, com, attr;
IntField adm, act;
CharField database, dba, dbaPassword, role;
@ -262,7 +263,7 @@ public:
Get(Config* firebirdConf, const char* plugName);
};
int setGsecCode(int code, int operation);
int setGsecCode(int code, unsigned int operation);
// tools to operate lists of security-related plugins
typedef Firebird::ObjectsArray<Firebird::PathName> ParsedList;

View File

@ -348,6 +348,7 @@ ComparativeBoolNode::ComparativeBoolNode(MemoryPool& pool, UCHAR aBlrOp,
ValueExprNode* aArg1, ValueExprNode* aArg2, ValueExprNode* aArg3)
: TypedNode<BoolExprNode, ExprNode::TYPE_COMPARATIVE_BOOL>(pool),
blrOp(aBlrOp),
dsqlCheckBoolean(false),
dsqlFlag(DFLAG_NONE),
arg1(aArg1),
arg2(aArg2),
@ -454,6 +455,18 @@ BoolExprNode* ComparativeBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
procArg2,
doDsqlPass(dsqlScratch, procArg3));
if (dsqlCheckBoolean)
{
dsc desc;
MAKE_desc(dsqlScratch, &desc, node->arg1);
if (desc.dsc_dtype != dtype_boolean && !desc.isNull())
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
Arg::Gds(isc_invalid_boolean_usage));
}
}
switch (blrOp)
{
case blr_eql:
@ -480,18 +493,6 @@ BoolExprNode* ComparativeBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
PASS1_set_parameter_type(dsqlScratch, node->arg3, procArg2, false);
}
dsc desc1, desc2;
MAKE_desc(dsqlScratch, &desc1, node->arg1);
MAKE_desc(dsqlScratch, &desc2, procArg2);
if ((desc1.dsc_dtype == dtype_boolean || desc2.dsc_dtype == dtype_boolean) &&
!(desc1.isNull() || desc2.isNull()) && desc1.dsc_dtype != desc2.dsc_dtype)
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
Arg::Gds(isc_invalid_boolean_usage));
}
break;
}
@ -1571,6 +1572,7 @@ BoolExprNode* NotBoolNode::process(DsqlCompilerScratch* dsqlScratch, bool invert
ComparativeBoolNode* node = FB_NEW_POOL(getPool()) ComparativeBoolNode(
getPool(), newBlrOp, cmpArg->arg1, cmpArg->arg2);
node->dsqlSpecialArg = cmpArg->dsqlSpecialArg;
node->dsqlCheckBoolean = cmpArg->dsqlCheckBoolean;
if (cmpArg->dsqlFlag == ComparativeBoolNode::DFLAG_ANSI_ANY)
node->dsqlFlag = ComparativeBoolNode::DFLAG_ANSI_ALL;

View File

@ -102,6 +102,7 @@ private:
public:
UCHAR blrOp;
bool dsqlCheckBoolean;
DsqlFlag dsqlFlag;
NestConst<ValueExprNode> arg1;
NestConst<ValueExprNode> arg2;

View File

@ -390,6 +390,27 @@ void defineComputed(DsqlCompilerScratch* dsqlScratch, RelationSourceNode* relati
field->subType = desc.dsc_sub_type;
}
if (field && field->precision == 0 && field->scale != 0)
{
switch (field->dtype)
{
case dtype_short:
field->precision = 4;
break;
case dtype_long:
field->precision = 9;
break;
case dtype_int64:
field->precision = 18;
break;
default:
fb_assert(!DTYPE_IS_EXACT(field->dtype));
}
}
dsqlScratch->resetContextStack();
// Generate the source text.
@ -882,7 +903,7 @@ void DdlNode::storePrivileges(thread_db* tdbb, jrd_tra* transaction,
const char* privileges)
{
Attachment* const attachment = transaction->tra_attachment;
const string& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->usr_user_name;
AutoCacheRequest request(tdbb, drq_s_usr_prvs, DYN_REQUESTS);
@ -945,7 +966,7 @@ void DdlNode::storeGlobalField(thread_db* tdbb, jrd_tra* transaction, MetaName&
const TypeClause* field, const string& computedSource, const BlrDebugWriter::BlrData& computedValue)
{
Attachment* const attachment = transaction->tra_attachment;
const string& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->usr_user_name;
const ValueListNode* elements = field->ranges;
const USHORT dims = elements ? elements->items.getCount() / 2 : 0;
@ -1653,7 +1674,7 @@ void CreateAlterFunctionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch
jrd_tra* transaction)
{
Attachment* const attachment = transaction->getAttachment();
const string& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->usr_user_name;
if (package.isEmpty())
{
@ -2640,7 +2661,7 @@ void CreateAlterProcedureNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc
jrd_tra* transaction)
{
Attachment* const attachment = transaction->getAttachment();
const string& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->usr_user_name;
if (package.isEmpty())
{
@ -3780,7 +3801,7 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
jrd_tra* transaction)
{
Attachment* const attachment = transaction->tra_attachment;
const string& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->usr_user_name;
// run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction);
@ -5243,7 +5264,7 @@ void CreateAlterExceptionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc
jrd_tra* transaction)
{
Attachment* const attachment = transaction->getAttachment();
const string& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->usr_user_name;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
DDL_TRIGGER_CREATE_EXCEPTION, name, NULL);
@ -5616,7 +5637,7 @@ SSHORT CreateAlterSequenceNode::store(thread_db* tdbb, jrd_tra* transaction, con
fb_sysflag sysFlag, SINT64 val, SLONG step)
{
Attachment* const attachment = transaction->tra_attachment;
const string& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->usr_user_name;
DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_generator);
@ -8283,7 +8304,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
jrd_tra* transaction)
{
Attachment* const attachment = transaction->tra_attachment;
const string& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->usr_user_name;
const dsql_rel* modifyingView = NULL;
@ -10603,7 +10624,7 @@ void CreateAlterUserNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
Auth::DynamicUserData* userData = FB_NEW_POOL(*transaction->tra_pool) Auth::DynamicUserData;
string text = name.c_str();
MetaName text = name.c_str();
if (text.isEmpty() && mode == USER_MOD)
{
// alter current user
@ -10804,12 +10825,15 @@ void GrantRevokeNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
if (grantAdminOption)
option = 2; // with admin option
const GranteeClause* rolesPtr = roles.begin();
const GranteeClause* rolesEnd = roles.end();
for (const GranteeClause* rolesPtr = roles.begin(); rolesPtr != rolesEnd; ++rolesPtr)
const bool* defaultRolesPtr = defaultRoles.begin();
for (; rolesPtr != rolesEnd; ++rolesPtr, ++defaultRolesPtr)
{
usersEnd = users.end();
const bool defaultRole = *defaultRolesPtr;
for (usersPtr = users.begin(); usersPtr != usersEnd; ++usersPtr)
grantRevoke(tdbb, transaction, rolesPtr, usersPtr, "M", NULL, option);
grantRevoke(tdbb, transaction, rolesPtr, usersPtr, "M", defaultRole ? "D" : NULL, option);
}
}
}
@ -10943,13 +10967,13 @@ void GrantRevokeNode::modifyPrivileges(thread_db* tdbb, jrd_tra* transaction, SS
// Execute SQL grant/revoke operation.
void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const GranteeClause* object,
const GranteeClause* userNod, const char* privs,
const MetaName& field, int options)
MetaName field, int options)
{
SSHORT userType = userNod->first;
MetaName user(userNod->second);
MetaName dummyName;
MetaName dummyName;
const SSHORT objType = object ? object->first : obj_type_MAX;
bool crdb = false;
bool crdb = false;
char privileges[16];
strcpy(privileges, privs ? privs : "");
@ -11115,7 +11139,8 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
PRIV.RDB$USER = user.c_str() AND
PRIV.RDB$USER_TYPE = userType AND
PRIV.RDB$GRANTOR EQ grantorRevoker.c_str() AND
PRIV.RDB$FIELD_NAME EQUIV NULLIF(field.c_str(), '')
(PRIV.RDB$FIELD_NAME EQUIV NULLIF(field.c_str(), '') OR
(PRIV.RDB$OBJECT_TYPE EQ obj_sql_role))
{
if (PRIV.RDB$GRANT_OPTION.NULL ||
PRIV.RDB$GRANT_OPTION ||
@ -11123,8 +11148,22 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
{
duplicate = true;
}
else
ERASE PRIV; // has to be 0 and options == 1
else if (!PRIV.RDB$FIELD_NAME.NULL)
{
field = PRIV.RDB$FIELD_NAME; // Keep DEFAULT ROLE while adding ADMIN OPTION
}
if (duplicate && objType == obj_sql_role && field == "D" &&
PRIV.RDB$FIELD_NAME.NULL)
{
// We have to reset duplicate to add DEFAULT ROLE and keep options to prevent reset of ADMIN OPTION
duplicate = false;
options = PRIV.RDB$GRANT_OPTION;
}
if (!duplicate)
ERASE PRIV;
}
END_FOR
@ -11137,9 +11176,12 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
if (userType == obj_sql_role)
{
// Temporary restriction. This should be removed once GRANT role1 TO rolex is
// supported and this message could be reused for blocking cycles of role grants.
status_exception::raise(Arg::PrivateDyn(192) << user.c_str());
// Check for blocking cycles of role grants.
Firebird::SortedArray<Firebird::MetaName> grantedRoles;
SCL_find_granted_roles(tdbb, objName, true, grantedRoles, false);
// 292: role @1 can not be granted to role @2
if (grantedRoles.exist(user.c_str()))
status_exception::raise(Arg::PrivateDyn(292) << objName.c_str() << user.c_str());
}
}
else
@ -11175,6 +11217,10 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
}
else // REVOKE
{
const bool revokeRoleDefault = (objType == obj_sql_role) && field.hasData();
MetaName curField;
int curOptions = options;
AutoCacheRequest request(tdbb, (field.hasData() ? drq_e_grant1 : drq_e_grant2), DYN_REQUESTS);
for (const char* pr = privileges; (priv[0] = *pr); ++pr)
@ -11182,7 +11228,7 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
bool grantErased = false;
bool badGrantor = false;
if (field.hasData())
if (field.hasData() && objType != obj_sql_role)
{
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
PRIV IN RDB$USER_PRIVILEGES
@ -11221,6 +11267,8 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
if (grantorRevoker == PRIV.RDB$GRANTOR)
{
curOptions = PRIV.RDB$GRANT_OPTION;
curField = PRIV.RDB$FIELD_NAME;
ERASE PRIV;
grantErased = true;
}
@ -11230,26 +11278,34 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
END_FOR
}
if (options && grantErased)
if (grantErased)
{
// Add the privilege without the grant option. There is a modify trigger on the
// rdb$user_privileges which disallows the table from being updated. It would have
// to be changed such that only the grant_option field can be updated.
if (revokeRoleDefault)
{
// Add role grant again without default
storePrivilege(tdbb, transaction, objName, user, NULL, pr, userType, objType,
curOptions, grantorRevoker);
}
else if (options)
{
// Add the privilege without the grant option. There is a modify trigger on the
// rdb$user_privileges which disallows the table from being updated. It would have
// to be changed such that only the grant_option field can be updated.
storePrivilege(tdbb, transaction, objName, user, field, pr, userType, objType,
0, grantorRevoker);
storePrivilege(tdbb, transaction, objName, user, curField, pr, userType, objType,
0, grantorRevoker);
}
}
if (badGrantor && !grantErased)
else
{
// msg 246: @1 is not grantor of @2 on @3 to @4.
status_exception::raise(Arg::PrivateDyn(246) <<
grantorRevoker.c_str() << privilegeName(priv[0]) << objName.c_str() <<
user.c_str());
}
if (badGrantor)
{
// msg 246: @1 is not grantor of @2 on @3 to @4.
status_exception::raise(Arg::PrivateDyn(246) <<
grantorRevoker.c_str() << privilegeName(priv[0]) << objName.c_str() <<
user.c_str());
}
if (!grantErased)
{
// msg 247: Warning: @1 on @2 is not granted to @3.
ERR_post_warning(
Arg::Warning(isc_dyn_miss_priv_warning) <<
@ -11457,7 +11513,57 @@ void GrantRevokeNode::checkGrantorCanGrant(thread_db* tdbb, jrd_tra* transaction
END_FOR
}
// Check if the grantor has admin privilege on the role.
/*
* Function takes a role and grantor name and go through all roles granted to specified one.
* If found target role with admin option returns 2, without admin option - 1.
* Otherwise returns 0;
*
*/
int getGrantorOption(thread_db* tdbb, jrd_tra* transaction, const MetaName& grantor, int grantorType, const MetaName& roleName)
{
AutoCacheRequest request(tdbb, drq_get_role_au, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
PRV IN RDB$USER_PRIVILEGES WITH
PRV.RDB$USER = UPPERCASE(grantor.c_str()) AND
PRV.RDB$USER_TYPE = grantorType AND
PRV.RDB$OBJECT_TYPE = obj_sql_role AND
PRV.RDB$PRIVILEGE EQ "M"
{
const Firebird::MetaName role = PRV.RDB$RELATION_NAME;
const bool grantable = PRV.RDB$GRANT_OPTION == 2;
if (role == roleName)
{
return grantable ? 2 : 1;
}
else
{
switch (getGrantorOption(tdbb, transaction, role, obj_sql_role, roleName))
{
case 0:
continue;
case 1: // call found roleName we should stop searching
return 1;
case 2: // call found roleName with admin option but have we admin option of intermediate roles?
return grantable ? 2 : 1;
}
}
}
END_FOR
// we and calls did not found granted roleName and have to return 0
return 0;
}
/*
* Check if the grantor has admin privilege on the role or admin privilege on another role
* which has admin privilege on it, etc
* If recoursive call of getGrantorOption returns:
* 0 - role does not grant to grantor.
* 1 - found but without admin option.
* 2 - with admin option.
*/
void GrantRevokeNode::checkGrantorCanGrantRole(thread_db* tdbb, jrd_tra* transaction,
const MetaName& grantor, const MetaName& roleName)
{
@ -11475,32 +11581,13 @@ void GrantRevokeNode::checkGrantorCanGrantRole(thread_db* tdbb, jrd_tra* transac
status_exception::raise(Arg::PrivateDyn(188) << roleName.c_str());
}
AutoCacheRequest request(tdbb, drq_get_role_au, DYN_REQUESTS);
bool grantable = false;
bool noAdmin = false;
const int r = getGrantorOption(tdbb, transaction, grantor, obj_user, roleName);
// The 'grantor' is not the owner of the ROLE, see if they have admin privilege on the role.
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
PRV IN RDB$USER_PRIVILEGES WITH
PRV.RDB$USER = UPPERCASE(grantor.c_str()) AND
PRV.RDB$USER_TYPE = obj_user AND
PRV.RDB$RELATION_NAME EQ roleName.c_str() AND
PRV.RDB$OBJECT_TYPE = obj_sql_role AND
PRV.RDB$PRIVILEGE EQ "M"
{
if (PRV.RDB$GRANT_OPTION == 2)
grantable = true;
else
noAdmin = true;
}
END_FOR
if (!grantable)
if (r < 2)
{
// 189: user have no admin option.
// 190: user is not a member of the role.
status_exception::raise(Arg::PrivateDyn(noAdmin ? 189 : 190) <<
grantor.c_str() << roleName.c_str());
status_exception::raise(Arg::PrivateDyn(r ? 189 : 190) << grantor.c_str() << roleName.c_str());
}
}
@ -11599,7 +11686,6 @@ void GrantRevokeNode::setFieldClassName(thread_db* tdbb, jrd_tra* transaction,
END_FOR
}
//----------------------

View File

@ -34,7 +34,7 @@
#include "../common/classes/array.h"
#include "../common/classes/ByteChunk.h"
#include "../common/classes/Nullable.h"
#include "../jrd/vio_proto.h"
#include "../jrd/Savepoint.h"
#include "../dsql/errd_proto.h"
namespace Jrd {
@ -405,7 +405,7 @@ public:
bool compiled;
bool invalid;
Firebird::MetaName package;
Firebird::string packageOwner;
Firebird::MetaName packageOwner;
bool privateScope;
bool preserveDefaults;
SLONG udfReturnPos;
@ -539,7 +539,7 @@ public:
bool compiled;
bool invalid;
Firebird::MetaName package;
Firebird::string packageOwner;
Firebird::MetaName packageOwner;
bool privateScope;
bool preserveDefaults;
};
@ -2118,6 +2118,7 @@ public:
isGrant(aIsGrant),
privileges(p),
roles(p),
defaultRoles(p),
object(NULL),
users(p),
grantAdminOption(false),
@ -2142,7 +2143,7 @@ protected:
private:
void modifyPrivileges(thread_db* tdbb, jrd_tra* transaction, SSHORT option, const GranteeClause* user);
void grantRevoke(thread_db* tdbb, jrd_tra* transaction, const GranteeClause* object,
const GranteeClause* userNod, const char* privs, const Firebird::MetaName& field, int options);
const GranteeClause* userNod, const char* privs, Firebird::MetaName field, int options);
static void checkGrantorCanGrant(thread_db* tdbb, jrd_tra* transaction, const char* grantor,
const char* privilege, const Firebird::MetaName& relationName,
const Firebird::MetaName& fieldName, bool topLevel);
@ -2197,6 +2198,7 @@ public:
bool isGrant;
Firebird::Array<PrivilegeClause> privileges;
Firebird::Array<GranteeClause> roles;
Firebird::Array<bool> defaultRoles;
NestConst<GranteeClause> object;
Firebird::Array<GranteeClause> users;
bool grantAdminOption;

View File

@ -2787,49 +2787,6 @@ dsc* CastNode::execute(thread_db* tdbb, jrd_req* request) const
if (!value)
return NULL;
dsc desc;
char* text;
UCHAR tempByte;
if (value->dsc_dtype == dtype_boolean &&
(DTYPE_IS_TEXT(impure->vlu_desc.dsc_dtype) || DTYPE_IS_BLOB(impure->vlu_desc.dsc_dtype)))
{
text = const_cast<char*>(MOV_get_boolean(value) ? "TRUE" : "FALSE");
desc.makeText(static_cast<USHORT>(strlen(text)), CS_ASCII, reinterpret_cast<UCHAR*>(text));
value = &desc;
}
else if (impure->vlu_desc.dsc_dtype == dtype_boolean &&
(DTYPE_IS_TEXT(value->dsc_dtype) || DTYPE_IS_BLOB(value->dsc_dtype)))
{
desc.makeBoolean(&tempByte);
MoveBuffer buffer;
UCHAR* address;
int len = MOV_make_string2(tdbb, value, CS_ASCII, &address, buffer);
// Remove heading and trailing spaces.
while (len > 0 && isspace(*address))
{
++address;
--len;
}
while (len > 0 && isspace(address[len - 1]))
--len;
if (len == 4 && fb_utils::strnicmp(reinterpret_cast<char*>(address), "TRUE", len) == 0)
{
tempByte = '\1';
value = &desc;
}
else if (len == 5 && fb_utils::strnicmp(reinterpret_cast<char*>(address), "FALSE", len) == 0)
{
tempByte = '\0';
value = &desc;
}
}
if (DTYPE_IS_BLOB(value->dsc_dtype) || DTYPE_IS_BLOB(impure->vlu_desc.dsc_dtype))
blb::move(tdbb, value, &impure->vlu_desc, NULL);
else
@ -11133,8 +11090,8 @@ dsc* UdfCallNode::execute(thread_db* tdbb, jrd_req* request) const
}
jrd_tra* transaction = request->req_transaction;
const SLONG savePointNumber = transaction->tra_save_point ?
transaction->tra_save_point->sav_number : 0;
const SavNumber savNumber = transaction->tra_save_point ?
transaction->tra_save_point->getNumber() : 0;
jrd_req* funcRequest = function->getStatement()->findRequest(tdbb);
@ -11158,10 +11115,10 @@ dsc* UdfCallNode::execute(thread_db* tdbb, jrd_req* request) const
// Clean up all savepoints started during execution of the procedure.
if (transaction != attachment->getSysTransaction())
if (!(transaction->tra_flags & TRA_system))
{
while (transaction->tra_save_point &&
transaction->tra_save_point->sav_number > savePointNumber)
transaction->tra_save_point->getNumber() > savNumber)
{
transaction->rollforwardSavepoint(tdbb);
}

View File

@ -491,7 +491,7 @@ void CreateAlterPackageNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch*
jrd_tra* transaction)
{
Attachment* attachment = transaction->getAttachment();
const string& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->usr_user_name;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
DDL_TRIGGER_CREATE_PACKAGE, name, NULL);

View File

@ -112,7 +112,7 @@ public:
Firebird::SortedArray<Firebird::MetaName> procedureNames;
private:
Firebird::string owner;
Firebird::MetaName owner;
};

View File

@ -800,9 +800,9 @@ int Parser::yylexAux()
if (charlen > 8)
{
char cbuff[32];
fb_assert(charlen <= 16); // charlen is always <= 16, see 10-15 lines upper
cbuff[0] = 'X';
strncpy(&cbuff[1], hexstring, charlen);
cbuff[charlen + 1] = '\0';
fb_utils::copy_terminate(&cbuff[1], hexstring, charlen + 1);
char* p = &cbuff[1];
UCHAR byte = 0;

View File

@ -188,8 +188,8 @@ public:
private:
template <typename T> T* setupNode(Node* node)
{
node->line = (ULONG) lex.lines_bk;
node->column = (ULONG) (lex.last_token_bk - lex.line_start_bk + 1);
node->line = yyposn.firstLine;
node->column = yyposn.firstColumn;
return static_cast<T*>(node);
}
@ -213,6 +213,8 @@ private:
ComparativeBoolNode* cmpNode = newNode<ComparativeBoolNode>(
blr_eql, value, MAKE_constant("1", CONSTANT_BOOLEAN));
cmpNode->dsqlCheckBoolean = true;
return cmpNode;
}

View File

@ -223,6 +223,16 @@ namespace
AutoSetRestore<USHORT> autoFlags;
AutoSetRestore<USHORT> autoScopeLevel;
};
class SavepointChangeMarker : public Savepoint::ChangeMarker
{
public:
explicit SavepointChangeMarker(jrd_tra* transaction)
: Savepoint::ChangeMarker(transaction->tra_flags & TRA_system ?
NULL : transaction->tra_save_point)
{}
};
} // namespace
@ -507,7 +517,7 @@ BlockNode* BlockNode::pass2(thread_db* tdbb, CompilerScratch* csb)
doPass2(tdbb, csb, action.getAddress(), this);
doPass2(tdbb, csb, handlers.getAddress(), this);
impureOffset = CMP_impure(csb, sizeof(SLONG));
impureOffset = CMP_impure(csb, sizeof(SavNumber));
return this;
}
@ -515,18 +525,16 @@ BlockNode* BlockNode::pass2(thread_db* tdbb, CompilerScratch* csb)
const StmtNode* BlockNode::execute(thread_db* tdbb, jrd_req* request, ExeState* exeState) const
{
jrd_tra* transaction = request->req_transaction;
jrd_tra* sysTransaction = request->req_attachment->getSysTransaction();
SLONG count;
SavNumber savNumber;
switch (request->req_operation)
{
case jrd_req::req_evaluate:
if (transaction != sysTransaction)
if (!(transaction->tra_flags & TRA_system))
{
VIO_start_save_point(tdbb, transaction);
const Savepoint* save_point = transaction->tra_save_point;
count = save_point->sav_number;
*request->getImpure<SLONG>(impureOffset) = count;
const Savepoint* const savepoint = transaction->startSavepoint();
savNumber = savepoint->getNumber();
*request->getImpure<SavNumber>(impureOffset) = savNumber;
}
return action;
@ -540,12 +548,12 @@ const StmtNode* BlockNode::execute(thread_db* tdbb, jrd_req* request, ExeState*
// BREAK/LEAVE/CONTINUE statement in the SP/trigger code.
// Do not perform the error handling stuff.
if (transaction != sysTransaction)
if (!(transaction->tra_flags & TRA_system))
{
count = *request->getImpure<SLONG>(impureOffset);
savNumber = *request->getImpure<SavNumber>(impureOffset);
while (transaction->tra_save_point &&
transaction->tra_save_point->sav_number >= count)
transaction->tra_save_point->getNumber() >= savNumber)
{
transaction->rollforwardSavepoint(tdbb);
}
@ -554,37 +562,38 @@ const StmtNode* BlockNode::execute(thread_db* tdbb, jrd_req* request, ExeState*
return parentStmt;
}
const StmtNode* temp;
const StmtNode* temp = parentStmt;
if (handlers && handlers->statements.getCount() > 0)
if (handlers && handlers->statements.hasData())
{
// First of all rollback failed work
if (transaction != sysTransaction)
if (!(transaction->tra_flags & TRA_system))
{
count = *request->getImpure<SLONG>(impureOffset);
savNumber = *request->getImpure<SavNumber>(impureOffset);
// Since there occurred an error (req_unwind), undo all savepoints
// up to, _but not including_, the savepoint of this block.
// That's why transaction->rollbackToSavepoint() cannot be used here
// The savepoint of this block will be dealt with below.
// Do this only if error handlers exist. If not - leave rollbacking to caller node
while (transaction->tra_save_point &&
count < transaction->tra_save_point->sav_number &&
transaction->tra_save_point->sav_next &&
count < transaction->tra_save_point->sav_next->sav_number)
savNumber < transaction->tra_save_point->getNumber() &&
transaction->tra_save_point->getNext() &&
savNumber < transaction->tra_save_point->getNext()->getNumber())
{
transaction->rollforwardSavepoint(tdbb);
}
// There can be no savepoints above the given one
if (transaction->tra_save_point && transaction->tra_save_point->sav_number > count)
{
if (transaction->tra_save_point && transaction->tra_save_point->getNumber() > savNumber)
transaction->rollbackSavepoint(tdbb);
}
// after that we still have to have our savepoint. If not - CORE-4424/4483 is sneaking around
fb_assert(transaction->tra_save_point && transaction->tra_save_point->sav_number == count);
fb_assert(transaction->tra_save_point && transaction->tra_save_point->getNumber() == savNumber);
}
temp = parentStmt;
bool handled = false;
const NestConst<StmtNode>* ptr = handlers->statements.begin();
@ -592,13 +601,11 @@ const StmtNode* BlockNode::execute(thread_db* tdbb, jrd_req* request, ExeState*
ptr != end;
++ptr)
{
const ErrorHandlerNode* handlerNode = (*ptr)->as<ErrorHandlerNode>();
const ExceptionArray& xcpNode = handlerNode->conditions;
const ErrorHandlerNode* const handlerNode = (*ptr)->as<ErrorHandlerNode>();
if (testAndFixupError(tdbb, request, xcpNode))
if (testAndFixupError(tdbb, request, handlerNode->conditions))
{
request->req_operation = jrd_req::req_evaluate;
temp = handlerNode->action;
exeState->errorPending = false;
// On entering looper exeState->oldRequest etc. are saved.
@ -618,7 +625,7 @@ const StmtNode* BlockNode::execute(thread_db* tdbb, jrd_req* request, ExeState*
const ULONG prev_req_error_handler =
request->req_flags & req_error_handler;
request->req_flags |= req_error_handler;
temp = EXE_looper(tdbb, request, temp);
temp = EXE_looper(tdbb, request, handlerNode->action);
request->req_flags &= ~req_error_handler;
request->req_flags |= prev_req_error_handler;
@ -640,13 +647,12 @@ const StmtNode* BlockNode::execute(thread_db* tdbb, jrd_req* request, ExeState*
request->req_caller = exeState->oldRequest;
handled = true;
}
}
}
// The error is dealt with by the application, cleanup
// this block's savepoint.
if (handled && transaction != sysTransaction)
if (handled && !(transaction->tra_flags & TRA_system))
{
// Check that exception handlers were executed in context of right savepoint.
// If not - mirror copy of CORE-4424 or CORE-4483 is around here.
@ -656,18 +662,17 @@ const StmtNode* BlockNode::execute(thread_db* tdbb, jrd_req* request, ExeState*
// outer before
// outer after (this block)
// inner after
// Because of this following assert is commentd out
//fb_assert(transaction->tra_save_point && transaction->tra_save_point->sav_number == count);
// Because of this following assert is commented out
//fb_assert(transaction->tra_save_point && transaction->tra_save_point->getNumber() == savNumber);
for (const Savepoint* save_point = transaction->tra_save_point;
save_point && count <= save_point->sav_number;
save_point && savNumber <= save_point->getNumber();
save_point = transaction->tra_save_point)
{
transaction->rollforwardSavepoint(tdbb);
}
}
}
else
temp = parentStmt;
// If the application didn't have an error handler, then
// the error will still be pending. Leave undo to outer blocks.
@ -676,13 +681,13 @@ const StmtNode* BlockNode::execute(thread_db* tdbb, jrd_req* request, ExeState*
}
case jrd_req::req_return:
if (transaction != sysTransaction)
if (!(transaction->tra_flags & TRA_system))
{
count = *request->getImpure<SLONG>(impureOffset);
savNumber = *request->getImpure<SavNumber>(impureOffset);
// rollforward all savepoints
for (const Savepoint* save_point = transaction->tra_save_point;
save_point && save_point->sav_next && count <= save_point->sav_number;
save_point && save_point->getNext() && savNumber <= save_point->getNumber();
save_point = transaction->tra_save_point)
{
transaction->rollforwardSavepoint(tdbb);
@ -2351,7 +2356,6 @@ const StmtNode* EraseNode::execute(thread_db* tdbb, jrd_req* request, ExeState*
// Perform erase operation.
const StmtNode* EraseNode::erase(thread_db* tdbb, jrd_req* request, WhichTrigger whichTrig) const
{
Jrd::Attachment* attachment = tdbb->getAttachment();
jrd_tra* transaction = request->req_transaction;
record_param* rpb = &request->req_rpb[stream];
jrd_rel* relation = rpb->rpb_relation;
@ -2393,12 +2397,11 @@ const StmtNode* EraseNode::erase(thread_db* tdbb, jrd_req* request, WhichTrigger
if (rpb->rpb_runtime_flags & RPB_refetch)
{
VIO_refetch_record(tdbb, rpb, transaction, false);
VIO_refetch_record(tdbb, rpb, transaction, false, false);
rpb->rpb_runtime_flags &= ~RPB_refetch;
}
if (transaction != attachment->getSysTransaction())
++transaction->tra_save_point->sav_verb_count;
SavepointChangeMarker scMarker(transaction);
// Handle pre-operation trigger.
preModifyEraseTriggers(tdbb, &relation->rel_pre_erase, whichTrig, rpb, NULL, TRIGGER_DELETE);
@ -2423,31 +2426,12 @@ const StmtNode* EraseNode::erase(thread_db* tdbb, jrd_req* request, WhichTrigger
if (!relation->rel_file && !relation->rel_view_rse && !relation->isVirtual())
IDX_erase(tdbb, rpb, transaction);
// CVC: Increment the counter only if we called VIO/EXT_erase() and we were successful.
if (!(request->req_view_flags & req_first_erase_return))
{
request->req_view_flags |= req_first_erase_return;
if (relation->rel_view_rse)
request->req_top_view_erase = relation;
}
if (relation == request->req_top_view_erase)
{
if (whichTrig == ALL_TRIGS || whichTrig == POST_TRIG)
{
request->req_records_deleted++;
request->req_records_affected.bumpModified(true);
}
}
else if (relation->rel_file || !relation->rel_view_rse)
if (!relation->rel_view_rse || (whichTrig == ALL_TRIGS || whichTrig == POST_TRIG))
{
request->req_records_deleted++;
request->req_records_affected.bumpModified(true);
}
if (transaction != attachment->getSysTransaction())
--transaction->tra_save_point->sav_verb_count;
rpb->rpb_number.setValid(false);
return parentStmt;
@ -2930,8 +2914,6 @@ void ExecProcedureNode::executeProcedure(thread_db* tdbb, jrd_req* request) cons
Arg::Str(procedure->getName().identifier) << Arg::Str(procedure->getName().package));
}
Jrd::Attachment* attachment = tdbb->getAttachment();
ULONG inMsgLength = 0;
UCHAR* inMsg = NULL;
@ -2971,8 +2953,8 @@ void ExecProcedureNode::executeProcedure(thread_db* tdbb, jrd_req* request) cons
}
jrd_tra* transaction = request->req_transaction;
const SLONG savePointNumber = transaction->tra_save_point ?
transaction->tra_save_point->sav_number : 0;
const SavNumber savNumber = transaction->tra_save_point ?
transaction->tra_save_point->getNumber() : 0;
jrd_req* procRequest = procedure->getStatement()->findRequest(tdbb);
@ -2994,10 +2976,10 @@ void ExecProcedureNode::executeProcedure(thread_db* tdbb, jrd_req* request) cons
// Clean up all savepoints started during execution of the procedure.
if (transaction != attachment->getSysTransaction())
if (!(transaction->tra_flags & TRA_system))
{
while (transaction->tra_save_point &&
transaction->tra_save_point->sav_number > savePointNumber)
transaction->tra_save_point->getNumber() > savNumber)
{
transaction->rollforwardSavepoint(tdbb);
}
@ -3704,8 +3686,8 @@ const StmtNode* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* r
request->req_auto_trans.push(org_transaction);
impure->traNumber = transaction->tra_number;
VIO_start_save_point(tdbb, transaction);
impure->savNumber = transaction->tra_save_point->sav_number;
const Savepoint* const savepoint = transaction->startSavepoint();
impure->savNumber = savepoint->getNumber();
if (!(attachment->att_flags & ATT_no_db_triggers))
{
@ -3717,7 +3699,7 @@ const StmtNode* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* r
}
jrd_tra* transaction = request->req_transaction;
fb_assert(transaction && transaction != attachment->getSysTransaction());
fb_assert(transaction && !(transaction->tra_flags & TRA_system));
if (!impure->traNumber)
return parentStmt;
@ -3734,8 +3716,8 @@ const StmtNode* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* r
}
if (transaction->tra_save_point &&
!(transaction->tra_save_point->sav_flags & SAV_user) &&
!transaction->tra_save_point->sav_verb_count)
transaction->tra_save_point->isSystem() &&
transaction->tra_save_point->isChanging())
{
transaction->rollforwardSavepoint(tdbb);
}
@ -3759,8 +3741,8 @@ const StmtNode* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* r
}
if (transaction->tra_save_point &&
!(transaction->tra_save_point->sav_flags & SAV_user) &&
!transaction->tra_save_point->sav_verb_count)
transaction->tra_save_point->isSystem() &&
transaction->tra_save_point->isChanging())
{
transaction->rollforwardSavepoint(tdbb);
}
@ -4689,7 +4671,7 @@ StmtNode* ForNode::pass2(thread_db* tdbb, CompilerScratch* csb)
// as implicit cursors are always positioned in a valid record, and the name is
// only used to raise isc_cursor_not_positioned.
impureOffset = CMP_impure(csb, sizeof(SLONG));
impureOffset = CMP_impure(csb, sizeof(SavNumber));
return this;
}
@ -4697,18 +4679,17 @@ StmtNode* ForNode::pass2(thread_db* tdbb, CompilerScratch* csb)
const StmtNode* ForNode::execute(thread_db* tdbb, jrd_req* request, ExeState* /*exeState*/) const
{
jrd_tra* transaction = request->req_transaction;
jrd_tra* sysTransaction = request->req_attachment->getSysTransaction();
switch (request->req_operation)
{
case jrd_req::req_evaluate:
*request->getImpure<SLONG>(impureOffset) = 0;
if (transaction != sysTransaction &&
transaction->tra_save_point && transaction->tra_save_point->sav_verb_actions)
*request->getImpure<SavNumber>(impureOffset) = 0;
if (!(transaction->tra_flags & TRA_system) &&
transaction->tra_save_point &&
transaction->tra_save_point->hasChanges())
{
VIO_start_save_point(tdbb, transaction);
const Savepoint* save_point = transaction->tra_save_point;
*request->getImpure<SLONG>(impureOffset) = save_point->sav_number;
const Savepoint* const savepoint = transaction->startSavepoint();
*request->getImpure<SavNumber>(impureOffset) = savepoint->getNumber();
}
cursor->open(tdbb);
request->req_records_affected.clear();
@ -4745,14 +4726,17 @@ const StmtNode* ForNode::execute(thread_db* tdbb, jrd_req* request, ExeState* /*
default:
{
const SLONG sav_number = *request->getImpure<SLONG>(impureOffset);
const SavNumber savNumber = *request->getImpure<SavNumber>(impureOffset);
if (sav_number)
if (savNumber)
{
while (transaction->tra_save_point &&
transaction->tra_save_point->sav_number >= sav_number)
transaction->tra_save_point->getNumber() >= savNumber)
{
VIO_verb_cleanup(tdbb, transaction);
if (transaction->tra_save_point->isChanging()) // we must rollback this savepoint
transaction->rollbackSavepoint(tdbb);
else
transaction->rollforwardSavepoint(tdbb);
}
}
@ -6107,7 +6091,6 @@ const StmtNode* ModifyNode::execute(thread_db* tdbb, jrd_req* request, ExeState*
// Execute a MODIFY statement.
const StmtNode* ModifyNode::modify(thread_db* tdbb, jrd_req* request, WhichTrigger whichTrig) const
{
Jrd::Attachment* attachment = tdbb->getAttachment();
jrd_tra* transaction = request->req_transaction;
impure_state* impure = request->getImpure<impure_state>(impureOffset);
@ -6142,8 +6125,7 @@ const StmtNode* ModifyNode::modify(thread_db* tdbb, jrd_req* request, WhichTrigg
// varchar field whose tail may contain garbage.
cleanupRpb(tdbb, newRpb);
if (transaction != attachment->getSysTransaction())
++transaction->tra_save_point->sav_verb_count;
SavepointChangeMarker scMarker(transaction);
preModifyEraseTriggers(tdbb, &relation->rel_pre_modify, whichTrig, orgRpb, newRpb,
TRIGGER_UPDATE);
@ -6177,28 +6159,8 @@ const StmtNode* ModifyNode::modify(thread_db* tdbb, jrd_req* request, WhichTrigg
if (!relation->rel_file && !relation->rel_view_rse && !relation->isVirtual())
IDX_modify_check_constraints(tdbb, orgRpb, newRpb, transaction);
if (transaction != attachment->getSysTransaction())
--transaction->tra_save_point->sav_verb_count;
// CVC: Increment the counter only if we called VIO/EXT_modify() and
// we were successful.
if (!(request->req_view_flags & req_first_modify_return))
{
request->req_view_flags |= req_first_modify_return;
if (relation->rel_view_rse)
request->req_top_view_modify = relation;
}
if (relation == request->req_top_view_modify)
{
if (!subMod && (whichTrig == ALL_TRIGS || whichTrig == POST_TRIG))
{
request->req_records_updated++;
request->req_records_affected.bumpModified(true);
}
}
else if (relation->rel_file || !relation->rel_view_rse)
if (!relation->rel_view_rse ||
(!subMod && (whichTrig == ALL_TRIGS || whichTrig == POST_TRIG)))
{
request->req_records_updated++;
request->req_records_affected.bumpModified(true);
@ -6232,7 +6194,7 @@ const StmtNode* ModifyNode::modify(thread_db* tdbb, jrd_req* request, WhichTrigg
if (orgRpb->rpb_runtime_flags & RPB_refetch)
{
VIO_refetch_record(tdbb, orgRpb, transaction, false);
VIO_refetch_record(tdbb, orgRpb, transaction, false, false);
orgRpb->rpb_runtime_flags &= ~RPB_refetch;
}
@ -6959,7 +6921,6 @@ const StmtNode* StoreNode::execute(thread_db* tdbb, jrd_req* request, ExeState*
// Execute a STORE statement.
const StmtNode* StoreNode::store(thread_db* tdbb, jrd_req* request, WhichTrigger whichTrig) const
{
Jrd::Attachment* attachment = tdbb->getAttachment();
jrd_tra* transaction = request->req_transaction;
impure_state* impure = request->getImpure<impure_state>(impureOffset);
@ -6979,79 +6940,61 @@ const StmtNode* StoreNode::store(thread_db* tdbb, jrd_req* request, WhichTrigger
break;
case jrd_req::req_return:
if (impure->sta_state)
return parentStmt;
if (transaction != attachment->getSysTransaction())
++transaction->tra_save_point->sav_verb_count;
if (relation->rel_pre_store && whichTrig != POST_TRIG)
if (!impure->sta_state)
{
EXE_execute_triggers(tdbb, &relation->rel_pre_store, NULL, rpb,
TRIGGER_INSERT, PRE_TRIG);
}
SavepointChangeMarker scMarker(transaction);
if (validations.hasData())
validateExpressions(tdbb, validations);
if (relation->rel_pre_store && whichTrig != POST_TRIG)
{
EXE_execute_triggers(tdbb, &relation->rel_pre_store, NULL, rpb,
TRIGGER_INSERT, PRE_TRIG);
}
// For optimum on-disk record compression, zero all unassigned
// fields. In addition, zero the tail of assigned varying fields
// so that previous remnants don't defeat compression efficiency.
if (validations.hasData())
validateExpressions(tdbb, validations);
// CVC: The code that was here was moved to its own routine: cleanupRpb()
// and replaced by the call shown below.
// For optimum on-disk record compression, zero all unassigned
// fields. In addition, zero the tail of assigned varying fields
// so that previous remnants don't defeat compression efficiency.
cleanupRpb(tdbb, rpb);
// CVC: The code that was here was moved to its own routine: cleanupRpb()
// and replaced by the call shown below.
if (relation->rel_file)
EXT_store(tdbb, rpb);
else if (relation->isVirtual())
VirtualTable::store(tdbb, rpb);
else if (!relation->rel_view_rse)
{
VIO_store(tdbb, rpb, transaction);
IDX_store(tdbb, rpb, transaction);
}
cleanupRpb(tdbb, rpb);
rpb->rpb_number.setValid(true);
if (relation->rel_file)
EXT_store(tdbb, rpb);
else if (relation->isVirtual())
VirtualTable::store(tdbb, rpb);
else if (!relation->rel_view_rse)
{
VIO_store(tdbb, rpb, transaction);
IDX_store(tdbb, rpb, transaction);
}
if (relation->rel_post_store && whichTrig != PRE_TRIG)
{
EXE_execute_triggers(tdbb, &relation->rel_post_store, NULL, rpb,
TRIGGER_INSERT, POST_TRIG);
}
rpb->rpb_number.setValid(true);
// CVC: Increment the counter only if we called VIO/EXT_store() and we were successful.
if (!(request->req_view_flags & req_first_store_return))
{
request->req_view_flags |= req_first_store_return;
if (relation->rel_view_rse)
request->req_top_view_store = relation;
}
if (relation->rel_post_store && whichTrig != PRE_TRIG)
{
EXE_execute_triggers(tdbb, &relation->rel_post_store, NULL, rpb,
TRIGGER_INSERT, POST_TRIG);
}
if (relation == request->req_top_view_store)
{
if (!subStore && (whichTrig == ALL_TRIGS || whichTrig == POST_TRIG))
if (!relation->rel_view_rse ||
(!subStore && (whichTrig == ALL_TRIGS || whichTrig == POST_TRIG)))
{
request->req_records_inserted++;
request->req_records_affected.bumpModified(true);
}
}
else if (relation->rel_file || !relation->rel_view_rse)
{
request->req_records_inserted++;
request->req_records_affected.bumpModified(true);
}
if (transaction != attachment->getSysTransaction())
--transaction->tra_save_point->sav_verb_count;
if (statement2)
{
impure->sta_state = 1;
request->req_operation = jrd_req::req_evaluate;
return statement2;
if (statement2)
{
impure->sta_state = 1;
request->req_operation = jrd_req::req_evaluate;
return statement2;
}
}
// fall into
default:
return parentStmt;
@ -7139,83 +7082,75 @@ const StmtNode* UserSavepointNode::execute(thread_db* tdbb, jrd_req* request, Ex
jrd_tra* transaction = request->req_transaction;
if (request->req_operation == jrd_req::req_evaluate &&
transaction != request->req_attachment->getSysTransaction())
!(transaction->tra_flags & TRA_system))
{
// Skip the savepoint created by EXE_start
Savepoint* savepoint = transaction->tra_save_point->sav_next;
Savepoint* previous = transaction->tra_save_point;
Savepoint* const previous = transaction->tra_save_point;
// Find savepoint
bool found = false;
while (true)
Savepoint* savepoint = NULL;
for (Savepoint::Iterator iter(previous); *iter; ++iter)
{
if (!savepoint || !(savepoint->sav_flags & SAV_user))
Savepoint* const current = *iter;
if (current == previous)
continue;
if (current->isSystem())
break;
if (name == savepoint->sav_name)
if (current->getName() == name)
{
found = true;
savepoint = current;
break;
}
previous = savepoint;
savepoint = savepoint->sav_next;
}
if (!found && command != CMD_SET)
if (!savepoint && command != CMD_SET)
ERR_post(Arg::Gds(isc_invalid_savepoint) << Arg::Str(name));
switch (command)
{
case CMD_SET:
// Release the savepoint
if (found)
{
savepoint->rollforward(tdbb);
previous->sav_next = savepoint->sav_next;
savepoint->sav_next = transaction->tra_save_free;
transaction->tra_save_free = savepoint;
}
if (savepoint)
savepoint->rollforward(tdbb, previous);
// Use the savepoint created by EXE_start
transaction->tra_save_point->sav_flags |= SAV_user;
transaction->tra_save_point->sav_name = name;
transaction->tra_save_point->setName(name);
break;
case CMD_RELEASE_ONLY:
{
// Release the savepoint
savepoint->rollforward(tdbb);
previous->sav_next = savepoint->sav_next;
savepoint->sav_next = transaction->tra_save_free;
transaction->tra_save_free = savepoint;
savepoint->rollforward(tdbb, previous);
break;
}
case CMD_RELEASE:
{
const SLONG sav_number = savepoint->sav_number;
const SavNumber savNumber = savepoint->getNumber();
// Release the savepoint and all subsequent ones
while (transaction->tra_save_point &&
transaction->tra_save_point->sav_number >= sav_number)
transaction->tra_save_point->getNumber() >= savNumber)
{
transaction->rollforwardSavepoint(tdbb);
}
// Restore the savepoint initially created by EXE_start
VIO_start_save_point(tdbb, transaction);
transaction->startSavepoint();
break;
}
case CMD_ROLLBACK:
{
transaction->rollbackToSavepoint(tdbb, savepoint->sav_number);
transaction->rollbackToSavepoint(tdbb, savepoint->getNumber());
// Now set the savepoint again to allow to return to it later
VIO_start_save_point(tdbb, transaction);
transaction->tra_save_point->sav_flags |= SAV_user;
transaction->tra_save_point->sav_name = name;
Savepoint* const savepoint = transaction->startSavepoint();
savepoint->setName(name);
break;
}
@ -7817,7 +7752,6 @@ void SavePointNode::genBlr(DsqlCompilerScratch* dsqlScratch)
const StmtNode* SavePointNode::execute(thread_db* tdbb, jrd_req* request, ExeState* exeState) const
{
jrd_tra* transaction = request->req_transaction;
jrd_tra* sysTransaction = request->req_attachment->getSysTransaction();
switch (blrOp)
{
@ -7825,8 +7759,8 @@ const StmtNode* SavePointNode::execute(thread_db* tdbb, jrd_req* request, ExeSta
if (request->req_operation == jrd_req::req_evaluate)
{
// Start a save point.
if (transaction != sysTransaction)
VIO_start_save_point(tdbb, transaction);
if (!(transaction->tra_flags & TRA_system))
transaction->startSavepoint();
request->req_operation = jrd_req::req_return;
}
@ -7837,7 +7771,7 @@ const StmtNode* SavePointNode::execute(thread_db* tdbb, jrd_req* request, ExeSta
request->req_operation == jrd_req::req_unwind)
{
// If any requested modify/delete/insert ops have completed, forget them.
if (transaction != sysTransaction)
if (!(transaction->tra_flags & TRA_system))
{
// If an error is still pending when the savepoint is supposed to end, then the
// application didn't handle the error and the savepoint should be undone.
@ -7982,6 +7916,8 @@ void SetRoleNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** transact
UserId* user = attachment->att_user;
fb_assert(user);
user->usr_granted_roles.clear();
if (trusted)
{
if (!user->usr_trusted_role.hasData())
@ -7995,7 +7931,17 @@ void SetRoleNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** transact
user->usr_sql_role_name = roleName.c_str();
}
if (SCL_admin_role(tdbb, user->usr_sql_role_name.c_str()))
if (!user->usr_sql_role_name.isEmpty() || user->usr_sql_role_name != NULL_ROLE)
{
// Add role itself and all roles cumulatively granted to it. Not only default.
user->usr_granted_roles.add(user->usr_sql_role_name);
SCL_find_granted_roles(tdbb, user->usr_sql_role_name, true, user->usr_granted_roles, false);
}
// Add all default roles granted to user
SCL_find_granted_roles(tdbb, user->usr_user_name, false, user->usr_granted_roles, true);
if (SCL_admin_role(tdbb, user->usr_granted_roles))
user->usr_flags |= USR_dba;
else
user->usr_flags &= ~USR_dba;

View File

@ -737,7 +737,7 @@ class InAutonomousTransactionNode : public TypedNode<StmtNode, StmtNode::TYPE_IN
struct Impure
{
TraNumber traNumber;
SLONG savNumber;
SavNumber savNumber;
};
public:

View File

@ -552,6 +552,9 @@ yyreduce:
reduce_posn = TRUE;
yyposn.firstLine = YYPOSNARG(1).firstLine;
yyposn.firstColumn = YYPOSNARG(1).firstColumn;
switch (yyn) {
%% trailer

View File

@ -546,8 +546,13 @@ void DSQL_execute_immediate(thread_db* tdbb, Jrd::Attachment* attachment, jrd_tr
Jrd::ContextPoolHolder context(tdbb, &request->getPool());
// A select with a non zero output length is a singleton select
const bool singleton = reqTypeWithCursor(statement->getType()) && out_msg;
// A select having cursor is a singleton select when executed immediate
const bool singleton = reqTypeWithCursor(statement->getType());
if (singleton && !(out_msg && out_meta))
{
ERRD_post(Arg::Gds(isc_dsql_sqlda_err) <<
Arg::Gds(isc_dsql_no_output_sqlda));
}
request->req_transaction = *tra_handle;

View File

@ -589,12 +589,17 @@ using namespace Firebird;
%token <metaNamePtr> REGR_SXY
%token <metaNamePtr> REGR_SYY
// tokens added for Firebird 4.0
%token <metaNamePtr> RDB_ROLE_IN_USE
// precedence declarations for expression evaluation
%left OR
%left AND
%left NOT
%left '=' '<' '>' IS BETWEEN LIKE CONTAINING STARTING SIMILAR KW_IN NEQ GEQ LEQ NOT_GTR NOT_LSS
%left '=' '<' '>' BETWEEN LIKE CONTAINING STARTING SIMILAR KW_IN NEQ GEQ LEQ NOT_GTR NOT_LSS
%left IS
%left '+' '-'
%left '*' '/'
%left UMINUS UPLUS
@ -875,7 +880,7 @@ grant0($node)
$node->grantor = $6;
$node->isDdl = true;
}
| role_name_list(NOTRIAL(&$node->roles)) TO role_grantee_list(NOTRIAL(&$node->users))
| role_name_list(NOTRIAL($node)) TO role_grantee_list(NOTRIAL(&$node->users))
role_admin_option granted_by
{
$node->grantAdminOption = $4;
@ -1132,7 +1137,7 @@ revoke0($node)
$node->grantor = $6;
$node->isDdl = true;
}
| rev_admin_option role_name_list(NOTRIAL(&$node->roles))
| rev_admin_option role_name_list(NOTRIAL($node))
FROM role_grantee_list(NOTRIAL(&$node->users)) granted_by
{
$node->grantAdminOption = $1;
@ -1190,16 +1195,24 @@ user_grantee($granteeArray)
{ $granteeArray->add(GranteeClause(obj_user_group, *$2)); }
;
%type role_name_list(<granteeArray>)
role_name_list($granteeArray)
: role_name($granteeArray)
| role_name_list ',' role_name($granteeArray)
%type role_name_list(<grantRevokeNode>)
role_name_list($grantRevokeNode)
: role_name($grantRevokeNode)
| role_name_list ',' role_name($grantRevokeNode)
;
%type role_name(<granteeArray>)
role_name($granteeArray)
%type role_name(<grantRevokeNode>)
role_name($grantRevokeNode)
: symbol_role_name
{ $granteeArray->add(GranteeClause(obj_sql_role, *$1)); }
{
$grantRevokeNode->roles.add(GranteeClause(obj_sql_role, *$1));
$grantRevokeNode->defaultRoles.add(false);
}
| DEFAULT symbol_role_name
{
$grantRevokeNode->roles.add(GranteeClause(obj_sql_role, *$2));
$grantRevokeNode->defaultRoles.add(true);
}
;
%type role_grantee_list(<granteeArray>)
@ -1210,10 +1223,11 @@ role_grantee_list($granteeArray)
%type role_grantee(<granteeArray>)
role_grantee($granteeArray)
: grantor { $granteeArray->add(GranteeClause(obj_user, *$1)); }
: symbol_user_name { $granteeArray->add(GranteeClause(obj_user_or_role, *$1)); }
| USER symbol_user_name { $granteeArray->add(GranteeClause(obj_user, *$2)); }
| ROLE symbol_user_name { $granteeArray->add(GranteeClause(obj_sql_role, *$2)); }
;
// DECLARE operations
%type <ddlNode> declare
@ -6011,9 +6025,17 @@ boolean_value_expression
| '(' boolean_value_expression ')'
{ $$ = $2; }
| value IS boolean_literal
{ $$ = newNode<ComparativeBoolNode>(blr_eql, $1, $3); }
{
ComparativeBoolNode* node = newNode<ComparativeBoolNode>(blr_eql, $1, $3);
node->dsqlCheckBoolean = true;
$$ = node;
}
| value IS NOT boolean_literal
{ $$ = newNode<NotBoolNode>(newNode<ComparativeBoolNode>(blr_eql, $1, $4)); }
{
ComparativeBoolNode* node = newNode<ComparativeBoolNode>(blr_eql, $1, $4);
node->dsqlCheckBoolean = true;
$$ = newNode<NotBoolNode>(node);
}
;
%type <boolExprNode> predicate
@ -7084,6 +7106,7 @@ system_function_std_syntax
| TANH
| TRUNC
| UUID_TO_CHAR
| RDB_ROLE_IN_USE
;
%type <sysFuncCallNode> system_function_special_syntax
@ -7774,6 +7797,7 @@ non_reserved_word
| SERVERWIDE
| INCREMENT
| TRUSTED
| RDB_ROLE_IN_USE // added in FB 4.0
;
%%

View File

@ -1135,7 +1135,7 @@ static void gen_blr(void* /*user_arg*/, SSHORT /*offset*/, const char* string)
{
char d = 0;
if (p1 < q && ((d = *p1++) == '_' || d == '$'))
strncpy(q1 - 4, "isc", 3);
memcpy(q1 - 4, "isc", 3);
else if (d)
*q1++ = d;
}

View File

@ -532,8 +532,7 @@ int main(int argc, char* argv[])
{
gpreGlob.global_db_count = 1;
char* dbn = gpreGlob.global_db_list[0].dbd_name;
strncpy(dbn, db->dbd_name->sym_string, dbd::dbd_size);
dbn[dbd::dbd_size - 1] = 0;
fb_utils::copy_terminate(dbn, db->dbd_name->sym_string, dbd::dbd_size);
}
#endif
break;

View File

@ -66,6 +66,7 @@
#include "dyn_consts.h"
#include "../jrd/ibase.h"
#include "../jrd/constants.h"
#include "../common/utils_proto.h"
#ifdef GPRE_FORTRAN
#if defined AIX || defined AIX_PPC || defined __sun
@ -1621,8 +1622,7 @@ public:
}
gpre_exception(const char* errmsg)
{
strncpy(msg, errmsg, sizeof(msg));
msg[sizeof(msg) - 1] = 0;
fb_utils::copy_terminate(msg, errmsg, sizeof(msg));
}
const char* what() const throw()
{

View File

@ -214,9 +214,8 @@ static void asgn_from( ref* reference, int column)
if (!field || field->fld_dtype == dtype_text)
fprintf(gpreGlob.out_file, VTO_CALL, JRD_VTOF, value, variable,
field ? field->fld_length : 0);
else if (!field || field->fld_dtype == dtype_cstring)
fprintf(gpreGlob.out_file, VTO_CALL, GDS_VTOV, value, variable,
field ? field->fld_length : 0);
else if (field->fld_dtype == dtype_cstring)
fprintf(gpreGlob.out_file, VTO_CALL, GDS_VTOV, value, variable, field->fld_length);
else
fprintf(gpreGlob.out_file, "%s = %s;", variable, value);
}
@ -243,7 +242,7 @@ static void asgn_to( ref* reference)
if (!field || field->fld_dtype == dtype_text)
fprintf(gpreGlob.out_file, "gds__ftov (%s, %d, %s, sizeof(%s));",
s, field ? field->fld_length : 0, reference->ref_value, reference->ref_value);
else if (!field || field->fld_dtype == dtype_cstring)
else if (field->fld_dtype == dtype_cstring)
fprintf(gpreGlob.out_file, "gds__vtov((const char*) %s, (char*) %s, sizeof(%s));",
s, reference->ref_value, reference->ref_value);
else

View File

@ -1147,7 +1147,7 @@ static void gen_blr(void* /*user_arg*/, SSHORT /*offset*/, const char* string)
{
char d = 0;
if (p1 < q && ((d = *p1++) == '_' || d == '$'))
strncpy(q1 - 4, "isc", 3);
memcpy(q1 - 4, "isc", 3);
else if (d)
*q1++ = d;
}

View File

@ -617,8 +617,7 @@ act* PAR_database(bool sql, const TEXT* base_directory)
strcat(s, ".");
if (!gpreGlob.ada_package[0] || !strcmp(gpreGlob.ada_package, s))
{
strncpy(gpreGlob.ada_package, s, MAXPATHLEN);
gpreGlob.ada_package[MAXPATHLEN - 1] = 0;
fb_utils::copy_terminate(gpreGlob.ada_package, s, MAXPATHLEN);
}
else
{

View File

@ -1721,6 +1721,7 @@ static gpre_ctx* par_alias_list( gpre_req* request, gpre_nod* alias_list)
// a base table having a matching table name or alias
if (!context)
{
for (context = request->req_contexts; context; context = context->ctx_next)
{
if (context->ctx_scope_level != request->req_scope_level)
@ -1732,12 +1733,13 @@ static gpre_ctx* par_alias_list( gpre_req* request, gpre_nod* alias_list)
break;
}
}
}
if (!context)
{
fb_utils::snprintf(error_string, sizeof(error_string),
"there is no alias or table named %s at this scope level",
(TEXT*) *arg);
if (!context)
{
fb_utils::snprintf(error_string, sizeof(error_string),
"there is no alias or table named %s at this scope level",
(TEXT*) *arg);
PAR_error(error_string);
}

View File

@ -5477,8 +5477,7 @@ static gpre_index* make_index( gpre_req* request, const TEXT* string)
// CVC: I've kept this silly code. What's the idea of the copy here?
// If we are trying to limit the index name, the correct length is NAME_SIZE.
TEXT s[ERROR_LENGTH];
strncpy(s, string, sizeof(s));
s[sizeof(s) - 1] = 0;
fb_utils::copy_terminate(s, string, sizeof(s));
gpre_index* index = MET_make_index(s);
if (request)
request->req_database = gpreGlob.isc_databases;
@ -5501,8 +5500,7 @@ static gpre_rel* make_relation( gpre_req* request, const TEXT* relation_name)
if (gpreGlob.isc_databases && !gpreGlob.isc_databases->dbb_next)
{
TEXT r[ERROR_LENGTH];
strncpy(r, relation_name, sizeof(r));
r[sizeof(r) - 1] = 0;
fb_utils::copy_terminate(r, relation_name, sizeof(r));
gpre_rel* relation = MET_make_relation(r);
relation->rel_database = gpreGlob.isc_databases;
@ -6793,8 +6791,7 @@ void SQL_resolve_identifier( const TEXT* err_mesg, TEXT* str_in, int in_size)
// or SQL escape sequences in quoted identifiers.
if (tk_string[0] == '\"')
strip_quotes(gpreGlob.token_global);
strncpy(str, tk_string, len);
str[len] = 0;
fb_utils::copy_terminate(str, tk_string, len + 1);
break;
case tok_ident:
to_upcase(tk_string, str, len + 1);

View File

@ -64,8 +64,7 @@ class MetIdentifier
public:
explicit MetIdentifier(const char* s)
{
strncpy(name, s, NAME_SIZE);
name[NAME_SIZE - 1] = 0;
fb_utils::copy_terminate(name, s, NAME_SIZE);
}
operator char*() {return name;}
operator const char*() const {return name;}

View File

@ -471,6 +471,9 @@
#define isc_spb_tra_id_64 46
#define isc_spb_single_tra_id_64 47
#define isc_spb_multi_tra_id_64 48
#define isc_spb_rpr_commit_trans_64 49
#define isc_spb_rpr_rollback_trans_64 50
#define isc_spb_rpr_recover_two_phase_64 51
#define isc_spb_rpr_validate_db 0x01
#define isc_spb_rpr_sweep_db 0x02

View File

@ -36,12 +36,10 @@ enum BlockType
type_irl,
type_idl,
type_sdw,
type_vct,
type_blf,
type_arr,
type_map,
type_prm,
type_sav,
type_idb,
type_tpc,
type_svc,

View File

@ -156,5 +156,6 @@ typedef FB_UINT64 TraNumber;
typedef FB_UINT64 StmtNumber;
typedef FB_UINT64 CommitNumber;
typedef ULONG SnapshotHandle;
typedef SINT64 SavNumber;
#endif /* INCLUDE_FB_TYPES_H */

View File

@ -629,7 +629,7 @@ interface IntUserField : UserField
interface User : Versioned
{
int operation();
uint operation();
CharUserField userName();
CharUserField password();
@ -645,6 +645,14 @@ interface User : Versioned
IntUserField admin();
void clear(Status status);
// code of operation()
const uint OP_USER_ADD = 1;
const uint OP_USER_MODIFY = 2;
const uint OP_USER_DELETE = 3;
const uint OP_USER_DISPLAY = 4;
const uint OP_USER_SET_MAP = 5;
const uint OP_USER_DROP_MAP = 6;
}
interface ListUsers : Versioned

View File

@ -2575,7 +2575,7 @@ namespace Firebird
public:
struct VTable : public IVersioned::VTable
{
int (CLOOP_CARG *operation)(IUser* self) throw();
unsigned (CLOOP_CARG *operation)(IUser* self) throw();
ICharUserField* (CLOOP_CARG *userName)(IUser* self) throw();
ICharUserField* (CLOOP_CARG *password)(IUser* self) throw();
ICharUserField* (CLOOP_CARG *firstName)(IUser* self) throw();
@ -2601,9 +2601,16 @@ namespace Firebird
public:
static const unsigned VERSION = 2;
int operation()
static const unsigned OP_USER_ADD = 1;
static const unsigned OP_USER_MODIFY = 2;
static const unsigned OP_USER_DELETE = 3;
static const unsigned OP_USER_DISPLAY = 4;
static const unsigned OP_USER_SET_MAP = 5;
static const unsigned OP_USER_DROP_MAP = 6;
unsigned operation()
{
int ret = static_cast<VTable*>(this->cloopVTable)->operation(this);
unsigned ret = static_cast<VTable*>(this->cloopVTable)->operation(this);
return ret;
}
@ -10469,7 +10476,7 @@ namespace Firebird
this->cloopVTable = &vTable;
}
static int CLOOP_CARG cloopoperationDispatcher(IUser* self) throw()
static unsigned CLOOP_CARG cloopoperationDispatcher(IUser* self) throw()
{
try
{
@ -10478,7 +10485,7 @@ namespace Firebird
catch (...)
{
StatusType::catchException(0);
return static_cast<int>(0);
return static_cast<unsigned>(0);
}
}
@ -10627,7 +10634,7 @@ namespace Firebird
{
}
virtual int operation() = 0;
virtual unsigned operation() = 0;
virtual ICharUserField* userName() = 0;
virtual ICharUserField* password() = 0;
virtual ICharUserField* firstName() = 0;

View File

@ -811,6 +811,7 @@ static const struct {
{"already_opened", 335545107},
{"bad_crypt_key", 335545108},
{"encrypt_error", 335545109},
{"max_idx_depth", 335545110},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},

View File

@ -845,6 +845,7 @@ const ISC_STATUS isc_login_error = 335545106L;
const ISC_STATUS isc_already_opened = 335545107L;
const ISC_STATUS isc_bad_crypt_key = 335545108L;
const ISC_STATUS isc_encrypt_error = 335545109L;
const ISC_STATUS isc_max_idx_depth = 335545110L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@ -1316,7 +1317,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 = 1260;
const ISC_STATUS isc_err_max = 1261;
#else /* c definitions */
@ -2131,6 +2132,7 @@ const ISC_STATUS isc_err_max = 1260;
#define isc_already_opened 335545107L
#define isc_bad_crypt_key 335545108L
#define isc_encrypt_error 335545109L
#define isc_max_idx_depth 335545110L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
@ -2602,7 +2604,7 @@ const ISC_STATUS isc_err_max = 1260;
#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 1260
#define isc_err_max 1261
#endif

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