mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
Merge mysqldev@production.mysql.com:my/mysql-5.0-release
into mysql.com:/opt/local/work/mysql-5.0-root BitKeeper/etc/ignore: auto-union include/my_sys.h: Auto merged mysql-test/r/information_schema.result: Auto merged mysql-test/t/ctype_ujis.test: Auto merged sql/ha_federated.cc: Auto merged sql/handler.cc: Auto merged sql/item_func.h: Auto merged sql/log.cc: Auto merged sql/sp_head.cc: Auto merged sql/sp_head.h: Auto merged sql/sql_acl.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_lex.h: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_view.cc: Auto merged sql/table.cc: Auto merged
This commit is contained in:
commit
38ebb6c638
58 changed files with 1789 additions and 986 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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
DROP TABLE IF EXISTS t1;
|
||||
select 1;
|
||||
1
|
||||
1
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1456,11 +1456,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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
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); }
|
||||
|
|
|
@ -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;
|
||||
|
|
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
|
||||
|
|
Loading…
Reference in a new issue