mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 10:14:19 +01:00
Merge mysql.com:/home/jimw/my/mysql-5.0-13361
into mysql.com:/home/jimw/my/mysql-5.0-clean sql/item_strfunc.cc: Auto merged
This commit is contained in:
commit
24971d0560
118 changed files with 3585 additions and 1330 deletions
|
@ -478,6 +478,8 @@ libmysqld/sql_cache.cc
|
|||
libmysqld/sql_class.cc
|
||||
libmysqld/sql_command
|
||||
libmysqld/sql_crypt.cc
|
||||
libmysqld/sql_cursor.cc
|
||||
libmysqld/sql_cursor.h
|
||||
libmysqld/sql_db.cc
|
||||
libmysqld/sql_delete.cc
|
||||
libmysqld/sql_derived.cc
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
AdditionalIncludeDirectories="../include,../libmysqld,../sql,../regex,../extra/yassl/include,../bdb/build_win32,../zlib"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;SAFEMALLOC;HAVE_BERKELEY_DB;USE_SYMDIR;SIGNAL_WITH_VIO_CLOSE;HAVE_DLOPEN;EMBEDDED_LIBRARY;HAVE_INNOBASE_DB;USE_TLS;__WIN__"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="0"
|
||||
RuntimeLibrary="1"
|
||||
PrecompiledHeaderFile=".\debug/libmysqld.pch"
|
||||
AssemblerListingLocation=".\debug/"
|
||||
ObjectFile=".\debug/"
|
||||
|
@ -37,11 +37,11 @@
|
|||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib ..\lib_debug\dbug_tls.lib ..\lib_debug\mysys_tls.lib ..\lib_debug\strings.lib ..\lib_debug\regex.lib ..\lib_debug\heap_tls.lib ..\lib_debug\innodb.lib ..\extra\yassl\Debug\yassl.lib"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib"
|
||||
OutputFile="../lib_debug/libmysqld.dll"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="TRUE"
|
||||
IgnoreDefaultLibraryNames="LIBCMTD"
|
||||
IgnoreDefaultLibraryNames=""
|
||||
ModuleDefinitionFile=".\libmysqld.def"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile=".\debug/libmysqld.pdb"
|
||||
|
@ -106,7 +106,7 @@
|
|||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\myisam_tls.lib ..\lib_release\myisammrg_tls.lib ..\lib_release\mysys_tls.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap_tls.lib ..\lib_release\innodb.lib ..\lib_release\zlib.lib ..\extra\yassl\Release\yassl.lib"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib"
|
||||
OutputFile="../lib_pro/libmysqld.dll"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="TRUE"
|
||||
|
@ -172,7 +172,7 @@
|
|||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\myisam_tls.lib ..\lib_release\myisammrg_tls.lib ..\lib_release\mysys_tls.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap_tls.lib ..\lib_release\innodb.lib ..\lib_release\bdb.lib ..\lib_release\zlib.lib ..\extra\yassl\Release\yassl.lib"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib"
|
||||
OutputFile="../lib_release/libmysqld.dll"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="TRUE"
|
||||
|
@ -238,7 +238,7 @@
|
|||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib ..\lib_release\myisam_tls.lib ..\lib_release\myisammrg_tls.lib ..\lib_release\mysys_tls.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap_tls.lib ..\lib_release\zlib.lib ..\extra\yassl\Release\yassl.lib"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib Wsock32.lib"
|
||||
OutputFile="../lib_classic/libmysqld.dll"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="TRUE"
|
||||
|
@ -2299,7 +2299,7 @@
|
|||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sql\protocol_cursor.cpp">
|
||||
RelativePath="..\sql\sql_cursor.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="libmysql.lib odbc32.lib odbccp32.lib"
|
||||
OutputFile=".\release/myTest.exe"
|
||||
OutputFile="..\client_release/myTest.exe"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="TRUE"
|
||||
AdditionalLibraryDirectories="..\lib_release"
|
||||
|
@ -74,7 +74,7 @@
|
|||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory=".\debug"
|
||||
OutputDirectory="..\client_debug"
|
||||
IntermediateDirectory=".\debug"
|
||||
ConfigurationType="1"
|
||||
UseOfMFC="0"
|
||||
|
@ -100,7 +100,7 @@
|
|||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="libmysql.lib odbc32.lib odbccp32.lib"
|
||||
OutputFile=".\debug/myTest.exe"
|
||||
OutputFile="../client_debug/myTest.exe"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="TRUE"
|
||||
AdditionalLibraryDirectories="..\lib_debug"
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="wsock32.lib setargv.obj ..\lib_release\myisam.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\zlib.lib"
|
||||
AdditionalDependencies="wsock32.lib setargv.obj"
|
||||
OutputFile="../client_classic/myisamchk.exe"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="TRUE"
|
||||
|
|
|
@ -37,6 +37,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmysqld", "libmysqld\libm
|
|||
{13D37150-54D0-46C5-9519-03923243C7C7} = {13D37150-54D0-46C5-9519-03923243C7C7}
|
||||
{BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB} = {BA86AE72-0CF5-423D-BBA2-E12B0D72EBFB}
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3} = {6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}
|
||||
{DB28DE80-837F-4497-9AA9-CC0A20584C98} = {DB28DE80-837F-4497-9AA9-CC0A20584C98}
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0} = {D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}
|
||||
{262280A8-37D5-4037-BDFB-242468DFB3D2} = {262280A8-37D5-4037-BDFB-242468DFB3D2}
|
||||
{8762A9B8-72A9-462E-A9A2-F3265081F8AF} = {8762A9B8-72A9-462E-A9A2-F3265081F8AF}
|
||||
|
@ -268,6 +269,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysqltest", "client\mysqlte
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysql_client_test", "tests\mysql_client_test.vcproj", "{DA224DAB-5006-42BE-BB77-16E8BE5326D5}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{26383276-4843-494B-8BE0-8936ED3EBAAB} = {26383276-4843-494B-8BE0-8936ED3EBAAB}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysql_test_run_new", "mysql-test\mysql_test_run_new.vcproj", "{6189F838-21C6-42A1-B2D0-9146316573F7}"
|
||||
|
@ -305,24 +307,32 @@ Global
|
|||
Release = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.classic.ActiveCfg = Debug|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.classic nt.ActiveCfg = Debug|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.classic.ActiveCfg = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.classic.Build.0 = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.classic nt.ActiveCfg = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.classic nt.Build.0 = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Debug.ActiveCfg = Debug|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Debug.Build.0 = Debug|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Classic.ActiveCfg = Debug|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Classic.Build.0 = Debug|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Classic.ActiveCfg = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Classic.Build.0 = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Debug.ActiveCfg = Debug|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Debug.Build.0 = Debug|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Pro.ActiveCfg = Debug|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Pro.ActiveCfg = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Pro.Build.0 = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Release.ActiveCfg = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Embedded_Release.Build.0 = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Max.ActiveCfg = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Max.Build.0 = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Max nt.ActiveCfg = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Max nt.Build.0 = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.nt.ActiveCfg = Debug|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro.ActiveCfg = Debug|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro nt.ActiveCfg = Debug|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Release.ActiveCfg = Debug|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.nt.ActiveCfg = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.nt.Build.0 = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro.ActiveCfg = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro.Build.0 = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro nt.ActiveCfg = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.pro nt.Build.0 = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Release.ActiveCfg = Max|Win32
|
||||
{6EEF697A-3772-48D8-A5BA-EF11B9AC46E3}.Release.Build.0 = Max|Win32
|
||||
{1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.classic.ActiveCfg = Release|Win32
|
||||
{1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.classic nt.ActiveCfg = Release|Win32
|
||||
{1FD8A136-B86A-4B54-95B0-FA4E2EE2CCBC}.classic nt.Build.0 = Release|Win32
|
||||
|
@ -349,11 +359,14 @@ Global
|
|||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.classic nt.Build.0 = Release|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Debug.ActiveCfg = Debug|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Debug.Build.0 = Debug|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Classic.ActiveCfg = Debug|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Classic.ActiveCfg = Release|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Classic.Build.0 = Release|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Debug.ActiveCfg = TLS_DEBUG|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Debug.Build.0 = TLS_DEBUG|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Pro.ActiveCfg = Debug|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Pro.ActiveCfg = Release|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Pro.Build.0 = Release|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Release.ActiveCfg = Release|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Embedded_Release.Build.0 = Release|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Max.ActiveCfg = Release|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Max.Build.0 = Release|Win32
|
||||
{FC369DF4-AEB7-4531-BF34-A638C4363BFE}.Max nt.ActiveCfg = Release|Win32
|
||||
|
@ -392,11 +405,14 @@ Global
|
|||
{C70A6DC7-7D45-4C16-8654-7E57713A4C04}.pro nt.Build.0 = Release|Win32
|
||||
{C70A6DC7-7D45-4C16-8654-7E57713A4C04}.Release.ActiveCfg = Release|Win32
|
||||
{C70A6DC7-7D45-4C16-8654-7E57713A4C04}.Release.Build.0 = Release|Win32
|
||||
{13D37150-54D0-46C5-9519-03923243C7C7}.classic.ActiveCfg = nt|Win32
|
||||
{13D37150-54D0-46C5-9519-03923243C7C7}.classic.ActiveCfg = Release|Win32
|
||||
{13D37150-54D0-46C5-9519-03923243C7C7}.classic.Build.0 = Release|Win32
|
||||
{13D37150-54D0-46C5-9519-03923243C7C7}.classic nt.ActiveCfg = nt|Win32
|
||||
{13D37150-54D0-46C5-9519-03923243C7C7}.classic nt.Build.0 = nt|Win32
|
||||
{13D37150-54D0-46C5-9519-03923243C7C7}.Debug.ActiveCfg = Debug|Win32
|
||||
{13D37150-54D0-46C5-9519-03923243C7C7}.Debug.Build.0 = Debug|Win32
|
||||
{13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Classic.ActiveCfg = nt|Win32
|
||||
{13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Classic.ActiveCfg = Release|Win32
|
||||
{13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Classic.Build.0 = Release|Win32
|
||||
{13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Debug.ActiveCfg = Debug|Win32
|
||||
{13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Debug.Build.0 = Debug|Win32
|
||||
{13D37150-54D0-46C5-9519-03923243C7C7}.Embedded_Pro.ActiveCfg = Release|Win32
|
||||
|
@ -454,8 +470,8 @@ Global
|
|||
{93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.pro.ActiveCfg = pro|Win32
|
||||
{93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.pro nt.ActiveCfg = pro|Win32
|
||||
{93CA92A0-D7B8-4FAE-9EBB-D92EFBF631C9}.Release.ActiveCfg = Release|Win32
|
||||
{2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.classic.ActiveCfg = Debug|Win32
|
||||
{2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.classic.Build.0 = Debug|Win32
|
||||
{2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.classic.ActiveCfg = Release|Win32
|
||||
{2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.classic.Build.0 = Release|Win32
|
||||
{2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.classic nt.ActiveCfg = Release|Win32
|
||||
{2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.classic nt.Build.0 = Release|Win32
|
||||
{2794E434-7CCE-44DB-B2FB-789ABE53D6B9}.Debug.ActiveCfg = Debug|Win32
|
||||
|
@ -507,6 +523,7 @@ Global
|
|||
{262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Classic.ActiveCfg = TLS|Win32
|
||||
{262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Classic.Build.0 = TLS|Win32
|
||||
{262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Debug.ActiveCfg = Debug|Win32
|
||||
{262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Debug.Build.0 = Debug|Win32
|
||||
{262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Pro.ActiveCfg = TLS|Win32
|
||||
{262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Pro.Build.0 = TLS|Win32
|
||||
{262280A8-37D5-4037-BDFB-242468DFB3D2}.Embedded_Release.ActiveCfg = TLS|Win32
|
||||
|
@ -589,8 +606,8 @@ Global
|
|||
{194F5EE6-9440-4298-A6FE-A9B4B480B44C}.pro nt.Build.0 = Release|Win32
|
||||
{194F5EE6-9440-4298-A6FE-A9B4B480B44C}.Release.ActiveCfg = Release|Win32
|
||||
{194F5EE6-9440-4298-A6FE-A9B4B480B44C}.Release.Build.0 = Release|Win32
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.classic.ActiveCfg = Debug|Win32
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.classic.Build.0 = Debug|Win32
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.classic.ActiveCfg = Release|Win32
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.classic.Build.0 = Release|Win32
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.classic nt.ActiveCfg = Release|Win32
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.classic nt.Build.0 = Release|Win32
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Debug.ActiveCfg = Debug|Win32
|
||||
|
@ -598,6 +615,7 @@ Global
|
|||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Classic.ActiveCfg = TLS|Win32
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Classic.Build.0 = TLS|Win32
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Debug.ActiveCfg = Debug|Win32
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Debug.Build.0 = Debug|Win32
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Pro.ActiveCfg = TLS|Win32
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Pro.Build.0 = TLS|Win32
|
||||
{D8E4B489-C5DD-407D-99DB-FE7C7A5A83A0}.Embedded_Release.ActiveCfg = TLS|Win32
|
||||
|
@ -724,8 +742,8 @@ Global
|
|||
{67154F28-D076-419E-B149-819EF548E670}.pro nt.Build.0 = Release|Win32
|
||||
{67154F28-D076-419E-B149-819EF548E670}.Release.ActiveCfg = Release|Win32
|
||||
{67154F28-D076-419E-B149-819EF548E670}.Release.Build.0 = Release|Win32
|
||||
{26383276-4843-494B-8BE0-8936ED3EBAAB}.classic.ActiveCfg = Debug|Win32
|
||||
{26383276-4843-494B-8BE0-8936ED3EBAAB}.classic.Build.0 = Debug|Win32
|
||||
{26383276-4843-494B-8BE0-8936ED3EBAAB}.classic.ActiveCfg = Release|Win32
|
||||
{26383276-4843-494B-8BE0-8936ED3EBAAB}.classic.Build.0 = Release|Win32
|
||||
{26383276-4843-494B-8BE0-8936ED3EBAAB}.classic nt.ActiveCfg = Release|Win32
|
||||
{26383276-4843-494B-8BE0-8936ED3EBAAB}.classic nt.Build.0 = Release|Win32
|
||||
{26383276-4843-494B-8BE0-8936ED3EBAAB}.Debug.ActiveCfg = Debug|Win32
|
||||
|
@ -911,9 +929,13 @@ Global
|
|||
{DB28DE80-837F-4497-9AA9-CC0A20584C98}.Debug.ActiveCfg = Debug|Win32
|
||||
{DB28DE80-837F-4497-9AA9-CC0A20584C98}.Debug.Build.0 = Debug|Win32
|
||||
{DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Classic.ActiveCfg = Release|Win32
|
||||
{DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Classic.Build.0 = Release|Win32
|
||||
{DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Debug.ActiveCfg = Debug|Win32
|
||||
{DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Debug.Build.0 = Debug|Win32
|
||||
{DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Pro.ActiveCfg = Release|Win32
|
||||
{DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Pro.Build.0 = Release|Win32
|
||||
{DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Release.ActiveCfg = Release|Win32
|
||||
{DB28DE80-837F-4497-9AA9-CC0A20584C98}.Embedded_Release.Build.0 = Release|Win32
|
||||
{DB28DE80-837F-4497-9AA9-CC0A20584C98}.Max.ActiveCfg = Release|Win32
|
||||
{DB28DE80-837F-4497-9AA9-CC0A20584C98}.Max.Build.0 = Release|Win32
|
||||
{DB28DE80-837F-4497-9AA9-CC0A20584C98}.Max nt.ActiveCfg = Release|Win32
|
||||
|
@ -1022,14 +1044,14 @@ Global
|
|||
{16699B52-ECC6-4A96-A99F-A043059BA2E7}.pro nt.Build.0 = Release|Win32
|
||||
{16699B52-ECC6-4A96-A99F-A043059BA2E7}.Release.ActiveCfg = Release|Win32
|
||||
{16699B52-ECC6-4A96-A99F-A043059BA2E7}.Release.Build.0 = Release|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.classic.ActiveCfg = Debug|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.classic.Build.0 = Debug|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.classic.ActiveCfg = Release|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.classic.Build.0 = Release|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.classic nt.ActiveCfg = Release|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.classic nt.Build.0 = Release|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.Debug.ActiveCfg = Debug|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.Debug.Build.0 = Debug|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Classic.ActiveCfg = Debug|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Classic.Build.0 = Debug|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Classic.ActiveCfg = Release|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Classic.Build.0 = Release|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Debug.ActiveCfg = Debug|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Debug.Build.0 = Debug|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.Embedded_Pro.ActiveCfg = Release|Win32
|
||||
|
@ -1048,8 +1070,8 @@ Global
|
|||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.pro nt.Build.0 = Release|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.Release.ActiveCfg = Release|Win32
|
||||
{EEC1300B-85A5-497C-B3E1-F708021DF859}.Release.Build.0 = Release|Win32
|
||||
{8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.classic.ActiveCfg = Debug|Win32
|
||||
{8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.classic.Build.0 = Debug|Win32
|
||||
{8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.classic.ActiveCfg = Release|Win32
|
||||
{8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.classic.Build.0 = Release|Win32
|
||||
{8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.classic nt.ActiveCfg = Debug|Win32
|
||||
{8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Debug.ActiveCfg = Debug|Win32
|
||||
{8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Debug.Build.0 = Debug|Win32
|
||||
|
@ -1065,7 +1087,6 @@ Global
|
|||
{8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Release.ActiveCfg = Release|Win32
|
||||
{8CB5AB80-05DA-49DA-BC9F-EAC20667E0D0}.Release.Build.0 = Release|Win32
|
||||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.classic.ActiveCfg = Release|Win32
|
||||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.classic.Build.0 = Release|Win32
|
||||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.classic nt.ActiveCfg = Release|Win32
|
||||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Debug.ActiveCfg = Release|Win32
|
||||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Embedded_Classic.ActiveCfg = Release|Win32
|
||||
|
@ -1074,12 +1095,10 @@ Global
|
|||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Embedded_Release.ActiveCfg = Release|Win32
|
||||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Max.ActiveCfg = Release|Win32
|
||||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Max nt.ActiveCfg = Release|Win32
|
||||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Max nt.Build.0 = Release|Win32
|
||||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.nt.ActiveCfg = Release|Win32
|
||||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.pro.ActiveCfg = Release|Win32
|
||||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.pro nt.ActiveCfg = Release|Win32
|
||||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Release.ActiveCfg = Release|Win32
|
||||
{6F01B69C-B1A5-4C45-B3A9-744E1EB0BED5}.Release.Build.0 = Release|Win32
|
||||
{7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.classic.ActiveCfg = Release|Win32
|
||||
{7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.classic.Build.0 = Release|Win32
|
||||
{7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.classic nt.ActiveCfg = Release|Win32
|
||||
|
@ -1102,16 +1121,20 @@ Global
|
|||
{7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.pro nt.Build.0 = Release|Win32
|
||||
{7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.Release.ActiveCfg = Release|Win32
|
||||
{7FFA3009-E0E1-4E4E-9CDF-F408AA108CC8}.Release.Build.0 = Release|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.classic.ActiveCfg = Debug|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.classic.Build.0 = Debug|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.classic.ActiveCfg = Release|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.classic.Build.0 = Release|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.classic nt.ActiveCfg = Release|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.classic nt.Build.0 = Release|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Debug.ActiveCfg = Debug|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Debug.Build.0 = Debug|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Classic.ActiveCfg = Debug|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Classic.ActiveCfg = Release|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Classic.Build.0 = Release|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Debug.ActiveCfg = Debug|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Pro.ActiveCfg = Debug|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Debug.Build.0 = Debug|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Pro.ActiveCfg = Release|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Pro.Build.0 = Release|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Release.ActiveCfg = Release|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Embedded_Release.Build.0 = Release|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Max.ActiveCfg = Release|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Max.Build.0 = Release|Win32
|
||||
{F74653C4-8003-4A79-8F53-FC69E0AD7A9B}.Max nt.ActiveCfg = Release|Win32
|
||||
|
@ -1133,6 +1156,7 @@ Global
|
|||
{8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Classic.ActiveCfg = Release|Win32
|
||||
{8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Classic.Build.0 = Release|Win32
|
||||
{8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Debug.ActiveCfg = Debug|Win32
|
||||
{8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Debug.Build.0 = Debug|Win32
|
||||
{8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Pro.ActiveCfg = Release|Win32
|
||||
{8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Pro.Build.0 = Release|Win32
|
||||
{8762A9B8-72A9-462E-A9A2-F3265081F8AF}.Embedded_Release.ActiveCfg = Release|Win32
|
||||
|
@ -1171,8 +1195,8 @@ Global
|
|||
{8961F149-C68A-4154-A499-A2AB39E607E8}.pro nt.Build.0 = Release|Win32
|
||||
{8961F149-C68A-4154-A499-A2AB39E607E8}.Release.ActiveCfg = Release|Win32
|
||||
{8961F149-C68A-4154-A499-A2AB39E607E8}.Release.Build.0 = Release|Win32
|
||||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.classic.ActiveCfg = Debug|Win32
|
||||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.classic.Build.0 = Debug|Win32
|
||||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.classic.ActiveCfg = Release|Win32
|
||||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.classic.Build.0 = Release|Win32
|
||||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.classic nt.ActiveCfg = Release|Win32
|
||||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.classic nt.Build.0 = Release|Win32
|
||||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Debug.ActiveCfg = Debug|Win32
|
||||
|
@ -1184,7 +1208,6 @@ Global
|
|||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Max.ActiveCfg = Release|Win32
|
||||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Max.Build.0 = Release|Win32
|
||||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Max nt.ActiveCfg = Release|Win32
|
||||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.Max nt.Build.0 = Release|Win32
|
||||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.nt.ActiveCfg = Release|Win32
|
||||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.nt.Build.0 = Release|Win32
|
||||
{DA224DAB-5006-42BE-BB77-16E8BE5326D5}.pro.ActiveCfg = Release|Win32
|
||||
|
|
0
VC++Files/mysqlserver/dummy.cpp
Executable file
0
VC++Files/mysqlserver/dummy.cpp
Executable file
|
@ -12,7 +12,7 @@
|
|||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory=".\Debug"
|
||||
OutputDirectory="..\lib_debug"
|
||||
IntermediateDirectory=".\Debug"
|
||||
ConfigurationType="4"
|
||||
UseOfMFC="0"
|
||||
|
@ -38,7 +38,7 @@
|
|||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile=".\Debug\mysqlserver.lib"
|
||||
OutputFile="$(OutDir)\mysqlserver.lib"
|
||||
SuppressStartupBanner="TRUE"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
|
@ -63,7 +63,7 @@
|
|||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory=".\release"
|
||||
OutputDirectory="..\lib_release"
|
||||
IntermediateDirectory=".\release"
|
||||
ConfigurationType="4"
|
||||
UseOfMFC="0"
|
||||
|
@ -90,7 +90,7 @@
|
|||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile=".\release\mysqlserver.lib"
|
||||
OutputFile="$(OutDir)\mysqlserver.lib"
|
||||
SuppressStartupBanner="TRUE"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
|
@ -117,6 +117,9 @@
|
|||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\dummy.cpp">
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
|
|
|
@ -4578,7 +4578,7 @@
|
|||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="protocol_cursor.cpp">
|
||||
RelativePath="sql_cursor.cpp">
|
||||
<FileConfiguration
|
||||
Name="classic nt|Win32">
|
||||
<Tool
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
AdditionalIncludeDirectories="../include,../"
|
||||
PreprocessorDefinitions="DBUG_OFF;_WINDOWS;SAFE_MUTEX;USE_TLS;MYSQL_CLIENT;__WIN__;_WIN32"
|
||||
StringPooling="TRUE"
|
||||
RuntimeLibrary="1"
|
||||
RuntimeLibrary="0"
|
||||
EnableFunctionLevelLinking="TRUE"
|
||||
PrecompiledHeaderFile=".\Release/mysql_client_test.pch"
|
||||
AssemblerListingLocation=".\Release/"
|
||||
|
@ -38,7 +38,7 @@
|
|||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib Ws2_32.lib mysqlclient.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib Ws2_32.lib"
|
||||
OutputFile="..\client_release\mysql_client_test.exe"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="TRUE"
|
||||
|
@ -98,7 +98,7 @@
|
|||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib mysqlclient.lib wsock32.lib mysys.lib regex.lib ..\extra\yassl\Debug\yassl.lib"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib"
|
||||
OutputFile="..\client_debug\mysql_client_test.exe"
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="TRUE"
|
||||
|
|
|
@ -4125,6 +4125,7 @@ int main(int argc, char **argv)
|
|||
error|= run_query(&cur_con->mysql, q, QUERY_REAP|QUERY_SEND);
|
||||
display_result_vertically= old_display_result_vertically;
|
||||
q->last_argument= q->end;
|
||||
query_executed= 1;
|
||||
break;
|
||||
}
|
||||
case Q_QUERY:
|
||||
|
|
|
@ -775,6 +775,7 @@ extern void my_free_lock(byte *ptr,myf flags);
|
|||
extern void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
|
||||
uint pre_alloc_size);
|
||||
extern gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size);
|
||||
extern gptr multi_alloc_root(MEM_ROOT *mem_root, ...);
|
||||
extern void free_root(MEM_ROOT *root, myf MyFLAGS);
|
||||
extern void set_prealloc_root(MEM_ROOT *root, char *ptr);
|
||||
extern void reset_root_defaults(MEM_ROOT *mem_root, uint block_size,
|
||||
|
|
|
@ -561,12 +561,12 @@ dtuple_convert_big_rec(
|
|||
}
|
||||
|
||||
/* We do not store externally fields which are smaller than
|
||||
DICT_MAX_COL_PREFIX_LEN */
|
||||
DICT_MAX_INDEX_COL_LEN */
|
||||
|
||||
ut_a(DICT_MAX_COL_PREFIX_LEN > REC_1BYTE_OFFS_LIMIT);
|
||||
ut_a(DICT_MAX_INDEX_COL_LEN > REC_1BYTE_OFFS_LIMIT);
|
||||
|
||||
if (longest < BTR_EXTERN_FIELD_REF_SIZE + 10
|
||||
+ DICT_MAX_COL_PREFIX_LEN) {
|
||||
+ DICT_MAX_INDEX_COL_LEN) {
|
||||
/* Cannot shorten more */
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
@ -588,10 +588,10 @@ dtuple_convert_big_rec(
|
|||
dfield = dtuple_get_nth_field(entry, longest_i);
|
||||
vector->fields[n_fields].field_no = longest_i;
|
||||
|
||||
ut_a(dfield->len > DICT_MAX_COL_PREFIX_LEN);
|
||||
ut_a(dfield->len > DICT_MAX_INDEX_COL_LEN);
|
||||
|
||||
vector->fields[n_fields].len = dfield->len
|
||||
- DICT_MAX_COL_PREFIX_LEN;
|
||||
- DICT_MAX_INDEX_COL_LEN;
|
||||
|
||||
vector->fields[n_fields].data = mem_heap_alloc(heap,
|
||||
vector->fields[n_fields].len);
|
||||
|
|
|
@ -1625,7 +1625,7 @@ dict_index_add_col(
|
|||
variable-length fields, so that the extern flag can be embedded in
|
||||
the length word. */
|
||||
|
||||
if (field->fixed_len > DICT_MAX_COL_PREFIX_LEN) {
|
||||
if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
|
||||
field->fixed_len = 0;
|
||||
}
|
||||
|
||||
|
@ -2189,7 +2189,7 @@ dict_foreign_error_report(
|
|||
dict_foreign_error_report_low(file, fk->foreign_table_name);
|
||||
fputs(msg, file);
|
||||
fputs(" Constraint:\n", file);
|
||||
dict_print_info_on_foreign_key_in_create_format(file, NULL, fk);
|
||||
dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
|
||||
if (fk->foreign_index) {
|
||||
fputs("\nThe index in the foreign key in table is ", file);
|
||||
ut_print_name(file, NULL, fk->foreign_index->name);
|
||||
|
@ -4330,9 +4330,10 @@ CREATE TABLE. */
|
|||
void
|
||||
dict_print_info_on_foreign_key_in_create_format(
|
||||
/*============================================*/
|
||||
FILE* file, /* in: file where to print */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_foreign_t* foreign)/* in: foreign key constraint */
|
||||
FILE* file, /* in: file where to print */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_foreign_t* foreign, /* in: foreign key constraint */
|
||||
ibool add_newline) /* in: whether to add a newline */
|
||||
{
|
||||
const char* stripped_id;
|
||||
ulint i;
|
||||
|
@ -4345,7 +4346,16 @@ dict_print_info_on_foreign_key_in_create_format(
|
|||
stripped_id = foreign->id;
|
||||
}
|
||||
|
||||
fputs(",\n CONSTRAINT ", file);
|
||||
putc(',', file);
|
||||
|
||||
if (add_newline) {
|
||||
/* SHOW CREATE TABLE wants constraints each printed nicely
|
||||
on its own line, while error messages want no newlines
|
||||
inserted. */
|
||||
fputs("\n ", file);
|
||||
}
|
||||
|
||||
fputs(" CONSTRAINT ", file);
|
||||
ut_print_name(file, trx, stripped_id);
|
||||
fputs(" FOREIGN KEY (", file);
|
||||
|
||||
|
@ -4447,7 +4457,7 @@ dict_print_info_on_foreign_keys(
|
|||
while (foreign != NULL) {
|
||||
if (create_table_format) {
|
||||
dict_print_info_on_foreign_key_in_create_format(
|
||||
file, trx, foreign);
|
||||
file, trx, foreign, TRUE);
|
||||
} else {
|
||||
ulint i;
|
||||
fputs("; (", file);
|
||||
|
|
|
@ -375,9 +375,10 @@ CREATE TABLE. */
|
|||
void
|
||||
dict_print_info_on_foreign_key_in_create_format(
|
||||
/*============================================*/
|
||||
FILE* file, /* in: file where to print */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_foreign_t* foreign);/* in: foreign key constraint */
|
||||
FILE* file, /* in: file where to print */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_foreign_t* foreign, /* in: foreign key constraint */
|
||||
ibool add_newline); /* in: whether to add a newline */
|
||||
/************************************************************************
|
||||
Displays the names of the index and the table. */
|
||||
void
|
||||
|
|
|
@ -152,12 +152,12 @@ struct dict_col_struct{
|
|||
in some of the functions below */
|
||||
};
|
||||
|
||||
/* DICT_MAX_COL_PREFIX_LEN is measured in bytes. Starting from 4.1.6, we
|
||||
set max col prefix len to < 3 * 256, so that one can create a column prefix
|
||||
index on 255 characters of a TEXT field also in the UTF-8 charset. In that
|
||||
charset, a character may take at most 3 bytes. */
|
||||
/* DICT_MAX_INDEX_COL_LEN is measured in bytes and is the max index column
|
||||
length + 1. Starting from 4.1.6, we set it to < 3 * 256, so that one can
|
||||
create a column prefix index on 255 characters of a TEXT field also in the
|
||||
UTF-8 charset. In that charset, a character may take at most 3 bytes. */
|
||||
|
||||
#define DICT_MAX_COL_PREFIX_LEN 768
|
||||
#define DICT_MAX_INDEX_COL_LEN 768
|
||||
|
||||
/* Data structure for a field in an index */
|
||||
struct dict_field_struct{
|
||||
|
@ -169,12 +169,12 @@ struct dict_field_struct{
|
|||
prefix in bytes in a MySQL index of
|
||||
type, e.g., INDEX (textcol(25));
|
||||
must be smaller than
|
||||
DICT_MAX_COL_PREFIX_LEN; NOTE that
|
||||
DICT_MAX_INDEX_COL_LEN; NOTE that
|
||||
in the UTF-8 charset, MySQL sets this
|
||||
to 3 * the prefix len in UTF-8 chars */
|
||||
ulint fixed_len; /* 0 or the fixed length of the
|
||||
column if smaller than
|
||||
DICT_MAX_COL_PREFIX_LEN */
|
||||
DICT_MAX_INDEX_COL_LEN */
|
||||
ulint fixed_offs; /* offset to the field, or
|
||||
ULINT_UNDEFINED if it is not fixed
|
||||
within the record (due to preceding
|
||||
|
|
|
@ -432,6 +432,17 @@ os_file_read(
|
|||
offset */
|
||||
ulint n); /* in: number of bytes to read */
|
||||
/***********************************************************************
|
||||
Rewind file to its start, read at most size - 1 bytes from it to str, and
|
||||
NUL-terminate str. All errors are silently ignored. This function is
|
||||
mostly meant to be used with temporary files. */
|
||||
|
||||
void
|
||||
os_file_read_string(
|
||||
/*================*/
|
||||
FILE* file, /* in: file to read from */
|
||||
char* str, /* in: buffer where to read */
|
||||
ulint size); /* in: size of buffer */
|
||||
/***********************************************************************
|
||||
Requests a synchronous positioned read operation. This function does not do
|
||||
any error handling. In case of error it returns FALSE. */
|
||||
|
||||
|
|
|
@ -335,8 +335,14 @@ int
|
|||
row_create_index_for_mysql(
|
||||
/*=======================*/
|
||||
/* out: error number or DB_SUCCESS */
|
||||
dict_index_t* index, /* in: index defintion */
|
||||
trx_t* trx); /* in: transaction handle */
|
||||
dict_index_t* index, /* in: index definition */
|
||||
trx_t* trx, /* in: transaction handle */
|
||||
const ulint* field_lengths); /* in: if not NULL, must contain
|
||||
dict_index_get_n_fields(index)
|
||||
actual field lengths for the
|
||||
index columns, which are
|
||||
then checked for not being too
|
||||
large. */
|
||||
/*************************************************************************
|
||||
Scans a table create SQL string and adds to the data dictionary
|
||||
the foreign key constraints declared in the string. This function
|
||||
|
|
|
@ -56,6 +56,22 @@ void
|
|||
trx_search_latch_release_if_reserved(
|
||||
/*=================================*/
|
||||
trx_t* trx); /* in: transaction */
|
||||
/**********************************************************************
|
||||
Set detailed error message for the transaction. */
|
||||
void
|
||||
trx_set_detailed_error(
|
||||
/*===================*/
|
||||
trx_t* trx, /* in: transaction struct */
|
||||
char* msg); /* in: detailed error message */
|
||||
/*****************************************************************
|
||||
Set detailed error message for the transaction from a file. Note that the
|
||||
file is rewinded before reading from it. */
|
||||
|
||||
void
|
||||
trx_set_detailed_error_from_file(
|
||||
/*=============================*/
|
||||
trx_t* trx, /* in: transaction struct */
|
||||
FILE* file); /* in: file to read message from */
|
||||
/********************************************************************
|
||||
Retrieves the error_info field from a trx. */
|
||||
|
||||
|
@ -205,7 +221,7 @@ trx_recover_for_mysql(
|
|||
XID* xid_list, /* in/out: prepared transactions */
|
||||
ulint len); /* in: number of slots in xid_list */
|
||||
/***********************************************************************
|
||||
This function is used to commit one X/Open XA distributed transaction
|
||||
This function is used to find one X/Open XA distributed transaction
|
||||
which is in the prepared state */
|
||||
trx_t *
|
||||
trx_get_trx_by_xid(
|
||||
|
@ -649,6 +665,9 @@ struct trx_struct{
|
|||
trx_undo_arr_t* undo_no_arr; /* array of undo numbers of undo log
|
||||
records which are currently processed
|
||||
by a rollback operation */
|
||||
/*------------------------------*/
|
||||
char detailed_error[256]; /* detailed error message for last
|
||||
error, or empty. */
|
||||
};
|
||||
|
||||
#define TRX_MAX_N_THREADS 32 /* maximum number of concurrent
|
||||
|
|
|
@ -118,6 +118,18 @@ UNIV_INLINE
|
|||
int
|
||||
ut_strcmp(const void* str1, const void* str2);
|
||||
|
||||
/**************************************************************************
|
||||
Copies up to size - 1 characters from the NUL-terminated string src to
|
||||
dst, NUL-terminating the result. Returns strlen(src), so truncation
|
||||
occurred if the return value >= size. */
|
||||
ulint
|
||||
ut_strlcpy(
|
||||
/*=======*/
|
||||
/* out: strlen(src) */
|
||||
char* dst, /* in: destination buffer */
|
||||
const char* src, /* in: source buffer */
|
||||
ulint size); /* in: size of destination buffer */
|
||||
|
||||
/**************************************************************************
|
||||
Compute strlen(ut_strcpyq(str, q)). */
|
||||
UNIV_INLINE
|
||||
|
|
|
@ -2248,6 +2248,29 @@ error_handling:
|
|||
return(FALSE);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
Rewind file to its start, read at most size - 1 bytes from it to str, and
|
||||
NUL-terminate str. All errors are silently ignored. This function is
|
||||
mostly meant to be used with temporary files. */
|
||||
|
||||
void
|
||||
os_file_read_string(
|
||||
/*================*/
|
||||
FILE* file, /* in: file to read from */
|
||||
char* str, /* in: buffer where to read */
|
||||
ulint size) /* in: size of buffer */
|
||||
{
|
||||
size_t flen;
|
||||
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
rewind(file);
|
||||
flen = fread(str, 1, size - 1, file);
|
||||
str[flen] = '\0';
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
Requests a synchronous write operation. */
|
||||
|
||||
|
|
|
@ -621,7 +621,7 @@ rec_set_nth_field_extern_bit_new(
|
|||
if (field->fixed_len) {
|
||||
/* fixed-length fields cannot be external
|
||||
(Fixed-length fields longer than
|
||||
DICT_MAX_COL_PREFIX_LEN will be treated as
|
||||
DICT_MAX_INDEX_COL_LEN will be treated as
|
||||
variable-length ones in dict_index_add_col().) */
|
||||
ut_ad(i != ith);
|
||||
continue;
|
||||
|
|
|
@ -578,6 +578,30 @@ row_ins_cascade_calc_update_vec(
|
|||
return(n_fields_updated);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Set detailed error message associated with foreign key errors for
|
||||
the given transaction. */
|
||||
static
|
||||
void
|
||||
row_ins_set_detailed(
|
||||
/*=================*/
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_foreign_t* foreign) /* in: foreign key constraint */
|
||||
{
|
||||
|
||||
FILE* tf = os_file_create_tmpfile();
|
||||
|
||||
ut_a(tf);
|
||||
|
||||
ut_print_name(tf, trx, foreign->foreign_table_name);
|
||||
dict_print_info_on_foreign_key_in_create_format(tf, trx,
|
||||
foreign, FALSE);
|
||||
|
||||
trx_set_detailed_error_from_file(trx, tf);
|
||||
|
||||
fclose(tf);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Reports a foreign key error associated with an update or a delete of a
|
||||
parent table index entry. */
|
||||
|
@ -598,6 +622,8 @@ row_ins_foreign_report_err(
|
|||
FILE* ef = dict_foreign_err_file;
|
||||
trx_t* trx = thr_get_trx(thr);
|
||||
|
||||
row_ins_set_detailed(trx, foreign);
|
||||
|
||||
mutex_enter(&dict_foreign_err_mutex);
|
||||
rewind(ef);
|
||||
ut_print_timestamp(ef);
|
||||
|
@ -607,7 +633,8 @@ row_ins_foreign_report_err(
|
|||
fputs("Foreign key constraint fails for table ", ef);
|
||||
ut_print_name(ef, trx, foreign->foreign_table_name);
|
||||
fputs(":\n", ef);
|
||||
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign);
|
||||
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
|
||||
TRUE);
|
||||
putc('\n', ef);
|
||||
fputs(errstr, ef);
|
||||
fputs(" in parent table, in index ", ef);
|
||||
|
@ -648,7 +675,9 @@ row_ins_foreign_report_add_err(
|
|||
child table */
|
||||
{
|
||||
FILE* ef = dict_foreign_err_file;
|
||||
|
||||
|
||||
row_ins_set_detailed(trx, foreign);
|
||||
|
||||
mutex_enter(&dict_foreign_err_mutex);
|
||||
rewind(ef);
|
||||
ut_print_timestamp(ef);
|
||||
|
@ -657,7 +686,8 @@ row_ins_foreign_report_add_err(
|
|||
fputs("Foreign key constraint fails for table ", ef);
|
||||
ut_print_name(ef, trx, foreign->foreign_table_name);
|
||||
fputs(":\n", ef);
|
||||
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign);
|
||||
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
|
||||
TRUE);
|
||||
fputs("\nTrying to add in child table, in index ", ef);
|
||||
ut_print_name(ef, trx, foreign->foreign_index->name);
|
||||
if (entry) {
|
||||
|
@ -1223,6 +1253,8 @@ run_again:
|
|||
|
||||
if (check_table == NULL || check_table->ibd_file_missing) {
|
||||
if (check_ref) {
|
||||
row_ins_set_detailed(trx, foreign);
|
||||
|
||||
FILE* ef = dict_foreign_err_file;
|
||||
mutex_enter(&dict_foreign_err_mutex);
|
||||
rewind(ef);
|
||||
|
@ -1233,7 +1265,7 @@ run_again:
|
|||
ut_print_name(ef, trx, foreign->foreign_table_name);
|
||||
fputs(":\n", ef);
|
||||
dict_print_info_on_foreign_key_in_create_format(ef,
|
||||
trx, foreign);
|
||||
trx, foreign, TRUE);
|
||||
fputs("\nTrying to add to index ", ef);
|
||||
ut_print_name(ef, trx, foreign->foreign_index->name);
|
||||
fputs(" tuple:\n", ef);
|
||||
|
|
|
@ -1973,13 +1973,20 @@ row_create_index_for_mysql(
|
|||
/*=======================*/
|
||||
/* out: error number or DB_SUCCESS */
|
||||
dict_index_t* index, /* in: index definition */
|
||||
trx_t* trx) /* in: transaction handle */
|
||||
trx_t* trx, /* in: transaction handle */
|
||||
const ulint* field_lengths) /* in: if not NULL, must contain
|
||||
dict_index_get_n_fields(index)
|
||||
actual field lengths for the
|
||||
index columns, which are
|
||||
then checked for not being too
|
||||
large. */
|
||||
{
|
||||
ind_node_t* node;
|
||||
mem_heap_t* heap;
|
||||
que_thr_t* thr;
|
||||
ulint err;
|
||||
ulint i, j;
|
||||
ulint len;
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
|
||||
|
@ -2018,10 +2025,16 @@ row_create_index_for_mysql(
|
|||
}
|
||||
}
|
||||
|
||||
/* Check also that prefix_len < DICT_MAX_COL_PREFIX_LEN */
|
||||
/* Check also that prefix_len and actual length
|
||||
< DICT_MAX_INDEX_COL_LEN */
|
||||
|
||||
if (dict_index_get_nth_field(index, i)->prefix_len
|
||||
>= DICT_MAX_COL_PREFIX_LEN) {
|
||||
len = dict_index_get_nth_field(index, i)->prefix_len;
|
||||
|
||||
if (field_lengths) {
|
||||
len = ut_max(len, field_lengths[i]);
|
||||
}
|
||||
|
||||
if (len >= DICT_MAX_INDEX_COL_LEN) {
|
||||
err = DB_TOO_BIG_RECORD;
|
||||
|
||||
goto error_handling;
|
||||
|
|
|
@ -52,6 +52,32 @@ trx_start_if_not_started_noninline(
|
|||
trx_start_if_not_started(trx);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Set detailed error message for the transaction. */
|
||||
|
||||
void
|
||||
trx_set_detailed_error(
|
||||
/*===================*/
|
||||
trx_t* trx, /* in: transaction struct */
|
||||
char* msg) /* in: detailed error message */
|
||||
{
|
||||
ut_strlcpy(trx->detailed_error, msg, sizeof(trx->detailed_error));
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Set detailed error message for the transaction from a file. Note that the
|
||||
file is rewinded before reading from it. */
|
||||
|
||||
void
|
||||
trx_set_detailed_error_from_file(
|
||||
/*=============================*/
|
||||
trx_t* trx, /* in: transaction struct */
|
||||
FILE* file) /* in: file to read message from */
|
||||
{
|
||||
os_file_read_string(file, trx->detailed_error,
|
||||
sizeof(trx->detailed_error));
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Retrieves the error_info field from a trx. */
|
||||
|
||||
|
@ -130,6 +156,7 @@ trx_create(
|
|||
trx->undo_no_arr = NULL;
|
||||
|
||||
trx->error_state = DB_SUCCESS;
|
||||
trx->detailed_error[0] = '\0';
|
||||
|
||||
trx->sess = sess;
|
||||
trx->que_state = TRX_QUE_RUNNING;
|
||||
|
|
|
@ -342,6 +342,31 @@ ut_free_all_mem(void)
|
|||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Copies up to size - 1 characters from the NUL-terminated string src to
|
||||
dst, NUL-terminating the result. Returns strlen(src), so truncation
|
||||
occurred if the return value >= size. */
|
||||
|
||||
ulint
|
||||
ut_strlcpy(
|
||||
/*=======*/
|
||||
/* out: strlen(src) */
|
||||
char* dst, /* in: destination buffer */
|
||||
const char* src, /* in: source buffer */
|
||||
ulint size) /* in: size of destination buffer */
|
||||
{
|
||||
ulint src_size = strlen(src);
|
||||
|
||||
if (size != 0) {
|
||||
ulint n = ut_min(src_size, size - 1);
|
||||
|
||||
memcpy(dst, src, n);
|
||||
dst[n] = '\0';
|
||||
}
|
||||
|
||||
return src_size;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Make a quoted copy of a NUL-terminated string. Leading and trailing
|
||||
quotes will not be included; only embedded quotes will be escaped.
|
||||
|
|
|
@ -60,7 +60,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
|
|||
sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \
|
||||
sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \
|
||||
unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \
|
||||
spatial.cc gstream.cc sql_help.cc tztime.cc protocol_cursor.cc \
|
||||
spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \
|
||||
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
|
||||
parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
|
||||
ha_blackhole.cc
|
||||
|
|
|
@ -2271,3 +2271,33 @@ select c1 from t1 where c1 like 'abcde111%' order by c1;
|
|||
c1
|
||||
abcde111
|
||||
drop table t1;
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
DROP PROCEDURE IF EXISTS sp1;
|
||||
set names ujis;
|
||||
set character_set_database = ujis;
|
||||
set character_set_server = ujis;
|
||||
CREATE TABLE t1(c1 char(2)) default charset = ujis;
|
||||
CREATE TABLE t2(c2 char(2)) default charset = ujis;
|
||||
INSERT INTO t1 VALUES(_ujis 0xA4A2);
|
||||
CREATE PROCEDURE sp1()
|
||||
BEGIN
|
||||
DECLARE a CHAR(1);
|
||||
DECLARE cur1 CURSOR FOR SELECT c1 FROM t1;
|
||||
OPEN cur1;
|
||||
FETCH cur1 INTO a;
|
||||
INSERT INTO t2 VALUES (a);
|
||||
CLOSE cur1;
|
||||
END|
|
||||
CALL sp1();
|
||||
SELECT c1,c2 FROM t1,t2;
|
||||
c1 c2
|
||||
¤¢ ¤¢
|
||||
SELECT hex(convert(_latin1 0xA4A2 using ujis)),hex(c2) FROM t1,t2;
|
||||
hex(convert(_latin1 0xA4A2 using ujis)) hex(c2)
|
||||
8FA2F0A1F1 A4A2
|
||||
DROP PROCEDURE sp1;
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t2;
|
||||
set names default;
|
||||
set character_set_database=default;
|
||||
set character_set_server=default;
|
||||
|
|
|
@ -821,6 +821,142 @@ SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
|
|||
MAX(id)
|
||||
NULL
|
||||
DROP TABLE t1;
|
||||
create table t1m (a int) engine=myisam;
|
||||
create table t1i (a int) engine=innodb;
|
||||
create table t2m (a int) engine=myisam;
|
||||
create table t2i (a int) engine=innodb;
|
||||
insert into t2m values (5);
|
||||
insert into t2i values (5);
|
||||
select min(a) from t1m;
|
||||
min(a)
|
||||
NULL
|
||||
select min(7) from t1m;
|
||||
min(7)
|
||||
NULL
|
||||
select min(7) from DUAL;
|
||||
min(7)
|
||||
NULL
|
||||
explain select min(7) from t2m join t1m;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
|
||||
select min(7) from t2m join t1m;
|
||||
min(7)
|
||||
NULL
|
||||
select max(a) from t1m;
|
||||
max(a)
|
||||
NULL
|
||||
select max(7) from t1m;
|
||||
max(7)
|
||||
NULL
|
||||
select max(7) from DUAL;
|
||||
max(7)
|
||||
NULL
|
||||
explain select max(7) from t2m join t1m;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
|
||||
select max(7) from t2m join t1m;
|
||||
max(7)
|
||||
NULL
|
||||
select 1, min(a) from t1m where a=99;
|
||||
1 min(a)
|
||||
1 NULL
|
||||
select 1, min(a) from t1m where 1=99;
|
||||
1 min(a)
|
||||
1 NULL
|
||||
select 1, min(1) from t1m where a=99;
|
||||
1 min(1)
|
||||
select 1, min(1) from t1m where 1=99;
|
||||
1 min(1)
|
||||
1 NULL
|
||||
select 1, max(a) from t1m where a=99;
|
||||
1 max(a)
|
||||
1 NULL
|
||||
select 1, max(a) from t1m where 1=99;
|
||||
1 max(a)
|
||||
1 NULL
|
||||
select 1, max(1) from t1m where a=99;
|
||||
1 max(1)
|
||||
select 1, max(1) from t1m where 1=99;
|
||||
1 max(1)
|
||||
1 NULL
|
||||
select min(a) from t1i;
|
||||
min(a)
|
||||
NULL
|
||||
select min(7) from t1i;
|
||||
min(7)
|
||||
NULL
|
||||
select min(7) from DUAL;
|
||||
min(7)
|
||||
NULL
|
||||
explain select min(7) from t2i join t1i;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2i ALL NULL NULL NULL NULL 1
|
||||
1 SIMPLE t1i ALL NULL NULL NULL NULL 1
|
||||
select min(7) from t2i join t1i;
|
||||
min(7)
|
||||
NULL
|
||||
select max(a) from t1i;
|
||||
max(a)
|
||||
NULL
|
||||
select max(7) from t1i;
|
||||
max(7)
|
||||
NULL
|
||||
select max(7) from DUAL;
|
||||
max(7)
|
||||
NULL
|
||||
explain select max(7) from t2i join t1i;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2i ALL NULL NULL NULL NULL 1
|
||||
1 SIMPLE t1i ALL NULL NULL NULL NULL 1
|
||||
select max(7) from t2i join t1i;
|
||||
max(7)
|
||||
NULL
|
||||
select 1, min(a) from t1i where a=99;
|
||||
1 min(a)
|
||||
1 NULL
|
||||
select 1, min(a) from t1i where 1=99;
|
||||
1 min(a)
|
||||
1 NULL
|
||||
select 1, min(1) from t1i where a=99;
|
||||
1 min(1)
|
||||
1 NULL
|
||||
select 1, min(1) from t1i where 1=99;
|
||||
1 min(1)
|
||||
1 NULL
|
||||
select 1, max(a) from t1i where a=99;
|
||||
1 max(a)
|
||||
1 NULL
|
||||
select 1, max(a) from t1i where 1=99;
|
||||
1 max(a)
|
||||
1 NULL
|
||||
select 1, max(1) from t1i where a=99;
|
||||
1 max(1)
|
||||
1 NULL
|
||||
select 1, max(1) from t1i where 1=99;
|
||||
1 max(1)
|
||||
1 NULL
|
||||
explain select count(*), min(7), max(7) from t1m, t1i;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found
|
||||
1 SIMPLE t1i ALL NULL NULL NULL NULL 1
|
||||
select count(*), min(7), max(7) from t1m, t1i;
|
||||
count(*) min(7) max(7)
|
||||
0 NULL NULL
|
||||
explain select count(*), min(7), max(7) from t1m, t2i;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found
|
||||
1 SIMPLE t2i ALL NULL NULL NULL NULL 1
|
||||
select count(*), min(7), max(7) from t1m, t2i;
|
||||
count(*) min(7) max(7)
|
||||
0 NULL NULL
|
||||
explain select count(*), min(7), max(7) from t2m, t1i;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2m system NULL NULL NULL NULL 1
|
||||
1 SIMPLE t1i ALL NULL NULL NULL NULL 1
|
||||
select count(*), min(7), max(7) from t2m, t1i;
|
||||
count(*) min(7) max(7)
|
||||
0 NULL NULL
|
||||
drop table t1m, t1i, t2m, t2i;
|
||||
create table t2 (ff double);
|
||||
insert into t2 values (2.2);
|
||||
select cast(sum(distinct ff) as decimal(5,2)) from t2;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
DROP TABLE IF EXISTS t0,t1,t2,t3,t5;
|
||||
DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5;
|
||||
DROP VIEW IF EXISTS v1;
|
||||
show variables where variable_name like "skip_show_database";
|
||||
Variable_name Value
|
||||
skip_show_database OFF
|
||||
|
@ -638,8 +639,8 @@ use test;
|
|||
create function sub1(i int) returns int
|
||||
return i+1;
|
||||
create table t1(f1 int);
|
||||
create view t2 (c) as select f1 from t1;
|
||||
create view t3 (c) as select sub1(1);
|
||||
create view v2 (c) as select f1 from t1;
|
||||
create view v3 (c) as select sub1(1);
|
||||
create table t4(f1 int, KEY f1_key (f1));
|
||||
drop table t1;
|
||||
drop function sub1;
|
||||
|
@ -647,29 +648,29 @@ select table_name from information_schema.views
|
|||
where table_schema='test';
|
||||
table_name
|
||||
Warnings:
|
||||
Warning 1356 View 'test.t2' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.t3' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s)
|
||||
select table_name from information_schema.views
|
||||
where table_schema='test';
|
||||
table_name
|
||||
Warnings:
|
||||
Warning 1356 View 'test.t2' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.t3' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s)
|
||||
select column_name from information_schema.columns
|
||||
where table_schema='test';
|
||||
column_name
|
||||
f1
|
||||
Warnings:
|
||||
Warning 1356 View 'test.t2' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.t3' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.v2' references invalid table(s) or column(s) or function(s)
|
||||
Warning 1356 View 'test.v3' references invalid table(s) or column(s) or function(s)
|
||||
select index_name from information_schema.statistics where table_schema='test';
|
||||
index_name
|
||||
f1_key
|
||||
select constraint_name from information_schema.table_constraints
|
||||
where table_schema='test';
|
||||
constraint_name
|
||||
drop view t2;
|
||||
drop view t3;
|
||||
drop view v2;
|
||||
drop view v3;
|
||||
drop table t4;
|
||||
select * from information_schema.table_names;
|
||||
ERROR 42S02: Unknown table 'table_names' in information_schema
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
DROP TABLE IF EXISTS t1,t2;
|
||||
DROP TABLE IF EXISTS t1,t2,t3;
|
||||
CREATE TABLE t1 (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB;
|
||||
CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id, id),
|
||||
FOREIGN KEY (t1_id) REFERENCES t1(id) ON DELETE CASCADE,
|
||||
|
|
|
@ -1378,9 +1378,9 @@ insert into `t2`values ( 1 ) ;
|
|||
create table `t3` (`id` int( 11 ) not null default '0',key `id` ( `id` ) ,constraint `t2_id_fk` foreign key ( `id` ) references `t2` (`id` )) engine = innodb;
|
||||
insert into `t3`values ( 1 ) ;
|
||||
delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
|
||||
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
|
||||
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`))
|
||||
update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
|
||||
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
|
||||
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`))
|
||||
update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
|
||||
ERROR 42S22: Unknown column 't1.id' in 'where clause'
|
||||
drop table t3,t2,t1;
|
||||
|
@ -1392,7 +1392,7 @@ foreign key(pid) references t1(id) on delete cascade) engine=innodb;
|
|||
insert into t1 values(0,0),(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6),
|
||||
(8,7),(9,8),(10,9),(11,10),(12,11),(13,12),(14,13),(15,14);
|
||||
delete from t1 where id=0;
|
||||
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
|
||||
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t1`, CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `t1` (`id`) ON DELETE CASCADE)
|
||||
delete from t1 where id=15;
|
||||
delete from t1 where id=0;
|
||||
drop table t1;
|
||||
|
@ -2559,3 +2559,60 @@ FOREIGN KEY (b) REFERENCES test.t1(id)
|
|||
) ENGINE=InnoDB;
|
||||
Got one of the listed errors
|
||||
DROP TABLE t1;
|
||||
create table t1 (col1 varchar(2000), index (col1(767)))
|
||||
character set = latin1 engine = innodb;
|
||||
create table t2 (col1 char(255), index (col1))
|
||||
character set = latin1 engine = innodb;
|
||||
create table t3 (col1 binary(255), index (col1))
|
||||
character set = latin1 engine = innodb;
|
||||
create table t4 (col1 varchar(767), index (col1))
|
||||
character set = latin1 engine = innodb;
|
||||
create table t5 (col1 varchar(767) primary key)
|
||||
character set = latin1 engine = innodb;
|
||||
create table t6 (col1 varbinary(767) primary key)
|
||||
character set = latin1 engine = innodb;
|
||||
create table t7 (col1 text, index(col1(767)))
|
||||
character set = latin1 engine = innodb;
|
||||
create table t8 (col1 blob, index(col1(767)))
|
||||
character set = latin1 engine = innodb;
|
||||
create table t9 (col1 varchar(512), col2 varchar(512), index(col1, col2))
|
||||
character set = latin1 engine = innodb;
|
||||
drop table t1, t2, t3, t4, t5, t6, t7, t8, t9;
|
||||
create table t1 (col1 varchar(768), index (col1))
|
||||
character set = latin1 engine = innodb;
|
||||
ERROR HY000: Can't create table './test/t1.frm' (errno: 139)
|
||||
create table t2 (col1 varchar(768) primary key)
|
||||
character set = latin1 engine = innodb;
|
||||
ERROR HY000: Can't create table './test/t2.frm' (errno: 139)
|
||||
create table t3 (col1 varbinary(768) primary key)
|
||||
character set = latin1 engine = innodb;
|
||||
ERROR HY000: Can't create table './test/t3.frm' (errno: 139)
|
||||
create table t4 (col1 text, index(col1(768)))
|
||||
character set = latin1 engine = innodb;
|
||||
ERROR HY000: Can't create table './test/t4.frm' (errno: 139)
|
||||
create table t5 (col1 blob, index(col1(768)))
|
||||
character set = latin1 engine = innodb;
|
||||
ERROR HY000: Can't create table './test/t5.frm' (errno: 139)
|
||||
CREATE TABLE t1
|
||||
(
|
||||
id INT PRIMARY KEY
|
||||
) ENGINE=InnoDB;
|
||||
CREATE TABLE t2
|
||||
(
|
||||
v INT,
|
||||
CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id)
|
||||
) ENGINE=InnoDB;
|
||||
INSERT INTO t2 VALUES(2);
|
||||
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`))
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t2 VALUES(1);
|
||||
DELETE FROM t1 WHERE id = 1;
|
||||
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`))
|
||||
DROP TABLE t1;
|
||||
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
DROP TABLE t1;
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
INSERT INTO t2 VALUES(3);
|
||||
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`))
|
||||
DROP TABLE t2;
|
||||
|
|
|
@ -66,6 +66,17 @@ a b
|
|||
3 row 3
|
||||
0
|
||||
drop table t1;
|
||||
SET @OLD_SQL_MODE=@@SQL_MODE, @@SQL_MODE=NO_AUTO_VALUE_ON_ZERO;
|
||||
create table t1(id integer not null auto_increment primary key);
|
||||
insert into t1 values(0);
|
||||
select * from t1;
|
||||
id
|
||||
0
|
||||
select * from t1;
|
||||
id
|
||||
0
|
||||
SET @@SQL_MODE=@OLD_SQL_MODE;
|
||||
drop table t1;
|
||||
create table t1 (a int default 100, b int, c varchar(60));
|
||||
load data infile '../../std_data/rpl_loaddata.dat' into table t1 (a, @b) set b=@b+10, c=concat("b=",@b);
|
||||
select * from t1;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
DROP TABLE IF EXISTS t1;
|
||||
select 1;
|
||||
1
|
||||
1
|
||||
|
|
|
@ -5,3 +5,10 @@ GRANT USAGE ON *.* TO 'mysqltest_1'@'127.0.0.1/255.255.255.255'
|
|||
GRANT ALL PRIVILEGES ON `test`.* TO 'mysqltest_1'@'127.0.0.1/255.255.255.255'
|
||||
REVOKE ALL ON test.* FROM mysqltest_1@'127.0.0.1/255.255.255.255';
|
||||
DROP USER mysqltest_1@'127.0.0.1/255.255.255.255';
|
||||
select user();
|
||||
user()
|
||||
#
|
||||
show processlist;
|
||||
Id User Host db Command Time State Info
|
||||
# root # test Sleep # NULL
|
||||
# root # test Query # NULL show processlist
|
||||
|
|
|
@ -13,3 +13,49 @@ select @value;
|
|||
3
|
||||
drop procedure test.longprocedure;
|
||||
drop table t1;
|
||||
create table t1 (f1 char(100) , f2 mediumint , f3 int , f4 real, f5 numeric);
|
||||
insert into t1 (f1, f2, f3, f4, f5) values
|
||||
("This is a test case for for Bug#9819", 1, 2, 3.0, 4.598);
|
||||
Warnings:
|
||||
Note 1265 Data truncated for column 'f5' at row 1
|
||||
create table t2 like t1;
|
||||
select count(*) from t1;
|
||||
count(*)
|
||||
256
|
||||
select count(*) from t2;
|
||||
count(*)
|
||||
0
|
||||
create procedure p1()
|
||||
begin
|
||||
declare done integer default 0;
|
||||
declare vf1 char(100) ;
|
||||
declare vf2 mediumint;
|
||||
declare vf3 int ;
|
||||
declare vf4 real ;
|
||||
declare vf5 numeric ;
|
||||
declare cur1 cursor for select f1,f2,f3,f4,f5 from t1;
|
||||
declare continue handler for sqlstate '02000' set done = 1;
|
||||
open cur1;
|
||||
while done <> 1 do
|
||||
fetch cur1 into vf1, vf2, vf3, vf4, vf5;
|
||||
if not done then
|
||||
insert into t2 values (vf1, vf2, vf3, vf4, vf5);
|
||||
end if;
|
||||
end while;
|
||||
close cur1;
|
||||
end|
|
||||
call p1();
|
||||
select count(*) from t1;
|
||||
count(*)
|
||||
256
|
||||
select count(*) from t2;
|
||||
count(*)
|
||||
256
|
||||
select f1 from t1 limit 1;
|
||||
f1
|
||||
This is a test case for for Bug#9819
|
||||
select f1 from t2 limit 1;
|
||||
f1
|
||||
This is a test case for for Bug#9819
|
||||
drop procedure p1;
|
||||
drop table t1, t2;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
drop table if exists t1,t2;
|
||||
drop view if exists v1;
|
||||
CREATE TABLE t1 (c int not null, d char (10) not null);
|
||||
insert into t1 values(1,""),(2,"a"),(3,"b");
|
||||
CREATE TEMPORARY TABLE t1 (a int not null, b char (10) not null);
|
||||
|
@ -99,32 +100,32 @@ Variable_name Value
|
|||
Created_tmp_disk_tables 0
|
||||
Created_tmp_tables 2
|
||||
drop table t1;
|
||||
create temporary table t1 as select 'This is temp. table' A;
|
||||
create view t1 as select 'This is view' A;
|
||||
select * from t1;
|
||||
create temporary table v1 as select 'This is temp. table' A;
|
||||
create view v1 as select 'This is view' A;
|
||||
select * from v1;
|
||||
A
|
||||
This is temp. table
|
||||
show create table t1;
|
||||
show create table v1;
|
||||
Table Create Table
|
||||
t1 CREATE TEMPORARY TABLE `t1` (
|
||||
v1 CREATE TEMPORARY TABLE `v1` (
|
||||
`A` varchar(19) NOT NULL default ''
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
show create view t1;
|
||||
show create view v1;
|
||||
View Create View
|
||||
t1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `t1` AS select _latin1'This is view' AS `A`
|
||||
drop view t1;
|
||||
select * from t1;
|
||||
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select _latin1'This is view' AS `A`
|
||||
drop view v1;
|
||||
select * from v1;
|
||||
A
|
||||
This is temp. table
|
||||
create view t1 as select 'This is view again' A;
|
||||
select * from t1;
|
||||
create view v1 as select 'This is view again' A;
|
||||
select * from v1;
|
||||
A
|
||||
This is temp. table
|
||||
drop table t1;
|
||||
select * from t1;
|
||||
drop table v1;
|
||||
select * from v1;
|
||||
A
|
||||
This is view again
|
||||
drop view t1;
|
||||
drop view v1;
|
||||
create table t1 (a int, b int, index(a), index(b));
|
||||
create table t2 (c int auto_increment, d varchar(255), primary key (c));
|
||||
insert into t1 values (3,1),(3,2);
|
||||
|
|
|
@ -553,3 +553,13 @@ sum(a1) b1+0 b2+0
|
|||
2 0 0
|
||||
4 2 2
|
||||
8 1 1
|
||||
select 1 from t1 join t2 on b1 = b2 group by b1 order by 1;
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
select b1+0,sum(b1), sum(b2) from t1 join t2 on b1 = b2 group by b1 order by 1;
|
||||
b1+0 sum(b1) sum(b2)
|
||||
0 0 0
|
||||
1 4 4
|
||||
2 2 2
|
||||
|
|
|
@ -672,6 +672,17 @@ a
|
|||
9999.999
|
||||
0000.000
|
||||
drop table t1;
|
||||
create table t1(a decimal(10,5), b decimal(10,1));
|
||||
insert into t1 values(123.12345, 123.12345);
|
||||
Warnings:
|
||||
Note 1265 Data truncated for column 'b' at row 1
|
||||
update t1 set b=a;
|
||||
Warnings:
|
||||
Note 1265 Data truncated for column 'b' at row 1
|
||||
select * from t1;
|
||||
a b
|
||||
123.12345 123.1
|
||||
drop table t1;
|
||||
CREATE TABLE t1
|
||||
(EMPNUM CHAR(3) NOT NULL,
|
||||
HOURS DECIMAL(5));
|
||||
|
|
|
@ -780,21 +780,6 @@ t1 CREATE TABLE `t1` (
|
|||
`b` longblob
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
drop table t1,t2;
|
||||
create table t1 (d decimal(10,1));
|
||||
create table t2 (d decimal(10,9));
|
||||
insert into t1 values ("100000000.0");
|
||||
insert into t2 values ("1.23456780");
|
||||
create table t3 select * from t2 union select * from t1;
|
||||
select * from t3;
|
||||
d
|
||||
1.234567800
|
||||
100000000.000000000
|
||||
show create table t3;
|
||||
Table Create Table
|
||||
t3 CREATE TABLE `t3` (
|
||||
`d` decimal(18,9) default NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
drop table t1,t2,t3;
|
||||
create table t1 select 1 union select -1;
|
||||
select * from t1;
|
||||
1
|
||||
|
|
|
@ -1151,3 +1151,45 @@ SET collation_connection='ujis_bin';
|
|||
-- source include/ctype_innodb_like.inc
|
||||
|
||||
# End of 4.1 tests
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
DROP PROCEDURE IF EXISTS sp1;
|
||||
--enable_warnings
|
||||
|
||||
set names ujis;
|
||||
set character_set_database = ujis;
|
||||
set character_set_server = ujis;
|
||||
|
||||
CREATE TABLE t1(c1 char(2)) default charset = ujis;
|
||||
CREATE TABLE t2(c2 char(2)) default charset = ujis;
|
||||
|
||||
INSERT INTO t1 VALUES(_ujis 0xA4A2);
|
||||
|
||||
DELIMITER |;
|
||||
CREATE PROCEDURE sp1()
|
||||
BEGIN
|
||||
DECLARE a CHAR(1);
|
||||
DECLARE cur1 CURSOR FOR SELECT c1 FROM t1;
|
||||
OPEN cur1;
|
||||
FETCH cur1 INTO a;
|
||||
INSERT INTO t2 VALUES (a);
|
||||
CLOSE cur1;
|
||||
END|
|
||||
DELIMITER ;|
|
||||
CALL sp1();
|
||||
|
||||
#The data in t1 and t2 should be the same but different
|
||||
SELECT c1,c2 FROM t1,t2;
|
||||
|
||||
#Since the result of hex(convert(_latin1 0xA4A2 using ujis))
|
||||
#equals to hex(c2), it seems that the value which was inserted
|
||||
#by using cursor is interpreted as latin1 character set
|
||||
SELECT hex(convert(_latin1 0xA4A2 using ujis)),hex(c2) FROM t1,t2;
|
||||
|
||||
DROP PROCEDURE sp1;
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t2;
|
||||
|
||||
set names default;
|
||||
set character_set_database=default;
|
||||
set character_set_server=default;
|
||||
|
|
|
@ -539,6 +539,75 @@ INSERT INTO t1 VALUES
|
|||
SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# Bug #12882 min/max inconsistent on empty table
|
||||
#
|
||||
|
||||
create table t1m (a int) engine=myisam;
|
||||
create table t1i (a int) engine=innodb;
|
||||
create table t2m (a int) engine=myisam;
|
||||
create table t2i (a int) engine=innodb;
|
||||
insert into t2m values (5);
|
||||
insert into t2i values (5);
|
||||
|
||||
# test with MyISAM
|
||||
select min(a) from t1m;
|
||||
select min(7) from t1m;
|
||||
select min(7) from DUAL;
|
||||
explain select min(7) from t2m join t1m;
|
||||
select min(7) from t2m join t1m;
|
||||
|
||||
select max(a) from t1m;
|
||||
select max(7) from t1m;
|
||||
select max(7) from DUAL;
|
||||
explain select max(7) from t2m join t1m;
|
||||
select max(7) from t2m join t1m;
|
||||
|
||||
select 1, min(a) from t1m where a=99;
|
||||
select 1, min(a) from t1m where 1=99;
|
||||
select 1, min(1) from t1m where a=99;
|
||||
select 1, min(1) from t1m where 1=99;
|
||||
|
||||
select 1, max(a) from t1m where a=99;
|
||||
select 1, max(a) from t1m where 1=99;
|
||||
select 1, max(1) from t1m where a=99;
|
||||
select 1, max(1) from t1m where 1=99;
|
||||
|
||||
# test with InnoDB
|
||||
select min(a) from t1i;
|
||||
select min(7) from t1i;
|
||||
select min(7) from DUAL;
|
||||
explain select min(7) from t2i join t1i;
|
||||
select min(7) from t2i join t1i;
|
||||
|
||||
select max(a) from t1i;
|
||||
select max(7) from t1i;
|
||||
select max(7) from DUAL;
|
||||
explain select max(7) from t2i join t1i;
|
||||
select max(7) from t2i join t1i;
|
||||
|
||||
select 1, min(a) from t1i where a=99;
|
||||
select 1, min(a) from t1i where 1=99;
|
||||
select 1, min(1) from t1i where a=99;
|
||||
select 1, min(1) from t1i where 1=99;
|
||||
|
||||
select 1, max(a) from t1i where a=99;
|
||||
select 1, max(a) from t1i where 1=99;
|
||||
select 1, max(1) from t1i where a=99;
|
||||
select 1, max(1) from t1i where 1=99;
|
||||
|
||||
# mixed MyISAM/InnoDB test
|
||||
explain select count(*), min(7), max(7) from t1m, t1i;
|
||||
select count(*), min(7), max(7) from t1m, t1i;
|
||||
|
||||
explain select count(*), min(7), max(7) from t1m, t2i;
|
||||
select count(*), min(7), max(7) from t1m, t2i;
|
||||
|
||||
explain select count(*), min(7), max(7) from t2m, t1i;
|
||||
select count(*), min(7), max(7) from t2m, t1i;
|
||||
|
||||
drop table t1m, t1i, t2m, t2i;
|
||||
|
||||
# End of 4.1 tests
|
||||
|
||||
#
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
# show databases
|
||||
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t0,t1,t2,t3,t5;
|
||||
DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5;
|
||||
DROP VIEW IF EXISTS v1;
|
||||
--enable_warnings
|
||||
|
||||
|
||||
|
@ -364,8 +365,8 @@ use test;
|
|||
create function sub1(i int) returns int
|
||||
return i+1;
|
||||
create table t1(f1 int);
|
||||
create view t2 (c) as select f1 from t1;
|
||||
create view t3 (c) as select sub1(1);
|
||||
create view v2 (c) as select f1 from t1;
|
||||
create view v3 (c) as select sub1(1);
|
||||
create table t4(f1 int, KEY f1_key (f1));
|
||||
drop table t1;
|
||||
drop function sub1;
|
||||
|
@ -378,8 +379,8 @@ where table_schema='test';
|
|||
select index_name from information_schema.statistics where table_schema='test';
|
||||
select constraint_name from information_schema.table_constraints
|
||||
where table_schema='test';
|
||||
drop view t2;
|
||||
drop view t3;
|
||||
drop view v2;
|
||||
drop view v3;
|
||||
drop table t4;
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
-- source include/have_innodb.inc
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1,t2;
|
||||
DROP TABLE IF EXISTS t1,t2,t3;
|
||||
--enable_warnings
|
||||
|
||||
#
|
||||
|
|
|
@ -978,9 +978,9 @@ create table `t2` (`id` int( 11 ) not null default '0',unique key `id` ( `id` )
|
|||
insert into `t2`values ( 1 ) ;
|
||||
create table `t3` (`id` int( 11 ) not null default '0',key `id` ( `id` ) ,constraint `t2_id_fk` foreign key ( `id` ) references `t2` (`id` )) engine = innodb;
|
||||
insert into `t3`values ( 1 ) ;
|
||||
--error 1217
|
||||
--error 1451
|
||||
delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
|
||||
--error 1217
|
||||
--error 1451
|
||||
update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
|
||||
--error 1054
|
||||
update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
|
||||
|
@ -996,7 +996,7 @@ create table t1(
|
|||
foreign key(pid) references t1(id) on delete cascade) engine=innodb;
|
||||
insert into t1 values(0,0),(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6),
|
||||
(8,7),(9,8),(10,9),(11,10),(12,11),(13,12),(14,13),(15,14);
|
||||
-- error 1217
|
||||
-- error 1451
|
||||
delete from t1 where id=0;
|
||||
delete from t1 where id=15;
|
||||
delete from t1 where id=0;
|
||||
|
@ -1482,3 +1482,85 @@ CREATE TEMPORARY TABLE t2
|
|||
FOREIGN KEY (b) REFERENCES test.t1(id)
|
||||
) ENGINE=InnoDB;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# Test that index column max sizes are checked (bug #13315)
|
||||
#
|
||||
|
||||
# prefix index
|
||||
create table t1 (col1 varchar(2000), index (col1(767)))
|
||||
character set = latin1 engine = innodb;
|
||||
|
||||
# normal indexes
|
||||
create table t2 (col1 char(255), index (col1))
|
||||
character set = latin1 engine = innodb;
|
||||
create table t3 (col1 binary(255), index (col1))
|
||||
character set = latin1 engine = innodb;
|
||||
create table t4 (col1 varchar(767), index (col1))
|
||||
character set = latin1 engine = innodb;
|
||||
create table t5 (col1 varchar(767) primary key)
|
||||
character set = latin1 engine = innodb;
|
||||
create table t6 (col1 varbinary(767) primary key)
|
||||
character set = latin1 engine = innodb;
|
||||
create table t7 (col1 text, index(col1(767)))
|
||||
character set = latin1 engine = innodb;
|
||||
create table t8 (col1 blob, index(col1(767)))
|
||||
character set = latin1 engine = innodb;
|
||||
|
||||
# multi-column indexes are allowed to be longer
|
||||
create table t9 (col1 varchar(512), col2 varchar(512), index(col1, col2))
|
||||
character set = latin1 engine = innodb;
|
||||
|
||||
drop table t1, t2, t3, t4, t5, t6, t7, t8, t9;
|
||||
|
||||
--error 1005
|
||||
create table t1 (col1 varchar(768), index (col1))
|
||||
character set = latin1 engine = innodb;
|
||||
--error 1005
|
||||
create table t2 (col1 varchar(768) primary key)
|
||||
character set = latin1 engine = innodb;
|
||||
--error 1005
|
||||
create table t3 (col1 varbinary(768) primary key)
|
||||
character set = latin1 engine = innodb;
|
||||
--error 1005
|
||||
create table t4 (col1 text, index(col1(768)))
|
||||
character set = latin1 engine = innodb;
|
||||
--error 1005
|
||||
create table t5 (col1 blob, index(col1(768)))
|
||||
character set = latin1 engine = innodb;
|
||||
|
||||
#
|
||||
# Test improved foreign key error messages (bug #3443)
|
||||
#
|
||||
|
||||
CREATE TABLE t1
|
||||
(
|
||||
id INT PRIMARY KEY
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE t2
|
||||
(
|
||||
v INT,
|
||||
CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
--error 1452
|
||||
INSERT INTO t2 VALUES(2);
|
||||
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t2 VALUES(1);
|
||||
|
||||
--error 1451
|
||||
DELETE FROM t1 WHERE id = 1;
|
||||
|
||||
--error 1217
|
||||
DROP TABLE t1;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
DROP TABLE t1;
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
|
||||
--error 1452
|
||||
INSERT INTO t2 VALUES(3);
|
||||
|
||||
DROP TABLE t2;
|
||||
|
|
|
@ -31,6 +31,34 @@ load data infile '../../std_data/loaddata4.dat' into table t1 fields terminated
|
|||
select * from t1;
|
||||
drop table t1;
|
||||
|
||||
|
||||
#
|
||||
# Bug #12053 LOAD DATA INFILE ignores NO_AUTO_VALUE_ON_ZERO setting
|
||||
#
|
||||
SET @OLD_SQL_MODE=@@SQL_MODE, @@SQL_MODE=NO_AUTO_VALUE_ON_ZERO;
|
||||
create table t1(id integer not null auto_increment primary key);
|
||||
insert into t1 values(0);
|
||||
disable_query_log;
|
||||
eval SELECT * INTO OUTFILE '$MYSQL_TEST_DIR/var/tmp/t1' from t1;
|
||||
delete from t1;
|
||||
eval load data infile '$MYSQL_TEST_DIR/var/tmp/t1' into table t1;
|
||||
enable_query_log;
|
||||
select * from t1;
|
||||
--exec rm $MYSQL_TEST_DIR/var/tmp/t1
|
||||
|
||||
disable_query_log;
|
||||
eval SELECT * INTO OUTFILE '$MYSQL_TEST_DIR/var/tmp/t1'
|
||||
FIELDS TERMINATED BY '' OPTIONALLY ENCLOSED BY '' LINES TERMINATED BY '\r\n'
|
||||
FROM t1;
|
||||
delete from t1;
|
||||
eval load data infile '$MYSQL_TEST_DIR/var/tmp/t1' into table t1
|
||||
FIELDS TERMINATED BY '' OPTIONALLY ENCLOSED BY '' LINES TERMINATED BY '\r\n';
|
||||
enable_query_log;
|
||||
select * from t1;
|
||||
--exec rm $MYSQL_TEST_DIR/var/tmp/t1
|
||||
SET @@SQL_MODE=@OLD_SQL_MODE;
|
||||
drop table t1;
|
||||
|
||||
# End of 4.1 tests
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
# PS doesn't support multi-statements
|
||||
--disable_ps_protocol
|
||||
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1;
|
||||
--enable_warnings
|
||||
|
||||
select 1;
|
||||
delimiter ||||;
|
||||
select 2;
|
||||
|
|
|
@ -24,7 +24,7 @@ connection master;
|
|||
delete from t1;
|
||||
delete from t2;
|
||||
|
||||
connection slave;
|
||||
sync_slave_with_master;
|
||||
# force a difference to see if master's multi-DELETE will correct it
|
||||
insert into t1 values(1);
|
||||
insert into t2 values(1);
|
||||
|
|
|
@ -33,7 +33,7 @@ delete from t2;
|
|||
insert into t1 values(1,1);
|
||||
insert into t2 values(1,1);
|
||||
|
||||
connection slave;
|
||||
sync_slave_with_master;
|
||||
# force a difference to see if master's multi-UPDATE will correct it
|
||||
update t1 set a=2;
|
||||
|
||||
|
|
|
@ -8,3 +8,13 @@ REVOKE ALL ON test.* FROM mysqltest_1@'127.0.0.1/255.255.255.255';
|
|||
DROP USER mysqltest_1@'127.0.0.1/255.255.255.255';
|
||||
|
||||
# End of 4.1 tests
|
||||
|
||||
# Bug #13407 "Remote connecting crashes server".
|
||||
# Server crashed when one used USER() function in connection for which
|
||||
# was impossible to obtain peer hostname.
|
||||
connect (con1, 127.0.0.1, root, , test, $MASTER_MYPORT, );
|
||||
--replace_column 1 #
|
||||
select user();
|
||||
--replace_column 1 # 6 # 3 #
|
||||
show processlist;
|
||||
connection default;
|
||||
|
|
|
@ -31,3 +31,52 @@ call test.longprocedure(@value); select @value;
|
|||
|
||||
drop procedure test.longprocedure;
|
||||
drop table t1;
|
||||
#
|
||||
# Bug #9819 "Cursors: Mysql Server Crash while fetching from table with 5
|
||||
# million records.":
|
||||
# To really test the bug, increase the number of loop iterations ($1).
|
||||
# For 4 millions set $1 to 22.
|
||||
create table t1 (f1 char(100) , f2 mediumint , f3 int , f4 real, f5 numeric);
|
||||
insert into t1 (f1, f2, f3, f4, f5) values
|
||||
("This is a test case for for Bug#9819", 1, 2, 3.0, 4.598);
|
||||
create table t2 like t1;
|
||||
let $1=8;
|
||||
--disable_query_log
|
||||
--disable_result_log
|
||||
while ($1)
|
||||
{
|
||||
eval insert into t1 select * from t1;
|
||||
dec $1;
|
||||
}
|
||||
--enable_result_log
|
||||
--enable_query_log
|
||||
select count(*) from t1;
|
||||
select count(*) from t2;
|
||||
delimiter |;
|
||||
create procedure p1()
|
||||
begin
|
||||
declare done integer default 0;
|
||||
declare vf1 char(100) ;
|
||||
declare vf2 mediumint;
|
||||
declare vf3 int ;
|
||||
declare vf4 real ;
|
||||
declare vf5 numeric ;
|
||||
declare cur1 cursor for select f1,f2,f3,f4,f5 from t1;
|
||||
declare continue handler for sqlstate '02000' set done = 1;
|
||||
open cur1;
|
||||
while done <> 1 do
|
||||
fetch cur1 into vf1, vf2, vf3, vf4, vf5;
|
||||
if not done then
|
||||
insert into t2 values (vf1, vf2, vf3, vf4, vf5);
|
||||
end if;
|
||||
end while;
|
||||
close cur1;
|
||||
end|
|
||||
delimiter ;|
|
||||
call p1();
|
||||
select count(*) from t1;
|
||||
select count(*) from t2;
|
||||
select f1 from t1 limit 1;
|
||||
select f1 from t2 limit 1;
|
||||
drop procedure p1;
|
||||
drop table t1, t2;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
--disable_warnings
|
||||
drop table if exists t1,t2;
|
||||
drop view if exists v1;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 (c int not null, d char (10) not null);
|
||||
|
@ -91,18 +92,18 @@ show status like "created_tmp%tables";
|
|||
drop table t1;
|
||||
|
||||
# Fix for BUG#8921: Check that temporary table is ingored by view commands.
|
||||
create temporary table t1 as select 'This is temp. table' A;
|
||||
create view t1 as select 'This is view' A;
|
||||
select * from t1;
|
||||
show create table t1;
|
||||
show create view t1;
|
||||
drop view t1;
|
||||
select * from t1;
|
||||
create view t1 as select 'This is view again' A;
|
||||
select * from t1;
|
||||
drop table t1;
|
||||
select * from t1;
|
||||
drop view t1;
|
||||
create temporary table v1 as select 'This is temp. table' A;
|
||||
create view v1 as select 'This is view' A;
|
||||
select * from v1;
|
||||
show create table v1;
|
||||
show create view v1;
|
||||
drop view v1;
|
||||
select * from v1;
|
||||
create view v1 as select 'This is view again' A;
|
||||
select * from v1;
|
||||
drop table v1;
|
||||
select * from v1;
|
||||
drop view v1;
|
||||
|
||||
# Bug #8497: tmpdir with extra slashes would cause failures
|
||||
#
|
||||
|
|
|
@ -224,3 +224,5 @@ select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2;
|
|||
select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2 order by a1;
|
||||
select a1, a2, b1+0, b2+0 from t1 join t2 on b1 = b2;
|
||||
select sum(a1), b1+0, b2+0 from t1 join t2 on b1 = b2 group by b1 order by 1;
|
||||
select 1 from t1 join t2 on b1 = b2 group by b1 order by 1;
|
||||
select b1+0,sum(b1), sum(b2) from t1 join t2 on b1 = b2 group by b1 order by 1;
|
||||
|
|
|
@ -268,6 +268,16 @@ insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000
|
|||
select * from t1;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Bug #7589: a problem with update from column
|
||||
#
|
||||
|
||||
create table t1(a decimal(10,5), b decimal(10,1));
|
||||
insert into t1 values(123.12345, 123.12345);
|
||||
update t1 set b=a;
|
||||
select * from t1;
|
||||
drop table t1;
|
||||
|
||||
# End of 4.1 tests
|
||||
|
||||
#
|
||||
|
|
|
@ -443,14 +443,6 @@ create table t1 SELECT b from t2 UNION select tx from t2;
|
|||
select * from t1;
|
||||
show create table t1;
|
||||
drop table t1,t2;
|
||||
create table t1 (d decimal(10,1));
|
||||
create table t2 (d decimal(10,9));
|
||||
insert into t1 values ("100000000.0");
|
||||
insert into t2 values ("1.23456780");
|
||||
create table t3 select * from t2 union select * from t1;
|
||||
select * from t3;
|
||||
show create table t3;
|
||||
drop table t1,t2,t3;
|
||||
create table t1 select 1 union select -1;
|
||||
select * from t1;
|
||||
show create table t1;
|
||||
|
|
|
@ -51,6 +51,16 @@
|
|||
fun:pthread_create
|
||||
}
|
||||
|
||||
{
|
||||
pthread pthread_key_create
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:*
|
||||
fun:*
|
||||
fun:pthread_key_create
|
||||
fun:my_thread_global_init
|
||||
}
|
||||
|
||||
{
|
||||
pthread strstr uninit
|
||||
Memcheck:Cond
|
||||
|
@ -127,8 +137,18 @@
|
|||
{
|
||||
libz deflate
|
||||
Memcheck:Cond
|
||||
obj:/usr/lib/libz.so.*
|
||||
obj:/usr/lib/libz.so.*
|
||||
obj:*/libz.so.*
|
||||
obj:*/libz.so.*
|
||||
fun:deflate
|
||||
fun:compress2
|
||||
}
|
||||
|
||||
{
|
||||
libz deflate2
|
||||
Memcheck:Cond
|
||||
obj:*/libz.so.*
|
||||
obj:*/libz.so.*
|
||||
fun:deflate
|
||||
obj:*/libz.so.*
|
||||
fun:gzflush
|
||||
}
|
||||
|
|
|
@ -221,6 +221,57 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Allocate many pointers at the same time.
|
||||
|
||||
DESCRIPTION
|
||||
ptr1, ptr2, etc all point into big allocated memory area.
|
||||
|
||||
SYNOPSIS
|
||||
multi_alloc_root()
|
||||
root Memory root
|
||||
ptr1, length1 Multiple arguments terminated by a NULL pointer
|
||||
ptr2, length2 ...
|
||||
...
|
||||
NULL
|
||||
|
||||
RETURN VALUE
|
||||
A pointer to the beginning of the allocated memory block
|
||||
in case of success or NULL if out of memory.
|
||||
*/
|
||||
|
||||
gptr multi_alloc_root(MEM_ROOT *root, ...)
|
||||
{
|
||||
va_list args;
|
||||
char **ptr, *start, *res;
|
||||
uint tot_length, length;
|
||||
DBUG_ENTER("multi_alloc_root");
|
||||
|
||||
va_start(args, root);
|
||||
tot_length= 0;
|
||||
while ((ptr= va_arg(args, char **)))
|
||||
{
|
||||
length= va_arg(args, uint);
|
||||
tot_length+= ALIGN_SIZE(length);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
if (!(start= (char*) alloc_root(root, tot_length)))
|
||||
DBUG_RETURN(0); /* purecov: inspected */
|
||||
|
||||
va_start(args, root);
|
||||
res= start;
|
||||
while ((ptr= va_arg(args, char **)))
|
||||
{
|
||||
*ptr= res;
|
||||
length= va_arg(args, uint);
|
||||
res+= ALIGN_SIZE(length);
|
||||
}
|
||||
va_end(args);
|
||||
DBUG_RETURN((gptr) start);
|
||||
}
|
||||
|
||||
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
|
||||
|
||||
/* Mark all data in blocks free for reusage */
|
||||
|
|
|
@ -169,7 +169,8 @@ for i in \
|
|||
libmysql_r/.libs/libmysqlclient_r.so* libmysql_r/libmysqlclient_r.* \
|
||||
mysys/libmysys.a strings/libmystrings.a dbug/libdbug.a \
|
||||
libmysqld/.libs/libmysqld.a libmysqld/.libs/libmysqld.so* \
|
||||
libmysqld/libmysqld.a netware/libmysql.imp
|
||||
libmysqld/libmysqld.a netware/libmysql.imp \
|
||||
zlib/.libs/libz.a
|
||||
do
|
||||
if [ -f $i ]
|
||||
then
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
OutputDirectory="../../client_debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
|
@ -63,7 +63,7 @@
|
|||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
OutputDirectory="../../client_release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
|
|
|
@ -61,7 +61,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
|
|||
tztime.h my_decimal.h\
|
||||
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
|
||||
parse_file.h sql_view.h sql_trigger.h \
|
||||
sql_array.h \
|
||||
sql_array.h sql_cursor.h \
|
||||
examples/ha_example.h examples/ha_archive.h \
|
||||
examples/ha_tina.h ha_blackhole.h \
|
||||
ha_federated.h
|
||||
|
@ -94,7 +94,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
|
|||
client.c sql_client.cc mini_client_errors.c pack.c\
|
||||
stacktrace.c repl_failsafe.h repl_failsafe.cc \
|
||||
sql_olap.cc sql_view.cc \
|
||||
gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \
|
||||
gstream.cc spatial.cc sql_help.cc sql_cursor.cc \
|
||||
tztime.cc my_time.c my_decimal.cc\
|
||||
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
|
||||
sp_cache.cc parse_file.cc sql_trigger.cc \
|
||||
|
|
|
@ -588,12 +588,15 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table,
|
|||
DBUG_ENTER("ha_federated::parse_url");
|
||||
|
||||
share->port= 0;
|
||||
share->socket= 0;
|
||||
DBUG_PRINT("info", ("Length %d \n", table->s->connect_string.length));
|
||||
DBUG_PRINT("info", ("String %.*s \n", table->s->connect_string.length,
|
||||
table->s->connect_string.str));
|
||||
share->scheme= my_strdup_with_length(table->s->connect_string.str,
|
||||
table->s->connect_string.length+1,
|
||||
MYF(0));
|
||||
share->scheme= my_strdup_with_length((const byte*)table->s->
|
||||
connect_string.str,
|
||||
table->s->connect_string.length,
|
||||
MYF(0));
|
||||
|
||||
// Add a null for later termination of table name
|
||||
share->scheme[table->s->connect_string.length]= 0;
|
||||
DBUG_PRINT("info",("parse_url alloced share->scheme %lx", share->scheme));
|
||||
|
@ -1374,13 +1377,9 @@ static int free_share(FEDERATED_SHARE *share)
|
|||
|
||||
if (!--share->use_count)
|
||||
{
|
||||
if (share->scheme)
|
||||
{
|
||||
my_free((gptr) share->scheme, MYF(0));
|
||||
share->scheme= 0;
|
||||
}
|
||||
|
||||
hash_delete(&federated_open_tables, (byte*) share);
|
||||
my_free((gptr) share->scheme, MYF(MY_ALLOW_ZERO_PTR));
|
||||
share->scheme= 0;
|
||||
thr_lock_delete(&share->lock);
|
||||
VOID(pthread_mutex_destroy(&share->mutex));
|
||||
my_free((gptr) share, MYF(0));
|
||||
|
@ -2626,7 +2625,8 @@ int ha_federated::stash_remote_error()
|
|||
{
|
||||
DBUG_ENTER("ha_federated::stash_remote_error()");
|
||||
remote_error_number= mysql_errno(mysql);
|
||||
snprintf(remote_error_buf, FEDERATED_QUERY_BUFFER_SIZE, mysql_error(mysql));
|
||||
my_snprintf(remote_error_buf, FEDERATED_QUERY_BUFFER_SIZE,
|
||||
mysql_error(mysql));
|
||||
DBUG_RETURN(HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM);
|
||||
}
|
||||
|
||||
|
|
|
@ -1252,7 +1252,7 @@ innobase_init(void)
|
|||
copy of it: */
|
||||
|
||||
internal_innobase_data_file_path = my_strdup(innobase_data_file_path,
|
||||
MYF(MY_WME));
|
||||
MYF(MY_FAE));
|
||||
|
||||
ret = (bool) srv_parse_data_file_paths_and_sizes(
|
||||
internal_innobase_data_file_path,
|
||||
|
@ -2386,7 +2386,7 @@ ha_innobase::open(
|
|||
"how you can resolve the problem.\n",
|
||||
norm_name);
|
||||
free_share(share);
|
||||
my_free((char*) upd_buff, MYF(0));
|
||||
my_free((gptr) upd_buff, MYF(0));
|
||||
my_errno = ENOENT;
|
||||
|
||||
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
|
||||
|
@ -2404,7 +2404,7 @@ ha_innobase::open(
|
|||
"how you can resolve the problem.\n",
|
||||
norm_name);
|
||||
free_share(share);
|
||||
my_free((char*) upd_buff, MYF(0));
|
||||
my_free((gptr) upd_buff, MYF(0));
|
||||
my_errno = ENOENT;
|
||||
|
||||
dict_table_decrement_handle_count(ib_table);
|
||||
|
@ -2498,7 +2498,7 @@ ha_innobase::close(void)
|
|||
|
||||
row_prebuilt_free((row_prebuilt_t*) innobase_prebuilt);
|
||||
|
||||
my_free((char*) upd_buff, MYF(0));
|
||||
my_free((gptr) upd_buff, MYF(0));
|
||||
free_share(share);
|
||||
|
||||
/* Tell InnoDB server that there might be work for
|
||||
|
@ -4492,7 +4492,8 @@ create_index(
|
|||
ulint is_unsigned;
|
||||
ulint i;
|
||||
ulint j;
|
||||
|
||||
ulint* field_lengths;
|
||||
|
||||
DBUG_ENTER("create_index");
|
||||
|
||||
key = form->key_info + key_num;
|
||||
|
@ -4514,6 +4515,10 @@ create_index(
|
|||
|
||||
index = dict_mem_index_create((char*) table_name, key->name, 0,
|
||||
ind_type, n_fields);
|
||||
|
||||
field_lengths = (ulint*) my_malloc(sizeof(ulint) * n_fields,
|
||||
MYF(MY_FAE));
|
||||
|
||||
for (i = 0; i < n_fields; i++) {
|
||||
key_part = key->key_part + i;
|
||||
|
||||
|
@ -4568,6 +4573,8 @@ create_index(
|
|||
prefix_len = 0;
|
||||
}
|
||||
|
||||
field_lengths[i] = key_part->length;
|
||||
|
||||
/* We assume all fields should be sorted in ascending
|
||||
order, hence the '0': */
|
||||
|
||||
|
@ -4576,10 +4583,12 @@ create_index(
|
|||
0, prefix_len);
|
||||
}
|
||||
|
||||
error = row_create_index_for_mysql(index, trx);
|
||||
error = row_create_index_for_mysql(index, trx, field_lengths);
|
||||
|
||||
error = convert_error_code_to_mysql(error, NULL);
|
||||
|
||||
my_free((gptr) field_lengths, MYF(0));
|
||||
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
@ -4602,7 +4611,7 @@ create_clustered_index_when_no_primary(
|
|||
index = dict_mem_index_create((char*) table_name,
|
||||
(char*) "GEN_CLUST_INDEX",
|
||||
0, DICT_CLUSTERED, 0);
|
||||
error = row_create_index_for_mysql(index, trx);
|
||||
error = row_create_index_for_mysql(index, trx, NULL);
|
||||
|
||||
error = convert_error_code_to_mysql(error, NULL);
|
||||
|
||||
|
@ -5138,7 +5147,7 @@ ha_innobase::records_in_range(
|
|||
mysql_byte* key_val_buff2 = (mysql_byte*) my_malloc(
|
||||
table->s->reclength
|
||||
+ table->s->max_key_length + 100,
|
||||
MYF(MY_WME));
|
||||
MYF(MY_FAE));
|
||||
ulint buff2_len = table->s->reclength
|
||||
+ table->s->max_key_length + 100;
|
||||
dtuple_t* range_start;
|
||||
|
@ -5197,7 +5206,7 @@ ha_innobase::records_in_range(
|
|||
dtuple_free_for_mysql(heap1);
|
||||
dtuple_free_for_mysql(heap2);
|
||||
|
||||
my_free((char*) key_val_buff2, MYF(0));
|
||||
my_free((gptr) key_val_buff2, MYF(0));
|
||||
|
||||
prebuilt->trx->op_info = (char*)"";
|
||||
|
||||
|
@ -6065,6 +6074,8 @@ ha_innobase::start_stmt(
|
|||
}
|
||||
}
|
||||
|
||||
trx->detailed_error[0] = '\0';
|
||||
|
||||
/* Set the MySQL flag to mark that there is an active transaction */
|
||||
if (trx->active_trans == 0) {
|
||||
|
||||
|
@ -6138,6 +6149,8 @@ ha_innobase::external_lock(
|
|||
if (lock_type != F_UNLCK) {
|
||||
/* MySQL is setting a new table lock */
|
||||
|
||||
trx->detailed_error[0] = '\0';
|
||||
|
||||
/* Set the MySQL flag to mark that there is an active
|
||||
transaction */
|
||||
if (trx->active_trans == 0) {
|
||||
|
@ -6941,6 +6954,18 @@ ha_innobase::reset_auto_increment(ulonglong value)
|
|||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/* See comment in handler.cc */
|
||||
bool
|
||||
ha_innobase::get_error_message(int error, String *buf)
|
||||
{
|
||||
trx_t* trx = check_trx_exists(current_thd);
|
||||
|
||||
buf->copy(trx->detailed_error, strlen(trx->detailed_error),
|
||||
system_charset_info);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
|
||||
If there is no explicitly declared non-null unique key or a primary key, then
|
||||
|
|
|
@ -174,6 +174,8 @@ class ha_innobase: public handler
|
|||
void init_table_handle_for_HANDLER();
|
||||
ulonglong get_auto_increment();
|
||||
int reset_auto_increment(ulonglong value);
|
||||
|
||||
virtual bool get_error_message(int error, String *buf);
|
||||
|
||||
uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; }
|
||||
/*
|
||||
|
|
|
@ -119,12 +119,12 @@ struct show_table_type_st sys_table_types[]=
|
|||
|
||||
struct show_table_alias_st sys_table_aliases[]=
|
||||
{
|
||||
{"INNOBASE", "InnoDB", NULL },
|
||||
{"NDB", "NDBCLUSTER", NULL},
|
||||
{"BDB", "BERKELEYDB", NULL},
|
||||
{"HEAP", "MEMORY", NULL},
|
||||
{"MERGE", "MRG_MYISAM", NULL},
|
||||
{NullS, NullS, NULL}
|
||||
{"INNOBASE", "InnoDB"},
|
||||
{"NDB", "NDBCLUSTER"},
|
||||
{"BDB", "BERKELEYDB"},
|
||||
{"HEAP", "MEMORY"},
|
||||
{"MERGE", "MRG_MYISAM"},
|
||||
{NullS, NullS}
|
||||
};
|
||||
|
||||
const char *ha_row_type[] = {
|
||||
|
@ -145,28 +145,32 @@ enum db_type ha_resolve_by_name(const char *name, uint namelen)
|
|||
THD *thd= current_thd;
|
||||
show_table_alias_st *table_alias;
|
||||
show_table_type_st *types;
|
||||
const char *ptr= name;
|
||||
|
||||
if (thd && !my_strcasecmp(&my_charset_latin1, name, "DEFAULT")) {
|
||||
if (thd && !my_strcasecmp(&my_charset_latin1, ptr, "DEFAULT"))
|
||||
return (enum db_type) thd->variables.table_type;
|
||||
}
|
||||
|
||||
retest:
|
||||
for (types= sys_table_types; types->type; types++)
|
||||
{
|
||||
if (!my_strcasecmp(&my_charset_latin1, name, types->type))
|
||||
if (!my_strcasecmp(&my_charset_latin1, ptr, types->type))
|
||||
return (enum db_type) types->db_type;
|
||||
}
|
||||
|
||||
/*
|
||||
We check for the historical aliases next.
|
||||
We check for the historical aliases.
|
||||
*/
|
||||
for (table_alias= sys_table_aliases; table_alias->type; table_alias++)
|
||||
{
|
||||
if (!my_strcasecmp(&my_charset_latin1, name, table_alias->alias) && table_alias->st)
|
||||
return (enum db_type) table_alias->st->db_type;
|
||||
if (!my_strcasecmp(&my_charset_latin1, ptr, table_alias->alias))
|
||||
{
|
||||
ptr= table_alias->type;
|
||||
goto retest;
|
||||
}
|
||||
}
|
||||
|
||||
return DB_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
const char *ha_get_storage_engine(enum db_type db_type)
|
||||
{
|
||||
show_table_type_st *types;
|
||||
|
@ -340,8 +344,8 @@ static int ha_init_errors(void)
|
|||
SETMSG(HA_ERR_READ_ONLY_TRANSACTION, ER(ER_READ_ONLY_TRANSACTION));
|
||||
SETMSG(HA_ERR_LOCK_DEADLOCK, ER(ER_LOCK_DEADLOCK));
|
||||
SETMSG(HA_ERR_CANNOT_ADD_FOREIGN, ER(ER_CANNOT_ADD_FOREIGN));
|
||||
SETMSG(HA_ERR_NO_REFERENCED_ROW, ER(ER_NO_REFERENCED_ROW));
|
||||
SETMSG(HA_ERR_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED));
|
||||
SETMSG(HA_ERR_NO_REFERENCED_ROW, ER(ER_NO_REFERENCED_ROW_2));
|
||||
SETMSG(HA_ERR_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED_2));
|
||||
SETMSG(HA_ERR_NO_SAVEPOINT, "No savepoint with that name");
|
||||
SETMSG(HA_ERR_NON_UNIQUE_BLOCK_SIZE, "Non unique key block size");
|
||||
SETMSG(HA_ERR_NO_SUCH_TABLE, "No such table: '%.64s'");
|
||||
|
@ -398,29 +402,20 @@ int ha_init()
|
|||
if (ha_init_errors())
|
||||
return 1;
|
||||
|
||||
/*
|
||||
This will go away soon.
|
||||
*/
|
||||
for (types= sys_table_types; types->type; types++)
|
||||
{
|
||||
switch (types->db_type) {
|
||||
case DB_TYPE_HEAP:
|
||||
types->ht= &heap_hton;
|
||||
for (table_alias= sys_table_aliases; table_alias->type; table_alias++)
|
||||
{
|
||||
if (!my_strcasecmp(&my_charset_latin1, types->ht->name,
|
||||
table_alias->type))
|
||||
table_alias->st= types;
|
||||
}
|
||||
break;
|
||||
case DB_TYPE_MYISAM:
|
||||
types->ht= &myisam_hton;
|
||||
break;
|
||||
case DB_TYPE_MRG_MYISAM:
|
||||
types->ht= &myisammrg_hton;
|
||||
for (table_alias= sys_table_aliases; table_alias->type; table_alias++)
|
||||
{
|
||||
if (!my_strcasecmp(&my_charset_latin1, types->ht->name,
|
||||
table_alias->type))
|
||||
table_alias->st= types;
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_BERKELEY_DB
|
||||
case DB_TYPE_BERKELEY_DB:
|
||||
|
@ -434,11 +429,6 @@ int ha_init()
|
|||
else
|
||||
{
|
||||
types->ht= &berkeley_hton;
|
||||
for (table_alias= sys_table_aliases; table_alias->type; table_alias++)
|
||||
{
|
||||
if (!my_strcasecmp(&my_charset_latin1, types->ht->name, table_alias->type))
|
||||
table_alias->st= types;
|
||||
}
|
||||
ha_was_inited_ok(ht++);
|
||||
}
|
||||
}
|
||||
|
@ -457,11 +447,6 @@ int ha_init()
|
|||
{
|
||||
ha_was_inited_ok(ht++);
|
||||
types->ht= &innobase_hton;
|
||||
for (table_alias= sys_table_aliases; table_alias->type; table_alias++)
|
||||
{
|
||||
if (!my_strcasecmp(&my_charset_latin1, types->ht->name, table_alias->type))
|
||||
table_alias->st= types;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -479,11 +464,6 @@ int ha_init()
|
|||
{
|
||||
ha_was_inited_ok(ht++);
|
||||
types->ht= &ndbcluster_hton;
|
||||
for (table_alias= sys_table_aliases; table_alias->type; table_alias++)
|
||||
{
|
||||
if (!my_strcasecmp(&my_charset_latin1, types->ht->name, table_alias->type))
|
||||
table_alias->st= types;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1456,11 +1436,9 @@ int handler::ha_open(const char *name, int mode, int test_if_locked)
|
|||
table->db_stat|=HA_READ_ONLY;
|
||||
(void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
|
||||
|
||||
if (!alloc_root_inited(&table->mem_root)) // If temporary table
|
||||
ref=(byte*) sql_alloc(ALIGN_SIZE(ref_length)*2);
|
||||
else
|
||||
ref=(byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2);
|
||||
if (!ref)
|
||||
DBUG_ASSERT(alloc_root_inited(&table->mem_root));
|
||||
|
||||
if (!(ref= (byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2)))
|
||||
{
|
||||
close();
|
||||
error=HA_ERR_OUT_OF_MEM;
|
||||
|
@ -1820,11 +1798,19 @@ void handler::print_error(int error, myf errflag)
|
|||
textno=ER_CANNOT_ADD_FOREIGN;
|
||||
break;
|
||||
case HA_ERR_ROW_IS_REFERENCED:
|
||||
textno=ER_ROW_IS_REFERENCED;
|
||||
break;
|
||||
{
|
||||
String str;
|
||||
get_error_message(error, &str);
|
||||
my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
case HA_ERR_NO_REFERENCED_ROW:
|
||||
textno=ER_NO_REFERENCED_ROW;
|
||||
break;
|
||||
{
|
||||
String str;
|
||||
get_error_message(error, &str);
|
||||
my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
case HA_ERR_TABLE_DEF_CHANGED:
|
||||
textno=ER_TABLE_DEF_CHANGED;
|
||||
break;
|
||||
|
|
|
@ -367,7 +367,6 @@ struct show_table_type_st {
|
|||
struct show_table_alias_st {
|
||||
const char *alias;
|
||||
const char *type;
|
||||
show_table_type_st *st;
|
||||
};
|
||||
|
||||
/* Possible flags of a handlerton */
|
||||
|
|
|
@ -1286,9 +1286,6 @@ public:
|
|||
{
|
||||
ft_handler->please->close_search(ft_handler);
|
||||
ft_handler=0;
|
||||
if (join_key)
|
||||
table->file->ft_handler=0;
|
||||
table->fulltext_searched=0;
|
||||
}
|
||||
concat= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
|
|
|
@ -1608,7 +1608,7 @@ String *Item_func_user::val_str(String *str)
|
|||
else
|
||||
{
|
||||
user= thd->main_security_ctx.user;
|
||||
host= thd->main_security_ctx.host;
|
||||
host= thd->main_security_ctx.host_or_ip;
|
||||
}
|
||||
|
||||
// For system threads (e.g. replication SQL thread) user may be empty
|
||||
|
|
|
@ -1468,7 +1468,7 @@ int subselect_single_select_engine::prepare()
|
|||
|
||||
int subselect_union_engine::prepare()
|
||||
{
|
||||
return unit->prepare(thd, result, SELECT_NO_UNLOCK, "");
|
||||
return unit->prepare(thd, result, SELECT_NO_UNLOCK);
|
||||
}
|
||||
|
||||
int subselect_uniquesubquery_engine::prepare()
|
||||
|
|
|
@ -1367,8 +1367,8 @@ void Item_sum_hybrid::cleanup()
|
|||
|
||||
void Item_sum_hybrid::no_rows_in_result()
|
||||
{
|
||||
Item_sum::no_rows_in_result();
|
||||
was_values= FALSE;
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2793,7 +2793,7 @@ void TC_LOG_MMAP::close()
|
|||
case 3:
|
||||
my_free((gptr)pages, MYF(0));
|
||||
case 2:
|
||||
my_munmap(data, (size_t)file_length);
|
||||
my_munmap((byte*)data, (size_t)file_length);
|
||||
case 1:
|
||||
my_close(fd, MYF(0));
|
||||
}
|
||||
|
|
|
@ -4208,7 +4208,7 @@ pthread_handler_decl(handle_connections_shared_memory,arg)
|
|||
errmsg= 0;
|
||||
goto errorconn;
|
||||
}
|
||||
thd->host= my_strdup(my_localhost,MYF(0)); /* Host is unknown */
|
||||
thd->security_ctx->host= my_strdup(my_localhost, MYF(0)); /* Host is unknown */
|
||||
create_new_thread(thd);
|
||||
connect_number++;
|
||||
continue;
|
||||
|
|
|
@ -80,6 +80,8 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
|||
List_iterator_fast<Item> it(all_fields);
|
||||
int const_result= 1;
|
||||
bool recalc_const_item= 0;
|
||||
longlong count= 1;
|
||||
bool is_exact_count= TRUE;
|
||||
table_map removed_tables= 0, outer_tables= 0, used_tables= 0;
|
||||
table_map where_tables= 0;
|
||||
Item *item;
|
||||
|
@ -88,9 +90,13 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
|||
if (conds)
|
||||
where_tables= conds->used_tables();
|
||||
|
||||
/* Don't replace expression on a table that is part of an outer join */
|
||||
/*
|
||||
Analyze outer join dependencies, and, if possible, compute the number
|
||||
of returned rows.
|
||||
*/
|
||||
for (TABLE_LIST *tl= tables; tl; tl= tl->next_leaf)
|
||||
{
|
||||
/* Don't replace expression on a table that is part of an outer join */
|
||||
if (tl->on_expr)
|
||||
{
|
||||
outer_tables|= tl->table->map;
|
||||
|
@ -102,15 +108,31 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
|||
WHERE t2.field IS NULL;
|
||||
*/
|
||||
if (tl->table->map & where_tables)
|
||||
return 0;
|
||||
const_result= 0;
|
||||
}
|
||||
else
|
||||
used_tables|= tl->table->map;
|
||||
|
||||
/*
|
||||
If the storage manager of 'tl' gives exact row count, compute the total
|
||||
number of rows. If there are no outer table dependencies, this count
|
||||
may be used as the real count.
|
||||
*/
|
||||
if (tl->table->file->table_flags() & HA_NOT_EXACT_COUNT)
|
||||
is_exact_count= FALSE;
|
||||
else
|
||||
{
|
||||
tl->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
|
||||
count*= tl->table->file->records;
|
||||
}
|
||||
}
|
||||
|
||||
if (!const_result)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
Iterate through item is select part and replace COUNT(), MIN() and MAX()
|
||||
with constants (if possible)
|
||||
Iterate through all items in the SELECT clause and replace
|
||||
COUNT(), MIN() and MAX() with constants (if possible).
|
||||
*/
|
||||
|
||||
while ((item= it++))
|
||||
|
@ -122,9 +144,11 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
|||
case Item_sum::COUNT_FUNC:
|
||||
/*
|
||||
If the expr in count(expr) can never be null we can change this
|
||||
to the number of rows in the tables
|
||||
to the number of rows in the tables if this number is exact and
|
||||
there are no outer joins.
|
||||
*/
|
||||
if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null)
|
||||
if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null &&
|
||||
!outer_tables && is_exact_count)
|
||||
{
|
||||
longlong count= 1;
|
||||
TABLE_LIST *table;
|
||||
|
@ -210,12 +234,27 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
|||
}
|
||||
removed_tables|= table->map;
|
||||
}
|
||||
else if (!expr->const_item()) // This is VERY seldom false
|
||||
else if (!expr->const_item() || !is_exact_count)
|
||||
{
|
||||
/*
|
||||
The optimization is not applicable in both cases:
|
||||
(a) 'expr' is a non-constant expression. Then we can't
|
||||
replace 'expr' by a constant.
|
||||
(b) 'expr' is a costant. According to ANSI, MIN/MAX must return
|
||||
NULL if the query does not return any rows. Thus, if we are not
|
||||
able to determine if the query returns any rows, we can't apply
|
||||
the optimization and replace MIN/MAX with a constant.
|
||||
*/
|
||||
const_result= 0;
|
||||
break;
|
||||
}
|
||||
((Item_sum_min*) item_sum)->reset();
|
||||
if (!count)
|
||||
{
|
||||
/* If count != 1, then we know that is_exact_count == TRUE. */
|
||||
((Item_sum_min*) item_sum)->clear(); /* Set to NULL. */
|
||||
}
|
||||
else
|
||||
((Item_sum_min*) item_sum)->reset(); /* Set to the constant value. */
|
||||
((Item_sum_min*) item_sum)->make_const();
|
||||
recalc_const_item= 1;
|
||||
break;
|
||||
|
@ -282,13 +321,28 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
|||
}
|
||||
removed_tables|= table->map;
|
||||
}
|
||||
else if (!expr->const_item()) // This is VERY seldom false
|
||||
else if (!expr->const_item() || !is_exact_count)
|
||||
{
|
||||
/*
|
||||
The optimization is not applicable in both cases:
|
||||
(a) 'expr' is a non-constant expression. Then we can't
|
||||
replace 'expr' by a constant.
|
||||
(b) 'expr' is a costant. According to ANSI, MIN/MAX must return
|
||||
NULL if the query does not return any rows. Thus, if we are not
|
||||
able to determine if the query returns any rows, we can't apply
|
||||
the optimization and replace MIN/MAX with a constant.
|
||||
*/
|
||||
const_result= 0;
|
||||
break;
|
||||
}
|
||||
((Item_sum_min*) item_sum)->reset();
|
||||
((Item_sum_min*) item_sum)->make_const();
|
||||
if (!count)
|
||||
{
|
||||
/* If count != 1, then we know that is_exact_count == TRUE. */
|
||||
((Item_sum_max*) item_sum)->clear(); /* Set to NULL. */
|
||||
}
|
||||
else
|
||||
((Item_sum_max*) item_sum)->reset(); /* Set to the constant value. */
|
||||
((Item_sum_max*) item_sum)->make_const();
|
||||
recalc_const_item= 1;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -150,30 +150,6 @@ public:
|
|||
virtual bool store(Field *field);
|
||||
};
|
||||
|
||||
class Protocol_cursor :public Protocol_simple
|
||||
{
|
||||
public:
|
||||
MEM_ROOT *alloc;
|
||||
MYSQL_FIELD *fields;
|
||||
MYSQL_ROWS *data;
|
||||
MYSQL_ROWS **prev_record;
|
||||
ulong row_count;
|
||||
|
||||
Protocol_cursor() :data(NULL) {}
|
||||
Protocol_cursor(THD *thd_arg, MEM_ROOT *ini_alloc) :Protocol_simple(thd_arg), alloc(ini_alloc), data(NULL) {}
|
||||
bool prepare_for_send(List<Item> *item_list)
|
||||
{
|
||||
row_count= 0;
|
||||
fields= NULL;
|
||||
data= NULL;
|
||||
prev_record= &data;
|
||||
return Protocol_simple::prepare_for_send(item_list);
|
||||
}
|
||||
bool send_fields(List<Item> *list, uint flags);
|
||||
bool write();
|
||||
uint get_field_count() { return field_count; }
|
||||
};
|
||||
|
||||
void send_warning(THD *thd, uint sql_errno, const char *err=0);
|
||||
void net_printf_error(THD *thd, uint sql_errno, ...);
|
||||
void net_send_error(THD *thd, uint sql_errno=0, const char *err=0);
|
||||
|
|
|
@ -5415,3 +5415,7 @@ ER_NO_SUCH_USER
|
|||
eng "There is not %-.64s@%-.64s registered"
|
||||
ER_FORBID_SCHEMA_CHANGE
|
||||
eng "Changing schema from '%-.64s' to '%-.64s' is not allowed."
|
||||
ER_ROW_IS_REFERENCED_2 23000
|
||||
eng "Cannot delete or update a parent row: a foreign key constraint fails (%.192s)"
|
||||
ER_NO_REFERENCED_ROW_2 23000
|
||||
eng "Cannot add or update a child row: a foreign key constraint fails (%.192s)"
|
||||
|
|
112
sql/sp_head.cc
112
sql/sp_head.cc
|
@ -199,11 +199,18 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
|
|||
Item *it= sp_prepare_func_item(thd, it_addr);
|
||||
uint rsize;
|
||||
Query_arena backup_arena;
|
||||
Item *old_item_next, *old_free_list, **p_free_list;
|
||||
DBUG_PRINT("info", ("type: %d", type));
|
||||
|
||||
if (!it)
|
||||
{
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
if (reuse)
|
||||
{
|
||||
old_item_next= reuse->next;
|
||||
p_free_list= use_callers_arena ? &thd->spcont->callers_arena->free_list :
|
||||
&thd->free_list;
|
||||
old_free_list= *p_free_list;
|
||||
}
|
||||
|
||||
switch (sp_map_result_type(type)) {
|
||||
|
@ -312,15 +319,23 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
|
|||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
it->rsize= rsize;
|
||||
|
||||
DBUG_RETURN(it);
|
||||
goto end;
|
||||
|
||||
return_null_item:
|
||||
CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_null(),
|
||||
use_callers_arena, &backup_arena);
|
||||
end:
|
||||
it->rsize= rsize;
|
||||
|
||||
if (reuse && it == reuse)
|
||||
{
|
||||
/*
|
||||
The Item constructor registered itself in the arena free list,
|
||||
while the item slot is reused, so we have to restore the list.
|
||||
*/
|
||||
it->next= old_item_next;
|
||||
*p_free_list= old_free_list;
|
||||
}
|
||||
DBUG_RETURN(it);
|
||||
}
|
||||
|
||||
|
@ -1358,14 +1373,6 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||
uint offset= static_cast<Item_splocal *>(it)->get_offset();
|
||||
Item *val= nctx->get_item(i);
|
||||
Item *orig= octx->get_item(offset);
|
||||
Item *o_item_next;
|
||||
/* we'll use callers_arena in sp_eval_func_item */
|
||||
Item *o_free_list= thd->spcont->callers_arena->free_list;
|
||||
|
||||
LINT_INIT(o_item_next);
|
||||
|
||||
if (orig)
|
||||
o_item_next= orig->next;
|
||||
|
||||
/*
|
||||
We might need to allocate new item if we weren't able to
|
||||
|
@ -1380,15 +1387,6 @@ int sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||
}
|
||||
if (copy != orig)
|
||||
octx->set_item(offset, copy);
|
||||
if (orig && copy == orig)
|
||||
{
|
||||
/*
|
||||
A reused item slot, where the constructor put it in the
|
||||
free_list, so we have to restore the list.
|
||||
*/
|
||||
thd->spcont->callers_arena->free_list= o_free_list;
|
||||
copy->next= o_item_next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2478,6 +2476,10 @@ sp_instr_cpop::backpatch(uint dest, sp_pcontext *dst_ctx)
|
|||
int
|
||||
sp_instr_copen::execute(THD *thd, uint *nextp)
|
||||
{
|
||||
/*
|
||||
We don't store a pointer to the cursor in the instruction to be
|
||||
able to reuse the same instruction among different threads in future.
|
||||
*/
|
||||
sp_cursor *c= thd->spcont->get_cursor(m_cursor);
|
||||
int res;
|
||||
DBUG_ENTER("sp_instr_copen::execute");
|
||||
|
@ -2486,41 +2488,33 @@ sp_instr_copen::execute(THD *thd, uint *nextp)
|
|||
res= -1;
|
||||
else
|
||||
{
|
||||
sp_lex_keeper *lex_keeper= c->pre_open(thd);
|
||||
if (!lex_keeper) // cursor already open or OOM
|
||||
{
|
||||
res= -1;
|
||||
*nextp= m_ip+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Query_arena *old_arena= thd->stmt_arena;
|
||||
sp_lex_keeper *lex_keeper= c->get_lex_keeper();
|
||||
Query_arena *old_arena= thd->stmt_arena;
|
||||
|
||||
/*
|
||||
Get the Query_arena from the cpush instruction, which contains
|
||||
the free_list of the query, so new items (if any) are stored in
|
||||
the right free_list, and we can cleanup after each open.
|
||||
*/
|
||||
thd->stmt_arena= c->get_instr();
|
||||
res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
|
||||
/* Cleanup the query's items */
|
||||
if (thd->stmt_arena->free_list)
|
||||
cleanup_items(thd->stmt_arena->free_list);
|
||||
thd->stmt_arena= old_arena;
|
||||
/*
|
||||
Work around the fact that errors in selects are not returned properly
|
||||
(but instead converted into a warning), so if a condition handler
|
||||
caught, we have lost the result code.
|
||||
*/
|
||||
if (!res)
|
||||
{
|
||||
uint dummy1, dummy2;
|
||||
/*
|
||||
Get the Query_arena from the cpush instruction, which contains
|
||||
the free_list of the query, so new items (if any) are stored in
|
||||
the right free_list, and we can cleanup after each open.
|
||||
*/
|
||||
thd->stmt_arena= c->get_instr();
|
||||
res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
|
||||
/* Cleanup the query's items */
|
||||
if (thd->stmt_arena->free_list)
|
||||
cleanup_items(thd->stmt_arena->free_list);
|
||||
thd->stmt_arena= old_arena;
|
||||
/*
|
||||
Work around the fact that errors in selects are not returned properly
|
||||
(but instead converted into a warning), so if a condition handler
|
||||
caught, we have lost the result code.
|
||||
*/
|
||||
if (!res)
|
||||
{
|
||||
uint dummy1, dummy2;
|
||||
|
||||
if (thd->spcont->found_handler(&dummy1, &dummy2))
|
||||
res= -1;
|
||||
}
|
||||
c->post_open(thd, res ? FALSE : TRUE);
|
||||
if (thd->spcont->found_handler(&dummy1, &dummy2))
|
||||
res= -1;
|
||||
}
|
||||
/* TODO: Assert here that we either have an error or a cursor */
|
||||
}
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
@ -2529,7 +2523,8 @@ sp_instr_copen::execute(THD *thd, uint *nextp)
|
|||
int
|
||||
sp_instr_copen::exec_core(THD *thd, uint *nextp)
|
||||
{
|
||||
int res= mysql_execute_command(thd);
|
||||
sp_cursor *c= thd->spcont->get_cursor(m_cursor);
|
||||
int res= c->open(thd);
|
||||
*nextp= m_ip+1;
|
||||
return res;
|
||||
}
|
||||
|
@ -2584,14 +2579,7 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp)
|
|||
Query_arena backup_arena;
|
||||
DBUG_ENTER("sp_instr_cfetch::execute");
|
||||
|
||||
if (! c)
|
||||
res= -1;
|
||||
else
|
||||
{
|
||||
thd->set_n_backup_active_arena(thd->spcont->callers_arena, &backup_arena);
|
||||
res= c->fetch(thd, &m_varlist);
|
||||
thd->restore_active_arena(thd->spcont->callers_arena, &backup_arena);
|
||||
}
|
||||
res= c ? c->fetch(thd, &m_varlist) : -1;
|
||||
|
||||
*nextp= m_ip+1;
|
||||
DBUG_RETURN(res);
|
||||
|
|
|
@ -866,6 +866,12 @@ public:
|
|||
|
||||
virtual void print(String *str);
|
||||
|
||||
/*
|
||||
This call is used to cleanup the instruction when a sensitive
|
||||
cursor is closed. For now stored procedures always use materialized
|
||||
cursors and the call is not used.
|
||||
*/
|
||||
virtual void cleanup_stmt() { /* no op */ }
|
||||
private:
|
||||
|
||||
sp_lex_keeper m_lex_keeper;
|
||||
|
@ -1036,4 +1042,7 @@ sp_add_to_query_tables(THD *thd, LEX *lex,
|
|||
const char *db, const char *name,
|
||||
thr_lock_type locktype);
|
||||
|
||||
Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type,
|
||||
Item *reuse, bool use_callers_arena);
|
||||
|
||||
#endif /* _SP_HEAD_H_ */
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "mysql.h"
|
||||
#include "sp_head.h"
|
||||
#include "sql_cursor.h"
|
||||
#include "sp_rcontext.h"
|
||||
#include "sp_pcontext.h"
|
||||
|
||||
|
@ -45,31 +46,18 @@ int
|
|||
sp_rcontext::set_item_eval(THD *thd, uint idx, Item **item_addr,
|
||||
enum_field_types type)
|
||||
{
|
||||
extern Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type,
|
||||
Item *reuse, bool use_callers_arena);
|
||||
Item *it;
|
||||
Item *reuse_it;
|
||||
Item *old_item_next;
|
||||
/* sp_eval_func_item will use callers_arena */
|
||||
Item *old_free_list= thd->spcont->callers_arena->free_list;
|
||||
int res;
|
||||
LINT_INIT(old_item_next);
|
||||
|
||||
if ((reuse_it= get_item(idx)))
|
||||
old_item_next= reuse_it->next;
|
||||
reuse_it= get_item(idx);
|
||||
it= sp_eval_func_item(thd, item_addr, type, reuse_it, TRUE);
|
||||
if (! it)
|
||||
res= -1;
|
||||
else
|
||||
{
|
||||
res= 0;
|
||||
if (reuse_it && it == reuse_it)
|
||||
{
|
||||
// A reused item slot, where the constructor put it in the free_list,
|
||||
// so we have to restore the list.
|
||||
thd->spcont->callers_arena->free_list= old_free_list;
|
||||
it->next= old_item_next;
|
||||
}
|
||||
set_item(idx, it);
|
||||
}
|
||||
|
||||
|
@ -170,7 +158,8 @@ sp_rcontext::pop_cursors(uint count)
|
|||
*/
|
||||
|
||||
sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
|
||||
:m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL),
|
||||
:m_lex_keeper(lex_keeper),
|
||||
server_side_cursor(NULL),
|
||||
m_i(i)
|
||||
{
|
||||
/*
|
||||
|
@ -182,59 +171,37 @@ sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
|
|||
|
||||
|
||||
/*
|
||||
pre_open cursor
|
||||
Open an SP cursor
|
||||
|
||||
SYNOPSIS
|
||||
pre_open()
|
||||
THD Thread handler
|
||||
open()
|
||||
THD Thread handler
|
||||
|
||||
NOTES
|
||||
We have to open cursor in two steps to make it easy for sp_instr_copen
|
||||
to reuse the sp_instr::exec_stmt() code.
|
||||
If this function returns 0, post_open should not be called
|
||||
|
||||
RETURN
|
||||
0 ERROR
|
||||
0 in case of success, -1 otherwise
|
||||
*/
|
||||
|
||||
sp_lex_keeper*
|
||||
sp_cursor::pre_open(THD *thd)
|
||||
int
|
||||
sp_cursor::open(THD *thd)
|
||||
{
|
||||
if (m_isopen)
|
||||
if (server_side_cursor)
|
||||
{
|
||||
my_message(ER_SP_CURSOR_ALREADY_OPEN, ER(ER_SP_CURSOR_ALREADY_OPEN),
|
||||
MYF(0));
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
init_alloc_root(&m_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
|
||||
if ((m_prot= new Protocol_cursor(thd, &m_mem_root)) == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Save for execution. Will be restored in post_open */
|
||||
m_oprot= thd->protocol;
|
||||
m_nseof= thd->net.no_send_eof;
|
||||
|
||||
/* Change protocol for execution */
|
||||
thd->protocol= m_prot;
|
||||
thd->net.no_send_eof= TRUE;
|
||||
return m_lex_keeper;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sp_cursor::post_open(THD *thd, my_bool was_opened)
|
||||
{
|
||||
thd->net.no_send_eof= m_nseof; // Restore the originals
|
||||
thd->protocol= m_oprot;
|
||||
if ((m_isopen= was_opened))
|
||||
m_current_row= m_prot->data;
|
||||
if (mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR, &result,
|
||||
&server_side_cursor))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sp_cursor::close(THD *thd)
|
||||
{
|
||||
if (! m_isopen)
|
||||
if (! server_side_cursor)
|
||||
{
|
||||
my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0));
|
||||
return -1;
|
||||
|
@ -247,106 +214,82 @@ sp_cursor::close(THD *thd)
|
|||
void
|
||||
sp_cursor::destroy()
|
||||
{
|
||||
if (m_prot)
|
||||
{
|
||||
delete m_prot;
|
||||
m_prot= NULL;
|
||||
free_root(&m_mem_root, MYF(0));
|
||||
}
|
||||
m_isopen= FALSE;
|
||||
delete server_side_cursor;
|
||||
server_side_cursor= 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars)
|
||||
{
|
||||
List_iterator_fast<struct sp_pvar> li(*vars);
|
||||
sp_pvar_t *pv;
|
||||
MYSQL_ROW row;
|
||||
uint fldcount;
|
||||
|
||||
if (! m_isopen)
|
||||
if (! server_side_cursor)
|
||||
{
|
||||
my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0));
|
||||
return -1;
|
||||
}
|
||||
if (m_current_row == NULL)
|
||||
{
|
||||
my_message(ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA), MYF(0));
|
||||
return -1;
|
||||
}
|
||||
|
||||
row= m_current_row->data;
|
||||
for (fldcount= 0 ; (pv= li++) ; fldcount++)
|
||||
{
|
||||
Item *it;
|
||||
Item *reuse;
|
||||
uint rsize;
|
||||
Item *old_item_next;
|
||||
Item *old_free_list= thd->free_list;
|
||||
const char *s;
|
||||
LINT_INIT(old_item_next);
|
||||
|
||||
if (fldcount >= m_prot->get_field_count())
|
||||
{
|
||||
my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS,
|
||||
ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((reuse= thd->spcont->get_item(pv->offset)))
|
||||
old_item_next= reuse->next;
|
||||
|
||||
s= row[fldcount];
|
||||
if (!s)
|
||||
it= new(reuse, &rsize) Item_null();
|
||||
else
|
||||
{
|
||||
/*
|
||||
Length of data can be calculated as:
|
||||
pointer_to_next_not_null_object - s -1
|
||||
where the last -1 is to remove the end \0
|
||||
*/
|
||||
uint len;
|
||||
MYSQL_ROW next= row+fldcount+1;
|
||||
while (!*next) // Skip nulls
|
||||
next++;
|
||||
len= (*next -s)-1;
|
||||
switch (sp_map_result_type(pv->type)) {
|
||||
case INT_RESULT:
|
||||
it= new(reuse, &rsize) Item_int(s);
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
it= new(reuse, &rsize) Item_float(s, len);
|
||||
break;
|
||||
case DECIMAL_RESULT:
|
||||
it= new(reuse, &rsize) Item_decimal(s, len, thd->db_charset);
|
||||
break;
|
||||
case STRING_RESULT:
|
||||
/* TODO: Document why we do an extra copy of the string 's' here */
|
||||
it= new(reuse, &rsize) Item_string(thd->strmake(s, len), len,
|
||||
thd->db_charset);
|
||||
break;
|
||||
case ROW_RESULT:
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
}
|
||||
it->rsize= rsize;
|
||||
if (reuse && it == reuse)
|
||||
{
|
||||
// A reused item slot, where the constructor put it in the free_list,
|
||||
// so we have to restore the list.
|
||||
thd->free_list= old_free_list;
|
||||
it->next= old_item_next;
|
||||
}
|
||||
thd->spcont->set_item(pv->offset, it);
|
||||
}
|
||||
if (fldcount < m_prot->get_field_count())
|
||||
if (vars->elements != result.get_field_count())
|
||||
{
|
||||
my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS,
|
||||
ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0));
|
||||
return -1;
|
||||
}
|
||||
m_current_row= m_current_row->next;
|
||||
|
||||
result.set_spvar_list(vars);
|
||||
|
||||
/* Attempt to fetch one row */
|
||||
if (server_side_cursor->is_open())
|
||||
server_side_cursor->fetch(1);
|
||||
|
||||
/*
|
||||
If the cursor was pointing after the last row, the fetch will
|
||||
close it instead of sending any rows.
|
||||
*/
|
||||
if (! server_side_cursor->is_open())
|
||||
{
|
||||
my_message(ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA), MYF(0));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Select_fetch_into_spvars
|
||||
****************************************************************************/
|
||||
|
||||
int Select_fetch_into_spvars::prepare(List<Item> &fields, SELECT_LEX_UNIT *u)
|
||||
{
|
||||
/*
|
||||
Cache the number of columns in the result set in order to easily
|
||||
return an error if column count does not match value count.
|
||||
*/
|
||||
field_count= fields.elements;
|
||||
return select_result_interceptor::prepare(fields, u);
|
||||
}
|
||||
|
||||
|
||||
bool Select_fetch_into_spvars::send_data(List<Item> &items)
|
||||
{
|
||||
List_iterator_fast<struct sp_pvar> pv_iter(*spvar_list);
|
||||
List_iterator_fast<Item> item_iter(items);
|
||||
sp_pvar_t *pv;
|
||||
Item *item;
|
||||
|
||||
/* Must be ensured by the caller */
|
||||
DBUG_ASSERT(spvar_list->elements == items.elements);
|
||||
|
||||
/*
|
||||
Assign the row fetched from a server side cursor to stored
|
||||
procedure variables.
|
||||
*/
|
||||
for (; pv= pv_iter++, item= item_iter++; )
|
||||
{
|
||||
Item *reuse= thd->spcont->get_item(pv->offset);
|
||||
/* Evaluate a new item on the arena of the calling instruction */
|
||||
Item *it= sp_eval_func_item(thd, &item, pv->type, reuse, TRUE);
|
||||
|
||||
thd->spcont->set_item(pv->offset, it);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -216,6 +216,27 @@ private:
|
|||
}; // class sp_rcontext : public Sql_alloc
|
||||
|
||||
|
||||
/*
|
||||
An interceptor of cursor result set used to implement
|
||||
FETCH <cname> INTO <varlist>.
|
||||
*/
|
||||
|
||||
class Select_fetch_into_spvars: public select_result_interceptor
|
||||
{
|
||||
List<struct sp_pvar> *spvar_list;
|
||||
uint field_count;
|
||||
public:
|
||||
uint get_field_count() { return field_count; }
|
||||
void set_spvar_list(List<struct sp_pvar> *vars) { spvar_list= vars; }
|
||||
|
||||
virtual bool send_eof() { return FALSE; }
|
||||
virtual bool send_data(List<Item> &items);
|
||||
virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
|
||||
};
|
||||
|
||||
|
||||
/* A mediator between stored procedures and server side cursors */
|
||||
|
||||
class sp_cursor : public Sql_alloc
|
||||
{
|
||||
public:
|
||||
|
@ -227,12 +248,11 @@ public:
|
|||
destroy();
|
||||
}
|
||||
|
||||
// We have split this in two to make it easy for sp_instr_copen
|
||||
// to reuse the sp_instr::exec_stmt() code.
|
||||
sp_lex_keeper *
|
||||
pre_open(THD *thd);
|
||||
void
|
||||
post_open(THD *thd, my_bool was_opened);
|
||||
get_lex_keeper() { return m_lex_keeper; }
|
||||
|
||||
int
|
||||
open(THD *thd);
|
||||
|
||||
int
|
||||
close(THD *thd);
|
||||
|
@ -240,7 +260,7 @@ public:
|
|||
inline my_bool
|
||||
is_open()
|
||||
{
|
||||
return m_isopen;
|
||||
return test(server_side_cursor);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -251,18 +271,13 @@ public:
|
|||
{
|
||||
return m_i;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
MEM_ROOT m_mem_root; // My own mem_root
|
||||
Select_fetch_into_spvars result;
|
||||
sp_lex_keeper *m_lex_keeper;
|
||||
Protocol_cursor *m_prot;
|
||||
my_bool m_isopen;
|
||||
my_bool m_nseof; // Original no_send_eof
|
||||
Protocol *m_oprot; // Original protcol
|
||||
MYSQL_ROWS *m_current_row;
|
||||
Server_side_cursor *server_side_cursor;
|
||||
sp_instr_cpush *m_i; // My push instruction
|
||||
|
||||
void
|
||||
destroy();
|
||||
|
||||
|
|
|
@ -1488,7 +1488,7 @@ bool is_acl_user(const char *host, const char *user)
|
|||
{
|
||||
bool res;
|
||||
VOID(pthread_mutex_lock(&acl_cache->lock));
|
||||
res= find_acl_user(host, user, TRUE);
|
||||
res= find_acl_user(host, user, TRUE) != NULL;
|
||||
VOID(pthread_mutex_unlock(&acl_cache->lock));
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -1327,6 +1327,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||
table->keys_in_use_for_query= table->s->keys_in_use;
|
||||
table->insert_values= 0;
|
||||
table->used_keys= table->s->keys_for_keyread;
|
||||
table->fulltext_searched= 0;
|
||||
table->file->ft_handler= 0;
|
||||
if (table->timestamp_field)
|
||||
table->timestamp_field_type= table->timestamp_field->get_auto_set_type();
|
||||
table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
|
||||
|
|
|
@ -1538,6 +1538,19 @@ void Query_arena::free_items()
|
|||
}
|
||||
|
||||
|
||||
void Query_arena::set_query_arena(Query_arena *set)
|
||||
{
|
||||
mem_root= set->mem_root;
|
||||
free_list= set->free_list;
|
||||
state= set->state;
|
||||
}
|
||||
|
||||
|
||||
void Query_arena::cleanup_stmt()
|
||||
{
|
||||
DBUG_ASSERT("Query_arena::cleanup_stmt()" == "not implemented");
|
||||
}
|
||||
|
||||
/*
|
||||
Statement functions
|
||||
*/
|
||||
|
@ -1595,12 +1608,6 @@ void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
|
|||
}
|
||||
|
||||
|
||||
void Statement::close_cursor()
|
||||
{
|
||||
DBUG_ASSERT("Statement::close_cursor()" == "not implemented");
|
||||
}
|
||||
|
||||
|
||||
void THD::end_statement()
|
||||
{
|
||||
/* Cleanup SQL processing state to resuse this statement in next query. */
|
||||
|
@ -1642,13 +1649,6 @@ void THD::restore_active_arena(Query_arena *set, Query_arena *backup)
|
|||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
void Query_arena::set_query_arena(Query_arena *set)
|
||||
{
|
||||
mem_root= set->mem_root;
|
||||
free_list= set->free_list;
|
||||
state= set->state;
|
||||
}
|
||||
|
||||
Statement::~Statement()
|
||||
{
|
||||
/*
|
||||
|
@ -1717,9 +1717,11 @@ int Statement_map::insert(Statement *statement)
|
|||
|
||||
void Statement_map::close_transient_cursors()
|
||||
{
|
||||
#ifdef TO_BE_IMPLEMENTED
|
||||
Statement *stmt;
|
||||
while ((stmt= transient_cursor_list.head()))
|
||||
stmt->close_cursor(); /* deletes itself from the list */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -738,10 +738,12 @@ public:
|
|||
void set_query_arena(Query_arena *set);
|
||||
|
||||
void free_items();
|
||||
/* Close the active state associated with execution of this statement */
|
||||
virtual void cleanup_stmt();
|
||||
};
|
||||
|
||||
|
||||
class Cursor;
|
||||
class Server_side_cursor;
|
||||
|
||||
/*
|
||||
State of a single command executed against this connection.
|
||||
|
@ -817,7 +819,7 @@ public:
|
|||
*/
|
||||
char *query;
|
||||
uint32 query_length; // current query length
|
||||
Cursor *cursor;
|
||||
Server_side_cursor *cursor;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -834,8 +836,6 @@ public:
|
|||
void restore_backup_statement(Statement *stmt, Statement *backup);
|
||||
/* return class type */
|
||||
virtual Type type() const;
|
||||
/* Close the cursor open for this statement, if there is one */
|
||||
virtual void close_cursor();
|
||||
};
|
||||
|
||||
|
||||
|
@ -887,9 +887,6 @@ public:
|
|||
}
|
||||
hash_delete(&st_hash, (byte *) statement);
|
||||
}
|
||||
void add_transient_cursor(Statement *stmt)
|
||||
{ transient_cursor_list.append(stmt); }
|
||||
void erase_transient_cursor(Statement *stmt) { stmt->unlink(); }
|
||||
/*
|
||||
Close all cursors of this connection that use tables of a storage
|
||||
engine that has transaction-specific state and therefore can not
|
||||
|
@ -1834,18 +1831,21 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class select_union :public select_result_interceptor {
|
||||
public:
|
||||
TABLE *table;
|
||||
class select_union :public select_result_interceptor
|
||||
{
|
||||
TMP_TABLE_PARAM tmp_table_param;
|
||||
public:
|
||||
TABLE *table;
|
||||
|
||||
select_union(TABLE *table_par);
|
||||
~select_union();
|
||||
select_union() :table(0) {}
|
||||
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
|
||||
bool send_data(List<Item> &items);
|
||||
bool send_eof();
|
||||
bool flush();
|
||||
void set_table(TABLE *tbl) { table= tbl; }
|
||||
|
||||
bool create_result_table(THD *thd, List<Item> *column_types,
|
||||
bool is_distinct, ulonglong options,
|
||||
const char *alias);
|
||||
};
|
||||
|
||||
/* Base subselect interface class */
|
||||
|
|
660
sql/sql_cursor.cc
Normal file
660
sql/sql_cursor.cc
Normal file
|
@ -0,0 +1,660 @@
|
|||
/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
#ifdef USE_PRAGMA_IMPLEMENTATION
|
||||
#pragma implementation /* gcc class implementation */
|
||||
#endif
|
||||
|
||||
#include "mysql_priv.h"
|
||||
#include "sql_cursor.h"
|
||||
#include "sql_select.h"
|
||||
|
||||
/****************************************************************************
|
||||
Declarations.
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
Sensitive_cursor -- a sensitive non-materialized server side
|
||||
cursor An instance of this class cursor has its own runtime
|
||||
state -- list of used items and memory root for runtime memory,
|
||||
open and locked tables, change list for the changes of the
|
||||
parsed tree. This state is freed when the cursor is closed.
|
||||
*/
|
||||
|
||||
class Sensitive_cursor: public Server_side_cursor
|
||||
{
|
||||
MEM_ROOT main_mem_root;
|
||||
Query_arena *stmt_arena;
|
||||
JOIN *join;
|
||||
TABLE *open_tables;
|
||||
MYSQL_LOCK *lock;
|
||||
TABLE *derived_tables;
|
||||
/* List of items created during execution */
|
||||
query_id_t query_id;
|
||||
struct Engine_info
|
||||
{
|
||||
const handlerton *ht;
|
||||
void *read_view;
|
||||
};
|
||||
Engine_info ht_info[MAX_HA];
|
||||
Item_change_list change_list;
|
||||
my_bool close_at_commit;
|
||||
THR_LOCK_OWNER lock_id;
|
||||
private:
|
||||
/* bzero cursor state in THD */
|
||||
void reset_thd(THD *thd);
|
||||
public:
|
||||
Sensitive_cursor(THD *thd, select_result *result_arg);
|
||||
|
||||
THR_LOCK_OWNER *get_lock_id() { return &lock_id; }
|
||||
/* Save THD state into cursor */
|
||||
void post_open(THD *thd);
|
||||
|
||||
virtual bool is_open() const { return join != 0; }
|
||||
virtual int open(JOIN *join);
|
||||
virtual void fetch(ulong num_rows);
|
||||
virtual void close();
|
||||
virtual ~Sensitive_cursor();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Materialized_cursor -- an insensitive materialized server-side
|
||||
cursor. The result set of this cursor is saved in a temporary
|
||||
table at open. The cursor itself is simply an interface for the
|
||||
handler of the temporary table.
|
||||
*/
|
||||
|
||||
class Materialized_cursor: public Server_side_cursor
|
||||
{
|
||||
MEM_ROOT main_mem_root;
|
||||
/* A fake unit to supply to select_send when fetching */
|
||||
SELECT_LEX_UNIT fake_unit;
|
||||
TABLE *table;
|
||||
List<Item> item_list;
|
||||
ulong fetch_limit;
|
||||
ulong fetch_count;
|
||||
public:
|
||||
Materialized_cursor(select_result *result, TABLE *table);
|
||||
|
||||
virtual bool is_open() const { return table != 0; }
|
||||
virtual int open(JOIN *join __attribute__((unused)));
|
||||
virtual void fetch(ulong num_rows);
|
||||
virtual void close();
|
||||
virtual ~Materialized_cursor();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Select_materialize -- a mediator between a cursor query and the
|
||||
protocol. In case we were not able to open a non-materialzed
|
||||
cursor, it creates an internal temporary HEAP table, and insert
|
||||
all rows into it. When the table reaches max_heap_table_size,
|
||||
it's converted to a MyISAM table. Later this table is used to
|
||||
create a Materialized_cursor.
|
||||
*/
|
||||
|
||||
class Select_materialize: public select_union
|
||||
{
|
||||
select_result *result; /* the result object of the caller (PS or SP) */
|
||||
public:
|
||||
Select_materialize(select_result *result_arg) :result(result_arg) {}
|
||||
virtual bool send_fields(List<Item> &list, uint flags);
|
||||
};
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/*
|
||||
Attempt to open a materialized or non-materialized cursor.
|
||||
|
||||
SYNOPSIS
|
||||
mysql_open_cursor()
|
||||
thd thread handle
|
||||
flags [in] create a materialized cursor or not
|
||||
result [in] result class of the caller used as a destination
|
||||
for the rows fetched from the cursor
|
||||
pcursor [out] a pointer to store a pointer to cursor in
|
||||
|
||||
RETURN VALUE
|
||||
0 the query has been successfully executed; in this
|
||||
case pcursor may or may not contain
|
||||
a pointer to an open cursor.
|
||||
non-zero an error, 'pcursor' has been left intact.
|
||||
*/
|
||||
|
||||
int mysql_open_cursor(THD *thd, uint flags, select_result *result,
|
||||
Server_side_cursor **pcursor)
|
||||
{
|
||||
Sensitive_cursor *sensitive_cursor;
|
||||
select_result *save_result;
|
||||
Select_materialize *result_materialize;
|
||||
LEX *lex= thd->lex;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
The lifetime of the sensitive cursor is the same or less as the
|
||||
lifetime of the runtime memory of the statement it's opened for.
|
||||
*/
|
||||
if (! (result_materialize= new (thd->mem_root) Select_materialize(result)))
|
||||
return 1;
|
||||
|
||||
if (! (sensitive_cursor= new (thd->mem_root) Sensitive_cursor(thd, result)))
|
||||
{
|
||||
delete result;
|
||||
return 1;
|
||||
}
|
||||
|
||||
save_result= lex->result;
|
||||
|
||||
lex->result= result_materialize;
|
||||
if (! (flags & (uint) ALWAYS_MATERIALIZED_CURSOR))
|
||||
{
|
||||
thd->lock_id= sensitive_cursor->get_lock_id();
|
||||
thd->cursor= sensitive_cursor;
|
||||
}
|
||||
|
||||
rc= mysql_execute_command(thd);
|
||||
|
||||
lex->result= save_result;
|
||||
thd->lock_id= &thd->main_lock_id;
|
||||
thd->cursor= 0;
|
||||
|
||||
/*
|
||||
Possible options here:
|
||||
- a sensitive cursor is open. In this case rc is 0 and
|
||||
result_materialize->table is NULL, or
|
||||
- a materialized cursor is open. In this case rc is 0 and
|
||||
result_materialize->table is not NULL
|
||||
- an error occured during materializaton.
|
||||
result_materialize->table is not NULL, but rc != 0
|
||||
- successful completion of mysql_execute_command without
|
||||
a cursor: rc is 0, result_materialize->table is NULL,
|
||||
sensitive_cursor is not open.
|
||||
This is possible if some command writes directly to the
|
||||
network, bypassing select_result mechanism. An example of
|
||||
such command is SHOW VARIABLES or SHOW STATUS.
|
||||
*/
|
||||
if (rc)
|
||||
goto err_open;
|
||||
|
||||
if (sensitive_cursor->is_open())
|
||||
{
|
||||
DBUG_ASSERT(!result_materialize->table);
|
||||
/*
|
||||
It's safer if we grab THD state after mysql_execute_command
|
||||
is finished and not in Sensitive_cursor::open(), because
|
||||
currently the call to Sensitive_cursor::open is buried deep
|
||||
in JOIN::exec of the top level join.
|
||||
*/
|
||||
sensitive_cursor->post_open(thd);
|
||||
*pcursor= sensitive_cursor;
|
||||
goto end;
|
||||
}
|
||||
else if (result_materialize->table)
|
||||
{
|
||||
Materialized_cursor *materialized_cursor;
|
||||
TABLE *table= result_materialize->table;
|
||||
MEM_ROOT *mem_root= &table->mem_root;
|
||||
|
||||
if (!(materialized_cursor= new (mem_root)
|
||||
Materialized_cursor(result, table)))
|
||||
{
|
||||
rc= 1;
|
||||
goto err_open;
|
||||
}
|
||||
|
||||
if ((rc= materialized_cursor->open(0)))
|
||||
{
|
||||
delete materialized_cursor;
|
||||
goto err_open;
|
||||
}
|
||||
|
||||
*pcursor= materialized_cursor;
|
||||
thd->stmt_arena->cleanup_stmt();
|
||||
goto end;
|
||||
}
|
||||
|
||||
err_open:
|
||||
DBUG_ASSERT(! (sensitive_cursor && sensitive_cursor->is_open()));
|
||||
delete sensitive_cursor;
|
||||
if (result_materialize->table)
|
||||
free_tmp_table(thd, result_materialize->table);
|
||||
end:
|
||||
delete result_materialize;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Server_side_cursor
|
||||
****************************************************************************/
|
||||
|
||||
Server_side_cursor::~Server_side_cursor()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Server_side_cursor::operator delete(void *ptr, size_t size)
|
||||
{
|
||||
Server_side_cursor *cursor= (Server_side_cursor*) ptr;
|
||||
MEM_ROOT own_root= *cursor->mem_root;
|
||||
|
||||
DBUG_ENTER("Server_side_cursor::operator delete");
|
||||
TRASH(ptr, size);
|
||||
/*
|
||||
If this cursor has never been opened mem_root is empty. Otherwise
|
||||
mem_root points to the memory the cursor object was allocated in.
|
||||
In this case it's important to call free_root last, and free a copy
|
||||
instead of *mem_root to avoid writing into freed memory.
|
||||
*/
|
||||
free_root(&own_root, MYF(0));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Sensitive_cursor
|
||||
****************************************************************************/
|
||||
|
||||
Sensitive_cursor::Sensitive_cursor(THD *thd, select_result *result_arg)
|
||||
:Server_side_cursor(&main_mem_root, result_arg),
|
||||
stmt_arena(0),
|
||||
join(0),
|
||||
close_at_commit(FALSE)
|
||||
{
|
||||
/* We will overwrite it at open anyway. */
|
||||
init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
|
||||
thr_lock_owner_init(&lock_id, &thd->lock_info);
|
||||
bzero((void*) ht_info, sizeof(ht_info));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Sensitive_cursor::post_open(THD *thd)
|
||||
{
|
||||
Engine_info *info;
|
||||
/*
|
||||
We need to save and reset thd->mem_root, otherwise it'll be
|
||||
freed later in mysql_parse.
|
||||
|
||||
We can't just change thd->mem_root here as we want to keep the
|
||||
things that are already allocated in thd->mem_root for
|
||||
Sensitive_cursor::fetch()
|
||||
*/
|
||||
*mem_root= *thd->mem_root;
|
||||
stmt_arena= thd->stmt_arena;
|
||||
state= stmt_arena->state;
|
||||
/* Allocate a new memory root for thd */
|
||||
init_sql_alloc(thd->mem_root,
|
||||
thd->variables.query_alloc_block_size,
|
||||
thd->variables.query_prealloc_size);
|
||||
|
||||
/*
|
||||
Save tables and zero THD pointers to prevent table close in
|
||||
close_thread_tables.
|
||||
*/
|
||||
derived_tables= thd->derived_tables;
|
||||
open_tables= thd->open_tables;
|
||||
lock= thd->lock;
|
||||
query_id= thd->query_id;
|
||||
free_list= thd->free_list;
|
||||
change_list= thd->change_list;
|
||||
reset_thd(thd);
|
||||
/* Now we have an active cursor and can cause a deadlock */
|
||||
thd->lock_info.n_cursors++;
|
||||
|
||||
close_at_commit= FALSE; /* reset in case we're reusing the cursor */
|
||||
info= &ht_info[0];
|
||||
for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++)
|
||||
{
|
||||
const handlerton *ht= *pht;
|
||||
close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT);
|
||||
if (ht->create_cursor_read_view)
|
||||
{
|
||||
info->ht= ht;
|
||||
info->read_view= (ht->create_cursor_read_view)();
|
||||
++info;
|
||||
}
|
||||
}
|
||||
/*
|
||||
XXX: thd->locked_tables is not changed.
|
||||
What problems can we have with it if cursor is open?
|
||||
TODO: must be fixed because of the prelocked mode.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Sensitive_cursor::reset_thd(THD *thd)
|
||||
{
|
||||
thd->derived_tables= 0;
|
||||
thd->open_tables= 0;
|
||||
thd->lock= 0;
|
||||
thd->free_list= 0;
|
||||
thd->change_list.empty();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Sensitive_cursor::open(JOIN *join_arg)
|
||||
{
|
||||
join= join_arg;
|
||||
THD *thd= join->thd;
|
||||
/* First non-constant table */
|
||||
JOIN_TAB *join_tab= join->join_tab + join->const_tables;
|
||||
DBUG_ENTER("Sensitive_cursor::open");
|
||||
|
||||
join->change_result(result);
|
||||
/*
|
||||
Send fields description to the client; server_status is sent
|
||||
in 'EOF' packet, which follows send_fields().
|
||||
We don't simply use SEND_EOF flag of send_fields because we also
|
||||
want to flush the network buffer, which is done only in a standalone
|
||||
send_eof().
|
||||
*/
|
||||
result->send_fields(*join->fields, Protocol::SEND_NUM_ROWS);
|
||||
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
|
||||
result->send_eof();
|
||||
thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
|
||||
|
||||
/* Prepare JOIN for reading rows. */
|
||||
join->tmp_table= 0;
|
||||
join->join_tab[join->tables-1].next_select= setup_end_select_func(join);
|
||||
join->send_records= 0;
|
||||
join->fetch_limit= join->unit->offset_limit_cnt;
|
||||
|
||||
/* Disable JOIN CACHE as it is not working with cursors yet */
|
||||
for (JOIN_TAB *tab= join_tab;
|
||||
tab != join->join_tab + join->tables - 1;
|
||||
tab++)
|
||||
{
|
||||
if (tab->next_select == sub_select_cache)
|
||||
tab->next_select= sub_select;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(join_tab->table->reginfo.not_exists_optimize == 0);
|
||||
DBUG_ASSERT(join_tab->not_used_in_distinct == 0);
|
||||
/*
|
||||
null_row is set only if row not found and it's outer join: should never
|
||||
happen for the first table in join_tab list
|
||||
*/
|
||||
DBUG_ASSERT(join_tab->table->null_row == 0);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
SYNOPSIS
|
||||
Sensitive_cursor::fetch()
|
||||
num_rows fetch up to this number of rows (maybe less)
|
||||
|
||||
DESCRIPTION
|
||||
Fetch next num_rows rows from the cursor and send them to the client
|
||||
|
||||
Precondition:
|
||||
Sensitive_cursor is open
|
||||
|
||||
RETURN VALUES:
|
||||
none, this function will send OK to the clinet or set an error
|
||||
message in THD
|
||||
*/
|
||||
|
||||
void
|
||||
Sensitive_cursor::fetch(ulong num_rows)
|
||||
{
|
||||
THD *thd= join->thd;
|
||||
JOIN_TAB *join_tab= join->join_tab + join->const_tables;
|
||||
enum_nested_loop_state error= NESTED_LOOP_OK;
|
||||
Query_arena backup_arena;
|
||||
Engine_info *info;
|
||||
DBUG_ENTER("Sensitive_cursor::fetch");
|
||||
DBUG_PRINT("enter",("rows: %lu", num_rows));
|
||||
|
||||
DBUG_ASSERT(thd->derived_tables == 0 && thd->open_tables == 0 &&
|
||||
thd->lock == 0);
|
||||
|
||||
thd->derived_tables= derived_tables;
|
||||
thd->open_tables= open_tables;
|
||||
thd->lock= lock;
|
||||
thd->query_id= query_id;
|
||||
thd->change_list= change_list;
|
||||
/* save references to memory allocated during fetch */
|
||||
thd->set_n_backup_active_arena(this, &backup_arena);
|
||||
|
||||
for (info= ht_info; info->read_view ; info++)
|
||||
(info->ht->set_cursor_read_view)(info->read_view);
|
||||
|
||||
join->fetch_limit+= num_rows;
|
||||
|
||||
error= sub_select(join, join_tab, 0);
|
||||
if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS)
|
||||
error= sub_select(join,join_tab,1);
|
||||
if (error == NESTED_LOOP_QUERY_LIMIT)
|
||||
error= NESTED_LOOP_OK; /* select_limit used */
|
||||
if (error == NESTED_LOOP_CURSOR_LIMIT)
|
||||
join->resume_nested_loop= TRUE;
|
||||
|
||||
#ifdef USING_TRANSACTIONS
|
||||
ha_release_temporary_latches(thd);
|
||||
#endif
|
||||
/* Grab free_list here to correctly free it in close */
|
||||
thd->restore_active_arena(this, &backup_arena);
|
||||
|
||||
change_list= thd->change_list;
|
||||
reset_thd(thd);
|
||||
|
||||
for (info= ht_info; info->read_view; info++)
|
||||
(info->ht->set_cursor_read_view)(0);
|
||||
|
||||
if (error == NESTED_LOOP_CURSOR_LIMIT)
|
||||
{
|
||||
/* Fetch limit worked, possibly more rows are there */
|
||||
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
|
||||
result->send_eof();
|
||||
thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
close();
|
||||
if (error == NESTED_LOOP_OK)
|
||||
{
|
||||
thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
|
||||
result->send_eof();
|
||||
thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT;
|
||||
}
|
||||
else if (error != NESTED_LOOP_KILLED)
|
||||
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Sensitive_cursor::close()
|
||||
{
|
||||
THD *thd= join->thd;
|
||||
DBUG_ENTER("Sensitive_cursor::close");
|
||||
|
||||
for (Engine_info *info= ht_info; info->read_view; info++)
|
||||
{
|
||||
(info->ht->close_cursor_read_view)(info->read_view);
|
||||
info->read_view= 0;
|
||||
info->ht= 0;
|
||||
}
|
||||
|
||||
thd->change_list= change_list;
|
||||
{
|
||||
/*
|
||||
XXX: Another hack: we need to set THD state as if in a fetch to be
|
||||
able to call stmt close.
|
||||
*/
|
||||
DBUG_ASSERT(lock || open_tables || derived_tables);
|
||||
|
||||
TABLE *tmp_derived_tables= thd->derived_tables;
|
||||
MYSQL_LOCK *tmp_lock= thd->lock;
|
||||
|
||||
thd->open_tables= open_tables;
|
||||
thd->derived_tables= derived_tables;
|
||||
thd->lock= lock;
|
||||
|
||||
/* Is expected to at least close tables and empty thd->change_list */
|
||||
stmt_arena->cleanup_stmt();
|
||||
|
||||
thd->open_tables= tmp_derived_tables;
|
||||
thd->derived_tables= tmp_derived_tables;
|
||||
thd->lock= tmp_lock;
|
||||
}
|
||||
thd->lock_info.n_cursors--; /* Decrease the number of active cursors */
|
||||
join= 0;
|
||||
stmt_arena= 0;
|
||||
free_items();
|
||||
change_list.empty();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
Sensitive_cursor::~Sensitive_cursor()
|
||||
{
|
||||
if (is_open())
|
||||
close();
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Materialized_cursor
|
||||
****************************************************************************/
|
||||
|
||||
Materialized_cursor::Materialized_cursor(select_result *result_arg,
|
||||
TABLE *table_arg)
|
||||
:Server_side_cursor(&table_arg->mem_root, result_arg),
|
||||
table(table_arg),
|
||||
fetch_limit(0),
|
||||
fetch_count(0)
|
||||
{
|
||||
fake_unit.init_query();
|
||||
fake_unit.thd= table->in_use;
|
||||
}
|
||||
|
||||
|
||||
int Materialized_cursor::open(JOIN *join __attribute__((unused)))
|
||||
{
|
||||
THD *thd= fake_unit.thd;
|
||||
int rc;
|
||||
Query_arena backup_arena;
|
||||
|
||||
thd->set_n_backup_active_arena(this, &backup_arena);
|
||||
/* Create a list of fields and start sequential scan */
|
||||
rc= (table->fill_item_list(&item_list) ||
|
||||
result->prepare(item_list, &fake_unit) ||
|
||||
table->file->ha_rnd_init(TRUE));
|
||||
thd->restore_active_arena(this, &backup_arena);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Fetch up to the given number of rows from a materialized cursor.
|
||||
|
||||
DESCRIPTION
|
||||
Precondition: the cursor is open.
|
||||
|
||||
If the cursor points after the last row, the fetch will automatically
|
||||
close the cursor and not send any data (except the 'EOF' packet
|
||||
with SERVER_STATUS_LAST_ROW_SENT). This is an extra round trip
|
||||
and probably should be improved to return
|
||||
SERVER_STATUS_LAST_ROW_SENT along with the last row.
|
||||
|
||||
RETURN VALUE
|
||||
none, in case of success the row is sent to the client, otherwise
|
||||
an error message is set in THD
|
||||
*/
|
||||
|
||||
void Materialized_cursor::fetch(ulong num_rows)
|
||||
{
|
||||
THD *thd= table->in_use;
|
||||
|
||||
int res= 0;
|
||||
for (fetch_limit+= num_rows; fetch_count < fetch_limit; fetch_count++)
|
||||
{
|
||||
if ((res= table->file->rnd_next(table->record[0])))
|
||||
break;
|
||||
/* Send data only if the read was successful. */
|
||||
result->send_data(item_list);
|
||||
}
|
||||
|
||||
switch (res) {
|
||||
case 0:
|
||||
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
|
||||
result->send_eof();
|
||||
thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
|
||||
break;
|
||||
case HA_ERR_END_OF_FILE:
|
||||
thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
|
||||
result->send_eof();
|
||||
thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT;
|
||||
close();
|
||||
break;
|
||||
default:
|
||||
table->file->print_error(res, MYF(0));
|
||||
close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Materialized_cursor::close()
|
||||
{
|
||||
/* Free item_list items */
|
||||
free_items();
|
||||
(void) table->file->ha_rnd_end();
|
||||
/*
|
||||
We need to grab table->mem_root to prevent free_tmp_table from freeing:
|
||||
the cursor object was allocated in this memory.
|
||||
*/
|
||||
main_mem_root= table->mem_root;
|
||||
mem_root= &main_mem_root;
|
||||
clear_alloc_root(&table->mem_root);
|
||||
free_tmp_table(table->in_use, table);
|
||||
table= 0;
|
||||
}
|
||||
|
||||
|
||||
Materialized_cursor::~Materialized_cursor()
|
||||
{
|
||||
if (is_open())
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Select_materialize
|
||||
****************************************************************************/
|
||||
|
||||
bool Select_materialize::send_fields(List<Item> &list, uint flags)
|
||||
{
|
||||
bool rc;
|
||||
DBUG_ASSERT(table == 0);
|
||||
if (create_result_table(unit->thd, unit->get_unit_column_types(),
|
||||
FALSE, thd->options | TMP_TABLE_ALL_COLUMNS, ""))
|
||||
return TRUE;
|
||||
/*
|
||||
We can't simply supply SEND_EOF flag to send_fields, because send_fields
|
||||
doesn't flush the network buffer.
|
||||
*/
|
||||
rc= result->send_fields(list, Protocol::SEND_NUM_ROWS);
|
||||
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
|
||||
result->send_eof();
|
||||
thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
|
||||
return rc;
|
||||
}
|
||||
|
65
sql/sql_cursor.h
Normal file
65
sql/sql_cursor.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
#ifndef _sql_cursor_h_
|
||||
#define _sql_cursor_h_
|
||||
/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#ifdef USE_PRAGMA_INTERFACE
|
||||
#pragma interface /* gcc class interface */
|
||||
#endif
|
||||
|
||||
/*
|
||||
Declarations for implementation of server side cursors. Only
|
||||
read-only non-scrollable cursors are currently implemented.
|
||||
*/
|
||||
|
||||
/*
|
||||
Server_side_cursor -- an interface for materialized and
|
||||
sensitive (non-materialized) implementation of cursors. All
|
||||
cursors are self-contained (created in their own memory root).
|
||||
For that reason they must be deleted only using a pointer to
|
||||
Server_side_cursor, not to its base class.
|
||||
*/
|
||||
|
||||
class Server_side_cursor: protected Query_arena, public Sql_alloc
|
||||
{
|
||||
protected:
|
||||
/* Row destination used for fetch */
|
||||
select_result *result;
|
||||
public:
|
||||
Server_side_cursor(MEM_ROOT *mem_root_arg, select_result *result_arg)
|
||||
:Query_arena(mem_root_arg, INITIALIZED), result(result_arg)
|
||||
{}
|
||||
|
||||
virtual bool is_open() const= 0;
|
||||
|
||||
virtual int open(JOIN *top_level_join)= 0;
|
||||
virtual void fetch(ulong num_rows)= 0;
|
||||
virtual void close()= 0;
|
||||
virtual ~Server_side_cursor();
|
||||
|
||||
static void operator delete(void *ptr, size_t size);
|
||||
};
|
||||
|
||||
|
||||
int mysql_open_cursor(THD *thd, uint flags,
|
||||
select_result *result,
|
||||
Server_side_cursor **res);
|
||||
|
||||
/* Possible values for flags */
|
||||
|
||||
enum { ANY_CURSOR= 1, ALWAYS_MATERIALIZED_CURSOR= 2 };
|
||||
|
||||
#endif /* _sql_cusor_h_ */
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
|
||||
/*
|
||||
call given derived table processor (preparing or filling tables)
|
||||
Call given derived table processor (preparing or filling tables)
|
||||
|
||||
SYNOPSIS
|
||||
mysql_handle_derived()
|
||||
|
@ -36,7 +36,6 @@
|
|||
|
||||
RETURN
|
||||
0 ok
|
||||
-1 Error
|
||||
1 Error and error message given
|
||||
*/
|
||||
|
||||
|
@ -97,14 +96,14 @@ out:
|
|||
|
||||
RETURN
|
||||
0 ok
|
||||
1 Error
|
||||
-1 Error and error message given
|
||||
*/
|
||||
1 Error and an error message was given
|
||||
*/
|
||||
|
||||
int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
|
||||
{
|
||||
SELECT_LEX_UNIT *unit= orig_table_list->derived;
|
||||
int res= 0;
|
||||
ulonglong create_options;
|
||||
DBUG_ENTER("mysql_derived_prepare");
|
||||
if (unit)
|
||||
{
|
||||
|
@ -118,21 +117,18 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
|
|||
for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select())
|
||||
sl->context.outer_context= 0;
|
||||
|
||||
if (!(derived_result= new select_union(0)))
|
||||
if (!(derived_result= new select_union))
|
||||
DBUG_RETURN(1); // out of memory
|
||||
|
||||
// st_select_lex_unit::prepare correctly work for single select
|
||||
if ((res= unit->prepare(thd, derived_result, 0, orig_table_list->alias)))
|
||||
if ((res= unit->prepare(thd, derived_result, 0)))
|
||||
goto exit;
|
||||
|
||||
if (check_duplicate_names(unit->types, 0))
|
||||
{
|
||||
res= -1;
|
||||
if ((res= check_duplicate_names(unit->types, 0)))
|
||||
goto exit;
|
||||
}
|
||||
|
||||
derived_result->tmp_table_param.init();
|
||||
derived_result->tmp_table_param.field_count= unit->types.elements;
|
||||
create_options= (first_select->options | thd->options |
|
||||
TMP_TABLE_ALL_COLUMNS);
|
||||
/*
|
||||
Temp table is created so that it hounours if UNION without ALL is to be
|
||||
processed
|
||||
|
@ -143,18 +139,12 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
|
|||
!unit->union_distinct->next_select() (i.e. it is union and last distinct
|
||||
SELECT is last SELECT of UNION).
|
||||
*/
|
||||
if (!(table= create_tmp_table(thd, &derived_result->tmp_table_param,
|
||||
unit->types, (ORDER*) 0,
|
||||
FALSE, 1,
|
||||
(first_select->options | thd->options |
|
||||
TMP_TABLE_ALL_COLUMNS),
|
||||
HA_POS_ERROR,
|
||||
orig_table_list->alias)))
|
||||
{
|
||||
res= -1;
|
||||
if ((res= derived_result->create_result_table(thd, &unit->types, FALSE,
|
||||
create_options,
|
||||
orig_table_list->alias)))
|
||||
goto exit;
|
||||
}
|
||||
derived_result->set_table(table);
|
||||
|
||||
table= derived_result->table;
|
||||
|
||||
exit:
|
||||
/* Hide "Unknown column" or "Unknown function" error */
|
||||
|
@ -231,9 +221,8 @@ exit:
|
|||
|
||||
RETURN
|
||||
0 ok
|
||||
1 Error
|
||||
-1 Error and error message given
|
||||
*/
|
||||
1 Error and an error message was given
|
||||
*/
|
||||
|
||||
int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
|
||||
{
|
||||
|
|
|
@ -432,10 +432,6 @@ public:
|
|||
{
|
||||
return my_reinterpret_cast(st_select_lex*)(slave);
|
||||
}
|
||||
st_select_lex* first_select_in_union()
|
||||
{
|
||||
return my_reinterpret_cast(st_select_lex*)(slave);
|
||||
}
|
||||
st_select_lex_unit* next_unit()
|
||||
{
|
||||
return my_reinterpret_cast(st_select_lex_unit*)(next);
|
||||
|
@ -445,8 +441,7 @@ public:
|
|||
void exclude_tree();
|
||||
|
||||
/* UNION methods */
|
||||
bool prepare(THD *thd, select_result *result, ulong additional_options,
|
||||
const char *tmp_table_alias);
|
||||
bool prepare(THD *thd, select_result *result, ulong additional_options);
|
||||
bool exec();
|
||||
bool cleanup();
|
||||
inline void unclean() { cleaned= 0; }
|
||||
|
@ -462,7 +457,10 @@ public:
|
|||
|
||||
friend void lex_start(THD *thd, uchar *buf, uint length);
|
||||
friend int subselect_union_engine::exec();
|
||||
|
||||
List<Item> *get_unit_column_types();
|
||||
};
|
||||
|
||||
typedef class st_select_lex_unit SELECT_LEX_UNIT;
|
||||
|
||||
/*
|
||||
|
|
|
@ -32,6 +32,8 @@ public:
|
|||
{
|
||||
return (void*) sql_alloc((uint) size);
|
||||
}
|
||||
static void *operator new[](size_t size, MEM_ROOT *mem_root)
|
||||
{ return (void*) alloc_root(mem_root, (uint) size); }
|
||||
static void *operator new(size_t size, MEM_ROOT *mem_root)
|
||||
{ return (void*) alloc_root(mem_root, (uint) size); }
|
||||
static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); }
|
||||
|
|
|
@ -544,6 +544,8 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
|
|||
while ((sql_field= (Item_field*) it++))
|
||||
{
|
||||
Field *field= sql_field->field;
|
||||
if (field == table->next_number_field)
|
||||
table->auto_increment_field_not_null= TRUE;
|
||||
/*
|
||||
No fields specified in fields_vars list can be null in this format.
|
||||
Mark field as not null, we should do this for each row because of
|
||||
|
@ -684,6 +686,8 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
|
|||
Field *field= ((Item_field *)item)->field;
|
||||
field->reset();
|
||||
field->set_null();
|
||||
if (field == table->next_number_field)
|
||||
table->auto_increment_field_not_null= TRUE;
|
||||
if (!field->maybe_null())
|
||||
{
|
||||
if (field->type() == FIELD_TYPE_TIMESTAMP)
|
||||
|
@ -701,9 +705,12 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
|
|||
|
||||
if (item->type() == Item::FIELD_ITEM)
|
||||
{
|
||||
|
||||
Field *field= ((Item_field *)item)->field;
|
||||
field->set_notnull();
|
||||
read_info.row_end[0]=0; // Safe to change end marker
|
||||
if (field == table->next_number_field)
|
||||
table->auto_increment_field_not_null= TRUE;
|
||||
field->store((char*) pos, length, read_info.read_charset);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -71,6 +71,7 @@ When one supplies long data for a placeholder:
|
|||
|
||||
#include "mysql_priv.h"
|
||||
#include "sql_select.h" // for JOIN
|
||||
#include "sql_cursor.h"
|
||||
#include "sp_head.h"
|
||||
#include "sp.h"
|
||||
#include "sp_cache.h"
|
||||
|
@ -81,6 +82,18 @@ When one supplies long data for a placeholder:
|
|||
#include <mysql_com.h>
|
||||
#endif
|
||||
|
||||
/* A result class used to send cursor rows using the binary protocol. */
|
||||
|
||||
class Select_fetch_protocol_prep: public select_send
|
||||
{
|
||||
Protocol_prep protocol;
|
||||
public:
|
||||
Select_fetch_protocol_prep(THD *thd);
|
||||
virtual bool send_fields(List<Item> &list, uint flags);
|
||||
virtual bool send_data(List<Item> &items);
|
||||
virtual bool send_eof();
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
Prepared_statement: a statement that can contain placeholders
|
||||
******************************************************************************/
|
||||
|
@ -89,6 +102,7 @@ class Prepared_statement: public Statement
|
|||
{
|
||||
public:
|
||||
THD *thd;
|
||||
Select_fetch_protocol_prep result;
|
||||
Protocol *protocol;
|
||||
Item_param **param_array;
|
||||
uint param_count;
|
||||
|
@ -109,8 +123,9 @@ public:
|
|||
virtual ~Prepared_statement();
|
||||
void setup_set_params();
|
||||
virtual Query_arena::Type type() const;
|
||||
virtual void close_cursor();
|
||||
virtual void cleanup_stmt();
|
||||
bool set_name(LEX_STRING *name);
|
||||
inline void close_cursor() { delete cursor; cursor= 0; }
|
||||
|
||||
bool prepare(const char *packet, uint packet_length);
|
||||
bool execute(String *expanded_query, bool open_cursor);
|
||||
|
@ -140,8 +155,6 @@ inline bool is_param_null(const uchar *pos, ulong param_no)
|
|||
return pos[param_no/8] & (1 << (param_no & 7));
|
||||
}
|
||||
|
||||
enum { STMT_QUERY_LOG_LENGTH= 8192 };
|
||||
|
||||
/*
|
||||
Find a prepared statement in the statement map by id.
|
||||
|
||||
|
@ -1264,7 +1277,7 @@ static int mysql_test_select(Prepared_statement *stmt,
|
|||
It is not SELECT COMMAND for sure, so setup_tables will be called as
|
||||
usual, and we pass 0 as setup_tables_done_option
|
||||
*/
|
||||
if (unit->prepare(thd, 0, 0, ""))
|
||||
if (unit->prepare(thd, 0, 0))
|
||||
goto error;
|
||||
if (!lex->describe && !text_protocol)
|
||||
{
|
||||
|
@ -1395,7 +1408,7 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
|
|||
thd->used_tables= 0; // Updated by setup_fields
|
||||
|
||||
/* Calls JOIN::prepare */
|
||||
DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option, ""));
|
||||
DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1785,19 +1798,6 @@ static bool init_param_array(Prepared_statement *stmt)
|
|||
}
|
||||
|
||||
|
||||
/* Cleanup PS after execute/prepare and restore THD state */
|
||||
|
||||
static void cleanup_stmt_and_thd_after_use(Statement *stmt, THD *thd)
|
||||
{
|
||||
DBUG_ENTER("cleanup_stmt_and_thd_after_use");
|
||||
stmt->lex->unit.cleanup();
|
||||
cleanup_items(stmt->free_list);
|
||||
thd->rollback_item_tree_changes();
|
||||
thd->cleanup_after_query();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
COM_STMT_PREPARE handler.
|
||||
|
||||
|
@ -2221,16 +2221,14 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
|
|||
test(flags & (ulong) CURSOR_TYPE_READ_ONLY));
|
||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
mysql_log.write(thd, COM_STMT_EXECUTE, "[%lu] %s", stmt->id, thd->query);
|
||||
if (rc == 0)
|
||||
mysql_log.write(thd, COM_STMT_EXECUTE, "[%lu] %s", stmt->id, thd->query);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
set_params_data_err:
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute");
|
||||
err:
|
||||
reset_stmt_params(stmt);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
@ -2285,14 +2283,16 @@ void mysql_sql_stmt_execute(THD *thd)
|
|||
|
||||
if (stmt->set_params_from_vars(stmt, lex->prepared_stmt_params,
|
||||
&expanded_query))
|
||||
{
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
goto set_params_data_err;
|
||||
|
||||
(void) stmt->execute(&expanded_query, FALSE);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
set_params_data_err:
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
|
||||
reset_stmt_params(stmt);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2313,7 +2313,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
|
|||
ulong num_rows= uint4korr(packet+4);
|
||||
Prepared_statement *stmt;
|
||||
Statement stmt_backup;
|
||||
Cursor *cursor;
|
||||
Server_side_cursor *cursor;
|
||||
DBUG_ENTER("mysql_stmt_fetch");
|
||||
|
||||
statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status);
|
||||
|
@ -2321,7 +2321,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
|
|||
DBUG_VOID_RETURN;
|
||||
|
||||
cursor= stmt->cursor;
|
||||
if (!cursor || !cursor->is_open())
|
||||
if (!cursor)
|
||||
{
|
||||
my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id);
|
||||
DBUG_VOID_RETURN;
|
||||
|
@ -2333,25 +2333,16 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
|
|||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
my_pthread_setprio(pthread_self(), QUERY_PRIOR);
|
||||
|
||||
thd->protocol= stmt->protocol; // Switch to binary protocol
|
||||
cursor->fetch(num_rows);
|
||||
thd->protocol= &thd->protocol_simple; // Use normal protocol
|
||||
|
||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
|
||||
|
||||
if (!cursor->is_open())
|
||||
{
|
||||
/* We're done with the fetch: reset PS for next execution */
|
||||
cleanup_stmt_and_thd_after_use(stmt, thd);
|
||||
stmt->close_cursor();
|
||||
thd->cursor= 0;
|
||||
reset_stmt_params(stmt);
|
||||
/*
|
||||
Must be the last, as some memory is still needed for
|
||||
the previous calls.
|
||||
*/
|
||||
free_root(cursor->mem_root, MYF(0));
|
||||
if (cursor->close_at_commit)
|
||||
thd->stmt_map.erase_transient_cursor(stmt);
|
||||
}
|
||||
|
||||
thd->restore_backup_statement(stmt, &stmt_backup);
|
||||
|
@ -2384,14 +2375,19 @@ void mysql_stmt_reset(THD *thd, char *packet)
|
|||
/* There is always space for 4 bytes in buffer */
|
||||
ulong stmt_id= uint4korr(packet);
|
||||
Prepared_statement *stmt;
|
||||
Cursor *cursor;
|
||||
DBUG_ENTER("mysql_stmt_reset");
|
||||
|
||||
statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status);
|
||||
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
stmt->close_cursor(); /* will reset statement params */
|
||||
stmt->close_cursor();
|
||||
|
||||
/*
|
||||
Clear parameters from data which could be set by
|
||||
mysql_stmt_send_long_data() call.
|
||||
*/
|
||||
reset_stmt_params(stmt);
|
||||
|
||||
stmt->state= Query_arena::PREPARED;
|
||||
|
||||
|
@ -2533,11 +2529,65 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
|
|||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Select_fetch_protocol_prep
|
||||
****************************************************************************/
|
||||
|
||||
Select_fetch_protocol_prep::Select_fetch_protocol_prep(THD *thd)
|
||||
:protocol(thd)
|
||||
{}
|
||||
|
||||
bool Select_fetch_protocol_prep::send_fields(List<Item> &list, uint flags)
|
||||
{
|
||||
bool rc;
|
||||
Protocol *save_protocol= thd->protocol;
|
||||
|
||||
/*
|
||||
Protocol::send_fields caches the information about column types:
|
||||
this information is later used to send data. Therefore, the same
|
||||
dedicated Protocol object must be used for all operations with
|
||||
a cursor.
|
||||
*/
|
||||
thd->protocol= &protocol;
|
||||
rc= select_send::send_fields(list, flags);
|
||||
thd->protocol= save_protocol;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool Select_fetch_protocol_prep::send_eof()
|
||||
{
|
||||
Protocol *save_protocol= thd->protocol;
|
||||
|
||||
thd->protocol= &protocol;
|
||||
::send_eof(thd);
|
||||
thd->protocol= save_protocol;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Select_fetch_protocol_prep::send_data(List<Item> &fields)
|
||||
{
|
||||
Protocol *save_protocol= thd->protocol;
|
||||
bool rc;
|
||||
|
||||
thd->protocol= &protocol;
|
||||
rc= select_send::send_data(fields);
|
||||
thd->protocol= save_protocol;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Prepared_statement
|
||||
****************************************************************************/
|
||||
|
||||
Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg)
|
||||
:Statement(INITIALIZED, ++thd_arg->statement_id_counter,
|
||||
thd_arg->variables.query_alloc_block_size,
|
||||
thd_arg->variables.query_prealloc_size),
|
||||
thd(thd_arg),
|
||||
result(thd_arg),
|
||||
protocol(protocol_arg),
|
||||
param_array(0),
|
||||
param_count(0),
|
||||
|
@ -2585,17 +2635,7 @@ Prepared_statement::~Prepared_statement()
|
|||
{
|
||||
DBUG_ENTER("Prepared_statement::~Prepared_statement");
|
||||
DBUG_PRINT("enter",("stmt: %p cursor: %p", this, cursor));
|
||||
if (cursor)
|
||||
{
|
||||
if (cursor->is_open())
|
||||
{
|
||||
cursor->close(FALSE);
|
||||
cleanup_items(free_list);
|
||||
thd->rollback_item_tree_changes();
|
||||
free_root(cursor->mem_root, MYF(0));
|
||||
}
|
||||
cursor->Cursor::~Cursor();
|
||||
}
|
||||
delete cursor;
|
||||
/*
|
||||
We have to call free on the items even if cleanup is called as some items,
|
||||
like Item_param, don't free everything until free_items()
|
||||
|
@ -2612,25 +2652,18 @@ Query_arena::Type Prepared_statement::type() const
|
|||
}
|
||||
|
||||
|
||||
void Prepared_statement::close_cursor()
|
||||
void Prepared_statement::cleanup_stmt()
|
||||
{
|
||||
DBUG_ENTER("Prepared_statement::close_cursor");
|
||||
DBUG_ENTER("Prepared_statement::cleanup_stmt");
|
||||
DBUG_PRINT("enter",("stmt: %p", this));
|
||||
|
||||
if (cursor && cursor->is_open())
|
||||
{
|
||||
thd->change_list= cursor->change_list;
|
||||
cursor->close(FALSE);
|
||||
cleanup_stmt_and_thd_after_use(this, thd);
|
||||
free_root(cursor->mem_root, MYF(0));
|
||||
if (cursor->close_at_commit)
|
||||
thd->stmt_map.erase_transient_cursor(this);
|
||||
}
|
||||
/*
|
||||
Clear parameters from data which could be set by
|
||||
mysql_stmt_send_long_data() call.
|
||||
*/
|
||||
reset_stmt_params(this);
|
||||
/* The order is important */
|
||||
lex->unit.cleanup();
|
||||
cleanup_items(free_list);
|
||||
thd->cleanup_after_query();
|
||||
close_thread_tables(thd);
|
||||
thd->rollback_item_tree_changes();
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
@ -2734,14 +2767,13 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
|||
if (rc == 0)
|
||||
rc= check_prepared_statement(this, name.str != 0);
|
||||
|
||||
if (rc && thd->lex->sphead)
|
||||
if (rc && lex->sphead)
|
||||
{
|
||||
delete thd->lex->sphead;
|
||||
thd->lex->sphead= NULL;
|
||||
delete lex->sphead;
|
||||
lex->sphead= NULL;
|
||||
}
|
||||
lex_end(lex);
|
||||
close_thread_tables(thd);
|
||||
cleanup_stmt_and_thd_after_use(this, thd);
|
||||
cleanup_stmt();
|
||||
thd->restore_backup_statement(this, &stmt_backup);
|
||||
thd->stmt_arena= old_stmt_arena;
|
||||
|
||||
|
@ -2781,7 +2813,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
|||
Statement stmt_backup;
|
||||
Query_arena *old_stmt_arena;
|
||||
Item *old_free_list;
|
||||
bool rc= 1;
|
||||
bool rc= TRUE;
|
||||
|
||||
statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status);
|
||||
|
||||
|
@ -2789,18 +2821,35 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
|||
if (state == Query_arena::ERROR)
|
||||
{
|
||||
my_message(last_errno, last_error, MYF(0));
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
if (flags & IS_IN_USE)
|
||||
{
|
||||
my_error(ER_PS_NO_RECURSION, MYF(0));
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
For SHOW VARIABLES lex->result is NULL, as it's a non-SELECT
|
||||
command. For such queries we don't return an error and don't
|
||||
open a cursor -- the client library will recognize this case and
|
||||
materialize the result set.
|
||||
For SELECT statements lex->result is created in
|
||||
check_prepared_statement. lex->result->simple_select() is FALSE
|
||||
in INSERT ... SELECT and similar commands.
|
||||
*/
|
||||
|
||||
if (open_cursor && lex->result && !lex->result->simple_select())
|
||||
{
|
||||
DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
|
||||
my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* In case the command has a call to SP which re-uses this statement name */
|
||||
flags|= IS_IN_USE;
|
||||
|
||||
if (cursor && cursor->is_open())
|
||||
close_cursor();
|
||||
close_cursor();
|
||||
|
||||
/*
|
||||
If the free_list is not empty, we'll wrongly free some externally
|
||||
|
@ -2808,32 +2857,6 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
|||
*/
|
||||
DBUG_ASSERT(thd->change_list.is_empty());
|
||||
DBUG_ASSERT(thd->free_list == NULL);
|
||||
if (open_cursor)
|
||||
{
|
||||
if (!lex->result || !lex->result->simple_select())
|
||||
{
|
||||
DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
|
||||
/*
|
||||
If lex->result is set in the parser, this is not a SELECT
|
||||
statement: we can't open a cursor for it.
|
||||
*/
|
||||
my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
|
||||
goto error;
|
||||
}
|
||||
|
||||
DBUG_PRINT("info",("Using READ_ONLY cursor"));
|
||||
if (!cursor && !(cursor= new (mem_root) Cursor(thd)))
|
||||
goto error;
|
||||
/* If lex->result is set, mysql_execute_command will use it */
|
||||
lex->result= &cursor->result;
|
||||
protocol= &cursor->protocol;
|
||||
thd->lock_id= &cursor->lock_id;
|
||||
/*
|
||||
Currently cursors can be used only from C API, so
|
||||
we don't have to create an own memory root for them:
|
||||
the one in THD is clean and can be used.
|
||||
*/
|
||||
}
|
||||
thd->set_n_backup_statement(this, &stmt_backup);
|
||||
if (expanded_query->length() &&
|
||||
alloc_query(thd, (char*) expanded_query->ptr(),
|
||||
|
@ -2862,38 +2885,27 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
|||
reinit_stmt_before_use(thd, lex);
|
||||
|
||||
thd->protocol= protocol; /* activate stmt protocol */
|
||||
mysql_execute_command(thd);
|
||||
rc= open_cursor ? mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
|
||||
&result, &cursor) :
|
||||
mysql_execute_command(thd);
|
||||
thd->protocol= &thd->protocol_simple; /* use normal protocol */
|
||||
|
||||
if (cursor && cursor->is_open())
|
||||
{
|
||||
/*
|
||||
It's safer if we grab THD state after mysql_execute_command is
|
||||
finished and not in Cursor::open(), because currently the call to
|
||||
Cursor::open is buried deep in JOIN::exec of the top level join.
|
||||
*/
|
||||
cursor->init_from_thd(thd);
|
||||
/* Assert that if an error, no cursor is open */
|
||||
DBUG_ASSERT(! (rc && cursor));
|
||||
|
||||
if (cursor->close_at_commit)
|
||||
thd->stmt_map.add_transient_cursor(this);
|
||||
}
|
||||
else
|
||||
if (! cursor)
|
||||
{
|
||||
close_thread_tables(thd);
|
||||
cleanup_stmt_and_thd_after_use(this, thd);
|
||||
cleanup_stmt();
|
||||
reset_stmt_params(this);
|
||||
}
|
||||
|
||||
thd->set_statement(&stmt_backup);
|
||||
thd->lock_id= &thd->main_lock_id;
|
||||
thd->stmt_arena= old_stmt_arena;
|
||||
|
||||
if (state == Query_arena::PREPARED)
|
||||
state= Query_arena::EXECUTED;
|
||||
|
||||
rc= 0;
|
||||
error:
|
||||
thd->lock_id= &thd->main_lock_id;
|
||||
flags&= ~IS_IN_USE;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "mysql_priv.h"
|
||||
#include "sql_select.h"
|
||||
#include "sql_cursor.h"
|
||||
|
||||
#include <m_ctype.h>
|
||||
#include <hash.h>
|
||||
|
@ -107,20 +108,15 @@ static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
|
|||
static bool open_tmp_table(TABLE *table);
|
||||
static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
|
||||
ulong options);
|
||||
static Next_select_func setup_end_select_func(JOIN *join);
|
||||
static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table,
|
||||
Procedure *proc);
|
||||
|
||||
static enum_nested_loop_state
|
||||
sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
||||
static enum_nested_loop_state
|
||||
evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
|
||||
int error, my_bool *report_error);
|
||||
static enum_nested_loop_state
|
||||
evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab);
|
||||
static enum_nested_loop_state
|
||||
sub_select(JOIN *join,JOIN_TAB *join_tab, bool end_of_records);
|
||||
static enum_nested_loop_state
|
||||
flush_cached_records(JOIN *join, JOIN_TAB *join_tab, bool skip_last);
|
||||
static enum_nested_loop_state
|
||||
end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
|
||||
|
@ -1716,262 +1712,6 @@ JOIN::destroy()
|
|||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
/************************* Cursor ******************************************/
|
||||
|
||||
Cursor::Cursor(THD *thd)
|
||||
:Query_arena(&main_mem_root, INITIALIZED),
|
||||
join(0), unit(0),
|
||||
protocol(thd),
|
||||
close_at_commit(FALSE)
|
||||
{
|
||||
/* We will overwrite it at open anyway. */
|
||||
init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
|
||||
thr_lock_owner_init(&lock_id, &thd->lock_info);
|
||||
bzero((void*) ht_info, sizeof(ht_info));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Cursor::init_from_thd(THD *thd)
|
||||
{
|
||||
Engine_info *info;
|
||||
/*
|
||||
We need to save and reset thd->mem_root, otherwise it'll be freed
|
||||
later in mysql_parse.
|
||||
|
||||
We can't just change the thd->mem_root here as we want to keep the
|
||||
things that are already allocated in thd->mem_root for Cursor::fetch()
|
||||
*/
|
||||
main_mem_root= *thd->mem_root;
|
||||
state= thd->stmt_arena->state;
|
||||
/* Allocate new memory root for thd */
|
||||
init_sql_alloc(thd->mem_root,
|
||||
thd->variables.query_alloc_block_size,
|
||||
thd->variables.query_prealloc_size);
|
||||
|
||||
/*
|
||||
The same is true for open tables and lock: save tables and zero THD
|
||||
pointers to prevent table close in close_thread_tables (This is a part
|
||||
of the temporary solution to make cursors work with minimal changes to
|
||||
the current source base).
|
||||
*/
|
||||
derived_tables= thd->derived_tables;
|
||||
open_tables= thd->open_tables;
|
||||
lock= thd->lock;
|
||||
query_id= thd->query_id;
|
||||
free_list= thd->free_list;
|
||||
change_list= thd->change_list;
|
||||
reset_thd(thd);
|
||||
/* Now we have an active cursor and can cause a deadlock */
|
||||
thd->lock_info.n_cursors++;
|
||||
|
||||
close_at_commit= FALSE; /* reset in case we're reusing the cursor */
|
||||
info= &ht_info[0];
|
||||
for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++)
|
||||
{
|
||||
const handlerton *ht= *pht;
|
||||
close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT);
|
||||
if (ht->create_cursor_read_view)
|
||||
{
|
||||
info->ht= ht;
|
||||
info->read_view= (ht->create_cursor_read_view)();
|
||||
++info;
|
||||
}
|
||||
}
|
||||
/*
|
||||
XXX: thd->locked_tables is not changed.
|
||||
What problems can we have with it if cursor is open?
|
||||
TODO: must be fixed because of the prelocked mode.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Cursor::reset_thd(THD *thd)
|
||||
{
|
||||
thd->derived_tables= 0;
|
||||
thd->open_tables= 0;
|
||||
thd->lock= 0;
|
||||
thd->free_list= 0;
|
||||
thd->change_list.empty();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Cursor::open(JOIN *join_arg)
|
||||
{
|
||||
join= join_arg;
|
||||
THD *thd= join->thd;
|
||||
/* First non-constant table */
|
||||
JOIN_TAB *join_tab= join->join_tab + join->const_tables;
|
||||
DBUG_ENTER("Cursor::open");
|
||||
|
||||
/*
|
||||
Send fields description to the client; server_status is sent
|
||||
in 'EOF' packet, which ends send_fields().
|
||||
*/
|
||||
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
|
||||
join->result->send_fields(*join->fields, Protocol::SEND_NUM_ROWS);
|
||||
::send_eof(thd);
|
||||
thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
|
||||
|
||||
/* Prepare JOIN for reading rows. */
|
||||
join->tmp_table= 0;
|
||||
join->join_tab[join->tables-1].next_select= setup_end_select_func(join);
|
||||
join->send_records= 0;
|
||||
join->fetch_limit= join->unit->offset_limit_cnt;
|
||||
|
||||
/* Disable JOIN CACHE as it is not working with cursors yet */
|
||||
for (JOIN_TAB *tab= join_tab;
|
||||
tab != join->join_tab + join->tables - 1;
|
||||
tab++)
|
||||
{
|
||||
if (tab->next_select == sub_select_cache)
|
||||
tab->next_select= sub_select;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(join_tab->table->reginfo.not_exists_optimize == 0);
|
||||
DBUG_ASSERT(join_tab->not_used_in_distinct == 0);
|
||||
/*
|
||||
null_row is set only if row not found and it's outer join: should never
|
||||
happen for the first table in join_tab list
|
||||
*/
|
||||
DBUG_ASSERT(join_tab->table->null_row == 0);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
Fetch next num_rows rows from the cursor and sent them to the client
|
||||
PRECONDITION:
|
||||
Cursor is open
|
||||
RETURN VALUES:
|
||||
none, this function will send error or OK to network if necessary.
|
||||
*/
|
||||
|
||||
void
|
||||
Cursor::fetch(ulong num_rows)
|
||||
{
|
||||
THD *thd= join->thd;
|
||||
JOIN_TAB *join_tab= join->join_tab + join->const_tables;
|
||||
enum_nested_loop_state error= NESTED_LOOP_OK;
|
||||
Query_arena backup_arena;
|
||||
Engine_info *info;
|
||||
DBUG_ENTER("Cursor::fetch");
|
||||
DBUG_PRINT("enter",("rows: %lu", num_rows));
|
||||
|
||||
DBUG_ASSERT(thd->derived_tables == 0 && thd->open_tables == 0 &&
|
||||
thd->lock == 0);
|
||||
|
||||
thd->derived_tables= derived_tables;
|
||||
thd->open_tables= open_tables;
|
||||
thd->lock= lock;
|
||||
thd->query_id= query_id;
|
||||
thd->change_list= change_list;
|
||||
/* save references to memory, allocated during fetch */
|
||||
thd->set_n_backup_active_arena(this, &backup_arena);
|
||||
|
||||
for (info= ht_info; info->read_view ; info++)
|
||||
(info->ht->set_cursor_read_view)(info->read_view);
|
||||
|
||||
join->fetch_limit+= num_rows;
|
||||
|
||||
error= sub_select(join, join_tab, 0);
|
||||
if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS)
|
||||
error= sub_select(join,join_tab,1);
|
||||
if (error == NESTED_LOOP_QUERY_LIMIT)
|
||||
error= NESTED_LOOP_OK; /* select_limit used */
|
||||
if (error == NESTED_LOOP_CURSOR_LIMIT)
|
||||
join->resume_nested_loop= TRUE;
|
||||
|
||||
#ifdef USING_TRANSACTIONS
|
||||
ha_release_temporary_latches(thd);
|
||||
#endif
|
||||
/* Grab free_list here to correctly free it in close */
|
||||
thd->restore_active_arena(this, &backup_arena);
|
||||
|
||||
for (info= ht_info; info->read_view; info++)
|
||||
(info->ht->set_cursor_read_view)(0);
|
||||
|
||||
if (error == NESTED_LOOP_CURSOR_LIMIT)
|
||||
{
|
||||
/* Fetch limit worked, possibly more rows are there */
|
||||
thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
|
||||
::send_eof(thd);
|
||||
thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
|
||||
change_list= thd->change_list;
|
||||
reset_thd(thd);
|
||||
}
|
||||
else
|
||||
{
|
||||
close(TRUE);
|
||||
if (error == NESTED_LOOP_OK)
|
||||
{
|
||||
thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
|
||||
::send_eof(thd);
|
||||
thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT;
|
||||
}
|
||||
else if (error != NESTED_LOOP_KILLED)
|
||||
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Cursor::close(bool is_active)
|
||||
{
|
||||
THD *thd= join->thd;
|
||||
DBUG_ENTER("Cursor::close");
|
||||
|
||||
/*
|
||||
In case of UNIONs JOIN is freed inside of unit->cleanup(),
|
||||
otherwise in select_lex->cleanup().
|
||||
*/
|
||||
if (unit)
|
||||
(void) unit->cleanup();
|
||||
else
|
||||
(void) join->select_lex->cleanup();
|
||||
|
||||
for (Engine_info *info= ht_info; info->read_view; info++)
|
||||
{
|
||||
(info->ht->close_cursor_read_view)(info->read_view);
|
||||
info->read_view= 0;
|
||||
info->ht= 0;
|
||||
}
|
||||
|
||||
if (is_active)
|
||||
close_thread_tables(thd);
|
||||
else
|
||||
{
|
||||
/* XXX: Another hack: closing tables used in the cursor */
|
||||
DBUG_ASSERT(lock || open_tables || derived_tables);
|
||||
|
||||
TABLE *tmp_derived_tables= thd->derived_tables;
|
||||
MYSQL_LOCK *tmp_lock= thd->lock;
|
||||
|
||||
thd->open_tables= open_tables;
|
||||
thd->derived_tables= derived_tables;
|
||||
thd->lock= lock;
|
||||
close_thread_tables(thd);
|
||||
|
||||
thd->open_tables= tmp_derived_tables;
|
||||
thd->derived_tables= tmp_derived_tables;
|
||||
thd->lock= tmp_lock;
|
||||
}
|
||||
thd->lock_info.n_cursors--; /* Decrease the number of active cursors */
|
||||
join= 0;
|
||||
unit= 0;
|
||||
free_items();
|
||||
change_list.empty();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
/*
|
||||
An entry point to single-unit select (a select without UNION).
|
||||
|
||||
|
@ -2051,9 +1791,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
|
|||
}
|
||||
else
|
||||
{
|
||||
if (join->prepare(rref_pointer_array, tables, wild_num,
|
||||
conds, og_num, order, group, having, proc_param,
|
||||
select_lex, unit))
|
||||
if (err= join->prepare(rref_pointer_array, tables, wild_num,
|
||||
conds, og_num, order, group, having, proc_param,
|
||||
select_lex, unit))
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
|
@ -2068,9 +1808,9 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
|
|||
DBUG_RETURN(TRUE);
|
||||
thd->proc_info="init";
|
||||
thd->used_tables=0; // Updated by setup_fields
|
||||
if (join->prepare(rref_pointer_array, tables, wild_num,
|
||||
conds, og_num, order, group, having, proc_param,
|
||||
select_lex, unit))
|
||||
if (err= join->prepare(rref_pointer_array, tables, wild_num,
|
||||
conds, og_num, order, group, having, proc_param,
|
||||
select_lex, unit))
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
|
@ -2112,7 +1852,7 @@ err:
|
|||
if (free_join)
|
||||
{
|
||||
thd->proc_info="end";
|
||||
err= select_lex->cleanup();
|
||||
err|= select_lex->cleanup();
|
||||
DBUG_RETURN(err || thd->net.report_error);
|
||||
}
|
||||
DBUG_RETURN(join->error);
|
||||
|
@ -5976,7 +5716,7 @@ void JOIN::join_free(bool full)
|
|||
cleanup(full);
|
||||
|
||||
for (unit= select_lex->first_inner_unit(); unit; unit= unit->next_unit())
|
||||
for (sl= unit->first_select_in_union(); sl; sl= sl->next_select())
|
||||
for (sl= unit->first_select(); sl; sl= sl->next_select())
|
||||
{
|
||||
JOIN *join= sl->join;
|
||||
if (join)
|
||||
|
@ -8077,18 +7817,24 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
|
|||
if (field->maybe_null && !field->field->maybe_null())
|
||||
{
|
||||
result= create_tmp_field_from_item(thd, item, table, NULL,
|
||||
modify_item, convert_blob_length);
|
||||
modify_item, convert_blob_length);
|
||||
*from_field= field->field;
|
||||
if (result && modify_item)
|
||||
((Item_field*)item)->result_field= result;
|
||||
field->result_field= result;
|
||||
}
|
||||
else if (table_cant_handle_bit_fields && field->field->type() == FIELD_TYPE_BIT)
|
||||
else if (table_cant_handle_bit_fields && field->field->type() ==
|
||||
FIELD_TYPE_BIT)
|
||||
{
|
||||
*from_field= field->field;
|
||||
result= create_tmp_field_from_item(thd, item, table, copy_func,
|
||||
modify_item, convert_blob_length);
|
||||
if (result && modify_item)
|
||||
field->result_field= result;
|
||||
}
|
||||
else
|
||||
result= create_tmp_field_from_field(thd, (*from_field= field->field),
|
||||
item->name, table,
|
||||
modify_item ? (Item_field*) item :
|
||||
modify_item ? field :
|
||||
NULL,
|
||||
convert_blob_length);
|
||||
if (orig_type == Item::REF_ITEM && orig_modify)
|
||||
|
@ -8122,9 +7868,31 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
|
|||
|
||||
/*
|
||||
Create a temp table according to a field list.
|
||||
Set distinct if duplicates could be removed
|
||||
Given fields field pointers are changed to point at tmp_table
|
||||
for send_fields
|
||||
|
||||
SYNOPSIS
|
||||
create_tmp_table()
|
||||
thd thread handle
|
||||
param a description used as input to create the table
|
||||
fields list of items that will be used to define
|
||||
column types of the table (also see NOTES)
|
||||
group TODO document
|
||||
distinct should table rows be distinct
|
||||
save_sum_fields see NOTES
|
||||
select_options
|
||||
rows_limit
|
||||
table_alias possible name of the temporary table that can be used
|
||||
for name resolving; can be "".
|
||||
|
||||
DESCRIPTION
|
||||
Given field pointers are changed to point at tmp_table for
|
||||
send_fields. The table object is self contained: it's
|
||||
allocated in its own memory root, as well as Field objects
|
||||
created for table columns.
|
||||
This function will replace Item_sum items in 'fields' list with
|
||||
corresponding Item_field items, pointing at the fields in the
|
||||
temporary table, unless this was prohibited by TRUE
|
||||
value of argument save_sum_fields. The Item_field objects
|
||||
are created in THD memory root.
|
||||
*/
|
||||
|
||||
#define STRING_TOTAL_LENGTH_TO_PACK_ROWS 128
|
||||
|
@ -8138,6 +7906,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
ulonglong select_options, ha_rows rows_limit,
|
||||
char *table_alias)
|
||||
{
|
||||
MEM_ROOT *mem_root_save, own_root;
|
||||
TABLE *table;
|
||||
uint i,field_count,null_count,null_pack_length;
|
||||
uint hidden_null_count, hidden_null_pack_length, hidden_field_count;
|
||||
|
@ -8202,29 +7971,33 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
|
||||
field_count=param->field_count+param->func_count+param->sum_func_count;
|
||||
hidden_field_count=param->hidden_field_count;
|
||||
if (!my_multi_malloc(MYF(MY_WME),
|
||||
&table,sizeof(*table),
|
||||
®_field, sizeof(Field*)*(field_count+1),
|
||||
&blob_field, sizeof(uint)*(field_count+1),
|
||||
&from_field, sizeof(Field*)*field_count,
|
||||
©_func,sizeof(*copy_func)*(param->func_count+1),
|
||||
¶m->keyinfo,sizeof(*param->keyinfo),
|
||||
&key_part_info,
|
||||
sizeof(*key_part_info)*(param->group_parts+1),
|
||||
¶m->start_recinfo,
|
||||
sizeof(*param->recinfo)*(field_count*2+4),
|
||||
&tmpname,(uint) strlen(path)+1,
|
||||
&group_buff,group && ! using_unique_constraint ?
|
||||
param->group_length : 0,
|
||||
NullS))
|
||||
|
||||
init_sql_alloc(&own_root, TABLE_ALLOC_BLOCK_SIZE, 0);
|
||||
|
||||
if (!multi_alloc_root(&own_root,
|
||||
&table, sizeof(*table),
|
||||
®_field, sizeof(Field*) * (field_count+1),
|
||||
&blob_field, sizeof(uint)*(field_count+1),
|
||||
&from_field, sizeof(Field*)*field_count,
|
||||
©_func, sizeof(*copy_func)*(param->func_count+1),
|
||||
¶m->keyinfo, sizeof(*param->keyinfo),
|
||||
&key_part_info,
|
||||
sizeof(*key_part_info)*(param->group_parts+1),
|
||||
¶m->start_recinfo,
|
||||
sizeof(*param->recinfo)*(field_count*2+4),
|
||||
&tmpname, (uint) strlen(path)+1,
|
||||
&group_buff, group && ! using_unique_constraint ?
|
||||
param->group_length : 0,
|
||||
NullS))
|
||||
{
|
||||
bitmap_clear_bit(&temp_pool, temp_pool_slot);
|
||||
DBUG_RETURN(NULL); /* purecov: inspected */
|
||||
}
|
||||
if (!(param->copy_field=copy=new Copy_field[field_count]))
|
||||
/* Copy_field belongs to TMP_TABLE_PARAM, allocate it in THD mem_root */
|
||||
if (!(param->copy_field= copy= new (thd->mem_root) Copy_field[field_count]))
|
||||
{
|
||||
bitmap_clear_bit(&temp_pool, temp_pool_slot);
|
||||
my_free((gptr) table,MYF(0)); /* purecov: inspected */
|
||||
free_root(&own_root, MYF(0)); /* purecov: inspected */
|
||||
DBUG_RETURN(NULL); /* purecov: inspected */
|
||||
}
|
||||
param->items_to_copy= copy_func;
|
||||
|
@ -8234,6 +8007,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
bzero((char*) table,sizeof(*table));
|
||||
bzero((char*) reg_field,sizeof(Field*)*(field_count+1));
|
||||
bzero((char*) from_field,sizeof(Field*)*field_count);
|
||||
|
||||
table->mem_root= own_root;
|
||||
mem_root_save= thd->mem_root;
|
||||
thd->mem_root= &table->mem_root;
|
||||
|
||||
table->field=reg_field;
|
||||
table->alias= table_alias;
|
||||
table->reginfo.lock_type=TL_WRITE; /* Will be updated */
|
||||
|
@ -8299,7 +8077,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
Field *new_field=
|
||||
create_tmp_field(thd, table, arg, arg->type(), ©_func,
|
||||
tmp_from_field, group != 0,not_all_columns,
|
||||
group || distinct,
|
||||
distinct,
|
||||
param->convert_blob_length);
|
||||
if (!new_field)
|
||||
goto err; // Should be OOM
|
||||
|
@ -8310,6 +8088,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
*blob_field++= (uint) (reg_field - table->field);
|
||||
blob_count++;
|
||||
}
|
||||
if (new_field->type() == FIELD_TYPE_BIT)
|
||||
total_uneven_bit_length+= new_field->field_length & 7;
|
||||
new_field->field_index= (uint) (reg_field - table->field);
|
||||
*(reg_field++)= new_field;
|
||||
if (new_field->real_type() == MYSQL_TYPE_STRING ||
|
||||
|
@ -8318,7 +8098,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
string_count++;
|
||||
string_total_length+= new_field->pack_length();
|
||||
}
|
||||
thd->mem_root= mem_root_save;
|
||||
thd->change_item_tree(argp, new Item_field(new_field));
|
||||
thd->mem_root= &table->mem_root;
|
||||
if (!(new_field->flags & NOT_NULL_FLAG))
|
||||
{
|
||||
null_count++;
|
||||
|
@ -8343,12 +8125,16 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
write rows to the temporary table.
|
||||
We here distinguish between UNION and multi-table-updates by the fact
|
||||
that in the later case group is set to the row pointer.
|
||||
|
||||
The test for item->marker == 4 is ensure we don't create a group-by
|
||||
key over a bit field as heap tables can't handle that.
|
||||
*/
|
||||
Field *new_field= (param->schema_table) ?
|
||||
create_tmp_field_for_schema(thd, item, table) :
|
||||
create_tmp_field(thd, table, item, type, ©_func,
|
||||
tmp_from_field, group != 0,
|
||||
not_all_columns || group != 0, 0,
|
||||
not_all_columns || group != 0,
|
||||
item->marker == 4,
|
||||
param->convert_blob_length);
|
||||
|
||||
if (!new_field)
|
||||
|
@ -8380,7 +8166,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
*(reg_field++) =new_field;
|
||||
}
|
||||
if (!--hidden_field_count)
|
||||
{
|
||||
/*
|
||||
This was the last hidden field; Remember how many hidden fields could
|
||||
have null
|
||||
*/
|
||||
hidden_null_count=null_count;
|
||||
null_count= 0;
|
||||
}
|
||||
}
|
||||
DBUG_ASSERT(field_count >= (uint) (reg_field - table->field));
|
||||
field_count= (uint) (reg_field - table->field);
|
||||
|
@ -8415,8 +8208,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
null_count++;
|
||||
}
|
||||
hidden_null_pack_length=(hidden_null_count+7)/8;
|
||||
null_pack_length= hidden_null_count +
|
||||
(null_count + total_uneven_bit_length + 7) / 8;
|
||||
null_pack_length= (hidden_null_pack_length +
|
||||
(null_count + total_uneven_bit_length + 7) / 8);
|
||||
reclength+=null_pack_length;
|
||||
if (!reclength)
|
||||
reclength=1; // Dummy select
|
||||
|
@ -8432,7 +8225,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
{
|
||||
uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1);
|
||||
table->s->rec_buff_length= alloc_length;
|
||||
if (!(table->record[0]= (byte *) my_malloc(alloc_length*3, MYF(MY_WME))))
|
||||
if (!(table->record[0]= (byte*)
|
||||
alloc_root(&table->mem_root, alloc_length*3)))
|
||||
goto err;
|
||||
table->record[1]= table->record[0]+alloc_length;
|
||||
table->s->default_values= table->record[1]+alloc_length;
|
||||
|
@ -8618,8 +8412,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
table->s->uniques= 1;
|
||||
}
|
||||
if (!(key_part_info= (KEY_PART_INFO*)
|
||||
sql_calloc((keyinfo->key_parts)*sizeof(KEY_PART_INFO))))
|
||||
alloc_root(&table->mem_root,
|
||||
keyinfo->key_parts * sizeof(KEY_PART_INFO))))
|
||||
goto err;
|
||||
bzero((void*) key_part_info, keyinfo->key_parts * sizeof(KEY_PART_INFO));
|
||||
table->key_info=keyinfo;
|
||||
keyinfo->key_part=key_part_info;
|
||||
keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL;
|
||||
|
@ -8667,10 +8463,15 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||
if (create_myisam_tmp_table(table,param,select_options))
|
||||
goto err;
|
||||
}
|
||||
if (!open_tmp_table(table))
|
||||
DBUG_RETURN(table);
|
||||
if (open_tmp_table(table))
|
||||
goto err;
|
||||
|
||||
err:
|
||||
thd->mem_root= mem_root_save;
|
||||
|
||||
DBUG_RETURN(table);
|
||||
|
||||
err:
|
||||
thd->mem_root= mem_root_save;
|
||||
free_tmp_table(thd,table); /* purecov: inspected */
|
||||
bitmap_clear_bit(&temp_pool, temp_pool_slot);
|
||||
DBUG_RETURN(NULL); /* purecov: inspected */
|
||||
|
@ -8815,11 +8616,12 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
|
|||
if (table->s->keys)
|
||||
{ // Get keys for ni_create
|
||||
bool using_unique_constraint=0;
|
||||
HA_KEYSEG *seg= (HA_KEYSEG*) sql_calloc(sizeof(*seg) *
|
||||
keyinfo->key_parts);
|
||||
HA_KEYSEG *seg= (HA_KEYSEG*) alloc_root(&table->mem_root,
|
||||
sizeof(*seg) * keyinfo->key_parts);
|
||||
if (!seg)
|
||||
goto err;
|
||||
|
||||
bzero(seg, sizeof(*seg) * keyinfo->key_parts);
|
||||
if (keyinfo->key_length >= table->file->max_key_length() ||
|
||||
keyinfo->key_parts > table->file->max_key_parts() ||
|
||||
table->s->uniques)
|
||||
|
@ -8916,13 +8718,14 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
|
|||
void
|
||||
free_tmp_table(THD *thd, TABLE *entry)
|
||||
{
|
||||
MEM_ROOT own_root= entry->mem_root;
|
||||
const char *save_proc_info;
|
||||
DBUG_ENTER("free_tmp_table");
|
||||
DBUG_PRINT("enter",("table: %s",entry->alias));
|
||||
|
||||
save_proc_info=thd->proc_info;
|
||||
thd->proc_info="removing tmp table";
|
||||
free_blobs(entry);
|
||||
|
||||
if (entry->file)
|
||||
{
|
||||
if (entry->db_stat)
|
||||
|
@ -8943,12 +8746,11 @@ free_tmp_table(THD *thd, TABLE *entry)
|
|||
/* free blobs */
|
||||
for (Field **ptr=entry->field ; *ptr ; ptr++)
|
||||
(*ptr)->free();
|
||||
my_free((gptr) entry->record[0],MYF(0));
|
||||
free_io_cache(entry);
|
||||
|
||||
bitmap_clear_bit(&temp_pool, entry->temp_pool_slot);
|
||||
|
||||
my_free((gptr) entry,MYF(0));
|
||||
free_root(&own_root, MYF(0)); /* the table is allocated in its own root */
|
||||
thd->proc_info=save_proc_info;
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
|
@ -9063,7 +8865,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
|
|||
end_select function to use. This function can't fail.
|
||||
*/
|
||||
|
||||
static Next_select_func setup_end_select_func(JOIN *join)
|
||||
Next_select_func setup_end_select_func(JOIN *join)
|
||||
{
|
||||
TABLE *table= join->tmp_table;
|
||||
Next_select_func end_select;
|
||||
|
@ -9218,7 +9020,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
|
|||
}
|
||||
|
||||
|
||||
static enum_nested_loop_state
|
||||
enum_nested_loop_state
|
||||
sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
|
||||
{
|
||||
enum_nested_loop_state rc;
|
||||
|
@ -9359,7 +9161,7 @@ sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
|
|||
return one of enum_nested_loop_state, except NESTED_LOOP_NO_MORE_ROWS.
|
||||
*/
|
||||
|
||||
static enum_nested_loop_state
|
||||
enum_nested_loop_state
|
||||
sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
|
||||
{
|
||||
join_tab->table->null_row=0;
|
||||
|
@ -12378,6 +12180,11 @@ calc_group_buffer(JOIN *join,ORDER *group)
|
|||
key_length+=MAX_BLOB_WIDTH; // Can't be used as a key
|
||||
else if (field->type() == MYSQL_TYPE_VARCHAR)
|
||||
key_length+= field->field_length + HA_KEY_BLOB_LENGTH;
|
||||
else if (field->type() == FIELD_TYPE_BIT)
|
||||
{
|
||||
/* Bit is usually stored as a longlong key for group fields */
|
||||
key_length+= 8; // Big enough
|
||||
}
|
||||
else
|
||||
key_length+= field->pack_length();
|
||||
}
|
||||
|
@ -13782,8 +13589,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
|
|||
unit->fake_select_lex->select_number= UINT_MAX; // jost for initialization
|
||||
unit->fake_select_lex->type= "UNION RESULT";
|
||||
unit->fake_select_lex->options|= SELECT_DESCRIBE;
|
||||
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE,
|
||||
"")))
|
||||
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
|
||||
res= unit->exec();
|
||||
res|= unit->cleanup();
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ enum enum_nested_loop_state
|
|||
typedef enum_nested_loop_state
|
||||
(*Next_select_func)(JOIN *, struct st_join_table *, bool);
|
||||
typedef int (*Read_record_func)(struct st_join_table *tab);
|
||||
|
||||
Next_select_func setup_end_select_func(JOIN *join);
|
||||
|
||||
typedef struct st_join_table {
|
||||
TABLE *table;
|
||||
|
@ -140,6 +140,11 @@ typedef struct st_join_table {
|
|||
void cleanup();
|
||||
} JOIN_TAB;
|
||||
|
||||
enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool
|
||||
end_of_records);
|
||||
enum_nested_loop_state sub_select(JOIN *join,JOIN_TAB *join_tab, bool
|
||||
end_of_records);
|
||||
|
||||
|
||||
typedef struct st_position /* Used in find_best */
|
||||
{
|
||||
|
@ -372,58 +377,6 @@ class JOIN :public Sql_alloc
|
|||
};
|
||||
|
||||
|
||||
/*
|
||||
Server-side cursor (now stands only for basic read-only cursor)
|
||||
See class implementation in sql_select.cc
|
||||
A cursor has its own runtime state - list of used items and memory root of
|
||||
used memory - which is different from Prepared statement runtime: it must
|
||||
be different at least for the purpose of reusing the same prepared
|
||||
statement for many cursors.
|
||||
*/
|
||||
|
||||
class Cursor: public Sql_alloc, public Query_arena
|
||||
{
|
||||
MEM_ROOT main_mem_root;
|
||||
JOIN *join;
|
||||
SELECT_LEX_UNIT *unit;
|
||||
|
||||
TABLE *open_tables;
|
||||
MYSQL_LOCK *lock;
|
||||
TABLE *derived_tables;
|
||||
/* List of items created during execution */
|
||||
query_id_t query_id;
|
||||
struct Engine_info
|
||||
{
|
||||
const handlerton *ht;
|
||||
void *read_view;
|
||||
};
|
||||
Engine_info ht_info[MAX_HA];
|
||||
public:
|
||||
Protocol_prep protocol;
|
||||
Item_change_list change_list;
|
||||
select_send result;
|
||||
THR_LOCK_OWNER lock_id;
|
||||
my_bool close_at_commit;
|
||||
|
||||
/* Temporary implementation as now we replace THD state by value */
|
||||
/* Save THD state into cursor */
|
||||
void init_from_thd(THD *thd);
|
||||
/* bzero cursor state in THD */
|
||||
void reset_thd(THD *thd);
|
||||
|
||||
int open(JOIN *join);
|
||||
void fetch(ulong num_rows);
|
||||
void reset() { join= 0; }
|
||||
bool is_open() const { return join != 0; }
|
||||
|
||||
void close(bool is_active);
|
||||
|
||||
void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; }
|
||||
Cursor(THD *thd);
|
||||
~Cursor() {}
|
||||
};
|
||||
|
||||
|
||||
typedef struct st_select_check {
|
||||
uint const_ref,reg_ref;
|
||||
} SELECT_CHECK;
|
||||
|
|
|
@ -1205,7 +1205,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
|
|||
"%s:%u", tmp_sctx->host_or_ip, tmp->peer_port);
|
||||
}
|
||||
else
|
||||
thd_info->host= thd->strdup(tmp_sctx->host);
|
||||
thd_info->host= thd->strdup(tmp_sctx->host_or_ip);
|
||||
if ((thd_info->db=tmp->db)) // Safe test
|
||||
thd_info->db=thd->strdup(thd_info->db);
|
||||
thd_info->command=(int) tmp->command;
|
||||
|
|
176
sql/sql_union.cc
176
sql/sql_union.cc
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "mysql_priv.h"
|
||||
#include "sql_select.h"
|
||||
#include "sql_cursor.h"
|
||||
|
||||
bool mysql_union(THD *thd, LEX *lex, select_result *result,
|
||||
SELECT_LEX_UNIT *unit, ulong setup_tables_done_option)
|
||||
|
@ -30,13 +31,9 @@ bool mysql_union(THD *thd, LEX *lex, select_result *result,
|
|||
DBUG_ENTER("mysql_union");
|
||||
bool res;
|
||||
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK |
|
||||
setup_tables_done_option, "")))
|
||||
setup_tables_done_option)))
|
||||
res= unit->exec();
|
||||
if (!res && thd->cursor && thd->cursor->is_open())
|
||||
{
|
||||
thd->cursor->set_unit(unit);
|
||||
}
|
||||
else
|
||||
if (res || !thd->cursor || !thd->cursor->is_open())
|
||||
res|= unit->cleanup();
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
@ -46,16 +43,6 @@ bool mysql_union(THD *thd, LEX *lex, select_result *result,
|
|||
** store records in temporary table for UNION
|
||||
***************************************************************************/
|
||||
|
||||
select_union::select_union(TABLE *table_par)
|
||||
:table(table_par)
|
||||
{
|
||||
}
|
||||
|
||||
select_union::~select_union()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
|
||||
{
|
||||
unit= u;
|
||||
|
@ -103,6 +90,45 @@ bool select_union::flush()
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Create a temporary table to store the result of select_union.
|
||||
|
||||
SYNOPSIS
|
||||
select_union::create_result_table()
|
||||
thd thread handle
|
||||
column_types a list of items used to define columns of the
|
||||
temporary table
|
||||
is_union_distinct if set, the temporary table will eliminate
|
||||
duplicates on insert
|
||||
options create options
|
||||
|
||||
DESCRIPTION
|
||||
Create a temporary table that is used to store the result of a UNION,
|
||||
derived table, or a materialized cursor.
|
||||
|
||||
RETURN VALUE
|
||||
0 The table has been created successfully.
|
||||
1 create_tmp_table failed.
|
||||
*/
|
||||
|
||||
bool
|
||||
select_union::create_result_table(THD *thd, List<Item> *column_types,
|
||||
bool is_union_distinct, ulonglong options,
|
||||
const char *alias)
|
||||
{
|
||||
DBUG_ASSERT(table == 0);
|
||||
tmp_table_param.init();
|
||||
tmp_table_param.field_count= column_types->elements;
|
||||
|
||||
if (! (table= create_tmp_table(thd, &tmp_table_param, *column_types,
|
||||
(ORDER*) 0, is_union_distinct, 1,
|
||||
options, HA_POS_ERROR, (char*) alias)))
|
||||
return TRUE;
|
||||
table->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
initialization procedures before fake_select_lex preparation()
|
||||
|
@ -133,11 +159,10 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd)
|
|||
|
||||
|
||||
bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
|
||||
ulong additional_options,
|
||||
const char *tmp_table_alias)
|
||||
ulong additional_options)
|
||||
{
|
||||
SELECT_LEX *lex_select_save= thd_arg->lex->current_select;
|
||||
SELECT_LEX *sl, *first_select;
|
||||
SELECT_LEX *sl, *first_sl= first_select();
|
||||
select_result *tmp_result;
|
||||
bool is_union;
|
||||
TABLE *empty_table= 0;
|
||||
|
@ -156,7 +181,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
|
|||
if (describe)
|
||||
{
|
||||
/* fast reinit for EXPLAIN */
|
||||
for (sl= first_select_in_union(); sl; sl= sl->next_select())
|
||||
for (sl= first_sl; sl; sl= sl->next_select())
|
||||
{
|
||||
sl->join->result= result;
|
||||
select_limit_cnt= HA_POS_ERROR;
|
||||
|
@ -175,17 +200,16 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
|
|||
prepared= 1;
|
||||
res= FALSE;
|
||||
|
||||
thd_arg->lex->current_select= sl= first_select= first_select_in_union();
|
||||
found_rows_for_union= first_select->options & OPTION_FOUND_ROWS;
|
||||
is_union= test(first_select->next_select());
|
||||
thd_arg->lex->current_select= sl= first_sl;
|
||||
found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS;
|
||||
is_union= test(first_sl->next_select());
|
||||
|
||||
/* Global option */
|
||||
|
||||
if (is_union)
|
||||
{
|
||||
if (!(tmp_result= union_result= new select_union(0)))
|
||||
if (!(tmp_result= union_result= new select_union))
|
||||
goto err;
|
||||
union_result->tmp_table_param.init();
|
||||
if (describe)
|
||||
tmp_result= sel_result;
|
||||
}
|
||||
|
@ -238,8 +262,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
|
|||
information about fields lengths and exact types
|
||||
*/
|
||||
if (!is_union)
|
||||
types= first_select_in_union()->item_list;
|
||||
else if (sl == first_select)
|
||||
types= first_sl->item_list;
|
||||
else if (sl == first_sl)
|
||||
{
|
||||
/*
|
||||
We need to create an empty table object. It is used
|
||||
|
@ -287,7 +311,6 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
|
|||
all collations together for UNION.
|
||||
*/
|
||||
List_iterator_fast<Item> tp(types);
|
||||
Query_arena *arena= thd->stmt_arena;
|
||||
Item *type;
|
||||
ulonglong create_options;
|
||||
|
||||
|
@ -301,7 +324,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
|
|||
}
|
||||
}
|
||||
|
||||
create_options= (first_select_in_union()->options | thd_arg->options |
|
||||
create_options= (first_sl->options | thd_arg->options |
|
||||
TMP_TABLE_ALL_COLUMNS);
|
||||
/*
|
||||
Force the temporary table to be a MyISAM table if we're going to use
|
||||
|
@ -312,47 +335,35 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
|
|||
if (global_parameters->ftfunc_list->elements)
|
||||
create_options= create_options | TMP_TABLE_FORCE_MYISAM;
|
||||
|
||||
union_result->tmp_table_param.field_count= types.elements;
|
||||
if (!(table= create_tmp_table(thd_arg,
|
||||
&union_result->tmp_table_param, types,
|
||||
(ORDER*) 0, (bool) union_distinct, 1,
|
||||
create_options, HA_POS_ERROR,
|
||||
(char *) tmp_table_alias)))
|
||||
if (union_result->create_result_table(thd, &types, test(union_distinct),
|
||||
create_options, ""))
|
||||
goto err;
|
||||
table->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
|
||||
bzero((char*) &result_table_list, sizeof(result_table_list));
|
||||
result_table_list.db= (char*) "";
|
||||
result_table_list.table_name= result_table_list.alias= (char*) "union";
|
||||
result_table_list.table= table;
|
||||
union_result->set_table(table);
|
||||
result_table_list.table= table= union_result->table;
|
||||
|
||||
thd_arg->lex->current_select= lex_select_save;
|
||||
if (!item_list.elements)
|
||||
{
|
||||
Field **field;
|
||||
Query_arena *tmp_arena,backup;
|
||||
tmp_arena= thd->activate_stmt_arena_if_needed(&backup);
|
||||
Query_arena *arena, backup_arena;
|
||||
|
||||
for (field= table->field; *field; field++)
|
||||
arena= thd->activate_stmt_arena_if_needed(&backup_arena);
|
||||
|
||||
res= table->fill_item_list(&item_list);
|
||||
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup_arena);
|
||||
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
if (thd->stmt_arena->is_stmt_prepare())
|
||||
{
|
||||
Item_field *item= new Item_field(*field);
|
||||
if (!item || item_list.push_back(item))
|
||||
{
|
||||
if (tmp_arena)
|
||||
thd->restore_active_arena(tmp_arena, &backup);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
if (tmp_arena)
|
||||
thd->restore_active_arena(tmp_arena, &backup);
|
||||
if (arena->is_stmt_prepare_or_first_sp_execute())
|
||||
{
|
||||
/* prepare fake select to initialize it correctly */
|
||||
/* Validate the global parameters of this union */
|
||||
|
||||
init_prepare_fake_select_lex(thd);
|
||||
/*
|
||||
Should be done only once (the only item_list per statement).
|
||||
*/
|
||||
/* Should be done only once (the only item_list per statement) */
|
||||
DBUG_ASSERT(fake_select_lex->join == 0);
|
||||
if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options,
|
||||
result)))
|
||||
|
@ -375,19 +386,14 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
|
|||
fake_select_lex->table_list.empty();
|
||||
}
|
||||
}
|
||||
else if (!arena->is_conventional())
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(!thd->stmt_arena->is_conventional());
|
||||
/*
|
||||
We're in execution of a prepared statement or stored procedure:
|
||||
reset field items to point at fields from the created temporary table.
|
||||
*/
|
||||
List_iterator_fast<Item> it(item_list);
|
||||
for (Field **field= table->field; *field; field++)
|
||||
{
|
||||
Item_field *item_field= (Item_field*) it++;
|
||||
DBUG_ASSERT(item_field != 0);
|
||||
item_field->reset_field(*field);
|
||||
}
|
||||
table->reset_item_list(&item_list);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,7 +410,7 @@ err:
|
|||
bool st_select_lex_unit::exec()
|
||||
{
|
||||
SELECT_LEX *lex_select_save= thd->lex->current_select;
|
||||
SELECT_LEX *select_cursor=first_select_in_union();
|
||||
SELECT_LEX *select_cursor=first_select();
|
||||
ulonglong add_rows=0;
|
||||
ha_rows examined_rows= 0;
|
||||
DBUG_ENTER("st_select_lex_unit::exec");
|
||||
|
@ -595,7 +601,7 @@ bool st_select_lex_unit::cleanup()
|
|||
table= 0; // Safety
|
||||
}
|
||||
|
||||
for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
|
||||
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
|
||||
error|= sl->cleanup();
|
||||
|
||||
if (fake_select_lex)
|
||||
|
@ -652,7 +658,7 @@ bool st_select_lex_unit::change_result(select_subselect *result,
|
|||
select_subselect *old_result)
|
||||
{
|
||||
bool res= FALSE;
|
||||
for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
|
||||
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
|
||||
{
|
||||
if (sl->join && sl->join->result == old_result)
|
||||
if (sl->join->change_result(result))
|
||||
|
@ -663,6 +669,36 @@ bool st_select_lex_unit::change_result(select_subselect *result,
|
|||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
Get column type information for this unit.
|
||||
|
||||
SYNOPSIS
|
||||
st_select_lex_unit::get_unit_column_types()
|
||||
|
||||
DESCRIPTION
|
||||
For a single-select the column types are taken
|
||||
from the list of selected items. For a union this function
|
||||
assumes that st_select_lex_unit::prepare has been called
|
||||
and returns the type holders that were created for unioned
|
||||
column types of all selects.
|
||||
|
||||
NOTES
|
||||
The implementation of this function should be in sync with
|
||||
st_select_lex_unit::prepare()
|
||||
*/
|
||||
|
||||
List<Item> *st_select_lex_unit::get_unit_column_types()
|
||||
{
|
||||
bool is_union= test(first_select()->next_select());
|
||||
|
||||
if (is_union)
|
||||
{
|
||||
DBUG_ASSERT(prepared);
|
||||
/* Types are generated during prepare */
|
||||
return &types;
|
||||
}
|
||||
return &first_select()->item_list;
|
||||
}
|
||||
|
||||
bool st_select_lex::cleanup()
|
||||
{
|
||||
|
|
|
@ -380,7 +380,7 @@ bool mysql_create_view(THD *thd,
|
|||
|
||||
/* prepare select to resolve all fields */
|
||||
lex->view_prepare_mode= 1;
|
||||
if (unit->prepare(thd, 0, 0, view->view_name.str))
|
||||
if (unit->prepare(thd, 0, 0))
|
||||
{
|
||||
/*
|
||||
some errors from prepare are reported to user, if is not then
|
||||
|
|
59
sql/table.cc
59
sql/table.cc
|
@ -349,7 +349,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
|
|||
char *buff;
|
||||
if (!(buff= alloc_root(&outparam->mem_root, n_length)))
|
||||
goto err;
|
||||
if (my_pread(file, buff, n_length, record_offset + share->reclength,
|
||||
if (my_pread(file, (byte*)buff, n_length, record_offset + share->reclength,
|
||||
MYF(MY_NABP)))
|
||||
goto err;
|
||||
share->connect_string.length= uint2korr(buff);
|
||||
|
@ -1691,6 +1691,63 @@ db_type get_table_type(THD *thd, const char *name)
|
|||
DBUG_RETURN(ha_checktype(thd,(enum db_type) (uint) *(head+3),0,0));
|
||||
}
|
||||
|
||||
/*
|
||||
Create Item_field for each column in the table.
|
||||
|
||||
SYNPOSIS
|
||||
st_table::fill_item_list()
|
||||
item_list a pointer to an empty list used to store items
|
||||
|
||||
DESCRIPTION
|
||||
Create Item_field object for each column in the table and
|
||||
initialize it with the corresponding Field. New items are
|
||||
created in the current THD memory root.
|
||||
|
||||
RETURN VALUE
|
||||
0 success
|
||||
1 out of memory
|
||||
*/
|
||||
|
||||
bool st_table::fill_item_list(List<Item> *item_list) const
|
||||
{
|
||||
/*
|
||||
All Item_field's created using a direct pointer to a field
|
||||
are fixed in Item_field constructor.
|
||||
*/
|
||||
for (Field **ptr= field; *ptr; ptr++)
|
||||
{
|
||||
Item_field *item= new Item_field(*ptr);
|
||||
if (!item || item_list->push_back(item))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
Reset an existing list of Item_field items to point to the
|
||||
Fields of this table.
|
||||
|
||||
SYNPOSIS
|
||||
st_table::fill_item_list()
|
||||
item_list a non-empty list with Item_fields
|
||||
|
||||
DESCRIPTION
|
||||
This is a counterpart of fill_item_list used to redirect
|
||||
Item_fields to the fields of a newly created table.
|
||||
The caller must ensure that number of items in the item_list
|
||||
is the same as the number of columns in the table.
|
||||
*/
|
||||
|
||||
void st_table::reset_item_list(List<Item> *item_list) const
|
||||
{
|
||||
List_iterator_fast<Item> it(*item_list);
|
||||
for (Field **ptr= field; *ptr; ptr++)
|
||||
{
|
||||
Item_field *item_field= (Item_field*) it++;
|
||||
DBUG_ASSERT(item_field != 0);
|
||||
item_field->reset_field(*ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
calculate md5 of query
|
||||
|
|
|
@ -267,6 +267,9 @@ struct st_table {
|
|||
GRANT_INFO grant;
|
||||
FILESORT_INFO sort;
|
||||
TABLE_SHARE share_not_to_be_used; /* To be deleted when true shares */
|
||||
|
||||
bool fill_item_list(List<Item> *item_list) const;
|
||||
void reset_item_list(List<Item> *item_list) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -153,8 +153,8 @@ bool mysql_create_frm(THD *thd, my_string file_name,
|
|||
{
|
||||
char buff[2];
|
||||
int2store(buff,create_info->connect_string.length);
|
||||
if (my_write(file, buff, sizeof(buff), MYF(MY_NABP)) ||
|
||||
my_write(file, create_info->connect_string.str,
|
||||
if (my_write(file, (const byte*)buff, sizeof(buff), MYF(MY_NABP)) ||
|
||||
my_write(file, (const byte*)create_info->connect_string.str,
|
||||
create_info->connect_string.length, MYF(MY_NABP)))
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -13828,8 +13828,11 @@ static void test_bug10760()
|
|||
rc= mysql_stmt_execute(stmt);
|
||||
check_execute(stmt, rc);
|
||||
rc= mysql_query(mysql, "update t1 set id=id+100");
|
||||
DIE_UNLESS(rc);
|
||||
if (!opt_silent)
|
||||
/*
|
||||
If cursors are not materialized, the update will return an error;
|
||||
we mainly test that it won't deadlock.
|
||||
*/
|
||||
if (rc && !opt_silent)
|
||||
printf("Got error (as expected): %s\n", mysql_error(mysql));
|
||||
/*
|
||||
2: check that MyISAM tables used in cursors survive
|
||||
|
|
|
@ -1,10 +1,96 @@
|
|||
|
||||
ChangeLog file for zlib
|
||||
Changes in port for MySQL (19 July 2004)
|
||||
- removed contrib, nt, os2, amiga, directories and some other files not used
|
||||
in MySQL distribution. If you are working on porting MySQL to one of rare
|
||||
platforms, you might find worth looking at the original zlib distribution
|
||||
and using appropriate Makefiles/project files from it.
|
||||
|
||||
Changes in 1.2.3 (18 July 2005)
|
||||
- Apply security vulnerability fixes to contrib/infback9 as well
|
||||
- Clean up some text files (carriage returns, trailing space)
|
||||
- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant]
|
||||
|
||||
Changes in 1.2.2.4 (11 July 2005)
|
||||
- Add inflatePrime() function for starting inflation at bit boundary
|
||||
- Avoid some Visual C warnings in deflate.c
|
||||
- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit
|
||||
compile
|
||||
- Fix some spelling errors in comments [Betts]
|
||||
- Correct inflateInit2() error return documentation in zlib.h
|
||||
- Added zran.c example of compressed data random access to examples
|
||||
directory, shows use of inflatePrime()
|
||||
- Fix cast for assignments to strm->state in inflate.c and infback.c
|
||||
- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer]
|
||||
- Move declarations of gf2 functions to right place in crc32.c [Oberhumer]
|
||||
- Add cast in trees.c t avoid a warning [Oberhumer]
|
||||
- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer]
|
||||
- Update make_vms.com [Zinser]
|
||||
- Initialize state->write in inflateReset() since copied in inflate_fast()
|
||||
- Be more strict on incomplete code sets in inflate_table() and increase
|
||||
ENOUGH and MAXD -- this repairs a possible security vulnerability for
|
||||
invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for
|
||||
discovering the vulnerability and providing test cases.
|
||||
- Add ia64 support to configure for HP-UX [Smith]
|
||||
- Add error return to gzread() for format or i/o error [Levin]
|
||||
- Use malloc.h for OS/2 [Necasek]
|
||||
|
||||
Changes in 1.2.2.3 (27 May 2005)
|
||||
- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile
|
||||
- Typecast fread() return values in gzio.c [Vollant]
|
||||
- Remove trailing space in minigzip.c outmode (VC++ can't deal with it)
|
||||
- Fix crc check bug in gzread() after gzungetc() [Heiner]
|
||||
- Add the deflateTune() function to adjust internal compression parameters
|
||||
- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack)
|
||||
- Remove an incorrect assertion in examples/zpipe.c
|
||||
- Add C++ wrapper in infback9.h [Donais]
|
||||
- Fix bug in inflateCopy() when decoding fixed codes
|
||||
- Note in zlib.h how much deflateSetDictionary() actually uses
|
||||
- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used)
|
||||
- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer]
|
||||
- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer]
|
||||
- Add gzdirect() function to indicate transparent reads
|
||||
- Update contrib/minizip [Vollant]
|
||||
- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer]
|
||||
- Add casts in crc32.c to avoid warnings [Oberhumer]
|
||||
- Add contrib/masmx64 [Vollant]
|
||||
- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant]
|
||||
|
||||
Changes in 1.2.2.2 (30 December 2004)
|
||||
- Replace structure assignments in deflate.c and inflate.c with zmemcpy to
|
||||
avoid implicit memcpy calls (portability for no-library compilation)
|
||||
- Increase sprintf() buffer size in gzdopen() to allow for large numbers
|
||||
- Add INFLATE_STRICT to check distances against zlib header
|
||||
- Improve WinCE errno handling and comments [Chang]
|
||||
- Remove comment about no gzip header processing in FAQ
|
||||
- Add Z_FIXED strategy option to deflateInit2() to force fixed trees
|
||||
- Add updated make_vms.com [Coghlan], update README
|
||||
- Create a new "examples" directory, move gzappend.c there, add zpipe.c,
|
||||
fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html.
|
||||
- Add FAQ entry and comments in deflate.c on uninitialized memory access
|
||||
- Add Solaris 9 make options in configure [Gilbert]
|
||||
- Allow strerror() usage in gzio.c for STDC
|
||||
- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer]
|
||||
- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant]
|
||||
- Use z_off_t for adler32_combine() and crc32_combine() lengths
|
||||
- Make adler32() much faster for small len
|
||||
- Use OS_CODE in deflate() default gzip header
|
||||
|
||||
Changes in 1.2.2.1 (31 October 2004)
|
||||
- Allow inflateSetDictionary() call for raw inflate
|
||||
- Fix inflate header crc check bug for file names and comments
|
||||
- Add deflateSetHeader() and gz_header structure for custom gzip headers
|
||||
- Add inflateGetheader() to retrieve gzip headers
|
||||
- Add crc32_combine() and adler32_combine() functions
|
||||
- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list
|
||||
- Use zstreamp consistently in zlib.h (inflate_back functions)
|
||||
- Remove GUNZIP condition from definition of inflate_mode in inflate.h
|
||||
and in contrib/inflate86/inffast.S [Truta, Anderson]
|
||||
- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson]
|
||||
- Update projects/README.projects and projects/visualc6 [Truta]
|
||||
- Update win32/DLL_FAQ.txt [Truta]
|
||||
- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta]
|
||||
- Deprecate Z_ASCII; use Z_TEXT instead [Truta]
|
||||
- Use a new algorithm for setting strm->data_type in trees.c [Truta]
|
||||
- Do not define an exit() prototype in zutil.c unless DEBUG defined
|
||||
- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta]
|
||||
- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate()
|
||||
- Fix Darwin build version identification [Peterson]
|
||||
|
||||
Changes in 1.2.2 (3 October 2004)
|
||||
- Update zlib.h comments on gzip in-memory processing
|
||||
|
@ -454,7 +540,7 @@ Changes in 1.0.7 (20 Jan 1998)
|
|||
Changes in 1.0.6 (19 Jan 1998)
|
||||
- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and
|
||||
gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)
|
||||
- Fix a deflate bug occuring only with compression level 0 (thanks to
|
||||
- Fix a deflate bug occurring only with compression level 0 (thanks to
|
||||
Andy Buckler for finding this one).
|
||||
- In minigzip, pass transparently also the first byte for .Z files.
|
||||
- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()
|
||||
|
|
26
zlib/FAQ
26
zlib/FAQ
|
@ -148,13 +148,6 @@ The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html
|
|||
format using deflateInit2(). You can also request that inflate decode
|
||||
the gzip format using inflateInit2(). Read zlib.h for more details.
|
||||
|
||||
Note that you cannot specify special gzip header contents (e.g. a file
|
||||
name or modification date), nor will inflate tell you what was in the
|
||||
gzip header. If you need to customize the header or see what's in it,
|
||||
you can use the raw deflate and inflate operations and the crc32()
|
||||
function and roll your own gzip encoding and decoding. Read the gzip
|
||||
RFC 1952 for details of the header and trailer format.
|
||||
|
||||
21. Is zlib thread-safe?
|
||||
|
||||
Yes. However any library routines that zlib uses and any application-
|
||||
|
@ -295,20 +288,29 @@ The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html
|
|||
were downright silly. So now, we simply make sure that the code always
|
||||
works.
|
||||
|
||||
36. Will zlib read the (insert any ancient or arcane format here) compressed
|
||||
36. Valgrind (or some similar memory access checker) says that deflate is
|
||||
performing a conditional jump that depends on an uninitialized value.
|
||||
Isn't that a bug?
|
||||
|
||||
No. That is intentional for performance reasons, and the output of
|
||||
deflate is not affected. This only started showing up recently since
|
||||
zlib 1.2.x uses malloc() by default for allocations, whereas earlier
|
||||
versions used calloc(), which zeros out the allocated memory.
|
||||
|
||||
37. Will zlib read the (insert any ancient or arcane format here) compressed
|
||||
data format?
|
||||
|
||||
Probably not. Look in the comp.compression FAQ for pointers to various
|
||||
formats and associated software.
|
||||
|
||||
37. How can I encrypt/decrypt zip files with zlib?
|
||||
38. How can I encrypt/decrypt zip files with zlib?
|
||||
|
||||
zlib doesn't support encryption. The original PKZIP encryption is very weak
|
||||
and can be broken with freely available programs. To get strong encryption,
|
||||
use GnuPG, http://www.gnupg.org/ , which already includes zlib compression.
|
||||
For PKZIP compatible "encryption", look at http://www.info-zip.org/
|
||||
|
||||
38. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings?
|
||||
39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings?
|
||||
|
||||
"gzip" is the gzip format, and "deflate" is the zlib format. They should
|
||||
probably have called the second one "zlib" instead to avoid confusion
|
||||
|
@ -324,14 +326,14 @@ The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html
|
|||
|
||||
Bottom line: use the gzip format for HTTP 1.1 encoding.
|
||||
|
||||
39. Does zlib support the new "Deflate64" format introduced by PKWare?
|
||||
40. Does zlib support the new "Deflate64" format introduced by PKWare?
|
||||
|
||||
No. PKWare has apparently decided to keep that format proprietary, since
|
||||
they have not documented it as they have previous compression formats.
|
||||
In any case, the compression improvements are so modest compared to other
|
||||
more modern approaches, that it's not worth the effort to implement.
|
||||
|
||||
40. Can you please sign these lengthy legal documents and fax them back to us
|
||||
41. Can you please sign these lengthy legal documents and fax them back to us
|
||||
so that we can use your software in our product?
|
||||
|
||||
No. Go away. Shoo.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
ZLIB DATA COMPRESSION LIBRARY
|
||||
|
||||
zlib 1.2.2 is a general purpose data compression library. All the code is
|
||||
zlib 1.2.3 is a general purpose data compression library. All the code is
|
||||
thread safe. The data format used by the zlib library is described by RFCs
|
||||
(Request for Comments) 1950 to 1952 in the files
|
||||
http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format)
|
||||
|
@ -16,9 +16,8 @@ minigzip.c.
|
|||
|
||||
To compile all files and run the test program, follow the instructions given at
|
||||
the top of Makefile. In short "make test; make install" should work for most
|
||||
machines. For Unix: "./configure; make test; make install" For MSDOS, use one
|
||||
of the special makefiles such as Makefile.msc. For VMS, use Make_vms.com or
|
||||
descrip.mms.
|
||||
machines. For Unix: "./configure; make test; make install". For MSDOS, use one
|
||||
of the special makefiles such as Makefile.msc. For VMS, use make_vms.com.
|
||||
|
||||
Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant
|
||||
<info@winimage.com> for the Windows DLL version. The zlib home page is
|
||||
|
@ -34,7 +33,7 @@ Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
|
|||
issue of Dr. Dobb's Journal; a copy of the article is available in
|
||||
http://dogma.net/markn/articles/zlibtool/zlibtool.htm
|
||||
|
||||
The changes made in version 1.2.2 are documented in the file ChangeLog.
|
||||
The changes made in version 1.2.3 are documented in the file ChangeLog.
|
||||
|
||||
Unsupported third party contributions are provided in directory "contrib".
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue