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:
commit
8f311f3c27
5
.editorconfig
Normal file
5
.editorconfig
Normal file
@ -0,0 +1,5 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
14
CHANGELOG.md
14
CHANGELOG.md
@ -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
|
||||
|
@ -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/
|
||||
|
||||
|
@ -573,3 +573,10 @@ haveLibrary() {
|
||||
return $?
|
||||
}
|
||||
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# refresh cache of dynamic loader after add/delete files in system libdir
|
||||
|
||||
reconfigDynamicLoader() {
|
||||
ldconfig
|
||||
}
|
||||
|
@ -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*
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,6 +1,6 @@
|
||||
#########################################
|
||||
#
|
||||
# Firebird version 3.0 configuration file
|
||||
# Firebird version 4.0 configuration file
|
||||
#
|
||||
# Comments
|
||||
# --------
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
@ -36,3 +36,5 @@ if [ -d $PidDir ]
|
||||
then
|
||||
rm -rf $PidDir
|
||||
fi
|
||||
|
||||
reconfigDynamicLoader
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
#
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
@ -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"
|
||||
>
|
||||
|
@ -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"
|
||||
>
|
||||
|
@ -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
|
||||
|
22
configure.ac
22
configure.ac
@ -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
|
||||
|
@ -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
|
||||
------
|
||||
|
@ -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
|
||||
|
@ -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 –
|
||||
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 –
|
||||
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 – 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 – 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 –
|
||||
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 – 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 …
|
||||
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 – 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 – 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 –
|
||||
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 –
|
||||
main interfaces calling which functions one gets access to all the
|
||||
rest of Firebird API), others – 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 – 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 – IDisposable and IRefCounted. The last
|
||||
one is used specially active to create other interfaces –
|
||||
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 – 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>
|
@ -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 “plugin”. 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 – 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 “plugin” 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 –
|
||||
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 “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>
|
||||
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 – 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 – 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>
|
||||
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 “reasonable” - 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 – 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 – 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,
|
||||
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 – 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 – 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 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 – 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 – 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 – 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 – 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 – 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 – 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 = 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’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 password’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>
|
||||
<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 – 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
53
doc/sql.extensions/README.cumulative_roles.txt
Normal file
53
doc/sql.extensions/README.cumulative_roles.txt
Normal 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;
|
@ -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
|
||||
|
@ -41,11 +41,6 @@ public:
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
IPluginModule* getModule()
|
||||
{
|
||||
return NULL; // OK for application, not for plugin
|
||||
}
|
||||
};
|
||||
|
||||
class App
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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");
|
||||
|
2
extern/btyacc/reader.c
vendored
2
extern/btyacc/reader.c
vendored
@ -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) {
|
||||
|
3
extern/libtommath/.gitignore
vendored
3
extern/libtommath/.gitignore
vendored
@ -1,2 +1,5 @@
|
||||
lib/
|
||||
temp/
|
||||
*.o
|
||||
*.l*
|
||||
.libs/
|
||||
|
2
extern/libtommath/makefile.shared
vendored
2
extern/libtommath/makefile.shared
vendored
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 "
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -208,7 +208,7 @@ public:
|
||||
|
||||
IStatus* clone() const
|
||||
{
|
||||
Final* ret = FB_NEW Final();
|
||||
IStatus* ret = MasterInterfacePtr()->getStatus();
|
||||
|
||||
ret->setWarnings(getWarnings());
|
||||
ret->setErrors(getErrors());
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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__
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 = ':';
|
||||
|
||||
|
@ -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 = ';';
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -102,6 +102,7 @@ private:
|
||||
|
||||
public:
|
||||
UCHAR blrOp;
|
||||
bool dsqlCheckBoolean;
|
||||
DsqlFlag dsqlFlag;
|
||||
NestConst<ValueExprNode> arg1;
|
||||
NestConst<ValueExprNode> arg2;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
//----------------------
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -112,7 +112,7 @@ public:
|
||||
Firebird::SortedArray<Firebird::MetaName> procedureNames;
|
||||
|
||||
private:
|
||||
Firebird::string owner;
|
||||
Firebird::MetaName owner;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -737,7 +737,7 @@ class InAutonomousTransactionNode : public TypedNode<StmtNode, StmtNode::TYPE_IN
|
||||
struct Impure
|
||||
{
|
||||
TraNumber traNumber;
|
||||
SLONG savNumber;
|
||||
SavNumber savNumber;
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -552,6 +552,9 @@ yyreduce:
|
||||
|
||||
reduce_posn = TRUE;
|
||||
|
||||
yyposn.firstLine = YYPOSNARG(1).firstLine;
|
||||
yyposn.firstColumn = YYPOSNARG(1).firstColumn;
|
||||
|
||||
switch (yyn) {
|
||||
|
||||
%% trailer
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
;
|
||||
|
||||
%%
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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},
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user