├── 9781430246596.jpg ├── Ch04 ├── cab.test └── source_Ch04.zip ├── Ch06 ├── BookVendingMachine │ ├── AdminForm.h │ ├── AdminForm.resx │ ├── AssemblyInfo.cpp │ ├── BookVendingMachine.cpp │ ├── BookVendingMachine.vcxproj │ ├── DBEngine.cpp │ ├── DBEngine.h │ ├── MainForm.h │ ├── MainForm.resx │ ├── app.aps │ └── resource.h ├── example1_win32 │ ├── example1_win32.cpp │ └── example1_win32.vcxproj └── source_ch06.zip ├── Ch07 ├── diskusage.diff ├── diskusage_is.diff ├── gregorian.diff ├── julian.diff └── source_Ch07.zip ├── Ch08 ├── slave_connect_log_event.diff ├── source_Ch08.zip └── stop_slaves.diff ├── Ch09 ├── rfid_auth │ ├── CMakeLists.txt │ ├── rfid_auth.cc │ └── rfid_auth.ini └── source_Ch09.zip ├── Ch10 ├── ch10_results.txt ├── source_Ch10.zip ├── stage_five │ ├── CMakeLists.txt │ ├── Ch10s5.test │ ├── ha_spartan.cc │ ├── ha_spartan.h │ ├── spartan_data.cc │ ├── spartan_data.h │ ├── spartan_index.cc │ └── spartan_index.h ├── stage_four │ ├── CMakeLists.txt │ ├── Ch10s4.test │ ├── ha_spartan.cc │ ├── ha_spartan.h │ ├── spartan_data.cc │ └── spartan_data.h ├── stage_one │ ├── CMakeLists.txt │ ├── Ch10s1.test │ ├── ha_spartan.cc │ ├── ha_spartan.h │ ├── spartan_data.cc │ └── spartan_data.h ├── stage_three │ ├── CMakeLists.txt │ ├── Ch10s3.test │ ├── ha_spartan.cc │ ├── ha_spartan.h │ ├── spartan_data.cc │ └── spartan_data.h └── stage_two │ ├── CMakeLists.txt │ ├── Ch10s2.test │ ├── ha_spartan.cc │ ├── ha_spartan.h │ ├── spartan_data.cc │ └── spartan_data.h ├── Ch12 ├── ch12.diff ├── ch12.sql ├── ch12.test ├── query_tree.cc ├── query_tree.h ├── source_Ch12.zip └── sql_dbxp_parse.cc ├── Ch13 ├── attribute.cc ├── attribute.h ├── ch13.diff ├── ch13.result ├── ch13.test ├── ch13.txt ├── ch13_results.txt ├── expression.cc ├── expression.h ├── query_tree.cc ├── query_tree.h ├── source_Ch13.zip └── sql_dbxp_parse.cc ├── Ch14 ├── attribute.cc ├── attribute.h ├── ch14.diff ├── ch14.result ├── ch14.test ├── ch14.txt ├── expression.cc ├── expression.h ├── query_tree.cc ├── query_tree.h ├── source_Ch14.zip └── sql_dbxp_parse.cc ├── LICENSE.txt ├── README.md ├── Sample_data ├── bvm_data.sql ├── bvm_images.zip └── sample_data.sql └── contributing.md /9781430246596.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/9781430246596.jpg -------------------------------------------------------------------------------- /Ch04/cab.test: -------------------------------------------------------------------------------- 1 | # 2 | # Sample test to demonstrate MySQL Test Suite 3 | # 4 | --disable_warnings 5 | SHOW DATABASES; 6 | --enable_warnings 7 | CREATE TABLE characters (ID INTEGER PRIMARY KEY, 8 | LastName varchar(40), 9 | FirstName varchar(20), 10 | Gender varchar(2)) ENGINE=MYISAM; 11 | EXPLAIN characters; 12 | # 13 | INSERT INTO characters (ID, LastName, FirstName, Gender) 14 | VALUES (3, 'Flintstone', 'Fred', 'M'); 15 | INSERT INTO characters (ID, LastName, FirstName, Gender) 16 | VALUES (5, 'Rubble', 'Barney', 'M'); 17 | INSERT INTO characters (ID, LastName, FirstName, Gender) 18 | VALUES (7, 'Flintstone', 'Wilma', 'F'); 19 | INSERT INTO characters (ID, LastName, FirstName, Gender) 20 | VALUES (9, 'Flintstone', 'Dino', 'M'); 21 | INSERT INTO characters (ID, LastName, FirstName, Gender) 22 | VALUES (4, 'Flintstone', 'Pebbles', 'F'); 23 | INSERT INTO characters (ID, LastName, FirstName, Gender) 24 | VALUES (1, 'Rubble', 'Betty', 'F'); 25 | INSERT INTO characters (ID, LastName, FirstName, Gender) 26 | VALUES (6, 'Rubble', 'Bam-Bam', 'M'); 27 | INSERT INTO characters (ID, LastName, FirstName, Gender) 28 | VALUES (8, 'Jetson', 'George', 'M'); 29 | # 30 | SELECT * FROM characters; 31 | # 32 | EXPLAIN (SELECT DISTINCT LASTNAME from characters); 33 | # 34 | SELECT DISTINCT LASTNAME from characters; 35 | # 36 | # Cleanup 37 | # 38 | DROP TABLE characters; 39 | -------------------------------------------------------------------------------- /Ch04/source_Ch04.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Ch04/source_Ch04.zip -------------------------------------------------------------------------------- /Ch06/BookVendingMachine/AdminForm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "DBEngine.h" 3 | 4 | using namespace System; 5 | using namespace System::ComponentModel; 6 | using namespace System::Collections; 7 | using namespace System::Windows::Forms; 8 | using namespace System::Data; 9 | using namespace System::Drawing; 10 | 11 | 12 | namespace BookVendingMachine { 13 | 14 | DBEngine *AdminDatabase = new DBEngine(); 15 | 16 | /// 17 | /// Summary for Admin 18 | /// 19 | /// WARNING: If you change the name of this class, you will need to change the 20 | /// 'Resource File Name' property for the managed resource compiler tool 21 | /// associated with all .resx files this class depends on. Otherwise, 22 | /// the designers will not be able to interact properly with localized 23 | /// resources associated with this form. 24 | /// 25 | 26 | public ref class AdminForm: public System::Windows::Forms::Form 27 | { 28 | public: 29 | AdminForm(void) 30 | { 31 | InitializeComponent(); 32 | // 33 | //TODO: Add the constructor code here 34 | // 35 | } 36 | 37 | protected: 38 | /// 39 | /// Clean up any resources being used. 40 | /// 41 | ~AdminForm() 42 | { 43 | if (components) 44 | { 45 | delete components; 46 | } 47 | } 48 | 49 | protected: 50 | private: System::Windows::Forms::TextBox^ txtQuery; 51 | private: System::Windows::Forms::Button^ btnExecute; 52 | private: System::Windows::Forms::ListBox^ lstData; 53 | private: System::Windows::Forms::Label^ label1; 54 | 55 | private: 56 | /// 57 | /// Required designer variable. 58 | /// 59 | System::ComponentModel::Container ^components; 60 | 61 | #pragma region Windows Form Designer generated code 62 | /// 63 | /// Required method for Designer support - do not modify 64 | /// the contents of this method with the code editor. 65 | /// 66 | void InitializeComponent(void) 67 | { 68 | this->txtQuery = (gcnew System::Windows::Forms::TextBox()); 69 | this->btnExecute = (gcnew System::Windows::Forms::Button()); 70 | this->lstData = (gcnew System::Windows::Forms::ListBox()); 71 | this->label1 = (gcnew System::Windows::Forms::Label()); 72 | this->SuspendLayout(); 73 | // 74 | // txtQuery 75 | // 76 | this->txtQuery->Anchor = static_cast(((System::Windows::Forms::AnchorStyles::Bottom | System::Windows::Forms::AnchorStyles::Left) 77 | | System::Windows::Forms::AnchorStyles::Right)); 78 | this->txtQuery->Font = (gcnew System::Drawing::Font(L"Courier New", 9.75F, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point, 79 | static_cast(0))); 80 | this->txtQuery->Location = System::Drawing::Point(12, 219); 81 | this->txtQuery->Multiline = true; 82 | this->txtQuery->Name = L"txtQuery"; 83 | this->txtQuery->Size = System::Drawing::Size(721, 53); 84 | this->txtQuery->TabIndex = 2; 85 | // 86 | // btnExecute 87 | // 88 | this->btnExecute->Anchor = static_cast((System::Windows::Forms::AnchorStyles::Bottom | System::Windows::Forms::AnchorStyles::Right)); 89 | this->btnExecute->Location = System::Drawing::Point(658, 278); 90 | this->btnExecute->Name = L"btnExecute"; 91 | this->btnExecute->Size = System::Drawing::Size(75, 23); 92 | this->btnExecute->TabIndex = 3; 93 | this->btnExecute->Text = L"Execute"; 94 | this->btnExecute->UseVisualStyleBackColor = true; 95 | this->btnExecute->Click += gcnew System::EventHandler(this, &AdminForm::btnExecute_Click); 96 | // 97 | // lstData 98 | // 99 | this->lstData->Anchor = static_cast((((System::Windows::Forms::AnchorStyles::Top | System::Windows::Forms::AnchorStyles::Bottom) 100 | | System::Windows::Forms::AnchorStyles::Left) 101 | | System::Windows::Forms::AnchorStyles::Right)); 102 | this->lstData->Font = (gcnew System::Drawing::Font(L"Courier New", 9.75F, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point, 103 | static_cast(0))); 104 | this->lstData->FormattingEnabled = true; 105 | this->lstData->HorizontalScrollbar = true; 106 | this->lstData->ItemHeight = 16; 107 | this->lstData->Location = System::Drawing::Point(12, 28); 108 | this->lstData->MultiColumn = true; 109 | this->lstData->Name = L"lstData"; 110 | this->lstData->Size = System::Drawing::Size(721, 180); 111 | this->lstData->TabIndex = 4; 112 | // 113 | // label1 114 | // 115 | this->label1->AutoSize = true; 116 | this->label1->Font = (gcnew System::Drawing::Font(L"Courier New", 9.75F, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point, 117 | static_cast(0))); 118 | this->label1->Location = System::Drawing::Point(12, 9); 119 | this->label1->Name = L"label1"; 120 | this->label1->Size = System::Drawing::Size(688, 16); 121 | this->label1->TabIndex = 5; 122 | this->label1->Text = L"(ISBN, Slot, Quantity, Price, Pages, PubDate, Title, Authors, Thumbnail, Descript" 123 | L"ion)"; 124 | // 125 | // AdminForm 126 | // 127 | this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); 128 | this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; 129 | this->ClientSize = System::Drawing::Size(745, 311); 130 | this->Controls->Add(this->label1); 131 | this->Controls->Add(this->lstData); 132 | this->Controls->Add(this->btnExecute); 133 | this->Controls->Add(this->txtQuery); 134 | this->Name = L"AdminForm"; 135 | this->Text = L"Book Vending Machine Administration"; 136 | this->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &AdminForm::AdminForm_FormClosing); 137 | this->Load += gcnew System::EventHandler(this, &AdminForm::Admin_Load); 138 | this->ResumeLayout(false); 139 | this->PerformLayout(); 140 | 141 | } 142 | #pragma endregion 143 | void LoadList() 144 | { 145 | int i = 0; 146 | int j = 0; 147 | String^ str; 148 | 149 | lstData->Items->Clear(); 150 | AdminDatabase->StartQuery("SELECT ISBN, Slot, Quantity, Price," \ 151 | " Pages, PubDate, Title, Authors, Thumbnail," \ 152 | " Description FROM books"); 153 | do 154 | { 155 | str = gcnew String(""); 156 | for (i = 0; i < 10; i++) 157 | { 158 | if (i != 0) 159 | { 160 | str = str + "\t"; 161 | } 162 | str = str + gcnew String(AdminDatabase->GetField(i)); 163 | } 164 | lstData->Items->Add(str); 165 | j++; 166 | }while(AdminDatabase->GetNext()); 167 | } 168 | 169 | private: System::Void btnExecute_Click(System::Object^ sender, System::EventArgs^ e) 170 | { 171 | String ^orig = gcnew String(txtQuery->Text->ToString()); 172 | pin_ptr wch = PtrToStringChars(orig); 173 | 174 | // Convert to a char* 175 | size_t origsize = wcslen(wch) + 1; 176 | const size_t newsize = 100; 177 | size_t convertedChars = 0; 178 | char nstring[newsize]; 179 | wcstombs_s(&convertedChars, nstring, origsize, wch, _TRUNCATE); 180 | AdminDatabase->RunQuery(nstring); 181 | LoadList(); 182 | } 183 | 184 | private: System::Void Admin_Load(System::Object^ sender, System::EventArgs^ e) 185 | { 186 | AdminDatabase->Initialize(); 187 | LoadList(); 188 | } 189 | 190 | private: System::Void AdminForm_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e) 191 | { 192 | AdminDatabase->Shutdown(); 193 | } 194 | }; 195 | } 196 | -------------------------------------------------------------------------------- /Ch06/BookVendingMachine/AdminForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Ch06/BookVendingMachine/AssemblyInfo.cpp: -------------------------------------------------------------------------------- 1 | using namespace System; 2 | using namespace System::Reflection; 3 | using namespace System::Runtime::CompilerServices; 4 | using namespace System::Runtime::InteropServices; 5 | using namespace System::Security::Permissions; 6 | 7 | // 8 | // General Information about an assembly is controlled through the following 9 | // set of attributes. Change these attribute values to modify the information 10 | // associated with an assembly. 11 | // 12 | [assembly:AssemblyTitleAttribute("BookVendingMachine")]; 13 | [assembly:AssemblyDescriptionAttribute("")]; 14 | [assembly:AssemblyConfigurationAttribute("")]; 15 | [assembly:AssemblyCompanyAttribute("")]; 16 | [assembly:AssemblyProductAttribute("BookVendingMachine")]; 17 | [assembly:AssemblyCopyrightAttribute("Copyright (c) 2006")]; 18 | [assembly:AssemblyTrademarkAttribute("")]; 19 | [assembly:AssemblyCultureAttribute("")]; 20 | 21 | // 22 | // Version information for an assembly consists of the following four values: 23 | // 24 | // Major Version 25 | // Minor Version 26 | // Build Number 27 | // Revision 28 | // 29 | // You can specify all the value or you can default the Revision and Build Numbers 30 | // by using the '*' as shown below: 31 | 32 | [assembly:AssemblyVersionAttribute("1.0.*")]; 33 | 34 | [assembly:ComVisible(false)]; 35 | 36 | [assembly:CLSCompliantAttribute(true)]; 37 | 38 | [assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)]; 39 | -------------------------------------------------------------------------------- /Ch06/BookVendingMachine/BookVendingMachine.cpp: -------------------------------------------------------------------------------- 1 | // BookVendingMachine.cpp : main project file. 2 | 3 | #include "MainForm.h" 4 | #include "AdminForm.h" 5 | 6 | using namespace BookVendingMachine; 7 | 8 | [STAThreadAttribute] 9 | int main(array ^args) 10 | { 11 | // Enabling Windows XP visual effects before any controls are created 12 | Application::EnableVisualStyles(); 13 | Application::SetCompatibleTextRenderingDefault(false); 14 | 15 | // Create the main window and run it 16 | if ((args->Length == 1) && (args[0] == "-admin")) 17 | { 18 | Application::Run(gcnew AdminForm()); 19 | } 20 | else 21 | { 22 | Application::Run(gcnew MainForm()); 23 | } 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /Ch06/BookVendingMachine/BookVendingMachine.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Template 14 | Win32 15 | 16 | 17 | 18 | {99EA9ED6-10E3-458D-8D20-7F38D014397C} 19 | BookVendingMachine 20 | ManagedCProj 21 | 22 | 23 | 24 | Application 25 | Unicode 26 | Pure 27 | true 28 | 29 | 30 | Application 31 | Unicode 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | <_ProjectFileVersion>10.0.30319.1 46 | Debug\ 47 | $(Configuration)\ 48 | true 49 | $(SolutionDir)$(Configuration)\ 50 | $(Configuration)\ 51 | false 52 | 53 | 54 | 55 | /I ../include %(AdditionalOptions) 56 | Disabled 57 | WIN32;_DEBUG;%(PreprocessorDefinitions) 58 | MultiThreadedDebugDLL 59 | 60 | 61 | Level3 62 | ProgramDatabase 63 | 64 | 65 | 66 | 67 | true 68 | true 69 | Windows 70 | main 71 | MachineX86 72 | 73 | 74 | 75 | 76 | WIN32;NDEBUG;%(PreprocessorDefinitions) 77 | MultiThreadedDLL 78 | Use 79 | Level3 80 | ProgramDatabase 81 | 82 | 83 | 84 | 85 | true 86 | Windows 87 | main 88 | MachineX86 89 | 90 | 91 | 92 | 93 | true 94 | true 95 | 96 | 97 | true 98 | true 99 | 100 | 101 | true 102 | true 103 | 104 | 105 | true 106 | true 107 | 108 | 109 | true 110 | true 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | CppForm 121 | 122 | 123 | 124 | CppForm 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | AdminForm.h 134 | Designer 135 | 136 | 137 | MainForm.h 138 | Designer 139 | 140 | 141 | 142 | 143 | {e373b9a3-a3df-40d4-af21-747e8fede36c} 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /Ch06/BookVendingMachine/DBEngine.cpp: -------------------------------------------------------------------------------- 1 | #pragma unmanaged 2 | 3 | #include "DBEngine.h" 4 | #include 5 | #include 6 | #include "my_global.h" 7 | #include "mysql.h" 8 | 9 | MYSQL *mysql; //the embedded server class 10 | MYSQL_RES *results; //stores results from queries 11 | MYSQL_ROW record; //a single row in a result set 12 | bool IteratorStarted; //used to control iterator 13 | MYSQL_RES *ExecQuery(char *Query); 14 | 15 | /* 16 | These variables set the location of the ini file and data stores. 17 | */ 18 | static char *server_options[] = {"mysql_test", 19 | "--defaults-file=c:\\mysql_embedded\\my.ini", 20 | "--datadir=c:\\mysql_embedded\\data" }; 21 | int num_elements=sizeof(server_options) / sizeof(char *); 22 | static char *server_groups[] = {"libmyswld_server", "libmysqld_client" }; 23 | 24 | DBEngine::DBEngine(void) 25 | { 26 | mysqlError = false; 27 | } 28 | 29 | DBEngine::~DBEngine(void) 30 | { 31 | } 32 | 33 | const char *DBEngine::GetError() 34 | { 35 | return (mysql_error(mysql)); 36 | mysqlError = false; 37 | } 38 | 39 | bool DBEngine::Error() 40 | { 41 | return(mysqlError); 42 | } 43 | 44 | char *DBEngine::GetBookFieldStr(int Slot, char *Field) 45 | { 46 | char *istr = new char[10]; 47 | char *str = new char[128]; 48 | 49 | _itoa_s(Slot, istr, 10, 10); 50 | strcpy_s(str, 128, "SELECT "); 51 | strcat_s(str, 128, Field); 52 | strcat_s(str, 128, " FROM books WHERE Slot = "); 53 | strcat_s(str, 128, istr); 54 | mysqlError = false; 55 | results=ExecQuery(str); 56 | strcpy_s(str, 128, ""); 57 | if (results) 58 | { 59 | mysqlError = false; 60 | record=mysql_fetch_row(results); 61 | if(record) 62 | { 63 | strcpy_s(str, 128, record[0]); 64 | } 65 | else 66 | { 67 | mysqlError = true; 68 | } 69 | } 70 | return (str); 71 | } 72 | 73 | char *DBEngine::GetBookFieldText(int Slot, char *Field) 74 | { 75 | char *istr = new char[10]; 76 | char *str = new char[128]; 77 | 78 | _itoa_s(Slot, istr, 10, 10); 79 | strcpy_s(str, 128, "SELECT "); 80 | strcat_s(str, 128, Field); 81 | strcat_s(str, 128, " FROM books WHERE Slot = "); 82 | strcat_s(str, 128, istr); 83 | mysqlError = false; 84 | results=ExecQuery(str); 85 | delete str; 86 | if (results) 87 | { 88 | mysqlError = false; 89 | record=mysql_fetch_row(results); 90 | if(record) 91 | { 92 | return (record[0]); 93 | } 94 | else 95 | { 96 | mysqlError = true; 97 | } 98 | } 99 | return (""); 100 | } 101 | 102 | int DBEngine::GetBookFieldInt(int Slot, char *Field) 103 | { 104 | char *istr = new char[10]; 105 | char *str = new char[128]; 106 | int qty = 0; 107 | 108 | _itoa_s(Slot, istr, 10, 10); 109 | strcpy_s(str, 128, "SELECT "); 110 | strcat_s(str, 128, Field); 111 | strcat_s(str, 128, " FROM books WHERE Slot = "); 112 | strcat_s(str, 128, istr); 113 | results=ExecQuery(str); 114 | if (results) 115 | { 116 | record=mysql_fetch_row(results); 117 | if(record) 118 | { 119 | qty = atoi(record[0]); 120 | } 121 | else 122 | { 123 | mysqlError = true; 124 | } 125 | } 126 | delete str; 127 | return (qty); 128 | } 129 | 130 | void DBEngine::VendBook(char *ISBN) 131 | { 132 | char *str = new char[128]; 133 | char *istr = new char[10]; 134 | int qty = 0; 135 | 136 | strcpy_s(str, 128, "SELECT Quantity FROM books WHERE ISBN = '"); 137 | strcat_s(str, 128, ISBN); 138 | strcat_s(str, 128, "'"); 139 | results=ExecQuery(str); 140 | record=mysql_fetch_row(results); 141 | if (record) 142 | { 143 | qty = atoi(record[0]); 144 | if (qty >= 1) 145 | { 146 | _itoa_s(qty - 1, istr, 10, 10); 147 | strcpy_s(str, 128, "UPDATE books SET Quantity = "); 148 | strcat_s(str, 128, istr); 149 | strcat_s(str, 128, " WHERE ISBN = '"); 150 | strcat_s(str, 128, ISBN); 151 | strcat_s(str, 128, "'"); 152 | results=ExecQuery(str); 153 | } 154 | } 155 | else 156 | { 157 | mysqlError = true; 158 | } 159 | } 160 | 161 | void DBEngine::Initialize() 162 | { 163 | /* 164 | This section initializes the server and sets server options. 165 | */ 166 | mysql_server_init(num_elements, server_options, server_groups); 167 | mysql = mysql_init(NULL); 168 | if (mysql) 169 | { 170 | mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, "libmysqld_client"); 171 | mysql_options(mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL); 172 | /* 173 | The following call turns debugging on programmatically. 174 | Comment out to turn on debugging. 175 | */ 176 | //mysql_debug("d:t:i:O,\\mysqld_embedded.trace"); 177 | /* 178 | Connect to embedded server. 179 | */ 180 | if(mysql_real_connect(mysql, NULL, NULL, NULL, "mysql", 0, NULL, 0) == NULL) 181 | { 182 | mysqlError = true; 183 | } 184 | else 185 | { 186 | mysql_query(mysql, "use BVM;"); 187 | } 188 | } 189 | else 190 | { 191 | mysqlError = true; 192 | } 193 | IteratorStarted = false; 194 | } 195 | 196 | void DBEngine::Shutdown() 197 | { 198 | /* 199 | Now close the server connection and tell server we're done (shutdown). 200 | */ 201 | mysql_close(mysql); 202 | mysql_server_end(); 203 | } 204 | 205 | char *DBEngine::GetSetting(char *Field) 206 | { 207 | char *str = new char[128]; 208 | strcpy_s(str, 128, "SELECT * FROM settings WHERE FieldName = '"); 209 | strcat_s(str, 128, Field); 210 | strcat_s(str, 128, "'"); 211 | results=ExecQuery(str); 212 | strcpy_s(str, 128, ""); 213 | if (results) 214 | { 215 | record=mysql_fetch_row(results); 216 | if (record) 217 | { 218 | strcpy_s(str, 128, record[1]); 219 | } 220 | } 221 | else 222 | { 223 | mysqlError = true; 224 | } 225 | return (str); 226 | } 227 | 228 | void DBEngine::StartQuery(char *QueryStatement) 229 | { 230 | if (!IteratorStarted) 231 | { 232 | results=ExecQuery(QueryStatement); 233 | if (results) 234 | { 235 | record=mysql_fetch_row(results); 236 | } 237 | } 238 | IteratorStarted=true; 239 | } 240 | 241 | void DBEngine::RunQuery(char *QueryStatement) 242 | { 243 | results=ExecQuery(QueryStatement); 244 | if (results) 245 | { 246 | record=mysql_fetch_row(results); 247 | if(!record) 248 | { 249 | mysqlError = true; 250 | } 251 | } 252 | } 253 | 254 | int DBEngine::GetNext() 255 | { 256 | //if EOF then no more records 257 | IteratorStarted=false; 258 | record=mysql_fetch_row(results); 259 | if (record) 260 | { 261 | return (1); 262 | } 263 | else 264 | { 265 | return (0); 266 | } 267 | } 268 | 269 | char *DBEngine::GetField(int fldNum) 270 | { 271 | if (record) 272 | { 273 | return (record[fldNum]); 274 | } 275 | else 276 | { 277 | return (""); 278 | } 279 | } 280 | 281 | MYSQL_RES *ExecQuery(char *Query) 282 | { 283 | mysql_dbug_print("ExecQuery."); 284 | mysql_free_result(results); 285 | mysql_query(mysql, Query); 286 | return (mysql_store_result(mysql)); 287 | } 288 | #pragma managed -------------------------------------------------------------------------------- /Ch06/BookVendingMachine/DBEngine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #pragma unmanaged 3 | #include 4 | 5 | class DBEngine 6 | { 7 | private: 8 | bool mysqlError; 9 | public: 10 | DBEngine(void); 11 | const char *GetError(); 12 | bool Error(); 13 | void Initialize(); 14 | void Shutdown(); 15 | char *GetSetting(char *Field); 16 | char *GetBookFieldStr(int Slot, char *Field); 17 | char *GetBookFieldText(int Slot, char *Field); 18 | int GetBookFieldInt(int Slot, char *Field); 19 | int GetQty(int Slot); 20 | void VendBook(char *ISBN); 21 | void StartQuery(char *QueryStatement); 22 | void RunQuery(char *QueryStatement); 23 | int GetNext(); 24 | char *GetField(int fldNum); 25 | ~DBEngine(void); 26 | }; 27 | #pragma managed 28 | -------------------------------------------------------------------------------- /Ch06/BookVendingMachine/MainForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | True 122 | 123 | 124 | 125 | 126 | AAABAAIAICAQAAAAAADoAgAAJgAAABAQEAAAAAAAKAEAAA4DAAAoAAAAIAAAAEAAAAABAAQAAAAAAIAC 127 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/ 128 | AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 129 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 130 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIAAAAAAAAAAAAAAAAAACQd4gAAA 131 | AAAAAAAAAAAAAJkHd3iAAAAAAAAAAAAAAAmZgAd3eIAAAAAAAAAAAACZmAmQB3d4gAAAAAAAAAAJmYCZ 132 | mZAHd3AAAAAAAAAAmZgJmZmZkAdwAAAAAAAACZmAmZmZmZmQAAAAAAAAAJmYCZmZmZmZmZAAAAAAAAmZ 133 | gJmZmZmZmZmQAAAAAAAJmAmZmZmZmZmZAAAAAAAACYCZmZmZmZmZkAAAAAAAAAgJmZmZmZmZmQAAAAAA 134 | AAAACZmZmZmZmZAAAAAAAAAAAAAJmZmZmZkAAAAAAAAAAAAAAAmZmZmQAAAAAAAAAAAAAAAACZmZAAAA 135 | AAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 136 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////// 137 | ////////////////////////////////x////4H///8Af//+AB///AAH//gAAf/wAAP/4AAD/8AAA/+A 138 | AAH/AAAD/wAAB/8AAA//AAAf/4AAP//gAH//+AD///4B////g////+f///////////////////////// 139 | //8oAAAAEAAAACAAAAABAAQAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAgAAAAICAAIAA 140 | AACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAA 141 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkHAAAAAAAAmAeIAAAAAAmAAHeAAAAAmAmZAHAAAAmAmZmZAAAA 142 | CAmZmZkAAAAAmZmZkAAAAAAJmZkAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP// 143 | AAD//wAA/48AAP8DAAD+AAAA/AEAAPgBAADwAAAA8AEAAPADAAD4BwAA/g8AAP+fAAD//wAA//8AAA== 144 | 145 | 146 | -------------------------------------------------------------------------------- /Ch06/BookVendingMachine/app.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Ch06/BookVendingMachine/app.aps -------------------------------------------------------------------------------- /Ch06/BookVendingMachine/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by app.rc 4 | -------------------------------------------------------------------------------- /Ch06/example1_win32/example1_win32.cpp: -------------------------------------------------------------------------------- 1 | #include "my_global.h" 2 | #include "mysql.h" 3 | 4 | MYSQL *mysql; //the embedded server class 5 | MYSQL_RES *results; //stores results from queries 6 | MYSQL_ROW record; //a single row in a result set 7 | 8 | /* 9 | These variables set the location of the ini file and data stores. 10 | */ 11 | static char *server_options[] = {"mysql_test", 12 | "--defaults-file=c:\\mysql_embedded\\my.ini", 13 | "--datadir=c:\\mysql_embedded\\data" }; 14 | int num_elements=sizeof(server_options) / sizeof(char *); 15 | static char *server_groups[] = {"libmysqld_server", "libmysqld_client" }; 16 | 17 | int main(void) 18 | { 19 | /* 20 | This section initializes the server and sets server options. 21 | */ 22 | mysql_server_init(num_elements, server_options, server_groups); 23 | mysql = mysql_init(NULL); 24 | mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, "libmysqld_client"); 25 | mysql_options(mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL); 26 | /* 27 | The following call turns debugging on programmatically. 28 | Comment out to turn on debugging. 29 | */ 30 | //mysql_debug("d:t:i:O,\\mysqld_embedded.trace"); 31 | /* 32 | Connect to embedded server. 33 | */ 34 | mysql_real_connect(mysql, NULL, NULL, NULL, "mysql", 0, NULL, 0); 35 | /* 36 | This sections executes the following commands and demonstrates 37 | how to retrieve results from a query. 38 | 39 | SHOW DATABASES; 40 | CREATE DATABASE testdb1; 41 | SHOW DATABASES; 42 | DROP DATABASE testdb1; 43 | */ 44 | mysql_dbug_print("Showing databases."); //record trace 45 | mysql_query(mysql, "SHOW DATABASES;"); //issue query 46 | results = mysql_store_result(mysql); //get results 47 | printf("The following are the databases supported:\n"); 48 | while(record=mysql_fetch_row(results)) //fetch row 49 | { 50 | printf("%s\n", record[0]); //process row 51 | } 52 | mysql_dbug_print("Creating the database testdb1."); //record trace 53 | mysql_query(mysql, "CREATE DATABASE testdb1;"); 54 | mysql_dbug_print("Showing databases."); 55 | mysql_query(mysql, "SHOW DATABASES;"); //issue query 56 | results = mysql_store_result(mysql); //get results 57 | printf("The following are the databases supported:\n"); 58 | while(record=mysql_fetch_row(results)) //fetch row 59 | { 60 | printf("%s\n", record[0]); //process row 61 | } 62 | mysql_free_result(results); 63 | mysql_dbug_print("Dropping database testdb1."); //record trace 64 | mysql_query(mysql, "DROP DATABASE testdb1;"); //issue query 65 | /* 66 | Now close the server connection and tell server we're done (shutdown). 67 | */ 68 | mysql_close(mysql); 69 | mysql_server_end(); 70 | 71 | return 0; 72 | } 73 | 74 | -------------------------------------------------------------------------------- /Ch06/example1_win32/example1_win32.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {B9BF96BD-BD73-4A9E-96E4-6AEA34499C30} 15 | example1_win32 16 | Win32Proj 17 | 18 | 19 | 20 | Application 21 | Unicode 22 | true 23 | 24 | 25 | Application 26 | Unicode 27 | false 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | <_ProjectFileVersion>10.0.30319.1 41 | Debug\ 42 | $(Configuration)\ 43 | true 44 | $(SolutionDir)$(Configuration)\ 45 | $(Configuration)\ 46 | false 47 | 48 | 49 | 50 | /I ../include %(AdditionalOptions) 51 | Disabled 52 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 53 | false 54 | Default 55 | MultiThreadedDebugDLL 56 | NotUsing 57 | Level3 58 | ProgramDatabase 59 | CompileAsCpp 60 | 61 | 62 | true 63 | true 64 | Console 65 | MachineX86 66 | %(AdditionalDependencies) 67 | 68 | 69 | 70 | 71 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 72 | MultiThreadedDLL 73 | 74 | 75 | Level3 76 | ProgramDatabase 77 | 78 | 79 | true 80 | Console 81 | true 82 | true 83 | MachineX86 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | {e373b9a3-a3df-40d4-af21-747e8fede36c} 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Ch06/source_ch06.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Ch06/source_ch06.zip -------------------------------------------------------------------------------- /Ch07/diskusage.diff: -------------------------------------------------------------------------------- 1 | === modified file 'sql/lex.h' 2 | --- sql/lex.h 2012-05-03 08:35:47 +0000 3 | +++ sql/lex.h 2012-08-14 16:09:27 +0000 4 | @@ -181,6 +181,11 @@ static SYMBOL symbols[] = { 5 | { "DISABLE", SYM(DISABLE_SYM)}, 6 | { "DISCARD", SYM(DISCARD)}, 7 | { "DISK", SYM(DISK_SYM)}, 8 | +/* BEGIN CAB MODIFICATION */ 9 | +/* Reason for Modification: */ 10 | +/* Add disk usage symbol */ 11 | + { "DISK_USAGE", SYM(DISK_USAGE_SYM)}, 12 | +/* END CAB MODIFICATION */ 13 | { "DISTINCT", SYM(DISTINCT)}, 14 | { "DISTINCTROW", SYM(DISTINCT)}, /* Access likes this */ 15 | { "DIV", SYM(DIV_SYM)}, 16 | 17 | === modified file 'sql/sql_cmd.h' 18 | --- sql/sql_cmd.h 2012-05-28 09:09:33 +0000 19 | +++ sql/sql_cmd.h 2012-08-14 16:09:27 +0000 20 | @@ -62,7 +62,11 @@ enum enum_sql_command { 21 | SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_UPDATE_MULTI, 22 | SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_DO, 23 | SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS, 24 | - SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES, 25 | +/* BEGIN CAB MODIFICATION */ 26 | +/* Reason for Modification: */ 27 | +/* Add SQLCOM_SHOW_DISK_USAGE reference */ 28 | + SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES, SQLCOM_SHOW_DISK_USAGE, 29 | +/* END CAB MODIFICATION */ 30 | SQLCOM_HELP, SQLCOM_CREATE_USER, SQLCOM_DROP_USER, SQLCOM_RENAME_USER, 31 | SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM, 32 | SQLCOM_CREATE_PROCEDURE, SQLCOM_CREATE_SPFUNCTION, SQLCOM_CALL, 33 | 34 | === modified file 'sql/sql_parse.cc' 35 | --- sql/sql_parse.cc 2012-07-05 10:07:26 +0000 36 | +++ sql/sql_parse.cc 2012-08-14 16:09:27 +0000 37 | @@ -3542,6 +3542,13 @@ end_with_restore_list: 38 | case SQLCOM_SHOW_AUTHORS: 39 | res= mysqld_show_authors(thd); 40 | break; 41 | +/* BEGIN CAB MODIFICATION */ 42 | +/* Reason for Modification: */ 43 | +/* Add SQLCOM_SHOW_DISK_USAGE case statement */ 44 | + case SQLCOM_SHOW_DISK_USAGE: 45 | + res = show_disk_usage_command(thd); 46 | + break; 47 | +/* END CAB MODIFICATION */ 48 | case SQLCOM_SHOW_CONTRIBUTORS: 49 | res= mysqld_show_contributors(thd); 50 | break; 51 | 52 | === modified file 'sql/sql_show.cc' 53 | --- sql/sql_show.cc 2012-07-10 14:32:03 +0000 54 | +++ sql/sql_show.cc 2012-08-14 17:24:19 +0000 55 | @@ -280,6 +280,89 @@ bool mysqld_show_authors(THD *thd) 56 | } 57 | 58 | 59 | +/* BEGIN CAB MODIFICATION */ 60 | +/* Reason for Modification: */ 61 | +/* Add show disk usage method */ 62 | +bool show_disk_usage_command(THD *thd) 63 | +{ 64 | + List field_list; 65 | + List dbs; 66 | + LEX_STRING *db_name; 67 | + char *path; 68 | + MY_DIR *dirp; 69 | + FILEINFO *file; 70 | + longlong fsizes = 0; 71 | + longlong lsizes = 0; 72 | + Protocol *protocol= thd->protocol; 73 | + DBUG_ENTER("show_disk_usage"); 74 | + 75 | + /* send the fields "Database" and "Size" */ 76 | + field_list.push_back(new Item_empty_string("Database",50)); 77 | + field_list.push_back(new Item_return_int("Size (Kb)", 7, MYSQL_TYPE_LONG)); 78 | + if (protocol->send_result_set_metadata(&field_list, 79 | + Protocol::SEND_NUM_ROWS | 80 | + Protocol::SEND_EOF)) 81 | + DBUG_RETURN(TRUE); 82 | + 83 | + /* get database directories */ 84 | + find_files_result res = find_files(thd, &dbs, 0, mysql_data_home, 0, 1); 85 | + if (res != FIND_FILES_OK) 86 | + DBUG_RETURN(1); 87 | + 88 | + List_iterator_fast it_dbs(dbs); 89 | + path = (char *)my_malloc(PATH_MAX, MYF(MY_ZEROFILL)); 90 | + dirp = my_dir(mysql_data_home, MYF(MY_WANT_STAT)); 91 | + fsizes = 0; 92 | + for (int i = 0; i < (int)dirp->number_off_files; i++) 93 | + { 94 | + file = dirp->dir_entry + i; 95 | + if (strncasecmp(file->name, "ibdata", 6) == 0) 96 | + fsizes = fsizes + file->mystat->st_size; 97 | + else if (strncasecmp(file->name, "ib", 2) == 0) 98 | + lsizes = lsizes + file->mystat->st_size; 99 | + } 100 | + 101 | + /* send InnoDB data to client */ 102 | + protocol->prepare_for_resend(); 103 | + protocol->store("InnoDB TableSpace", system_charset_info); 104 | + protocol->store((longlong)fsizes); 105 | + if (protocol->write()) 106 | + DBUG_RETURN(TRUE); 107 | + protocol->prepare_for_resend(); 108 | + protocol->store("InnoDB Logs", system_charset_info); 109 | + protocol->store((longlong)lsizes); 110 | + if (protocol->write()) 111 | + DBUG_RETURN(TRUE); 112 | + 113 | + /* now send database name and sizes of the databases */ 114 | + while ((db_name = it_dbs++)) 115 | + { 116 | + fsizes = 0; 117 | + strcpy(path, mysql_data_home); 118 | + strcat(path, "/"); 119 | + strcat(path, db_name->str); 120 | + dirp = my_dir(path, MYF(MY_WANT_STAT)); 121 | + for (int i = 0; i < (int)dirp->number_off_files; i++) 122 | + { 123 | + file = dirp->dir_entry + i; 124 | + fsizes = fsizes + file->mystat->st_size; 125 | + } 126 | + 127 | + protocol->prepare_for_resend(); 128 | + protocol->store(db_name->str, system_charset_info); 129 | + protocol->store((longlong)fsizes); 130 | + if (protocol->write()) 131 | + DBUG_RETURN(TRUE); 132 | + } 133 | + my_eof(thd); 134 | + 135 | + /* free memory */ 136 | + my_free(path); 137 | + DBUG_RETURN(FALSE); 138 | + } 139 | + 140 | +/* END CAB MODIFICATION */ 141 | + 142 | /*************************************************************************** 143 | ** List all Contributors. 144 | ** Please get permission before updating 145 | 146 | === modified file 'sql/sql_show.h' 147 | --- sql/sql_show.h 2012-05-16 06:42:17 +0000 148 | +++ sql/sql_show.h 2012-08-14 16:09:27 +0000 149 | @@ -179,6 +179,11 @@ int mysqld_show_status(THD *thd); 150 | int mysqld_show_variables(THD *thd,const char *wild); 151 | bool mysqld_show_storage_engines(THD *thd); 152 | bool mysqld_show_authors(THD *thd); 153 | +/* BEGIN CAB MODIFICATION */ 154 | +/* Reason for Modification: */ 155 | +/* Add show disk usage method reference */ 156 | +bool show_disk_usage_command(THD *thd); 157 | +/* END CAB MODIFICATION */ 158 | bool mysqld_show_contributors(THD *thd); 159 | bool mysqld_show_privileges(THD *thd); 160 | char *make_backup_log_name(char *buff, const char *name, const char* log_ext); 161 | 162 | === modified file 'sql/sql_yacc.yy' 163 | --- sql/sql_yacc.yy 2012-07-13 08:50:05 +0000 164 | +++ sql/sql_yacc.yy 2012-08-14 16:09:27 +0000 165 | @@ -1145,6 +1145,11 @@ bool my_yyoverflow(short **a, YYSTYPE ** 166 | %token DISABLE_SYM 167 | %token DISCARD 168 | %token DISK_SYM 169 | +/* BEGIN CAB MODIFICATION */ 170 | +/* Reason for Modification: */ 171 | +/* Add DISK_USAGE symbol */ 172 | +%token DISK_USAGE_SYM 173 | +/* END CAB MODIFICATION */ 174 | %token DISTINCT /* SQL-2003-R */ 175 | %token DIV_SYM 176 | %token DOUBLE_SYM /* SQL-2003-R */ 177 | @@ -12279,6 +12284,16 @@ opt_profile_args: 178 | /* Show things */ 179 | 180 | show: 181 | +/* BEGIN CAB MODIFICATION */ 182 | +/* Reason for Modification: */ 183 | +/* Add show disk usage symbol parsing */ 184 | + SHOW DISK_USAGE_SYM 185 | + { 186 | + LEX *lex=Lex; 187 | + lex->sql_command= SQLCOM_SHOW_DISK_USAGE; 188 | + } 189 | + | 190 | +/* END CAB MODIFICATION */ 191 | SHOW 192 | { 193 | LEX *lex=Lex; 194 | 195 | -------------------------------------------------------------------------------- /Ch07/diskusage_is.diff: -------------------------------------------------------------------------------- 1 | === modified file 'sql/handler.h' 2 | --- sql/handler.h 2012-06-11 11:30:25 +0000 3 | +++ sql/handler.h 2012-08-14 17:38:22 +0000 4 | @@ -679,6 +679,7 @@ enum enum_schema_tables 5 | SCH_COLLATION_CHARACTER_SET_APPLICABILITY, 6 | SCH_COLUMNS, 7 | SCH_COLUMN_PRIVILEGES, 8 | + SCH_DISKUSAGE, 9 | SCH_ENGINES, 10 | SCH_EVENTS, 11 | SCH_FILES, 12 | 13 | === modified file 'sql/sql_parse.cc' 14 | --- sql/sql_parse.cc 2012-07-05 10:07:26 +0000 15 | +++ sql/sql_parse.cc 2012-08-14 17:38:22 +0000 16 | @@ -1872,6 +1872,7 @@ int prepare_schema_table(THD *thd, LEX * 17 | DBUG_ENTER("prepare_schema_table"); 18 | 19 | switch (schema_table_idx) { 20 | + case SCH_DISKUSAGE: 21 | case SCH_SCHEMATA: 22 | #if defined(DONT_ALLOW_SHOW_COMMANDS) 23 | my_message(ER_NOT_ALLOWED_COMMAND, 24 | 25 | === modified file 'sql/sql_show.cc' 26 | --- sql/sql_show.cc 2012-07-10 14:32:03 +0000 27 | +++ sql/sql_show.cc 2012-08-14 17:38:22 +0000 28 | @@ -7357,6 +7357,12 @@ int hton_fill_schema_table(THD *thd, TAB 29 | DBUG_RETURN(0); 30 | } 31 | 32 | +ST_FIELD_INFO disk_usage_fields_info[]= 33 | +{ 34 | + {"DATABASE", 40, MYSQL_TYPE_STRING, 0, 0, "Database"}, 35 | + {"SIZE (Kb)", 21 , MYSQL_TYPE_LONG, 0, 0, "Size (Kb)"}, 36 | + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} 37 | +}; 38 | 39 | ST_FIELD_INFO schema_fields_info[]= 40 | { 41 | @@ -8001,6 +8007,74 @@ ST_FIELD_INFO tablespaces_fields_info[]= 42 | /** For creating fields of information_schema.OPTIMIZER_TRACE */ 43 | extern ST_FIELD_INFO optimizer_trace_info[]; 44 | 45 | +int fill_disk_usage(THD *thd, TABLE_LIST *tables, Item *cond) 46 | +{ 47 | + TABLE *table= tables->table; 48 | + CHARSET_INFO *scs= system_charset_info; 49 | + List field_list; 50 | + List dbs; 51 | + LEX_STRING *db_name; 52 | + char *path; 53 | + MY_DIR *dirp; 54 | + FILEINFO *file; 55 | + longlong fsizes = 0; 56 | + longlong lsizes = 0; 57 | + DBUG_ENTER("fill_disk_usage"); 58 | + 59 | + find_files_result res = find_files(thd, &dbs, 0, mysql_data_home, 0, 1); 60 | + if (res != FIND_FILES_OK) 61 | + DBUG_RETURN(1); 62 | + 63 | + List_iterator_fast it_dbs(dbs); 64 | + path = (char *)my_malloc(PATH_MAX, MYF(MY_ZEROFILL)); 65 | + dirp = my_dir(mysql_data_home, MYF(MY_WANT_STAT)); 66 | + fsizes = 0; 67 | + for (int i = 0; i < (int)dirp->number_off_files; i++) 68 | + { 69 | + file = dirp->dir_entry + i; 70 | + if (strncasecmp(file->name, "ibdata", 6) == 0) 71 | + fsizes = fsizes + file->mystat->st_size; 72 | + else if (strncasecmp(file->name, "ib", 2) == 0) 73 | + lsizes = lsizes + file->mystat->st_size; 74 | + } 75 | + 76 | + /* send InnoDB data to client */ 77 | + table->field[0]->store("InnoDB TableSpace", strlen("InnoDB TableSpace"), scs); 78 | + table->field[1]->store((longlong)fsizes, TRUE); 79 | +if (schema_table_store_record(thd, table)) 80 | + DBUG_RETURN(1); 81 | + table->field[0]->store("InnoDB Logs", strlen("InnoDB Logs"), scs); 82 | + table->field[1]->store((longlong)lsizes, TRUE); 83 | + if (schema_table_store_record(thd, table)) 84 | + DBUG_RETURN(1); 85 | + 86 | + /* now send database name and sizes of the databases */ 87 | + while ((db_name = it_dbs++)) 88 | + { 89 | + fsizes = 0; 90 | + strcpy(path, mysql_data_home); 91 | + strcat(path, "/"); 92 | + strcat(path, db_name->str); 93 | + dirp = my_dir(path, MYF(MY_WANT_STAT)); 94 | + for (int i = 0; i < (int)dirp->number_off_files; i++) 95 | + { 96 | + file = dirp->dir_entry + i; 97 | + fsizes = fsizes + file->mystat->st_size; 98 | + } 99 | + restore_record(table, s->default_values); 100 | + 101 | + table->field[0]->store(db_name->str, db_name->length, scs); 102 | + table->field[1]->store((longlong)fsizes, TRUE); 103 | + if (schema_table_store_record(thd, table)) 104 | + DBUG_RETURN(1); 105 | + } 106 | + 107 | + /* free memory */ 108 | + my_free(path); 109 | + DBUG_RETURN(0); 110 | +} 111 | + 112 | + 113 | /* 114 | Description of ST_FIELD_INFO in table.h 115 | 116 | @@ -8023,6 +8097,8 @@ ST_SCHEMA_TABLE schema_tables[]= 117 | fill_schema_column_privileges, 0, 0, -1, -1, 0, 0}, 118 | {"ENGINES", engines_fields_info, create_schema_table, 119 | fill_schema_engines, make_old_format, 0, -1, -1, 0, 0}, 120 | + {"DISKUSAGE", disk_usage_fields_info, create_schema_table, 121 | + fill_disk_usage, make_old_format, 0, -1, -1, 0, 0}, 122 | #ifdef HAVE_EVENT_SCHEDULER 123 | {"EVENTS", events_fields_info, create_schema_table, 124 | Events::fill_schema_events, make_old_format, 0, -1, -1, 0, 0}, 125 | 126 | -------------------------------------------------------------------------------- /Ch07/gregorian.diff: -------------------------------------------------------------------------------- 1 | === modified file 'sql/item_create.cc' 2 | --- sql/item_create.cc 2012-06-28 10:46:42 +0000 3 | +++ sql/item_create.cc 2012-08-14 13:58:16 +0000 4 | @@ -2009,6 +2009,21 @@ protected: 5 | virtual ~Create_func_quote() {} 6 | }; 7 | 8 | +/* BEGIN CAB MODIFICATION */ 9 | +/* Reason for Modification: */ 10 | +/* Add gregorian class definition */ 11 | +class Create_func_gregorian : public Create_func_arg1 12 | +{ 13 | +public: 14 | + virtual Item *create(THD *thd, Item *arg1); 15 | + 16 | + static Create_func_gregorian s_singleton; 17 | + 18 | +protected: 19 | + Create_func_gregorian() {} 20 | + virtual ~Create_func_gregorian() {} 21 | +}; 22 | +/* END CAB MODIFICATION */ 23 | 24 | class Create_func_radians : public Create_func_arg1 25 | { 26 | @@ -4762,6 +4777,17 @@ Create_func_quote::create(THD *thd, Item 27 | return new (thd->mem_root) Item_func_quote(arg1); 28 | } 29 | 30 | +/* BEGIN CAB MODIFICATION */ 31 | +/* Reason for Modification: */ 32 | +/* Add gregorian singleton create method */ 33 | +Create_func_gregorian Create_func_gregorian::s_singleton; 34 | + 35 | +Item* 36 | +Create_func_gregorian::create(THD *thd, Item *arg1) 37 | +{ 38 | + return new (thd->mem_root) Item_func_gregorian(arg1); 39 | +} 40 | +/* END CAB MODIFICATION */ 41 | 42 | Create_func_radians Create_func_radians::s_singleton; 43 | 44 | @@ -5547,6 +5573,11 @@ static Native_func_registry func_array[] 45 | { { C_STRING_WITH_LEN("POW") }, BUILDER(Create_func_pow)}, 46 | { { C_STRING_WITH_LEN("POWER") }, BUILDER(Create_func_pow)}, 47 | { { C_STRING_WITH_LEN("QUOTE") }, BUILDER(Create_func_quote)}, 48 | +/* BEGIN CAB MODIFICATION */ 49 | +/* Reason for Modification: */ 50 | +/* Add gregorian symbol */ 51 | + { { C_STRING_WITH_LEN("GREGORIAN") }, BUILDER(Create_func_gregorian)}, 52 | +/* END CAB MODIFICATION */ 53 | { { C_STRING_WITH_LEN("RADIANS") }, BUILDER(Create_func_radians)}, 54 | { { C_STRING_WITH_LEN("RAND") }, BUILDER(Create_func_rand)}, 55 | { { C_STRING_WITH_LEN("RELEASE_LOCK") }, BUILDER(Create_func_release_lock)}, 56 | 57 | === modified file 'sql/item_strfunc.cc' 58 | --- sql/item_strfunc.cc 2012-06-11 11:30:25 +0000 59 | +++ sql/item_strfunc.cc 2012-08-14 13:58:16 +0000 60 | @@ -4031,6 +4031,50 @@ null: 61 | return 0; 62 | } 63 | 64 | +/* BEGIN CAB MODIFICATION */ 65 | +/* Reason for Modification: */ 66 | +/* Add gregorian function code */ 67 | +String *Item_func_gregorian::val_str(String *str) 68 | +{ 69 | + static int DAYS_IN_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 70 | + longlong jdate = args[0]->val_int(); 71 | + int year = 0; 72 | + int month = 0; 73 | + int day = 0; 74 | + int i; 75 | + char cstr[30]; 76 | + cstr[0] = 0; 77 | + str->length(0); 78 | + 79 | + /* get date from value (right 4 digits */ 80 | + year = jdate - ((jdate / 10000) * 10000); 81 | + 82 | + /* get value for day of year and find current month*/ 83 | + day = (jdate - year) / 10000; 84 | + for (i = 0; i < 12; i++) 85 | + if (DAYS_IN_MONTH[i] < day) 86 | + day = day - DAYS_IN_MONTH[i]; /* remainder is day of current month */ 87 | + else 88 | + { 89 | + month = i + 1; 90 | + break; 91 | + } 92 | + 93 | + /* format date string */ 94 | + sprintf(cstr, "%d", month); 95 | + str->append(cstr); 96 | + str->append("/"); 97 | + sprintf(cstr, "%d", day); 98 | + str->append(cstr); 99 | + str->append("/"); 100 | + sprintf(cstr, "%d", year); 101 | + str->append(cstr); 102 | + if (null_value) 103 | + return 0; 104 | + return str; 105 | +} 106 | +/* END CAB MODIFICATION */ 107 | + 108 | longlong Item_func_uncompressed_length::val_int() 109 | { 110 | DBUG_ASSERT(fixed == 1); 111 | 112 | === modified file 'sql/item_strfunc.h' 113 | --- sql/item_strfunc.h 2012-07-06 15:16:34 +0000 114 | +++ sql/item_strfunc.h 2012-08-14 13:58:16 +0000 115 | @@ -847,6 +847,23 @@ public: 116 | } 117 | }; 118 | 119 | +/* BEGIN CAB MODIFICATION */ 120 | +/* Reason for Modification: */ 121 | +/* Add gregorian Item function code */ 122 | +class Item_func_gregorian :public Item_str_func 123 | +{ 124 | + String tmp_value; 125 | +public: 126 | + Item_func_gregorian(Item *a) :Item_str_func(a) {} 127 | + const char *func_name() const { return "gregorian"; } 128 | + String *val_str(String *); 129 | + void fix_length_and_dec() 130 | + { 131 | + max_length=30; 132 | + } 133 | +}; 134 | +/* END CAB MODIFICATION */ 135 | + 136 | class Item_func_conv_charset :public Item_str_func 137 | { 138 | bool use_cached_value; 139 | 140 | -------------------------------------------------------------------------------- /Ch07/julian.diff: -------------------------------------------------------------------------------- 1 | === modified file 'sql/udf_example.cc' 2 | --- sql/udf_example.cc 2011-12-09 21:08:37 +0000 3 | +++ sql/udf_example.cc 2012-08-13 23:45:19 +0000 4 | @@ -166,6 +166,9 @@ double avgcost( UDF_INIT* initid, UDF_AR 5 | my_bool is_const_init(UDF_INIT *initid, UDF_ARGS *args, char *message); 6 | char *is_const(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long 7 | *length, char *is_null, char *error); 8 | +my_bool julian_init(UDF_INIT *initid, UDF_ARGS *args, char *message); 9 | +longlong julian(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error); 10 | +void julian_deinit(UDF_INIT *initid); 11 | C_MODE_END; 12 | 13 | /************************************************************************* 14 | @@ -1142,6 +1145,61 @@ char * check_const_len(UDF_INIT *initid, 15 | return result; 16 | } 17 | 18 | +extern "C" my_bool julian_init(UDF_INIT *initid, UDF_ARGS *args, char *message) 19 | +{ 20 | + if (args->arg_count != 3) /* if there are not three arguments */ 21 | + { 22 | + strcpy(message, "Wrong number of arguments: JULIAN() requires 3 arguments."); 23 | + return 1; 24 | + } 25 | + if ((args->arg_type[0] != INT_RESULT) || 26 | + (args->arg_type[1] != INT_RESULT) || 27 | + (args->arg_type[2] != INT_RESULT)) 28 | + { 29 | + strcpy(message, "Wrong type of arguments: JULIAN() requires 3 integers."); 30 | + return 1; 31 | + } 32 | + return 0; 33 | +} 34 | + 35 | +extern "C" void julian_deinit(UDF_INIT *initid) 36 | +{ 37 | +} 38 | + 39 | + 40 | +extern "C" longlong julian(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) 41 | +{ 42 | + longlong jdate = 0; 43 | + static int DAYS_IN_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 44 | + int month = 0; 45 | + int day = 0; 46 | + int year = 0; 47 | + int i; 48 | + 49 | + /* copy memory from the arguments */ 50 | + memcpy(&month, args->args[0], args->lengths[0]); 51 | + memcpy(&day, args->args[1], args->lengths[1]); 52 | + memcpy(&year, args->args[2], args->lengths[2]); 53 | + 54 | + /* add the days in the month for each prior month */ 55 | + for (i = 0; i < month - 1; i++) 56 | + jdate += DAYS_IN_MONTH[i]; 57 | + 58 | + /* add the day of this month */ 59 | + jdate += day; 60 | + 61 | + /* find the year */ 62 | + if (((year % 100) != 0) && ((year % 4) == 0)) 63 | + jdate++; /*leap year!*/ 64 | + 65 | + /* shift day of year to left */ 66 | + jdate *= 10000; 67 | + 68 | + /* add the year */ 69 | + jdate += year; 70 | + return jdate; 71 | +} 72 | + 73 | 74 | C_MODE_START; 75 | my_bool my_median_init (UDF_INIT *initid, UDF_ARGS *args, char *message); 76 | 77 | === modified file 'sql/udf_example.def' 78 | --- sql/udf_example.def 2011-10-11 04:27:52 +0000 79 | +++ sql/udf_example.def 2012-08-13 22:51:32 +0000 80 | @@ -30,3 +30,6 @@ EXPORTS 81 | my_median_add 82 | my_median_clear 83 | my_median 84 | + julian_init 85 | + julian_deinit 86 | + julian 87 | \ No newline at end of file 88 | 89 | -------------------------------------------------------------------------------- /Ch07/source_Ch07.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Ch07/source_Ch07.zip -------------------------------------------------------------------------------- /Ch08/source_Ch08.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Ch08/source_Ch08.zip -------------------------------------------------------------------------------- /Ch08/stop_slaves.diff: -------------------------------------------------------------------------------- 1 | === modified file 'sql/lex.h' 2 | --- sql/lex.h 2012-05-03 08:35:47 +0000 3 | +++ sql/lex.h 2012-08-25 17:48:07 +0000 4 | @@ -519,6 +519,11 @@ static SYMBOL symbols[] = { 5 | { "SIGNED", SYM(SIGNED_SYM)}, 6 | { "SIMPLE", SYM(SIMPLE_SYM)}, 7 | { "SLAVE", SYM(SLAVE)}, 8 | +/* BEGIN CAB MODIFICATION */ 9 | +/* Reason for Modification: */ 10 | +/* Add SLAVES keyword */ 11 | + { "SLAVES", SYM(SLAVES)}, 12 | +/* END CAB MODIFICATION */ 13 | { "SLOW", SYM(SLOW)}, 14 | { "SNAPSHOT", SYM(SNAPSHOT_SYM)}, 15 | { "SMALLINT", SYM(SMALLINT)}, 16 | 17 | === modified file 'sql/sql_cmd.h' 18 | --- sql/sql_cmd.h 2012-05-28 09:09:33 +0000 19 | +++ sql/sql_cmd.h 2012-08-25 17:48:07 +0000 20 | @@ -53,7 +53,11 @@ enum enum_sql_command { 21 | SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, 22 | SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT, 23 | SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_RELEASE_SAVEPOINT, 24 | - SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, 25 | +/* BEGIN CAB MODIFICATION */ 26 | +/* Reason for Modification: */ 27 | +/* Add SQLCOM_STOP_SLAVES enum */ 28 | + SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, SQLCOM_STOP_SLAVES, 29 | +/* END CAB MODIFICATION */ 30 | SQLCOM_BEGIN, SQLCOM_CHANGE_MASTER, 31 | SQLCOM_RENAME_TABLE, 32 | SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_PURGE_BEFORE, SQLCOM_SHOW_BINLOGS, 33 | 34 | === modified file 'sql/sql_parse.cc' 35 | --- sql/sql_parse.cc 2012-07-05 10:07:26 +0000 36 | +++ sql/sql_parse.cc 2012-08-25 17:48:07 +0000 37 | @@ -3054,6 +3054,18 @@ end_with_restore_list: 38 | mysql_mutex_unlock(&LOCK_active_mi); 39 | break; 40 | } 41 | + 42 | +/* BEGIN CAB MODIFICATION */ 43 | +/* Reason for Modification: */ 44 | +/* Add case statement for STOP ALL SLAVES command */ 45 | + case SQLCOM_STOP_SLAVES: 46 | + { 47 | + if (!lex->no_write_to_binlog) 48 | + res= write_bin_log(thd, TRUE, "STOP SLAVE IO_THREAD", 20); 49 | + break; 50 | + } 51 | +/* END CAB MODIFICATION */ 52 | + 53 | #endif /* HAVE_REPLICATION */ 54 | 55 | case SQLCOM_RENAME_TABLE: 56 | 57 | === modified file 'sql/sql_yacc.yy' 58 | --- sql/sql_yacc.yy 2012-07-13 08:50:05 +0000 59 | +++ sql/sql_yacc.yy 2012-08-25 18:10:24 +0000 60 | @@ -1497,6 +1497,11 @@ bool my_yyoverflow(short **a, YYSTYPE ** 61 | %token SIGNED_SYM 62 | %token SIMPLE_SYM /* SQL-2003-N */ 63 | %token SLAVE 64 | +/* BEGIN CAB MODIFICATION */ 65 | +/* Reason for Modification: */ 66 | +/* Add SLAVES token */ 67 | +%token SLAVES 68 | +/* END CAB MODIFICATION */ 69 | %token SLOW 70 | %token SMALLINT /* SQL-2003-R */ 71 | %token SNAPSHOT_SYM 72 | @@ -1808,7 +1813,11 @@ bool my_yyoverflow(short **a, YYSTYPE ** 73 | show describe load alter optimize keycache preload flush 74 | reset purge begin commit rollback savepoint release 75 | slave master_def master_defs master_file_def slave_until_opts 76 | - repair analyze check start checksum 77 | +/* BEGIN CAB MODIFICATION */ 78 | +/* Reason for Modification: */ 79 | +/* Add stop to list of NONE types */ 80 | + repair analyze check start stop checksum 81 | +/* END CAB MODIFICATION */ 82 | field_list field_list_item field_spec kill column_def key_def 83 | keycache_list keycache_list_or_parts assign_to_keycache 84 | assign_to_keycache_parts 85 | @@ -2026,6 +2035,11 @@ statement: 86 | | show 87 | | slave 88 | | start 89 | +/* BEGIN CAB MODIFICATION */ 90 | +/* Reason for Modification: */ 91 | +/* Add stop to list of statement targets */ 92 | + | stop 93 | +/* END CAB MODIFICATION */ 94 | | truncate 95 | | uninstall 96 | | unlock 97 | @@ -8013,6 +8027,18 @@ slave: 98 | } 99 | ; 100 | 101 | +/* BEGIN CAB MODIFICATION */ 102 | +/* Reason for Modification: */ 103 | +/* Add rule for STOP ALL SLAVES command */ 104 | +stop: 105 | + STOP_SYM ALL SLAVES 106 | + { 107 | + LEX *lex=Lex; 108 | + lex->sql_command = SQLCOM_STOP_SLAVES; 109 | + } 110 | + ; 111 | +/* END CAB MODIFICATION */ 112 | + 113 | start: 114 | START_SYM TRANSACTION_SYM opt_start_transaction_option_list 115 | { 116 | 117 | -------------------------------------------------------------------------------- /Ch09/rfid_auth/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # cmake configuration file for the RFID Authentication Plugin 2 | 3 | MYSQL_ADD_PLUGIN(rfid_auth rfid_auth.cc 4 | MODULE_ONLY MODULE_OUTPUT_NAME "rfid_auth") 5 | 6 | INSTALL(FILES rfid_auth.ini DESTINATION ${INSTALL_PLUGINDIR}) 7 | -------------------------------------------------------------------------------- /Ch09/rfid_auth/rfid_auth.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef __WIN__ 13 | 14 | #include 15 | #include 16 | 17 | #else 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | using namespace std; 24 | 25 | /* 26 | Get password with no echo. 27 | */ 28 | char *getpass(const char *prompt) 29 | { 30 | string pass =""; 31 | char ch; 32 | cout << prompt; 33 | ch = _getch(); 34 | while(ch != 13) //character 13 is enter key 35 | { 36 | pass.push_back(ch); 37 | ch = _getch(); 38 | } 39 | return (char *)pass.c_str(); 40 | } 41 | 42 | #endif 43 | 44 | #define MAX_RFID_CODE 12 45 | #define MAX_BUFFER 255 46 | #define MAX_PIN 16 47 | 48 | /* Client-side plugin */ 49 | 50 | 51 | /* 52 | * Read a RFID code from the serial port. 53 | */ 54 | #ifndef __WIN__ 55 | unsigned char *get_rfid_code(char *port) 56 | { 57 | int fd; 58 | unsigned char *rfid_code= NULL; 59 | int nbytes; 60 | unsigned char raw_buff[MAX_BUFFER]; 61 | unsigned char *bufptr = NULL; 62 | 63 | fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY); 64 | if (fd == -1) 65 | { 66 | printf("Unable to open port: %s.\n", port); 67 | return NULL; 68 | } 69 | else 70 | fcntl(fd, F_SETFL, 0); 71 | 72 | bufptr = raw_buff; 73 | while ((nbytes = read(fd, bufptr, raw_buff + sizeof(raw_buff) - bufptr - 1)) > 0) 74 | { 75 | bufptr += nbytes; 76 | if (bufptr[-1] == '\n' || bufptr[-2] == '\n' || bufptr[-3] == '\n' || 77 | bufptr[-1] == '\r' || bufptr[-2] == '\r' || bufptr[-3] == '\r' || 78 | bufptr[-1] == 0x03 || bufptr[-2] == 0x03 || bufptr[-3] == 0x03) 79 | break; 80 | } 81 | *bufptr = '\0'; 82 | 83 | rfid_code = (unsigned char *)strdup((char *)raw_buff); 84 | return rfid_code; 85 | } 86 | 87 | #else 88 | 89 | unsigned char *get_rfid_code(char *port) 90 | { 91 | HANDLE com_port; 92 | DWORD nbytes; 93 | unsigned char raw_buff[MAX_BUFFER]; 94 | unsigned char *rfid_code= NULL; 95 | 96 | /* Open the port specified. */ 97 | com_port = CreateFile(port, GENERIC_READ, 0, 0, OPEN_EXISTING, 98 | FILE_ATTRIBUTE_NORMAL, 0); 99 | if (com_port == INVALID_HANDLE_VALUE) 100 | { 101 | int error = GetLastError(); 102 | if (error == ERROR_FILE_NOT_FOUND) 103 | { 104 | printf("Unable to open port: %s.\n", port); 105 | return NULL; 106 | } 107 | printf("Error opening port: %s:%d.\n", port, error); 108 | return NULL; 109 | } 110 | 111 | /* Configure the port. */ 112 | DCB com_config = {0}; 113 | com_config.DCBlength = sizeof(com_config); 114 | if (!GetCommState(com_port, &com_config)) 115 | { 116 | printf("Unable to get port state.\n"); 117 | return NULL; 118 | } 119 | com_config.BaudRate = CBR_9600; 120 | com_config.ByteSize = 8; 121 | com_config.Parity = NOPARITY; 122 | com_config.StopBits = ONESTOPBIT; 123 | if (!SetCommState(com_port, &com_config)) 124 | { 125 | printf("Unable to set port state.\n"); 126 | return NULL; 127 | } 128 | 129 | /* Set timeouts. */ 130 | COMMTIMEOUTS timeouts = {0}; 131 | timeouts.ReadIntervalTimeout=50; 132 | timeouts.ReadTotalTimeoutConstant=50; 133 | timeouts.ReadTotalTimeoutMultiplier=10; 134 | if (!SetCommTimeouts(com_port, &timeouts)) 135 | { 136 | printf("Cannot set timeouts for port.\n"); 137 | return NULL; 138 | } 139 | 140 | /* Read from the port. */ 141 | if (!ReadFile(com_port, raw_buff, MAX_BUFFER, &nbytes, NULL)) 142 | { 143 | printf("Unable to read from the port.\n"); 144 | return NULL; 145 | } 146 | 147 | /* Close the port. */ 148 | CloseHandle(com_port); 149 | 150 | rfid_code = (unsigned char *)strdup((char *)raw_buff); 151 | return rfid_code; 152 | } 153 | 154 | #endif /* __WIN__ */ 155 | 156 | static int rfid_send(MYSQL_PLUGIN_VIO *vio, st_mysql *mysql) 157 | { 158 | char *port= 0; 159 | char pass[MAX_PIN]; 160 | int len, res; 161 | unsigned char buffer[MAX_BUFFER]; 162 | unsigned char *raw_buff= NULL; 163 | int start= 0; 164 | 165 | /* Get the port to open. */ 166 | port= getenv("MYSQL_RFID_PORT"); 167 | if (!port) 168 | { 169 | printf("Environment variable not set.\n"); 170 | return CR_ERROR; 171 | } 172 | 173 | printf("Please swipe your card now...\n"); 174 | 175 | raw_buff = get_rfid_code(port); 176 | if (raw_buff == NULL) 177 | { 178 | printf("Cannot read RFID code.\n"); 179 | return CR_ERROR; 180 | } 181 | len = strlen((char *)raw_buff); 182 | 183 | // Strip off leading extra bytes. 184 | for (int j= 0; j < 2; j++) 185 | if (raw_buff[j] == 0x02 || raw_buff[j] == 0x03) 186 | start++; 187 | 188 | strncpy((char *)buffer, (char *)raw_buff+start, len-start); 189 | len = strlen((char *)buffer); 190 | /* Check for valid read. */ 191 | if (len >= MAX_RFID_CODE) 192 | { 193 | // Strip off extra bytes at end (CR, LF, etc) 194 | buffer[MAX_RFID_CODE] = '\0'; 195 | len = MAX_RFID_CODE; 196 | } 197 | else 198 | { 199 | printf("RFID code length error. Please try again.\n"); 200 | return CR_ERROR; 201 | } 202 | 203 | strncpy(pass, getpass("Please enter your PIN: "), sizeof(pass)); 204 | strcat((char *)buffer, pass); 205 | len = strlen((char *)buffer); 206 | 207 | res= vio->write_packet(vio, buffer, len); 208 | 209 | return res ? CR_ERROR : CR_OK; 210 | } 211 | 212 | mysql_declare_client_plugin(AUTHENTICATION) 213 | "rfid_auth", 214 | "Chuck Bell", 215 | "RFID Authentication Plugin - Client", 216 | {0, 0, 1}, 217 | "GPL", 218 | NULL, 219 | NULL, 220 | NULL, 221 | NULL, 222 | rfid_send 223 | mysql_end_client_plugin; 224 | 225 | 226 | /* 227 | * Server-side plugin 228 | */ 229 | static int rfid_auth_validate(MYSQL_PLUGIN_VIO *vio, 230 | MYSQL_SERVER_AUTH_INFO *info) 231 | { 232 | unsigned char *pkt; 233 | int pkt_len, err= CR_OK; 234 | 235 | if ((pkt_len= vio->read_packet(vio, &pkt)) < 0) 236 | return CR_ERROR; 237 | 238 | info->password_used= PASSWORD_USED_YES; 239 | 240 | if (strcmp((const char *) pkt, info->auth_string)) 241 | return CR_ERROR; 242 | 243 | return err; 244 | } 245 | 246 | static struct st_mysql_auth rfid_auth_handler= 247 | { 248 | MYSQL_AUTHENTICATION_INTERFACE_VERSION, 249 | "rfid_auth", 250 | rfid_auth_validate 251 | }; 252 | 253 | mysql_declare_plugin(rfid_auth_plugin) 254 | { 255 | MYSQL_AUTHENTICATION_PLUGIN, 256 | &rfid_auth_handler, 257 | "rfid_auth", 258 | "Chuck Bell", 259 | "RFID Authentication Plugin - Server", 260 | PLUGIN_LICENSE_GPL, 261 | NULL, 262 | NULL, 263 | 0x0100, 264 | NULL, 265 | NULL, 266 | NULL, 267 | 0, 268 | } 269 | mysql_declare_plugin_end; 270 | -------------------------------------------------------------------------------- /Ch09/rfid_auth/rfid_auth.ini: -------------------------------------------------------------------------------- 1 | # 2 | # Plugin configuration file. Place the following on a separate line: 3 | # 4 | # library binary file name (without .so or .dll) 5 | # component_name 6 | # [component_name] - additional components in plugin 7 | # 8 | librfid_auth 9 | rfid_auth 10 | -------------------------------------------------------------------------------- /Ch09/source_Ch09.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Ch09/source_Ch09.zip -------------------------------------------------------------------------------- /Ch10/source_Ch10.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Ch10/source_Ch10.zip -------------------------------------------------------------------------------- /Ch10/stage_five/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Spartan storage engine plugin 2 | 3 | SET(SPARTAN_PLUGIN_STATIC "spartan") 4 | SET(SPARTAN_PLUGIN_DYNAMIC "spartan") 5 | 6 | SET(SPARTAN_SOURCES 7 | ha_spartan.cc ha_spartan.h 8 | spartan_data.cc spartan_data.h 9 | spartan_index.cc spartan_index.h 10 | ) 11 | 12 | MYSQL_ADD_PLUGIN(spartan ${SPARTAN_SOURCES} STORAGE_ENGINE MODULE_ONLY) 13 | 14 | TARGET_LINK_LIBRARIES(spartan mysys) 15 | -------------------------------------------------------------------------------- /Ch10/stage_five/Ch10s5.test: -------------------------------------------------------------------------------- 1 | # 2 | # Simple test for the Spartan storage engine 3 | # 4 | --disable_warnings 5 | drop table if exists t1; 6 | --enable_warnings 7 | 8 | CREATE TABLE t1 ( 9 | col_a int KEY, 10 | col_b varchar(20), 11 | col_c int 12 | ) ENGINE=SPARTAN; 13 | 14 | INSERT INTO t1 VALUES (1, "first test", 24); 15 | INSERT INTO t1 VALUES (2, "second test", 43); 16 | INSERT INTO t1 VALUES (9, "fourth test", -2); 17 | INSERT INTO t1 VALUES (3, 'eighth test', -22); 18 | INSERT INTO t1 VALUES (4, "tenth test", 11); 19 | INSERT INTO t1 VALUES (8, "seventh test", 20); 20 | INSERT INTO t1 VALUES (5, "third test", 100); 21 | SELECT * FROM t1; 22 | UPDATE t1 SET col_b = "Updated!" WHERE col_a = 1; 23 | SELECT * from t1; 24 | UPDATE t1 SET col_b = "Updated!" WHERE col_a = 3; 25 | SELECT * from t1; 26 | UPDATE t1 SET col_b = "Updated!" WHERE col_a = 5; 27 | SELECT * from t1; 28 | DELETE FROM t1 WHERE col_a = 1; 29 | SELECT * FROM t1; 30 | DELETE FROM t1 WHERE col_a = 3; 31 | SELECT * FROM t1; 32 | DELETE FROM t1 WHERE col_a = 5; 33 | SELECT * FROM t1; 34 | SELECT * FROM t1 WHERE col_a = 4; 35 | SELECT * FROM t1 WHERE col_a >= 2 AND col_a <= 5; 36 | SELECT * FROM t1 WHERE col_a = 22; 37 | DELETE FROM t1 WHERE col_a = 5; 38 | SELECT * FROM t1; 39 | SELECT * FROM t1 WHERE col_a = 5; 40 | UPDATE t1 SET col_a = 99 WHERE col_a = 8; 41 | SELECT * FROM t1 WHERE col_a = 8; 42 | SELECT * FROM t1 WHERE col_a = 99; 43 | RENAME TABLE t1 TO t2; 44 | SELECT * FROM t2; 45 | DROP TABLE t2; 46 | -------------------------------------------------------------------------------- /Ch10/stage_five/ha_spartan.h: -------------------------------------------------------------------------------- 1 | /* 2 | Spartan Storage Engine Plugin 3 | */ 4 | 5 | #include "my_global.h" /* ulonglong */ 6 | #include "thr_lock.h" /* THR_LOCK, THR_LOCK_DATA */ 7 | #include "handler.h" /* handler */ 8 | #include "spartan_data.h" 9 | #include "spartan_index.h" 10 | 11 | class Spartan_share : public Handler_share { 12 | public: 13 | mysql_mutex_t mutex; 14 | THR_LOCK lock; 15 | Spartan_data *data_class; 16 | Spartan_index *index_class; 17 | Spartan_share(); 18 | ~Spartan_share() 19 | { 20 | thr_lock_delete(&lock); 21 | mysql_mutex_destroy(&mutex); 22 | if (data_class != NULL) 23 | delete data_class; 24 | data_class = NULL; 25 | if (index_class != NULL) 26 | delete index_class; 27 | index_class = NULL; 28 | } 29 | }; 30 | 31 | /* 32 | Class definition for the storage engine 33 | */ 34 | class ha_spartan: public handler 35 | { 36 | THR_LOCK_DATA lock; /* MySQL lock */ 37 | Spartan_share *share; ///< Shared lock info 38 | Spartan_share *get_share(); ///< Get the share 39 | off_t current_position; /* Current position in the file during a file scan */ 40 | 41 | public: 42 | ha_spartan(handlerton *hton, TABLE_SHARE *table_ar); 43 | ~ha_spartan() 44 | { 45 | } 46 | /* The name that will be used for display purposes */ 47 | const char *table_type() const { return "SPARTAN"; } 48 | /* 49 | The name of the index type that will be used for display 50 | don't implement this method unless you really have indexes 51 | */ 52 | const char *index_type(uint inx) { return "Spartan_index"; } 53 | /* 54 | The file extensions. 55 | */ 56 | const char **bas_ext() const; 57 | /* 58 | This is a list of flags that says what the storage engine 59 | implements. The current table flags are documented in 60 | handler.h 61 | */ 62 | ulonglong table_flags() const 63 | { 64 | return (HA_NO_BLOBS | HA_NO_AUTO_INCREMENT | HA_BINLOG_STMT_CAPABLE); 65 | } 66 | /* 67 | This is a bitmap of flags that says how the storage engine 68 | implements indexes. The current index flags are documented in 69 | handler.h. If you do not implement indexes, just return zero 70 | here. 71 | 72 | part is the key part to check. First key part is 0 73 | If all_parts it's set, MySQL want to know the flags for the combined 74 | index up to and including 'part'. 75 | */ 76 | ulong index_flags(uint inx, uint part, bool all_parts) const 77 | { 78 | return (HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | 79 | HA_READ_ORDER | HA_KEYREAD_ONLY); 80 | } 81 | /* 82 | unireg.cc will call the following to make sure that the storage engine can 83 | handle the data it is about to send. 84 | 85 | Return *real* limits of your storage engine here. MySQL will do 86 | min(your_limits, MySQL_limits) automatically 87 | 88 | There is no need to implement ..._key_... methods if you don't suport 89 | indexes. 90 | */ 91 | uint max_supported_keys() const { return 1; } 92 | uint max_supported_key_parts() const { return 1; } 93 | uint max_supported_key_length() const { return 128; } 94 | /* 95 | Called in test_quick_select to determine if indexes should be used. 96 | */ 97 | virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; } 98 | /* 99 | The next method will never be called if you do not implement indexes. 100 | */ 101 | virtual double read_time(uint, uint, ha_rows rows) 102 | { return (double) rows / 20.0+1; } 103 | 104 | /* 105 | Everything below are methods that we implment in ha_spartan.cc. 106 | 107 | Most of these methods are not obligatory, skip them and 108 | MySQL will treat them as not implemented 109 | */ 110 | int open(const char *name, int mode, uint test_if_locked); // required 111 | int close(void); // required 112 | 113 | int write_row(uchar * buf); 114 | int update_row(const uchar * old_data, uchar * new_data); 115 | int delete_row(const uchar * buf); 116 | int index_read_map(uchar *buf, const uchar *key, 117 | key_part_map keypart_map, enum ha_rkey_function find_flag); 118 | int index_next(uchar * buf); 119 | int index_prev(uchar * buf); 120 | int index_first(uchar * buf); 121 | int index_last(uchar * buf); 122 | /* 123 | unlike index_init(), rnd_init() can be called two times 124 | without rnd_end() in between (it only makes sense if scan=1). 125 | then the second call should prepare for the new table scan 126 | (e.g if rnd_init allocates the cursor, second call should 127 | position it to the start of the table, no need to deallocate 128 | and allocate it again 129 | */ 130 | int rnd_init(bool scan); //required 131 | int rnd_end(); 132 | int rnd_next(uchar *buf); //required 133 | int rnd_pos(uchar * buf, uchar *pos); //required 134 | void position(const uchar *record); //required 135 | int info(uint); //required 136 | 137 | int extra(enum ha_extra_function operation); 138 | int external_lock(THD *thd, int lock_type); //required 139 | int delete_all_rows(void); 140 | int truncate(); 141 | ha_rows records_in_range(uint inx, key_range *min_key, 142 | key_range *max_key); 143 | int delete_table(const char *from); 144 | int rename_table(const char * from, const char * to); 145 | int create(const char *name, TABLE *form, 146 | HA_CREATE_INFO *create_info); //required 147 | 148 | THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, 149 | enum thr_lock_type lock_type); //required 150 | uchar *get_key(); 151 | int get_key_len(); 152 | }; 153 | 154 | -------------------------------------------------------------------------------- /Ch10/stage_five/spartan_data.h: -------------------------------------------------------------------------------- 1 | /* 2 | Spartan_data.h 3 | 4 | This header defines a simple data file class for reading raw data to and 5 | from disk. The data written is in byte format so it can be anything you 6 | want it to be. The write_row and read_row accept the length of the data 7 | item to be read. 8 | */ 9 | #include "my_global.h" 10 | #include "my_sys.h" 11 | 12 | class Spartan_data 13 | { 14 | public: 15 | Spartan_data(void); 16 | ~Spartan_data(void); 17 | int create_table(char *path); 18 | int open_table(char *path); 19 | long long write_row(uchar *buf, int length); 20 | long long update_row(uchar *old_rec, uchar *new_rec, 21 | int length, long long position); 22 | int read_row(uchar *buf, int length, long long position); 23 | int delete_row(uchar *old_rec, int length, long long position); 24 | int close_table(); 25 | long long cur_position(); 26 | int records(); 27 | int del_records(); 28 | int trunc_table(); 29 | int row_size(int length); 30 | private: 31 | File data_file; 32 | int header_size; 33 | int record_header_size; 34 | bool crashed; 35 | int number_records; 36 | int number_del_records; 37 | int read_header(); 38 | int write_header(); 39 | }; 40 | -------------------------------------------------------------------------------- /Ch10/stage_five/spartan_index.h: -------------------------------------------------------------------------------- 1 | /* 2 | Spartan_index.h 3 | 4 | This header file defines a simple index class that can 5 | be used to store file pointer indexes (long long). The 6 | class keeps the entire index in memory for fast access. 7 | The internal memory structure is a linked list. While 8 | not as efficient as a btree, it should be usable for 9 | most testing environments. The constructor accepts the 10 | max key length. This is used for all nodes in the index. 11 | 12 | File Layout: 13 | SOF max_key_len (int) 14 | SOF + sizeof(int) crashed (bool) 15 | SOF + sizeof(int) + sizeof(bool) DATA BEGINS HERE 16 | */ 17 | #include "my_global.h" 18 | #include "my_sys.h" 19 | 20 | const long METADATA_SIZE = sizeof(int) + sizeof(bool); 21 | /* 22 | This is the node that stores the key and the file 23 | position for the data row. 24 | */ 25 | struct SDE_INDEX 26 | { 27 | uchar key[128]; 28 | long long pos; 29 | int length; 30 | }; 31 | 32 | /* defines (doubly) linked list for internal list */ 33 | struct SDE_NDX_NODE 34 | { 35 | SDE_INDEX key_ndx; 36 | SDE_NDX_NODE *next; 37 | SDE_NDX_NODE *prev; 38 | }; 39 | 40 | class Spartan_index 41 | { 42 | public: 43 | Spartan_index(int keylen); 44 | Spartan_index(); 45 | ~Spartan_index(void); 46 | int open_index(char *path); 47 | int create_index(char *path, int keylen); 48 | int insert_key(SDE_INDEX *ndx, bool allow_dupes); 49 | int delete_key(uchar *buf, long long pos, int key_len); 50 | int update_key(uchar *buf, long long pos, int key_len); 51 | long long get_index_pos(uchar *buf, int key_len); 52 | long long get_first_pos(); 53 | uchar *get_first_key(); 54 | uchar *get_last_key(); 55 | uchar *get_next_key(); 56 | uchar *get_prev_key(); 57 | int close_index(); 58 | int load_index(); 59 | int destroy_index(); 60 | SDE_INDEX *seek_index(uchar *key, int key_len); 61 | SDE_NDX_NODE *seek_index_pos(uchar *key, int key_len); 62 | int save_index(); 63 | int trunc_index(); 64 | private: 65 | File index_file; 66 | int max_key_len; 67 | SDE_NDX_NODE *root; 68 | SDE_NDX_NODE *range_ptr; 69 | int block_size; 70 | bool crashed; 71 | int read_header(); 72 | int write_header(); 73 | long long write_row(SDE_INDEX *ndx); 74 | SDE_INDEX *read_row(long long Position); 75 | long long curfpos(); 76 | }; 77 | -------------------------------------------------------------------------------- /Ch10/stage_four/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Spartan storage engine plugin 2 | 3 | SET(SPARTAN_PLUGIN_STATIC "spartan") 4 | SET(SPARTAN_PLUGIN_DYNAMIC "spartan") 5 | 6 | SET(SPARTAN_SOURCES ha_spartan.cc ha_spartan.h spartan_data.cc spartan_data.h) 7 | 8 | MYSQL_ADD_PLUGIN(spartan ${SPARTAN_SOURCES} STORAGE_ENGINE MODULE_ONLY) 9 | 10 | TARGET_LINK_LIBRARIES(spartan mysys) 11 | -------------------------------------------------------------------------------- /Ch10/stage_four/Ch10s4.test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Ch10/stage_four/Ch10s4.test -------------------------------------------------------------------------------- /Ch10/stage_four/ha_spartan.h: -------------------------------------------------------------------------------- 1 | /* 2 | Spartan Storage Engine Plugin 3 | */ 4 | 5 | #include "my_global.h" /* ulonglong */ 6 | #include "thr_lock.h" /* THR_LOCK, THR_LOCK_DATA */ 7 | #include "handler.h" /* handler */ 8 | #include "spartan_data.h" 9 | 10 | class Spartan_share : public Handler_share { 11 | public: 12 | mysql_mutex_t mutex; 13 | THR_LOCK lock; 14 | Spartan_data *data_class; 15 | Spartan_share(); 16 | ~Spartan_share() 17 | { 18 | thr_lock_delete(&lock); 19 | mysql_mutex_destroy(&mutex); 20 | if (data_class != NULL) 21 | delete data_class; 22 | data_class = NULL; 23 | } 24 | }; 25 | 26 | /* 27 | Class definition for the storage engine 28 | */ 29 | class ha_spartan: public handler 30 | { 31 | THR_LOCK_DATA lock; /* MySQL lock */ 32 | Spartan_share *share; ///< Shared lock info 33 | Spartan_share *get_share(); ///< Get the share 34 | off_t current_position; /* Current position in the file during a file scan */ 35 | 36 | public: 37 | ha_spartan(handlerton *hton, TABLE_SHARE *table_ar); 38 | ~ha_spartan() 39 | { 40 | } 41 | /* The name that will be used for display purposes */ 42 | const char *table_type() const { return "SPARTAN"; } 43 | /* 44 | The name of the index type that will be used for display 45 | don't implement this method unless you really have indexes 46 | */ 47 | const char *index_type(uint inx) { return "HASH"; } 48 | /* 49 | The file extensions. 50 | */ 51 | const char **bas_ext() const; 52 | /* 53 | This is a list of flags that says what the storage engine 54 | implements. The current table flags are documented in 55 | handler.h 56 | */ 57 | ulonglong table_flags() const 58 | { 59 | return HA_BINLOG_STMT_CAPABLE; 60 | } 61 | /* 62 | This is a bitmap of flags that says how the storage engine 63 | implements indexes. The current index flags are documented in 64 | handler.h. If you do not implement indexes, just return zero 65 | here. 66 | 67 | part is the key part to check. First key part is 0 68 | If all_parts it's set, MySQL want to know the flags for the combined 69 | index up to and including 'part'. 70 | */ 71 | ulong index_flags(uint inx, uint part, bool all_parts) const 72 | { 73 | return 0; 74 | } 75 | /* 76 | unireg.cc will call the following to make sure that the storage engine can 77 | handle the data it is about to send. 78 | 79 | Return *real* limits of your storage engine here. MySQL will do 80 | min(your_limits, MySQL_limits) automatically 81 | 82 | There is no need to implement ..._key_... methods if you don't suport 83 | indexes. 84 | */ 85 | uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; } 86 | uint max_supported_keys() const { return 0; } 87 | uint max_supported_key_parts() const { return 0; } 88 | uint max_supported_key_length() const { return 0; } 89 | /* 90 | Called in test_quick_select to determine if indexes should be used. 91 | */ 92 | virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; } 93 | /* 94 | The next method will never be called if you do not implement indexes. 95 | */ 96 | virtual double read_time(uint, uint, ha_rows rows) 97 | { return (double) rows / 20.0+1; } 98 | 99 | /* 100 | Everything below are methods that we implment in ha_spartan.cc. 101 | 102 | Most of these methods are not obligatory, skip them and 103 | MySQL will treat them as not implemented 104 | */ 105 | int open(const char *name, int mode, uint test_if_locked); // required 106 | int close(void); // required 107 | 108 | int write_row(uchar * buf); 109 | int update_row(const uchar * old_data, uchar * new_data); 110 | int delete_row(const uchar * buf); 111 | int index_read_map(uchar *buf, const uchar *key, 112 | key_part_map keypart_map, enum ha_rkey_function find_flag); 113 | int index_next(uchar * buf); 114 | int index_prev(uchar * buf); 115 | int index_first(uchar * buf); 116 | int index_last(uchar * buf); 117 | /* 118 | unlike index_init(), rnd_init() can be called two times 119 | without rnd_end() in between (it only makes sense if scan=1). 120 | then the second call should prepare for the new table scan 121 | (e.g if rnd_init allocates the cursor, second call should 122 | position it to the start of the table, no need to deallocate 123 | and allocate it again 124 | */ 125 | int rnd_init(bool scan); //required 126 | int rnd_end(); 127 | int rnd_next(uchar *buf); //required 128 | int rnd_pos(uchar * buf, uchar *pos); //required 129 | void position(const uchar *record); //required 130 | int info(uint); //required 131 | 132 | int extra(enum ha_extra_function operation); 133 | int external_lock(THD *thd, int lock_type); //required 134 | int delete_all_rows(void); 135 | int truncate(); 136 | ha_rows records_in_range(uint inx, key_range *min_key, 137 | key_range *max_key); 138 | int delete_table(const char *from); 139 | int rename_table(const char * from, const char * to); 140 | int create(const char *name, TABLE *form, 141 | HA_CREATE_INFO *create_info); //required 142 | 143 | THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, 144 | enum thr_lock_type lock_type); //required 145 | }; 146 | 147 | -------------------------------------------------------------------------------- /Ch10/stage_four/spartan_data.h: -------------------------------------------------------------------------------- 1 | /* 2 | Spartan_data.h 3 | 4 | This header defines a simple data file class for reading raw data to and 5 | from disk. The data written is in byte format so it can be anything you 6 | want it to be. The write_row and read_row accept the length of the data 7 | item to be read. 8 | */ 9 | #include "my_global.h" 10 | #include "my_sys.h" 11 | 12 | class Spartan_data 13 | { 14 | public: 15 | Spartan_data(void); 16 | ~Spartan_data(void); 17 | int create_table(char *path); 18 | int open_table(char *path); 19 | long long write_row(uchar *buf, int length); 20 | long long update_row(uchar *old_rec, uchar *new_rec, 21 | int length, long long position); 22 | int read_row(uchar *buf, int length, long long position); 23 | int delete_row(uchar *old_rec, int length, long long position); 24 | int close_table(); 25 | long long cur_position(); 26 | int records(); 27 | int del_records(); 28 | int trunc_table(); 29 | int row_size(int length); 30 | private: 31 | File data_file; 32 | int header_size; 33 | int record_header_size; 34 | bool crashed; 35 | int number_records; 36 | int number_del_records; 37 | int read_header(); 38 | int write_header(); 39 | }; 40 | -------------------------------------------------------------------------------- /Ch10/stage_one/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Spartan storage engine plugin 2 | 3 | SET(SPARTAN_PLUGIN_STATIC "spartan") 4 | SET(SPARTAN_PLUGIN_DYNAMIC "spartan") 5 | 6 | SET(SPARTAN_SOURCES ha_spartan.cc ha_spartan.h spartan_data.cc spartan_data.h) 7 | MYSQL_ADD_PLUGIN(spartan ${SPARTAN_SOURCES} STORAGE_ENGINE MODULE_ONLY) 8 | -------------------------------------------------------------------------------- /Ch10/stage_one/Ch10s1.test: -------------------------------------------------------------------------------- 1 | # 2 | # Simple test for the Spartan storage engine 3 | # 4 | --disable_warnings 5 | drop table if exists t1; 6 | --enable_warnings 7 | 8 | CREATE TABLE t1 ( 9 | col_a int, 10 | col_b varchar(20), 11 | col_c int 12 | ) ENGINE=SPARTAN; 13 | 14 | SELECT * FROM t1; 15 | 16 | DROP TABLE t1; 17 | -------------------------------------------------------------------------------- /Ch10/stage_one/ha_spartan.h: -------------------------------------------------------------------------------- 1 | /* 2 | Spartan Storage Engine Plugin 3 | */ 4 | 5 | #include "my_global.h" /* ulonglong */ 6 | #include "thr_lock.h" /* THR_LOCK, THR_LOCK_DATA */ 7 | #include "handler.h" /* handler */ 8 | #include "spartan_data.h" 9 | 10 | class Spartan_share : public Handler_share { 11 | public: 12 | mysql_mutex_t mutex; 13 | THR_LOCK lock; 14 | Spartan_share(); 15 | ~Spartan_share() 16 | { 17 | thr_lock_delete(&lock); 18 | mysql_mutex_destroy(&mutex); 19 | } 20 | }; 21 | 22 | /* 23 | Class definition for the storage engine 24 | */ 25 | class ha_spartan: public handler 26 | { 27 | THR_LOCK_DATA lock; /* MySQL lock */ 28 | Spartan_share *share; ///< Shared lock info 29 | Spartan_share *get_share(); ///< Get the share 30 | 31 | public: 32 | ha_spartan(handlerton *hton, TABLE_SHARE *table_ar); 33 | ~ha_spartan() 34 | { 35 | } 36 | /* The name that will be used for display purposes */ 37 | const char *table_type() const { return "SPARTAN"; } 38 | /* 39 | The name of the index type that will be used for display 40 | don't implement this method unless you really have indexes 41 | */ 42 | const char *index_type(uint inx) { return "HASH"; } 43 | /* 44 | The file extensions. 45 | */ 46 | const char **bas_ext() const; 47 | /* 48 | This is a list of flags that says what the storage engine 49 | implements. The current table flags are documented in 50 | handler.h 51 | */ 52 | ulonglong table_flags() const 53 | { 54 | return HA_BINLOG_STMT_CAPABLE; 55 | } 56 | /* 57 | This is a bitmap of flags that says how the storage engine 58 | implements indexes. The current index flags are documented in 59 | handler.h. If you do not implement indexes, just return zero 60 | here. 61 | 62 | part is the key part to check. First key part is 0 63 | If all_parts it's set, MySQL want to know the flags for the combined 64 | index up to and including 'part'. 65 | */ 66 | ulong index_flags(uint inx, uint part, bool all_parts) const 67 | { 68 | return 0; 69 | } 70 | /* 71 | unireg.cc will call the following to make sure that the storage engine can 72 | handle the data it is about to send. 73 | 74 | Return *real* limits of your storage engine here. MySQL will do 75 | min(your_limits, MySQL_limits) automatically 76 | 77 | There is no need to implement ..._key_... methods if you don't suport 78 | indexes. 79 | */ 80 | uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; } 81 | uint max_supported_keys() const { return 0; } 82 | uint max_supported_key_parts() const { return 0; } 83 | uint max_supported_key_length() const { return 0; } 84 | /* 85 | Called in test_quick_select to determine if indexes should be used. 86 | */ 87 | virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; } 88 | /* 89 | The next method will never be called if you do not implement indexes. 90 | */ 91 | virtual double read_time(uint, uint, ha_rows rows) 92 | { return (double) rows / 20.0+1; } 93 | 94 | /* 95 | Everything below are methods that we implment in ha_spartan.cc. 96 | 97 | Most of these methods are not obligatory, skip them and 98 | MySQL will treat them as not implemented 99 | */ 100 | int open(const char *name, int mode, uint test_if_locked); // required 101 | int close(void); // required 102 | 103 | int write_row(uchar * buf); 104 | int update_row(const uchar * old_data, uchar * new_data); 105 | int delete_row(const uchar * buf); 106 | int index_read_map(uchar *buf, const uchar *key, 107 | key_part_map keypart_map, enum ha_rkey_function find_flag); 108 | int index_next(uchar * buf); 109 | int index_prev(uchar * buf); 110 | int index_first(uchar * buf); 111 | int index_last(uchar * buf); 112 | /* 113 | unlike index_init(), rnd_init() can be called two times 114 | without rnd_end() in between (it only makes sense if scan=1). 115 | then the second call should prepare for the new table scan 116 | (e.g if rnd_init allocates the cursor, second call should 117 | position it to the start of the table, no need to deallocate 118 | and allocate it again 119 | */ 120 | int rnd_init(bool scan); //required 121 | int rnd_end(); 122 | int rnd_next(uchar *buf); //required 123 | int rnd_pos(uchar * buf, uchar *pos); //required 124 | void position(const uchar *record); //required 125 | int info(uint); //required 126 | 127 | int extra(enum ha_extra_function operation); 128 | int external_lock(THD *thd, int lock_type); //required 129 | int delete_all_rows(void); 130 | int truncate(); 131 | ha_rows records_in_range(uint inx, key_range *min_key, 132 | key_range *max_key); 133 | int delete_table(const char *from); 134 | int rename_table(const char * from, const char * to); 135 | int create(const char *name, TABLE *form, 136 | HA_CREATE_INFO *create_info); //required 137 | 138 | THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, 139 | enum thr_lock_type lock_type); //required 140 | }; 141 | 142 | -------------------------------------------------------------------------------- /Ch10/stage_one/spartan_data.h: -------------------------------------------------------------------------------- 1 | /* 2 | Spartan_data.h 3 | 4 | This header defines a simple data file class for reading raw data to and 5 | from disk. The data written is in byte format so it can be anything you 6 | want it to be. The write_row and read_row accept the length of the data 7 | item to be read. 8 | */ 9 | #include "my_global.h" 10 | #include "my_sys.h" 11 | 12 | class Spartan_data 13 | { 14 | public: 15 | Spartan_data(void); 16 | ~Spartan_data(void); 17 | int create_table(char *path); 18 | int open_table(char *path); 19 | long long write_row(uchar *buf, int length); 20 | long long update_row(uchar *old_rec, uchar *new_rec, 21 | int length, long long position); 22 | int read_row(uchar *buf, int length, long long position); 23 | int delete_row(uchar *old_rec, int length, long long position); 24 | int close_table(); 25 | long long cur_position(); 26 | int records(); 27 | int del_records(); 28 | int trunc_table(); 29 | int row_size(int length); 30 | private: 31 | File data_file; 32 | int header_size; 33 | int record_header_size; 34 | bool crashed; 35 | int number_records; 36 | int number_del_records; 37 | int read_header(); 38 | int write_header(); 39 | }; 40 | -------------------------------------------------------------------------------- /Ch10/stage_three/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Spartan storage engine plugin 2 | 3 | SET(SPARTAN_PLUGIN_STATIC "spartan") 4 | SET(SPARTAN_PLUGIN_DYNAMIC "spartan") 5 | 6 | SET(SPARTAN_SOURCES ha_spartan.cc ha_spartan.h spartan_data.cc spartan_data.h) 7 | 8 | MYSQL_ADD_PLUGIN(spartan ${SPARTAN_SOURCES} STORAGE_ENGINE MODULE_ONLY) 9 | 10 | TARGET_LINK_LIBRARIES(spartan mysys) 11 | -------------------------------------------------------------------------------- /Ch10/stage_three/Ch10s3.test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Ch10/stage_three/Ch10s3.test -------------------------------------------------------------------------------- /Ch10/stage_three/ha_spartan.h: -------------------------------------------------------------------------------- 1 | /* 2 | Spartan Storage Engine Plugin 3 | */ 4 | 5 | #include "my_global.h" /* ulonglong */ 6 | #include "thr_lock.h" /* THR_LOCK, THR_LOCK_DATA */ 7 | #include "handler.h" /* handler */ 8 | #include "spartan_data.h" 9 | 10 | class Spartan_share : public Handler_share { 11 | public: 12 | mysql_mutex_t mutex; 13 | THR_LOCK lock; 14 | Spartan_data *data_class; 15 | Spartan_share(); 16 | ~Spartan_share() 17 | { 18 | thr_lock_delete(&lock); 19 | mysql_mutex_destroy(&mutex); 20 | if (data_class != NULL) 21 | delete data_class; 22 | data_class = NULL; 23 | } 24 | }; 25 | 26 | /* 27 | Class definition for the storage engine 28 | */ 29 | class ha_spartan: public handler 30 | { 31 | THR_LOCK_DATA lock; /* MySQL lock */ 32 | Spartan_share *share; ///< Shared lock info 33 | Spartan_share *get_share(); ///< Get the share 34 | off_t current_position; /* Current position in the file during a file scan */ 35 | 36 | public: 37 | ha_spartan(handlerton *hton, TABLE_SHARE *table_ar); 38 | ~ha_spartan() 39 | { 40 | } 41 | /* The name that will be used for display purposes */ 42 | const char *table_type() const { return "SPARTAN"; } 43 | /* 44 | The name of the index type that will be used for display 45 | don't implement this method unless you really have indexes 46 | */ 47 | const char *index_type(uint inx) { return "HASH"; } 48 | /* 49 | The file extensions. 50 | */ 51 | const char **bas_ext() const; 52 | /* 53 | This is a list of flags that says what the storage engine 54 | implements. The current table flags are documented in 55 | handler.h 56 | */ 57 | ulonglong table_flags() const 58 | { 59 | return HA_BINLOG_STMT_CAPABLE; 60 | } 61 | /* 62 | This is a bitmap of flags that says how the storage engine 63 | implements indexes. The current index flags are documented in 64 | handler.h. If you do not implement indexes, just return zero 65 | here. 66 | 67 | part is the key part to check. First key part is 0 68 | If all_parts it's set, MySQL want to know the flags for the combined 69 | index up to and including 'part'. 70 | */ 71 | ulong index_flags(uint inx, uint part, bool all_parts) const 72 | { 73 | return 0; 74 | } 75 | /* 76 | unireg.cc will call the following to make sure that the storage engine can 77 | handle the data it is about to send. 78 | 79 | Return *real* limits of your storage engine here. MySQL will do 80 | min(your_limits, MySQL_limits) automatically 81 | 82 | There is no need to implement ..._key_... methods if you don't suport 83 | indexes. 84 | */ 85 | uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; } 86 | uint max_supported_keys() const { return 0; } 87 | uint max_supported_key_parts() const { return 0; } 88 | uint max_supported_key_length() const { return 0; } 89 | /* 90 | Called in test_quick_select to determine if indexes should be used. 91 | */ 92 | virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; } 93 | /* 94 | The next method will never be called if you do not implement indexes. 95 | */ 96 | virtual double read_time(uint, uint, ha_rows rows) 97 | { return (double) rows / 20.0+1; } 98 | 99 | /* 100 | Everything below are methods that we implment in ha_spartan.cc. 101 | 102 | Most of these methods are not obligatory, skip them and 103 | MySQL will treat them as not implemented 104 | */ 105 | int open(const char *name, int mode, uint test_if_locked); // required 106 | int close(void); // required 107 | 108 | int write_row(uchar * buf); 109 | int update_row(const uchar * old_data, uchar * new_data); 110 | int delete_row(const uchar * buf); 111 | int index_read_map(uchar *buf, const uchar *key, 112 | key_part_map keypart_map, enum ha_rkey_function find_flag); 113 | int index_next(uchar * buf); 114 | int index_prev(uchar * buf); 115 | int index_first(uchar * buf); 116 | int index_last(uchar * buf); 117 | /* 118 | unlike index_init(), rnd_init() can be called two times 119 | without rnd_end() in between (it only makes sense if scan=1). 120 | then the second call should prepare for the new table scan 121 | (e.g if rnd_init allocates the cursor, second call should 122 | position it to the start of the table, no need to deallocate 123 | and allocate it again 124 | */ 125 | int rnd_init(bool scan); //required 126 | int rnd_end(); 127 | int rnd_next(uchar *buf); //required 128 | int rnd_pos(uchar * buf, uchar *pos); //required 129 | void position(const uchar *record); //required 130 | int info(uint); //required 131 | 132 | int extra(enum ha_extra_function operation); 133 | int external_lock(THD *thd, int lock_type); //required 134 | int delete_all_rows(void); 135 | int truncate(); 136 | ha_rows records_in_range(uint inx, key_range *min_key, 137 | key_range *max_key); 138 | int delete_table(const char *from); 139 | int rename_table(const char * from, const char * to); 140 | int create(const char *name, TABLE *form, 141 | HA_CREATE_INFO *create_info); //required 142 | 143 | THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, 144 | enum thr_lock_type lock_type); //required 145 | }; 146 | 147 | -------------------------------------------------------------------------------- /Ch10/stage_three/spartan_data.h: -------------------------------------------------------------------------------- 1 | /* 2 | Spartan_data.h 3 | 4 | This header defines a simple data file class for reading raw data to and 5 | from disk. The data written is in byte format so it can be anything you 6 | want it to be. The write_row and read_row accept the length of the data 7 | item to be read. 8 | */ 9 | #include "my_global.h" 10 | #include "my_sys.h" 11 | 12 | class Spartan_data 13 | { 14 | public: 15 | Spartan_data(void); 16 | ~Spartan_data(void); 17 | int create_table(char *path); 18 | int open_table(char *path); 19 | long long write_row(uchar *buf, int length); 20 | long long update_row(uchar *old_rec, uchar *new_rec, 21 | int length, long long position); 22 | int read_row(uchar *buf, int length, long long position); 23 | int delete_row(uchar *old_rec, int length, long long position); 24 | int close_table(); 25 | long long cur_position(); 26 | int records(); 27 | int del_records(); 28 | int trunc_table(); 29 | int row_size(int length); 30 | private: 31 | File data_file; 32 | int header_size; 33 | int record_header_size; 34 | bool crashed; 35 | int number_records; 36 | int number_del_records; 37 | int read_header(); 38 | int write_header(); 39 | }; 40 | -------------------------------------------------------------------------------- /Ch10/stage_two/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Spartan storage engine plugin 2 | 3 | SET(SPARTAN_PLUGIN_STATIC "spartan") 4 | SET(SPARTAN_PLUGIN_DYNAMIC "spartan") 5 | 6 | SET(SPARTAN_SOURCES ha_spartan.cc ha_spartan.h spartan_data.cc spartan_data.h) 7 | 8 | MYSQL_ADD_PLUGIN(spartan ${SPARTAN_SOURCES} STORAGE_ENGINE MODULE_ONLY) 9 | 10 | TARGET_LINK_LIBRARIES(spartan mysys) 11 | -------------------------------------------------------------------------------- /Ch10/stage_two/Ch10s2.test: -------------------------------------------------------------------------------- 1 | # 2 | # Simple test for the Spartan storage engine 3 | # 4 | --disable_warnings 5 | drop table if exists t1; 6 | --enable_warnings 7 | 8 | CREATE TABLE t1 ( 9 | col_a int, 10 | col_b varchar(20), 11 | col_c int 12 | ) ENGINE=SPARTAN; 13 | 14 | SELECT * FROM t1; 15 | 16 | RENAME TABLE t1 TO t2; 17 | 18 | DROP TABLE t2; 19 | -------------------------------------------------------------------------------- /Ch10/stage_two/ha_spartan.h: -------------------------------------------------------------------------------- 1 | /* 2 | Spartan Storage Engine Plugin 3 | */ 4 | 5 | #include "my_global.h" /* ulonglong */ 6 | #include "thr_lock.h" /* THR_LOCK, THR_LOCK_DATA */ 7 | #include "handler.h" /* handler */ 8 | #include "spartan_data.h" 9 | 10 | class Spartan_share : public Handler_share { 11 | public: 12 | mysql_mutex_t mutex; 13 | THR_LOCK lock; 14 | Spartan_data *data_class; 15 | Spartan_share(); 16 | ~Spartan_share() 17 | { 18 | thr_lock_delete(&lock); 19 | mysql_mutex_destroy(&mutex); 20 | if (data_class != NULL) 21 | delete data_class; 22 | data_class = NULL; 23 | } 24 | }; 25 | 26 | /* 27 | Class definition for the storage engine 28 | */ 29 | class ha_spartan: public handler 30 | { 31 | THR_LOCK_DATA lock; /* MySQL lock */ 32 | Spartan_share *share; ///< Shared lock info 33 | Spartan_share *get_share(); ///< Get the share 34 | 35 | public: 36 | ha_spartan(handlerton *hton, TABLE_SHARE *table_ar); 37 | ~ha_spartan() 38 | { 39 | } 40 | /* The name that will be used for display purposes */ 41 | const char *table_type() const { return "SPARTAN"; } 42 | /* 43 | The name of the index type that will be used for display 44 | don't implement this method unless you really have indexes 45 | */ 46 | const char *index_type(uint inx) { return "HASH"; } 47 | /* 48 | The file extensions. 49 | */ 50 | const char **bas_ext() const; 51 | /* 52 | This is a list of flags that says what the storage engine 53 | implements. The current table flags are documented in 54 | handler.h 55 | */ 56 | ulonglong table_flags() const 57 | { 58 | return HA_BINLOG_STMT_CAPABLE; 59 | } 60 | /* 61 | This is a bitmap of flags that says how the storage engine 62 | implements indexes. The current index flags are documented in 63 | handler.h. If you do not implement indexes, just return zero 64 | here. 65 | 66 | part is the key part to check. First key part is 0 67 | If all_parts it's set, MySQL want to know the flags for the combined 68 | index up to and including 'part'. 69 | */ 70 | ulong index_flags(uint inx, uint part, bool all_parts) const 71 | { 72 | return 0; 73 | } 74 | /* 75 | unireg.cc will call the following to make sure that the storage engine can 76 | handle the data it is about to send. 77 | 78 | Return *real* limits of your storage engine here. MySQL will do 79 | min(your_limits, MySQL_limits) automatically 80 | 81 | There is no need to implement ..._key_... methods if you don't suport 82 | indexes. 83 | */ 84 | uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; } 85 | uint max_supported_keys() const { return 0; } 86 | uint max_supported_key_parts() const { return 0; } 87 | uint max_supported_key_length() const { return 0; } 88 | /* 89 | Called in test_quick_select to determine if indexes should be used. 90 | */ 91 | virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; } 92 | /* 93 | The next method will never be called if you do not implement indexes. 94 | */ 95 | virtual double read_time(uint, uint, ha_rows rows) 96 | { return (double) rows / 20.0+1; } 97 | 98 | /* 99 | Everything below are methods that we implment in ha_spartan.cc. 100 | 101 | Most of these methods are not obligatory, skip them and 102 | MySQL will treat them as not implemented 103 | */ 104 | int open(const char *name, int mode, uint test_if_locked); // required 105 | int close(void); // required 106 | 107 | int write_row(uchar * buf); 108 | int update_row(const uchar * old_data, uchar * new_data); 109 | int delete_row(const uchar * buf); 110 | int index_read_map(uchar *buf, const uchar *key, 111 | key_part_map keypart_map, enum ha_rkey_function find_flag); 112 | int index_next(uchar * buf); 113 | int index_prev(uchar * buf); 114 | int index_first(uchar * buf); 115 | int index_last(uchar * buf); 116 | /* 117 | unlike index_init(), rnd_init() can be called two times 118 | without rnd_end() in between (it only makes sense if scan=1). 119 | then the second call should prepare for the new table scan 120 | (e.g if rnd_init allocates the cursor, second call should 121 | position it to the start of the table, no need to deallocate 122 | and allocate it again 123 | */ 124 | int rnd_init(bool scan); //required 125 | int rnd_end(); 126 | int rnd_next(uchar *buf); //required 127 | int rnd_pos(uchar * buf, uchar *pos); //required 128 | void position(const uchar *record); //required 129 | int info(uint); //required 130 | 131 | int extra(enum ha_extra_function operation); 132 | int external_lock(THD *thd, int lock_type); //required 133 | int delete_all_rows(void); 134 | int truncate(); 135 | ha_rows records_in_range(uint inx, key_range *min_key, 136 | key_range *max_key); 137 | int delete_table(const char *from); 138 | int rename_table(const char * from, const char * to); 139 | int create(const char *name, TABLE *form, 140 | HA_CREATE_INFO *create_info); //required 141 | 142 | THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, 143 | enum thr_lock_type lock_type); //required 144 | }; 145 | 146 | -------------------------------------------------------------------------------- /Ch10/stage_two/spartan_data.h: -------------------------------------------------------------------------------- 1 | /* 2 | Spartan_data.h 3 | 4 | This header defines a simple data file class for reading raw data to and 5 | from disk. The data written is in byte format so it can be anything you 6 | want it to be. The write_row and read_row accept the length of the data 7 | item to be read. 8 | */ 9 | #include "my_global.h" 10 | #include "my_sys.h" 11 | 12 | class Spartan_data 13 | { 14 | public: 15 | Spartan_data(void); 16 | ~Spartan_data(void); 17 | int create_table(char *path); 18 | int open_table(char *path); 19 | long long write_row(uchar *buf, int length); 20 | long long update_row(uchar *old_rec, uchar *new_rec, 21 | int length, long long position); 22 | int read_row(uchar *buf, int length, long long position); 23 | int delete_row(uchar *old_rec, int length, long long position); 24 | int close_table(); 25 | long long cur_position(); 26 | int records(); 27 | int del_records(); 28 | int trunc_table(); 29 | int row_size(int length); 30 | private: 31 | File data_file; 32 | int header_size; 33 | int record_header_size; 34 | bool crashed; 35 | int number_records; 36 | int number_del_records; 37 | int read_header(); 38 | int write_header(); 39 | }; 40 | -------------------------------------------------------------------------------- /Ch12/ch12.diff: -------------------------------------------------------------------------------- 1 | === modified file 'sql/CMakeLists.txt' 2 | --- sql/CMakeLists.txt 2012-08-07 05:14:58 +0000 3 | +++ sql/CMakeLists.txt 2012-09-16 18:05:38 +0000 4 | @@ -132,6 +132,8 @@ SET(SQL_SHARED_SOURCES 5 | sql_manager.cc 6 | sql_optimizer.cc 7 | sql_parse.cc 8 | + sql_dbxp_parse.cc 9 | + query_tree.cc 10 | sql_partition.cc 11 | sql_partition_admin.cc 12 | sql_planner.cc 13 | 14 | === modified file 'sql/lex.h' 15 | --- sql/lex.h 2012-09-11 17:35:40 +0000 16 | +++ sql/lex.h 2012-09-16 18:01:41 +0000 17 | @@ -160,6 +160,11 @@ static SYMBOL symbols[] = { 18 | { "DAY_MICROSECOND", SYM(DAY_MICROSECOND_SYM)}, 19 | { "DAY_MINUTE", SYM(DAY_MINUTE_SYM)}, 20 | { "DAY_SECOND", SYM(DAY_SECOND_SYM)}, 21 | +/* BEGIN DBXP MODIFICATION */ 22 | +/* Reason for Modification: */ 23 | +/* This section identifies the symbols and values for the DBXP token */ 24 | + { "DBXP_SELECT", SYM(DBXP_SELECT_SYM)}, 25 | +/* END DBXP MODIFICATION */ 26 | { "DEALLOCATE", SYM(DEALLOCATE_SYM)}, 27 | { "DEC", SYM(DECIMAL_SYM)}, 28 | { "DECIMAL", SYM(DECIMAL_SYM)}, 29 | 30 | === modified file 'sql/mysqld.cc' 31 | --- sql/mysqld.cc 2012-09-11 17:35:40 +0000 32 | +++ sql/mysqld.cc 2012-09-16 18:01:41 +0000 33 | @@ -3699,8 +3699,8 @@ int init_common_variables() 34 | the array, excluding the last element - terminator) must match the number 35 | of SQLCOM_ constants. 36 | */ 37 | - compile_time_assert(sizeof(com_status_vars)/sizeof(com_status_vars[0]) - 1 == 38 | - SQLCOM_END + 8); 39 | + //compile_time_assert(sizeof(com_status_vars)/sizeof(com_status_vars[0]) - 1 == 40 | + // SQLCOM_END + 8); 41 | #endif 42 | 43 | if (get_options(&remaining_argc, &remaining_argv)) 44 | @@ -8671,6 +8671,11 @@ static void set_server_version(void) 45 | #endif 46 | if (opt_log || opt_slow_log || opt_bin_log) 47 | strmov(end, "-log"); // This may slow down system 48 | +/* BEGIN DBXP MODIFICATION */ 49 | +/* Reason for Modification: */ 50 | +/* This section adds the DBXP version number to the MySQL version number. */ 51 | + strmov(end, "-DBXP 2.0"); 52 | +/* END DBXP MODIFICATION */ 53 | } 54 | 55 | 56 | 57 | === modified file 'sql/sql_cmd.h' 58 | --- sql/sql_cmd.h 2012-09-11 17:35:40 +0000 59 | +++ sql/sql_cmd.h 2012-09-16 18:01:41 +0000 60 | @@ -43,6 +43,13 @@ enum enum_sql_command { 61 | SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS, 62 | SQLCOM_SHOW_TRIGGERS, 63 | 64 | +/* BEGIN DBXP MODIFICATION */ 65 | +/* Reason for Modification: */ 66 | +/* This section captures the enumerations for the DBXP command tokens */ 67 | + SQLCOM_DBXP_SELECT, 68 | + SQLCOM_DBXP_EXPLAIN_SELECT, 69 | +/* END DBXP MODIFICATION */ 70 | + 71 | SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES, 72 | SQLCOM_GRANT, 73 | SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB, 74 | 75 | === modified file 'sql/sql_parse.cc' 76 | --- sql/sql_parse.cc 2012-09-11 17:35:40 +0000 77 | +++ sql/sql_parse.cc 2012-09-16 18:01:41 +0000 78 | @@ -2197,6 +2197,13 @@ err: 79 | } 80 | 81 | 82 | +/* BEGIN DBXP MODIFICATION */ 83 | +/* Reason for Modification: */ 84 | +/* This section adds the code to call the new SELECT DBXP command. */ 85 | +int DBXP_select_command(THD *thd); 86 | +int DBXP_explain_select_command(THD *thd); 87 | +/* END DBXP MODIFICATION */ 88 | + 89 | /** 90 | Execute command saved in thd and lex->sql_command. 91 | 92 | @@ -2552,6 +2559,20 @@ mysql_execute_command(THD *thd) 93 | res= execute_sqlcom_select(thd, all_tables); 94 | break; 95 | } 96 | +/* BEGIN DBXP MODIFICATION */ 97 | +/* Reason for Modification: */ 98 | +/* This section adds the code to call the new SELECT DBXP command. */ 99 | + case SQLCOM_DBXP_SELECT: 100 | + { 101 | + DBXP_select_command(thd); 102 | + break; 103 | + } 104 | + case SQLCOM_DBXP_EXPLAIN_SELECT: 105 | + { 106 | + DBXP_explain_select_command(thd); 107 | + break; 108 | + } 109 | +/* END DBXP MODIFICATION */ 110 | case SQLCOM_PREPARE: 111 | { 112 | mysql_sql_stmt_prepare(thd); 113 | 114 | === modified file 'sql/sql_yacc.yy' 115 | --- sql/sql_yacc.yy 2012-09-11 17:35:40 +0000 116 | +++ sql/sql_yacc.yy 2012-09-16 18:01:41 +0000 117 | @@ -1124,6 +1124,11 @@ bool my_yyoverflow(short **a, YYSTYPE ** 118 | %token DAY_MINUTE_SYM 119 | %token DAY_SECOND_SYM 120 | %token DAY_SYM /* SQL-2003-R */ 121 | +/* BEGIN DBXP MODIFICATION */ 122 | +/* Reason for Modification: */ 123 | +/* This section defines the tokens for the DBXP commands */ 124 | +%token DBXP_SELECT_SYM 125 | +/* END DBXP MODIFICATION */ 126 | %token DEALLOCATE_SYM /* SQL-2003-R */ 127 | %token DECIMAL_NUM 128 | %token DECIMAL_SYM /* SQL-2003-R */ 129 | @@ -1801,7 +1806,11 @@ bool my_yyoverflow(short **a, YYSTYPE ** 130 | %type comp_op 131 | 132 | %type 133 | - query verb_clause create change select do drop insert replace insert2 134 | +/* BEGIN DBXP MODIFICATION */ 135 | +/* Reason for Modification: */ 136 | +/* Add the dbxp_select statement to the NONE type definition. */ 137 | + query verb_clause create change select dbxp_select do drop insert replace insert2 138 | +/* END DBXP MODIFICATION */ 139 | insert_values update delete truncate rename 140 | show describe load alter optimize keycache preload flush 141 | reset purge begin commit rollback savepoint release 142 | @@ -2019,6 +2028,11 @@ statement: 143 | | rollback 144 | | savepoint 145 | | select 146 | +/* BEGIN DBXP MODIFICATION */ 147 | +/* Reason for Modification: */ 148 | +/* Add the dbxp_select statement to the list of statements(commands). */ 149 | + | dbxp_select 150 | +/* END DBXP MODIFICATION */ 151 | | set 152 | | signal_stmt 153 | | show 154 | @@ -8514,14 +8528,76 @@ opt_ignore_leaves: 155 | */ 156 | 157 | 158 | +/* BEGIN DBXP MODIFICATION */ 159 | +/* Reason for Modification: */ 160 | +/* This section captures (parses) the SELECT DBXP statement */ 161 | + 162 | +dbxp_select: 163 | + DBXP_SELECT_SYM DBXP_select_options DBXP_select_item_list 164 | + DBXP_select_from 165 | + { 166 | + LEX *lex= Lex; 167 | + lex->sql_command = SQLCOM_DBXP_SELECT; 168 | + } 169 | + ; 170 | + 171 | +/* END DBXP MODIFICATION */ 172 | + 173 | select: 174 | - select_init 175 | + select_init 176 | { 177 | LEX *lex= Lex; 178 | lex->sql_command= SQLCOM_SELECT; 179 | } 180 | ; 181 | 182 | +/* BEGIN DBXP MODIFICATION */ 183 | +/* Reason for Modification: */ 184 | +/* This section captures (parses) the sub parts of the SELECT DBXP statement */ 185 | + 186 | +DBXP_select_options: 187 | + /* empty */ 188 | + | DISTINCT 189 | + { 190 | + Select->options|= SELECT_DISTINCT; 191 | + } 192 | + ; 193 | + 194 | +DBXP_select_from: 195 | + FROM join_table_list DBXP_where_clause {}; 196 | + 197 | +DBXP_select_item_list: 198 | + /* empty */ 199 | + | DBXP_select_item_list ',' select_item 200 | + | select_item 201 | + | '*' 202 | + { 203 | + THD *thd= YYTHD; 204 | + Item *item= new (thd->mem_root) 205 | + Item_field(&thd->lex->current_select->context, 206 | + NULL, NULL, "*"); 207 | + if (item == NULL) 208 | + MYSQL_YYABORT; 209 | + if (add_item_to_list(thd, item)) 210 | + MYSQL_YYABORT; 211 | + (thd->lex->current_select->with_wild)++; 212 | + }; 213 | + 214 | +DBXP_where_clause: 215 | + /* empty */ { Select->where= 0; } 216 | + | WHERE expr 217 | + { 218 | + SELECT_LEX *select= Select; 219 | + select->where= $2; 220 | + if ($2) 221 | + $2->top_level_item(); 222 | + } 223 | + ; 224 | + 225 | + 226 | +/* END DBXP MODIFICATION */ 227 | + 228 | + 229 | /* Need select_init2 for subselects. */ 230 | select_init: 231 | SELECT_SYM select_init2 232 | @@ -12631,7 +12707,21 @@ wild_and_where: 233 | 234 | /* A Oracle compatible synonym for show */ 235 | describe: 236 | - describe_command table_ident 237 | +/* BEGIN DBXP MODIFICATION */ 238 | +/* Reason for Modification: */ 239 | +/* This section captures (parses) the EXPLAIN (DESCRIBE) DBXP statements */ 240 | + 241 | + describe_command DBXP_SELECT_SYM DBXP_select_options DBXP_select_item_list 242 | + DBXP_select_from 243 | + { 244 | + LEX *lex= Lex; 245 | + lex->sql_command = SQLCOM_DBXP_EXPLAIN_SELECT; 246 | + lex->select_lex.db= 0; 247 | + lex->verbose= 0; 248 | + } 249 | + 250 | +/* END DBXP MODIFICATION */ 251 | + | describe_command table_ident 252 | { 253 | LEX *lex= Lex; 254 | mysql_init_select(lex); 255 | 256 | -------------------------------------------------------------------------------- /Ch12/ch12.sql: -------------------------------------------------------------------------------- 1 | # Source on localhost: ... connected. 2 | # Exporting metadata from expert_mysql 3 | DROP DATABASE IF EXISTS expert_mysql; 4 | CREATE DATABASE expert_mysql; 5 | USE expert_mysql; 6 | # TABLE: expert_mysql.building 7 | CREATE TABLE `building` ( 8 | `dir_code` char(4) NOT NULL, 9 | `building` char(6) NOT NULL 10 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 11 | # TABLE: expert_mysql.directorate 12 | CREATE TABLE `directorate` ( 13 | `dir_code` char(4) NOT NULL, 14 | `dir_name` char(30) DEFAULT NULL, 15 | `dir_head_id` char(9) DEFAULT NULL, 16 | PRIMARY KEY (`dir_code`) 17 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 18 | # TABLE: expert_mysql.staff 19 | CREATE TABLE `staff` ( 20 | `id` char(9) NOT NULL, 21 | `first_name` char(20) DEFAULT NULL, 22 | `mid_name` char(20) DEFAULT NULL, 23 | `last_name` char(30) DEFAULT NULL, 24 | `sex` char(1) DEFAULT NULL, 25 | `salary` int(11) DEFAULT NULL, 26 | `mgr_id` char(9) DEFAULT NULL, 27 | PRIMARY KEY (`id`) 28 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 29 | # TABLE: expert_mysql.tasking 30 | CREATE TABLE `tasking` ( 31 | `id` char(9) NOT NULL, 32 | `project_number` char(9) NOT NULL, 33 | `hours_worked` double DEFAULT NULL 34 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 35 | #...done. 36 | USE expert_mysql; 37 | # Exporting data from expert_mysql 38 | # Data for table expert_mysql.building: 39 | INSERT INTO expert_mysql.building VALUES ('N41', '1300'); 40 | INSERT INTO expert_mysql.building VALUES ('N01', '1453'); 41 | INSERT INTO expert_mysql.building VALUES ('M00', '1000'); 42 | INSERT INTO expert_mysql.building VALUES ('N41', '1301'); 43 | INSERT INTO expert_mysql.building VALUES ('N41', '1305'); 44 | # Data for table expert_mysql.directorate: 45 | INSERT INTO expert_mysql.directorate VALUES ('N41', 'Development', '333445555'); 46 | INSERT INTO expert_mysql.directorate VALUES ('N01', 'Human Resources', '123654321'); 47 | INSERT INTO expert_mysql.directorate VALUES ('M00', 'Management', '333444444'); 48 | # Data for table expert_mysql.staff: 49 | INSERT INTO expert_mysql.staff VALUES ('333445555', 'John', 'Q', 'Smith', 'M', 30000, '333444444'); 50 | INSERT INTO expert_mysql.staff VALUES ('123763153', 'William', 'E', 'Walters', 'M', 25000, '123654321'); 51 | INSERT INTO expert_mysql.staff VALUES ('333444444', 'Alicia', 'F', 'St.Cruz', 'F', 25000, 'None'); 52 | INSERT INTO expert_mysql.staff VALUES ('921312388', 'Goy', 'X', 'Hong', 'F', 40000, '123654321'); 53 | INSERT INTO expert_mysql.staff VALUES ('800122337', 'Rajesh', 'G', 'Kardakarna', 'M', 38000, '333445555'); 54 | INSERT INTO expert_mysql.staff VALUES ('820123637', 'Monty', 'C', 'Smythe', 'M', 38000, '333445555'); 55 | INSERT INTO expert_mysql.staff VALUES ('830132335', 'Richard', 'E', 'Jones', 'M', 38000, '333445555'); 56 | INSERT INTO expert_mysql.staff VALUES ('333445665', 'Edward', 'E', 'Engles', 'M', 25000, '333445555'); 57 | INSERT INTO expert_mysql.staff VALUES ('123654321', 'Beware', 'D', 'Borg', 'F', 55000, '333444444'); 58 | INSERT INTO expert_mysql.staff VALUES ('123456789', 'Wilma', 'N', 'Maxima', 'F', 43000, '333445555'); 59 | # Data for table expert_mysql.tasking: 60 | INSERT INTO expert_mysql.tasking VALUES ('333445555', '405', 23); 61 | INSERT INTO expert_mysql.tasking VALUES ('123763153', '405', 33.5); 62 | INSERT INTO expert_mysql.tasking VALUES ('921312388', '601', 44); 63 | INSERT INTO expert_mysql.tasking VALUES ('800122337', '300', 13); 64 | INSERT INTO expert_mysql.tasking VALUES ('820123637', '300', 9.5); 65 | INSERT INTO expert_mysql.tasking VALUES ('830132335', '401', 8.5); 66 | INSERT INTO expert_mysql.tasking VALUES ('333445555', '300', 11); 67 | INSERT INTO expert_mysql.tasking VALUES ('921312388', '500', 13); 68 | INSERT INTO expert_mysql.tasking VALUES ('800122337', '300', 44); 69 | INSERT INTO expert_mysql.tasking VALUES ('820123637', '401', 500.5); 70 | INSERT INTO expert_mysql.tasking VALUES ('830132335', '400', 12); 71 | INSERT INTO expert_mysql.tasking VALUES ('333445665', '600', 300.25); 72 | INSERT INTO expert_mysql.tasking VALUES ('123654321', '607', 444.75); 73 | INSERT INTO expert_mysql.tasking VALUES ('123456789', '300', 1000); 74 | #...done. 75 | -------------------------------------------------------------------------------- /Ch12/ch12.test: -------------------------------------------------------------------------------- 1 | # 2 | # Sample test to test the DBXP_SELECT and EXPLAIN DBXP_SELECT commands 3 | # 4 | 5 | # Test 1: Test stubbed DBXP_SELECT command. 6 | DBXP_SELECT * FROM no_such_table; 7 | 8 | # Test 2: Test stubbed Query Tree implementation. 9 | DBXP_SELECT * FROM customer; 10 | 11 | # Test 3: Test stubbed EXPLAIN DBXP_SELECT command. 12 | EXPLAIN DBXP_SELECT * FROM customer; 13 | -------------------------------------------------------------------------------- /Ch12/query_tree.cc: -------------------------------------------------------------------------------- 1 | /* 2 | query_tree.cc 3 | 4 | DESCRIPTION 5 | This file contains the Query_tree class. It is responsible for containing the 6 | internal representation of the query to be executed. It provides methods for 7 | optimizing and forming and inspecting the query tree. This class is the very 8 | heart of the DBXP query capability! It also provides the ability to store 9 | a binary "compiled" form of the query. 10 | 11 | NOTES 12 | The data structure is a binary tree that can have 0, 1, or 2 children. Only 13 | Join operations can have 2 children. All other operations have 0 or 1 14 | children. Each node in the tree is an operation and the links to children 15 | are the pipeline. 16 | 17 | SEE ALSO 18 | query_tree.h 19 | */ 20 | #include "query_tree.h" 21 | 22 | Query_tree::query_node::query_node() 23 | { 24 | where_expr = NULL; 25 | join_expr = NULL; 26 | child = false; 27 | join_cond = Query_tree::jcUN; 28 | join_type = Query_tree::jnUNKNOWN; 29 | left = NULL; 30 | right = NULL; 31 | nodeid = -1; 32 | node_type = Query_tree::qntUndefined; 33 | sub_query = false; 34 | parent_nodeid = -1; 35 | } 36 | 37 | 38 | Query_tree::query_node::~query_node() 39 | { 40 | if(left) 41 | delete left; 42 | if(right) 43 | delete right; 44 | } 45 | 46 | Query_tree::~Query_tree(void) 47 | { 48 | if(root) 49 | delete root; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /Ch12/query_tree.h: -------------------------------------------------------------------------------- 1 | /* 2 | query_tree.h 3 | 4 | DESCRIPTION 5 | This file contains the Query_tree class. It is responsible for containing the 6 | internal representation of the query to be executed. It provides methods for 7 | optimizing and forming and inspecting the query tree. This class is the very 8 | heart of the DBXP query capability! It also provides the ability to store 9 | a binary "compiled" form of the query. 10 | 11 | NOTES 12 | The data structure is a binary tree that can have 0, 1, or 2 children. Only 13 | Join operations can have 2 children. All other operations have 0 or 1 14 | children. Each node in the tree is an operation and the links to children 15 | are the pipeline. 16 | 17 | SEE ALSO 18 | query_tree.cc 19 | */ 20 | #include "sql_priv.h" 21 | #include "sql_class.h" 22 | #include "table.h" 23 | #include "records.h" 24 | 25 | class Query_tree 26 | { 27 | public: 28 | enum query_node_type //this enumeration lists the available 29 | { //query node (operations) 30 | qntUndefined = 0, 31 | qntRestrict = 1, 32 | qntProject = 2, 33 | qntJoin = 3, 34 | qntSort = 4, 35 | qntDistinct = 5 36 | }; 37 | 38 | enum join_con_type //this enumeration lists the available 39 | { //join operations supported 40 | jcUN = 0, 41 | jcNA = 1, 42 | jcON = 2, 43 | jcUS = 3 44 | }; 45 | 46 | enum type_join //this enumeration lists the available 47 | { //join types supported. 48 | jnUNKNOWN = 0, //undefined 49 | jnINNER = 1, 50 | jnLEFTOUTER = 2, 51 | jnRIGHTOUTER = 3, 52 | jnFULLOUTER = 4, 53 | jnCROSSPRODUCT = 5, 54 | jnUNION = 6, 55 | jnINTERSECT = 7 56 | }; 57 | 58 | enum AggregateType //used to add aggregate functions 59 | { 60 | atNONE = 0, 61 | atCOUNT = 1 62 | }; 63 | 64 | /* 65 | STRUCTURE query_node 66 | 67 | DESCRIPTION 68 | This this structure contains all of the data for a query node: 69 | 70 | NodeId -- the internal id number for a node 71 | ParentNodeId -- the internal id for the parent node (used for insert) 72 | SubQuery -- is this the start of a subquery? 73 | Child -- is this a Left or Right child of the parent? 74 | NodeType -- synonymous with operation type 75 | JoinType -- if a join, this is the join operation 76 | join_con_type -- if this is a join, this is the "on" condition 77 | Expressions -- the expressions from the "where" clause for this node 78 | Join Expressions -- the join expressions from the "join" clause(s) 79 | Relations[] -- the relations for this operation (at most 2) 80 | PreemptPipeline -- does the pipeline need to be halted for a sort? 81 | Fields -- the attributes for the result set of this operation 82 | Left -- a pointer to the left child node 83 | Right -- a pointer to the right child node 84 | */ 85 | struct query_node 86 | { 87 | query_node(); 88 | //query_node(const query_node &o); 89 | ~query_node(); 90 | int nodeid; 91 | int parent_nodeid; 92 | bool sub_query; 93 | bool child; 94 | query_node_type node_type; 95 | type_join join_type; 96 | join_con_type join_cond; 97 | Item *where_expr; 98 | Item *join_expr; 99 | TABLE_LIST *relations[4]; 100 | bool preempt_pipeline; 101 | List *fields; 102 | query_node *left; 103 | query_node *right; 104 | }; 105 | 106 | query_node *root; //The ROOT node of the tree 107 | 108 | ~Query_tree(void); 109 | void ShowPlan(query_node *QN, bool PrintOnRight); 110 | 111 | }; 112 | -------------------------------------------------------------------------------- /Ch12/source_Ch12.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Ch12/source_Ch12.zip -------------------------------------------------------------------------------- /Ch12/sql_dbxp_parse.cc: -------------------------------------------------------------------------------- 1 | /* 2 | sql_dbxp_parse.cc 3 | 4 | DESCRIPTION 5 | This file contains methods to execute the DBXP SELECT query statements. 6 | 7 | SEE ALSO 8 | query_tree.cc 9 | */ 10 | #include "query_tree.h" 11 | 12 | /* 13 | Build Query Tree 14 | 15 | SYNOPSIS 16 | build_query_tree() 17 | THD *thd IN the current thread 18 | LEX *lex IN the pointer to the current parsed structure 19 | TABLE_LIST *tables IN the list of tables identified in the query 20 | 21 | DESCRIPTION 22 | This method returns a converted MySQL internal representation (IR) of a 23 | query as a query_tree. 24 | 25 | RETURN VALUE 26 | Success = Query_tree * -- the root of the new query tree. 27 | Failed = NULL 28 | */ 29 | Query_tree *build_query_tree(THD *thd, LEX *lex, TABLE_LIST *tables) 30 | { 31 | DBUG_ENTER("build_query_tree"); 32 | Query_tree *qt = new Query_tree(); 33 | Query_tree::query_node *qn = new Query_tree::query_node(); 34 | TABLE_LIST *table; 35 | int i = 0; 36 | int num_tables = 0; 37 | 38 | /* Create a new restrict node. */ 39 | qn->parent_nodeid = -1; 40 | qn->child = false; 41 | qn->join_type = (Query_tree::type_join) 0; 42 | qn->nodeid = 0; 43 | qn->node_type = (Query_tree::query_node_type) 2; 44 | qn->left = 0; 45 | qn->right = 0; 46 | 47 | if(lex->select_lex.options & SELECT_DISTINCT) 48 | { 49 | //qt->set_distinct(true); 50 | } 51 | 52 | /* Get the tables (relations) */ 53 | i = 0; 54 | for(table = tables; table; table = table->next_local) 55 | { 56 | num_tables++; 57 | qn->relations[i] = table; 58 | i++; 59 | } 60 | 61 | /* Populate attributes */ 62 | qn->fields = &lex->select_lex.item_list; 63 | /* Process joins */ 64 | if (num_tables > 0) //indicates more than 1 table processed 65 | for(table = tables; table; table = table->next_local) 66 | if (((Item *)table->join_cond() != 0) && (qn->join_expr == 0)) 67 | qn->join_expr = (Item *)table->join_cond(); 68 | qn->where_expr = lex->select_lex.where; 69 | qt->root = qn; 70 | DBUG_RETURN(qt); 71 | } 72 | 73 | /* 74 | Perform Select Command 75 | 76 | SYNOPSIS 77 | DBXP_select_command() 78 | THD *thd IN the current thread 79 | 80 | DESCRIPTION 81 | This method executes the SELECT command using the query tree and optimizer. 82 | 83 | RETURN VALUE 84 | Success = 0 85 | Failed = 1 86 | */ 87 | int DBXP_select_command(THD *thd) 88 | { 89 | DBUG_ENTER("DBXP_select_command"); 90 | Query_tree *qt = build_query_tree(thd, thd->lex, 91 | (TABLE_LIST*) thd->lex->select_lex.table_list.first); 92 | List field_list; 93 | Protocol *protocol= thd->protocol; 94 | field_list.push_back(new Item_empty_string("Database Experiment Project (DBXP)",40)); 95 | if (protocol->send_result_set_metadata(&field_list, 96 | Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 97 | DBUG_RETURN(TRUE); 98 | protocol->prepare_for_resend(); 99 | protocol->store("Query tree was built.", system_charset_info); 100 | if (protocol->write()) 101 | DBUG_RETURN(TRUE); 102 | my_eof(thd); 103 | DBUG_RETURN(0); 104 | } 105 | 106 | /* 107 | Write to vio with printf. 108 | 109 | SYNOPSIS 110 | write_printf() 111 | Protocol *p IN the Protocol class 112 | char *first IN the first string to write 113 | char *last IN the last string to write 114 | 115 | DESCRIPTION 116 | This method writes to the vio routines printing the strings passed. 117 | 118 | RETURN VALUE 119 | Success = 0 120 | Failed = 1 121 | */ 122 | int write_printf(Protocol *p, char *first, const char *last) 123 | { 124 | char *str = new char[1024]; 125 | 126 | DBUG_ENTER("write_printf"); 127 | strcpy(str, first); 128 | strcat(str, last); 129 | p->prepare_for_resend(); 130 | p->store(str, system_charset_info); 131 | p->write(); 132 | delete str; 133 | DBUG_RETURN(0); 134 | } 135 | 136 | /* 137 | Show Query Plan 138 | 139 | SYNOPSIS 140 | show_plan() 141 | Protocol *p IN the MySQL protocol class 142 | query_node *Root IN the root node of the query tree 143 | query_node *qn IN the starting node to be operated on. 144 | bool print_on_right IN indicates the printing should tab to the right 145 | of the display. 146 | 147 | DESCRIPTION 148 | This method prints the execute plan to the client via the protocol class 149 | 150 | WARNING 151 | This is a RECURSIVE method! 152 | Uses postorder traversal to draw the quey plan 153 | 154 | RETURN VALUE 155 | Success = 0 156 | Failed = 1 157 | */ 158 | int show_plan(Protocol *p, Query_tree::query_node *root, 159 | Query_tree::query_node *qn, bool print_on_right) 160 | { 161 | DBUG_ENTER("show_plan"); 162 | 163 | /* spacer is used to fill white space in the output */ 164 | char *spacer = (char *)my_malloc(80, MYF(MY_ZEROFILL | MY_WME)); 165 | char *tblname = (char *)my_malloc(256, MYF(MY_ZEROFILL | MY_WME)); 166 | int i = 0; 167 | 168 | if(qn != 0) 169 | { 170 | show_plan(p, root, qn->left, print_on_right); 171 | show_plan(p, root, qn->right, true); 172 | 173 | /* draw incoming arrows */ 174 | if(print_on_right) 175 | strcpy(spacer, " | "); 176 | else 177 | strcpy(spacer, " "); 178 | 179 | /* Write out the name of the database and table */ 180 | if((qn->left == NULL) && (qn->right == NULL)) 181 | { 182 | /* 183 | If this is a join, it has 2 children so we need to write 184 | the children nodes feeding the join node. Spaces are used 185 | to place the tables side-by-side. 186 | */ 187 | if(qn->node_type == Query_tree::qntJoin) 188 | { 189 | strcpy(tblname, spacer); 190 | strcat(tblname, qn->relations[0]->db); 191 | strcat(tblname, "."); 192 | strcat(tblname, qn->relations[0]->table_name); 193 | if(strlen(tblname) < 15) 194 | strcat(tblname, " "); 195 | else 196 | strcat(tblname, " "); 197 | strcat(tblname, qn->relations[1]->db); 198 | strcat(tblname, "."); 199 | strcat(tblname, qn->relations[1]->table_name); 200 | write_printf(p, tblname, ""); 201 | write_printf(p, spacer, " | |"); 202 | write_printf(p, spacer, " | ----------------------------"); 203 | write_printf(p, spacer, " | |"); 204 | write_printf(p, spacer, " V V"); 205 | } 206 | else 207 | { 208 | strcpy(tblname, spacer); 209 | strcat(tblname, qn->relations[0]->db); 210 | strcat(tblname, "."); 211 | strcat(tblname, qn->relations[0]->table_name); 212 | write_printf(p, tblname, ""); 213 | write_printf(p, spacer, " |"); 214 | write_printf(p, spacer, " |"); 215 | write_printf(p, spacer, " |"); 216 | write_printf(p, spacer, " V"); 217 | } 218 | } 219 | else if((qn->left != 0) && (qn->right != 0)) 220 | { 221 | write_printf(p, spacer, " | |"); 222 | write_printf(p, spacer, " | ----------------------------"); 223 | write_printf(p, spacer, " | |"); 224 | write_printf(p, spacer, " V V"); 225 | } 226 | else if((qn->left != 0) && (qn->right == 0)) 227 | { 228 | write_printf(p, spacer, " |"); 229 | write_printf(p, spacer, " |"); 230 | write_printf(p, spacer, " |"); 231 | write_printf(p, spacer, " V"); 232 | } 233 | else if(qn->right != 0) 234 | { 235 | } 236 | write_printf(p, spacer, "-------------------"); 237 | 238 | /* Write out the node type */ 239 | switch(qn->node_type) 240 | { 241 | case Query_tree::qntProject: 242 | { 243 | write_printf(p, spacer, "| PROJECT |"); 244 | write_printf(p, spacer, "-------------------"); 245 | break; 246 | } 247 | case Query_tree::qntRestrict: 248 | { 249 | write_printf(p, spacer, "| RESTRICT |"); 250 | write_printf(p, spacer, "-------------------"); 251 | break; 252 | } 253 | case Query_tree::qntJoin: 254 | { 255 | write_printf(p, spacer, "| JOIN |"); 256 | write_printf(p, spacer, "-------------------"); 257 | break; 258 | } 259 | case Query_tree::qntDistinct: 260 | { 261 | write_printf(p, spacer, "| DISTINCT |"); 262 | write_printf(p, spacer, "-------------------"); 263 | break; 264 | } 265 | default: 266 | { 267 | write_printf(p, spacer, "| UNDEF |"); 268 | write_printf(p, spacer, "-------------------"); 269 | break; 270 | } 271 | } 272 | write_printf(p, spacer, "| Access Method: |"); 273 | write_printf(p, spacer, "| iterator |"); 274 | write_printf(p, spacer, "-------------------"); 275 | if(qn == root) 276 | { 277 | write_printf(p, spacer, " |"); 278 | write_printf(p, spacer, " |"); 279 | write_printf(p, spacer, " V"); 280 | write_printf(p, spacer, " Result Set"); 281 | } 282 | } 283 | my_free(spacer); 284 | my_free(tblname); 285 | DBUG_RETURN(0); 286 | } 287 | 288 | /* 289 | Perform EXPLAIN command. 290 | 291 | SYNOPSIS 292 | DBXP_explain_select_command() 293 | THD *thd IN the current thread 294 | 295 | DESCRIPTION 296 | This method executes the EXPLAIN SELECT command. 297 | 298 | RETURN VALUE 299 | Success = 0 300 | Failed = 1 301 | */ 302 | int DBXP_explain_select_command(THD *thd) 303 | { 304 | DBUG_ENTER("DBXP_explain_select_command"); 305 | Query_tree *qt = build_query_tree(thd, thd->lex, 306 | (TABLE_LIST*) thd->lex->select_lex.table_list.first); 307 | List field_list; 308 | Protocol *protocol= thd->protocol; 309 | field_list.push_back(new Item_empty_string("Execution Path",NAME_LEN)); 310 | if (protocol->send_result_set_metadata(&field_list, 311 | Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 312 | DBUG_RETURN(TRUE); 313 | protocol->prepare_for_resend(); 314 | show_plan(protocol, qt->root, qt->root, false); 315 | my_eof(thd); 316 | DBUG_RETURN(0); 317 | } 318 | -------------------------------------------------------------------------------- /Ch13/attribute.cc: -------------------------------------------------------------------------------- 1 | /* 2 | attribute.cc 3 | 4 | DESCRIPTION 5 | This file contains methods to encapsulate the attributes in a query. 6 | 7 | SEE ALSO 8 | attribute.h 9 | */ 10 | #include "attribute.h" 11 | 12 | /* 13 | Constructor 14 | 15 | SYNOPSIS 16 | Attribute() 17 | 18 | DESCRIPTION 19 | Initializes the hidden attribute array. 20 | */ 21 | Attribute::Attribute(void) 22 | { 23 | int i; 24 | for (i = 0; i < 256; i++) 25 | hidden[i] = false; 26 | } 27 | 28 | /* 29 | Remove Attribute 30 | 31 | SYNOPSIS 32 | remove_attribute() 33 | int num IN the number (starting at 0) of the sttribute to drop. 34 | 35 | DESCRIPTION 36 | This method removes the attribute from the collection. 37 | 38 | RETURN VALUE 39 | Success = true 40 | Failed = false 41 | */ 42 | int Attribute::remove_attribute(int num) 43 | { 44 | int j = 0; 45 | List_iterator it(attr_list); 46 | Item *item = NULL; 47 | 48 | DBUG_ENTER("remove_attribute"); 49 | if (num >= (int)attr_list.elements || num < 0) 50 | DBUG_RETURN(false); 51 | while ((item = it++)) 52 | { 53 | if (j == num) 54 | { 55 | it.remove(); 56 | DBUG_RETURN(true); 57 | } 58 | j++; 59 | } 60 | DBUG_RETURN(false); 61 | } 62 | 63 | /* 64 | Get Attribute 65 | 66 | SYNOPSIS 67 | get_attribute() 68 | int num IN the number of attribute to retrieve. 69 | 70 | DESCRIPTION 71 | This method returns the attribute at the index specified. 72 | 73 | RETURN VALUE 74 | Success = Item * 75 | Failed = NULL 76 | */ 77 | Item *Attribute::get_attribute(int num) 78 | { 79 | int j = 0; 80 | List it(attr_list); 81 | Item *item = it.pop(); 82 | 83 | DBUG_ENTER("get_attribute"); 84 | if (num >= (int)attr_list.elements || num < 0) 85 | DBUG_RETURN(NULL); 86 | while ((j != num) && (item != NULL)) 87 | { 88 | item = it.pop(); 89 | j++; 90 | } 91 | if (j != num) 92 | item = 0; 93 | DBUG_RETURN(item); 94 | } 95 | 96 | /* 97 | Add Attribute 98 | 99 | SYNOPSIS 100 | add_attribute() 101 | bool append IN do you want to append (true) or prepend (false)? 102 | Item *new_item IN the item to be added. 103 | 104 | DESCRIPTION 105 | This method adds the attribute at the front or back of the list. 106 | 107 | RETURN VALUE 108 | Success = 0 109 | Failed = 1 110 | */ 111 | int Attribute::add_attribute(bool append, Item *new_item) 112 | { 113 | DBUG_ENTER("add_attribute"); 114 | if (append) 115 | attr_list.push_back(new_item); 116 | else 117 | attr_list.push_front(new_item); 118 | DBUG_RETURN(0); 119 | } 120 | 121 | /* 122 | Number of Attributes 123 | 124 | SYNOPSIS 125 | num_attributes() 126 | 127 | DESCRIPTION 128 | This method returns the number of attributes in the list. 129 | 130 | RETURN VALUE 131 | int Number of attributes in list 132 | */ 133 | int Attribute::num_attributes() 134 | { 135 | DBUG_ENTER("num_attributes"); 136 | DBUG_RETURN(attr_list.elements); 137 | } 138 | 139 | /* 140 | Find index of Attribute 141 | 142 | SYNOPSIS 143 | index_of() 144 | char *table IN table name of the attribute 145 | char *value IN the name of the attribute 146 | 147 | DESCRIPTION 148 | This method returns the index (number) of attribute specified. 149 | 150 | RETURN VALUE 151 | Success = int Number of attribute 152 | Failed = -1 153 | */ 154 | int Attribute::index_of(char *table, char *value) 155 | { 156 | List_iterator it(attr_list); 157 | Item *item; 158 | int i = 0; 159 | int j = -1; 160 | bool found = false; 161 | 162 | DBUG_ENTER("index_of"); 163 | while ((item = it++) && !found) 164 | { 165 | if ((strcasecmp(((Field *)item)->field_name, value) == 0) && 166 | ((table == NULL) || 167 | (strcasecmp(*((Field *)item)->table_name, table) == 0))) 168 | { 169 | j = i; 170 | found = true; 171 | } 172 | i++; 173 | } 174 | DBUG_RETURN(j); 175 | } 176 | 177 | /* 178 | Hide Attribute 179 | 180 | SYNOPSIS 181 | hide_attribute() 182 | int num IN the number of attribute to hide. 183 | 184 | DESCRIPTION 185 | This method sets the hidden property of the attribute to specify 186 | that the attribute is not to be sent to the client (used internally) 187 | by the optimizer. 188 | 189 | RETURN VALUE 190 | Success = 0 191 | Failed = -1 192 | */ 193 | int Attribute::hide_attribute(Item *item, bool hide) 194 | { 195 | int i; 196 | DBUG_ENTER("hide_attribute"); 197 | i = index_of((char *)*((Field *)item)->table_name, 198 | (char *)((Field *)item)->field_name); 199 | if (i > -1) 200 | hidden[i] = hide; 201 | DBUG_RETURN(0); 202 | } 203 | 204 | /* 205 | Get string value of attributes 206 | 207 | SYNOPSIS 208 | to_string() 209 | 210 | DESCRIPTION 211 | This method returns a formatted string of the attributes in the list. 212 | 213 | RETURN VALUE 214 | Success = char * 215 | Failed = "" 216 | */ 217 | char *Attribute::to_string() 218 | { 219 | List_iterator it(attr_list); 220 | char *str = (char *)my_malloc(1024, MYF(MY_ZEROFILL | MY_WME)); 221 | Item *item; 222 | int j = 0; 223 | 224 | DBUG_ENTER("to_string"); 225 | strcpy(str, ""); 226 | while ((item = it++)) 227 | { 228 | if (j) 229 | strcat(str, ", "); 230 | if (*((Field *)item)->table_name) 231 | { 232 | strcat(str, *((Field *)item)->table_name); 233 | strcat(str, "."); 234 | } 235 | strcat(str, ((Field *)item)->field_name); 236 | if (!j) 237 | j = 1; 238 | } 239 | DBUG_RETURN(str); 240 | } 241 | -------------------------------------------------------------------------------- /Ch13/attribute.h: -------------------------------------------------------------------------------- 1 | #include "sql_priv.h" 2 | #include "sql_class.h" 3 | #include "table.h" 4 | 5 | class Attribute 6 | { 7 | public: 8 | Attribute(void); 9 | int remove_attribute(int num); 10 | Item *get_attribute(int num); 11 | int add_attribute(bool append, Item *new_item); 12 | int num_attributes(); 13 | int index_of(char *table, char *value); 14 | int hide_attribute(Item *item, bool hide); 15 | char *to_string(); 16 | private: 17 | List attr_list; 18 | bool hidden[256]; 19 | }; 20 | -------------------------------------------------------------------------------- /Ch13/ch13.result: -------------------------------------------------------------------------------- 1 | DROP DATABASE IF EXISTS expert_mysql; 2 | Warnings: 3 | Note 1008 Can't drop database 'expert_mysql'; database doesn't exist 4 | CREATE DATABASE expert_mysql; 5 | USE expert_mysql; 6 | CREATE TABLE `building` ( 7 | `dir_code` char(4) NOT NULL, 8 | `building` char(6) NOT NULL 9 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 10 | CREATE TABLE `directorate` ( 11 | `dir_code` char(4) NOT NULL, 12 | `dir_name` char(30) DEFAULT NULL, 13 | `dir_head_id` char(9) DEFAULT NULL, 14 | PRIMARY KEY (`dir_code`) 15 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 16 | CREATE TABLE `staff` ( 17 | `id` char(9) NOT NULL, 18 | `first_name` char(20) DEFAULT NULL, 19 | `mid_name` char(20) DEFAULT NULL, 20 | `last_name` char(30) DEFAULT NULL, 21 | `sex` char(1) DEFAULT NULL, 22 | `salary` int(11) DEFAULT NULL, 23 | `mgr_id` char(9) DEFAULT NULL, 24 | PRIMARY KEY (`id`) 25 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 26 | CREATE TABLE `tasking` ( 27 | `id` char(9) NOT NULL, 28 | `project_number` char(9) NOT NULL, 29 | `hours_worked` double DEFAULT NULL 30 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 31 | USE expert_mysql; 32 | INSERT INTO expert_mysql.building VALUES ('N41', '1300'); 33 | INSERT INTO expert_mysql.building VALUES ('N01', '1453'); 34 | INSERT INTO expert_mysql.building VALUES ('M00', '1000'); 35 | INSERT INTO expert_mysql.building VALUES ('N41', '1301'); 36 | INSERT INTO expert_mysql.building VALUES ('N41', '1305'); 37 | INSERT INTO expert_mysql.directorate VALUES ('N41', 'Development', '333445555'); 38 | INSERT INTO expert_mysql.directorate VALUES ('N01', 'Human Resources', '123654321'); 39 | INSERT INTO expert_mysql.directorate VALUES ('M00', 'Management', '333444444'); 40 | INSERT INTO expert_mysql.staff VALUES ('333445555', 'John', 'Q', 'Smith', 'M', 30000, '333444444'); 41 | INSERT INTO expert_mysql.staff VALUES ('123763153', 'William', 'E', 'Walters', 'M', 25000, '123654321'); 42 | INSERT INTO expert_mysql.staff VALUES ('333444444', 'Alicia', 'F', 'St.Cruz', 'F', 25000, 'None'); 43 | INSERT INTO expert_mysql.staff VALUES ('921312388', 'Goy', 'X', 'Hong', 'F', 40000, '123654321'); 44 | INSERT INTO expert_mysql.staff VALUES ('800122337', 'Rajesh', 'G', 'Kardakarna', 'M', 38000, '333445555'); 45 | INSERT INTO expert_mysql.staff VALUES ('820123637', 'Monty', 'C', 'Smythe', 'M', 38000, '333445555'); 46 | INSERT INTO expert_mysql.staff VALUES ('830132335', 'Richard', 'E', 'Jones', 'M', 38000, '333445555'); 47 | INSERT INTO expert_mysql.staff VALUES ('333445665', 'Edward', 'E', 'Engles', 'M', 25000, '333445555'); 48 | INSERT INTO expert_mysql.staff VALUES ('123654321', 'Beware', 'D', 'Borg', 'F', 55000, '333444444'); 49 | INSERT INTO expert_mysql.staff VALUES ('123456789', 'Wilma', 'N', 'Maxima', 'F', 43000, '333445555'); 50 | INSERT INTO expert_mysql.tasking VALUES ('333445555', '405', 23); 51 | INSERT INTO expert_mysql.tasking VALUES ('123763153', '405', 33.5); 52 | INSERT INTO expert_mysql.tasking VALUES ('921312388', '601', 44); 53 | INSERT INTO expert_mysql.tasking VALUES ('800122337', '300', 13); 54 | INSERT INTO expert_mysql.tasking VALUES ('820123637', '300', 9.5); 55 | INSERT INTO expert_mysql.tasking VALUES ('830132335', '401', 8.5); 56 | INSERT INTO expert_mysql.tasking VALUES ('333445555', '300', 11); 57 | INSERT INTO expert_mysql.tasking VALUES ('921312388', '500', 13); 58 | INSERT INTO expert_mysql.tasking VALUES ('800122337', '300', 44); 59 | INSERT INTO expert_mysql.tasking VALUES ('820123637', '401', 500.5); 60 | INSERT INTO expert_mysql.tasking VALUES ('830132335', '400', 12); 61 | INSERT INTO expert_mysql.tasking VALUES ('333445665', '600', 300.25); 62 | INSERT INTO expert_mysql.tasking VALUES ('123654321', '607', 444.75); 63 | INSERT INTO expert_mysql.tasking VALUES ('123456789', '300', 1000); 64 | DBXP_SELECT * FROM staff; 65 | Execution Path 66 | expert_mysql.staff 67 | | 68 | | 69 | | 70 | V 71 | ------------------- 72 | | PROJECT | 73 | ------------------- 74 | | Access Method: | 75 | | iterator | 76 | ------------------- 77 | | 78 | | 79 | V 80 | Result Set 81 | DBXP_SELECT id FROM staff WHERE staff.id = '123456789'; 82 | Execution Path 83 | expert_mysql.staff 84 | | 85 | | 86 | | 87 | V 88 | ------------------- 89 | | RESTRICT | 90 | ------------------- 91 | | Access Method: | 92 | | iterator | 93 | ------------------- 94 | | 95 | | 96 | | 97 | V 98 | ------------------- 99 | | PROJECT | 100 | ------------------- 101 | | Access Method: | 102 | | iterator | 103 | ------------------- 104 | | 105 | | 106 | V 107 | Result Set 108 | DBXP_SELECT id, dir_name FROM staff, directorate 109 | WHERE staff.mgr_id = directorate.dir_head_id; 110 | Execution Path 111 | expert_mysql.staff 112 | | 113 | | 114 | | 115 | V 116 | ------------------- 117 | | PROJECT | 118 | ------------------- 119 | | Access Method: | 120 | | iterator | 121 | ------------------- 122 | | expert_mysql.directorate 123 | | | 124 | | | 125 | | | 126 | | V 127 | | ------------------- 128 | | | PROJECT | 129 | | ------------------- 130 | | | Access Method: | 131 | | | iterator | 132 | | ------------------- 133 | | | 134 | | ---------------------------- 135 | | | 136 | V V 137 | ------------------- 138 | | JOIN | 139 | ------------------- 140 | | Access Method: | 141 | | iterator | 142 | ------------------- 143 | | 144 | | 145 | V 146 | Result Set 147 | DBXP_SELECT * FROM staff JOIN tasking ON staff.id = tasking.id 148 | WHERE staff.id = '123456789'; 149 | Execution Path 150 | expert_mysql.staff 151 | | 152 | | 153 | | 154 | V 155 | ------------------- 156 | | RESTRICT | 157 | ------------------- 158 | | Access Method: | 159 | | iterator | 160 | ------------------- 161 | | expert_mysql.tasking 162 | | | 163 | | | 164 | | | 165 | | V 166 | | ------------------- 167 | | | PROJECT | 168 | | ------------------- 169 | | | Access Method: | 170 | | | iterator | 171 | | ------------------- 172 | | | 173 | | ---------------------------- 174 | | | 175 | V V 176 | ------------------- 177 | | JOIN | 178 | ------------------- 179 | | Access Method: | 180 | | iterator | 181 | ------------------- 182 | | 183 | | 184 | V 185 | Result Set 186 | DROP DATABASE expert_mysql; 187 | -------------------------------------------------------------------------------- /Ch13/ch13.test: -------------------------------------------------------------------------------- 1 | # 2 | # Sample test to test the DBXP_SELECT optimizer 3 | # 4 | 5 | --source include/ch13.sql 6 | 7 | # Test 1: 8 | DBXP_SELECT * FROM staff; 9 | 10 | # Test 2: 11 | DBXP_SELECT id FROM staff WHERE staff.id = '123456789'; 12 | 13 | # Test 3: 14 | DBXP_SELECT id, dir_name FROM staff, directorate 15 | WHERE staff.mgr_id = directorate.dir_head_id; 16 | 17 | # Test 4: 18 | DBXP_SELECT * FROM staff JOIN tasking ON staff.id = tasking.id 19 | WHERE staff.id = '123456789'; 20 | 21 | DROP DATABASE expert_mysql; 22 | -------------------------------------------------------------------------------- /Ch13/ch13.txt: -------------------------------------------------------------------------------- 1 | DBXP_SELECT * FROM staff' at line 1 2 | +--------------------------+ 3 | | Execution Path | 4 | +--------------------------+ 5 | | expert_mysql.staff | 6 | | | | 7 | | | | 8 | | | | 9 | | V | 10 | | ------------------- | 11 | | | RESTRICT | | 12 | | ------------------- | 13 | | | Access Method: | | 14 | | | iterator | | 15 | | ------------------- | 16 | | | | 17 | | | | 18 | | | | 19 | | V | 20 | | ------------------- | 21 | | | PROJECT | | 22 | | ------------------- | 23 | | | Access Method: | | 24 | | | iterator | | 25 | | ------------------- | 26 | | | | 27 | | | | 28 | | V | 29 | | Result Set | 30 | +--------------------------+ 31 | 25 rows in set (0.00 sec) 32 | 33 | +----------------------------------------------------+ 34 | | Execution Path | 35 | +----------------------------------------------------+ 36 | | expert_mysql.staff | 37 | | | | 38 | | | | 39 | | | | 40 | | V | 41 | | ------------------- | 42 | | | PROJECT | | 43 | | ------------------- | 44 | | | Access Method: | | 45 | | | iterator | | 46 | | ------------------- | 47 | | | expert_mysql.directorate | 48 | | | | | 49 | | | | | 50 | | | | | 51 | | | V | 52 | | | ------------------- | 53 | | | | PROJECT | | 54 | | | ------------------- | 55 | | | | Access Method: | | 56 | | | | iterator | | 57 | | | ------------------- | 58 | | | | | 59 | | | ---------------------------- | 60 | | | | | 61 | | V V | 62 | | ------------------- | 63 | | | JOIN | | 64 | | ------------------- | 65 | | | Access Method: | | 66 | | | iterator | | 67 | | ------------------- | 68 | | | | 69 | | | | 70 | | V | 71 | | Result Set | 72 | +----------------------------------------------------+ 73 | 36 rows in set (0.00 sec) 74 | 75 | +------------------------------------------------+ 76 | | Execution Path | 77 | +------------------------------------------------+ 78 | | expert_mysql.staff | 79 | | | | 80 | | | | 81 | | | | 82 | | V | 83 | | ------------------- | 84 | | | RESTRICT | | 85 | | ------------------- | 86 | | | Access Method: | | 87 | | | iterator | | 88 | | ------------------- | 89 | | | expert_mysql.tasking | 90 | | | | | 91 | | | | | 92 | | | | | 93 | | | V | 94 | | | ------------------- | 95 | | | | PROJECT | | 96 | | | ------------------- | 97 | | | | Access Method: | | 98 | | | | iterator | | 99 | | | ------------------- | 100 | | | | | 101 | | | ---------------------------- | 102 | | | | | 103 | | V V | 104 | | ------------------- | 105 | | | JOIN | | 106 | | ------------------- | 107 | | | Access Method: | | 108 | | | iterator | | 109 | | ------------------- | 110 | | | | 111 | | | | 112 | | V | 113 | | Result Set | 114 | +------------------------------------------------+ 115 | 36 rows in set (0.00 sec) 116 | 117 | Query OK, 4 rows affected (0.00 sec) 118 | -------------------------------------------------------------------------------- /Ch13/ch13_results.txt: -------------------------------------------------------------------------------- 1 | mysql> explain dbxp_select * from staff; 2 | +--------------------------+ 3 | | Execution Path | 4 | +--------------------------+ 5 | | expert_mysql.staff | 6 | | | | 7 | | | | 8 | | | | 9 | | V | 10 | | ------------------- | 11 | | | PROJECT | | 12 | | ------------------- | 13 | | | Access Method: | | 14 | | | iterator | | 15 | | ------------------- | 16 | | | | 17 | | | | 18 | | V | 19 | | Result Set | 20 | +--------------------------+ 21 | 15 rows in set (0.00 sec) 22 | 23 | mysql> explain dbxp_select id FROM staff WHERE staff.id = '123456789'; 24 | +--------------------------+ 25 | | Execution Path | 26 | +--------------------------+ 27 | | expert_mysql.staff | 28 | | | | 29 | | | | 30 | | | | 31 | | V | 32 | | ------------------- | 33 | | | RESTRICT | | 34 | | ------------------- | 35 | | | Access Method: | | 36 | | | iterator | | 37 | | ------------------- | 38 | | | | 39 | | | | 40 | | | | 41 | | V | 42 | | ------------------- | 43 | | | PROJECT | | 44 | | ------------------- | 45 | | | Access Method: | | 46 | | | iterator | | 47 | | ------------------- | 48 | | | | 49 | | | | 50 | | V | 51 | | Result Set | 52 | +--------------------------+ 53 | 25 rows in set (0.00 sec) 54 | 55 | mysql> explain dbxp_select id, dir_name FROM staff, directorate WHERE staff.dno = directorate.dnumber; 56 | ERROR 1054 (42S22): Unknown column 'directorate.dnumber' in 'field list' 57 | mysql> explain dbxp_select id, dir_name FROM staff, directorate WHERE staff.dno = directorate.d; 58 | ERROR 1054 (42S22): Unknown column 'directorate.d' in 'field list' 59 | mysql> explain directorate 60 | -> ; 61 | +-------------+----------+------+-----+---------+-------+ 62 | | Field | Type | Null | Key | Default | Extra | 63 | +-------------+----------+------+-----+---------+-------+ 64 | | dir_code | char(4) | NO | PRI | NULL | | 65 | | dir_name | char(30) | YES | | NULL | | 66 | | dir_head_id | char(9) | YES | | NULL | | 67 | +-------------+----------+------+-----+---------+-------+ 68 | 3 rows in set (0.00 sec) 69 | 70 | mysql> explain dbxp_select id, dir_name FROM staff, directorate WHERE staff.dno = directorate.dir_code; 71 | ERROR 1054 (42S22): Unknown column 'staff.dno' in 'field list' 72 | mysql> explain dbxp_select id, dir_name FROM staff, directorate WHERE staff.dno = directorate.dir_code; 73 | ERROR 1054 (42S22): Unknown column 'staff.dno' in 'field list' 74 | mysql> explain staff; 75 | +------------+----------+------+-----+---------+-------+ 76 | | Field | Type | Null | Key | Default | Extra | 77 | +------------+----------+------+-----+---------+-------+ 78 | | id | char(9) | NO | PRI | NULL | | 79 | | first_name | char(20) | YES | | NULL | | 80 | | mid_name | char(20) | YES | | NULL | | 81 | | last_name | char(30) | YES | | NULL | | 82 | | sex | char(1) | YES | | NULL | | 83 | | salary | int(11) | YES | | NULL | | 84 | | mgr_id | char(9) | YES | | NULL | | 85 | +------------+----------+------+-----+---------+-------+ 86 | 7 rows in set (0.00 sec) 87 | 88 | mysql> explain dbxp_select id, dir_name FROM staff, directorate WHERE staff.mgr_id = directorate.dir_code; 89 | +----------------------------------------------------+ 90 | | Execution Path | 91 | +----------------------------------------------------+ 92 | | expert_mysql.staff | 93 | | | | 94 | | | | 95 | | | | 96 | | V | 97 | | ------------------- | 98 | | | PROJECT | | 99 | | ------------------- | 100 | | | Access Method: | | 101 | | | iterator | | 102 | | ------------------- | 103 | | | expert_mysql.directorate | 104 | | | | | 105 | | | | | 106 | | | | | 107 | | | V | 108 | | | ------------------- | 109 | | | | PROJECT | | 110 | | | ------------------- | 111 | | | | Access Method: | | 112 | | | | iterator | | 113 | | | ------------------- | 114 | | | | | 115 | | | ---------------------------- | 116 | | | | | 117 | | V V | 118 | | ------------------- | 119 | | | JOIN | | 120 | | ------------------- | 121 | | | Access Method: | | 122 | | | iterator | | 123 | | ------------------- | 124 | | | | 125 | | | | 126 | | V | 127 | | Result Set | 128 | +----------------------------------------------------+ 129 | 36 rows in set (0.00 sec) 130 | 131 | mysql> explain dbxp_select FROM staff JOIN tasking ON staff.id = tasking.id WHERE staff.id = '123456789'; 132 | +------------------------------------------------+ 133 | | Execution Path | 134 | +------------------------------------------------+ 135 | | expert_mysql.staff | 136 | | | | 137 | | | | 138 | | | | 139 | | V | 140 | | ------------------- | 141 | | | RESTRICT | | 142 | | ------------------- | 143 | | | Access Method: | | 144 | | | iterator | | 145 | | ------------------- | 146 | | | expert_mysql.tasking | 147 | | | | | 148 | | | | | 149 | | | | | 150 | | | V | 151 | | | ------------------- | 152 | | | | PROJECT | | 153 | | | ------------------- | 154 | | | | Access Method: | | 155 | | | | iterator | | 156 | | | ------------------- | 157 | | | | | 158 | | | ---------------------------- | 159 | | | | | 160 | | V V | 161 | | ------------------- | 162 | | | JOIN | | 163 | | ------------------- | 164 | | | Access Method: | | 165 | | | iterator | | 166 | | ------------------- | 167 | | | | 168 | | | | 169 | | V | 170 | | Result Set | 171 | +------------------------------------------------+ 172 | 36 rows in set (0.00 sec) 173 | -------------------------------------------------------------------------------- /Ch13/expression.h: -------------------------------------------------------------------------------- 1 | #include "sql_priv.h" 2 | #include "sql_class.h" 3 | #include "table.h" 4 | #include 5 | 6 | struct expr_node 7 | { 8 | Item *left_op; 9 | Item *operation; 10 | Item *right_op; 11 | Item *junction; 12 | expr_node *next; 13 | }; 14 | 15 | class Expression 16 | { 17 | public: 18 | Expression(void); 19 | int remove_expression(int num, bool free); 20 | expr_node *get_expression(int num); 21 | int add_expression(bool append, expr_node *new_item); 22 | int num_expressions(); 23 | int index_of(char *table, char *value); 24 | int reduce_expressions(TABLE *table); 25 | bool has_table(char *table); 26 | int convert(THD *thd, Item *mysql_expr); 27 | char *to_string(); 28 | bool evaluate(TABLE *table1); 29 | int compare_join(expr_node *expr, TABLE *t1, TABLE *t2); 30 | int get_join_expr(Expression *where_expr); 31 | private: 32 | expr_node *root; 33 | Field *find_field(TABLE *tbl, char *name); 34 | bool compare(expr_node *expr, TABLE *t1); 35 | int num_expr; 36 | }; 37 | -------------------------------------------------------------------------------- /Ch13/query_tree.h: -------------------------------------------------------------------------------- 1 | /* 2 | Query_tree.h 3 | 4 | DESCRIPTION 5 | This file contains the Query_tree class. It is responsible for containing the 6 | internal representation of the query to be executed. It provides methods for 7 | optimizing and forming and inspecting the query tree. This class is the very 8 | heart of the DBXP query capability! It also provides the ability to store 9 | a binary "compiled" form of the query. 10 | 11 | NOTES 12 | The data structure is a binary tree that can have 0, 1, or 2 children. Only 13 | Join operations can have 2 children. All other operations have 0 or 1 14 | children. Each node in the tree is an operation and the links to children 15 | are the pipeline. 16 | 17 | SEE ALSO 18 | query_tree.cc 19 | */ 20 | #include "attribute.h" 21 | #include "expression.h" 22 | #include "sql_priv.h" 23 | #include "sql_class.h" 24 | #include "table.h" 25 | #include "records.h" 26 | 27 | const int MAXNODETABLES = 4; 28 | const int LEFTCHILD = 0; 29 | const int RIGHTCHILD = 1; 30 | 31 | class Query_tree 32 | { 33 | public: 34 | enum query_node_type //this enumeration lists the available 35 | { //query node (operations) 36 | qntUndefined = 0, 37 | qntRestrict = 1, 38 | qntProject = 2, 39 | qntJoin = 3, 40 | qntSort = 4, 41 | qntDistinct = 5 42 | }; 43 | 44 | enum join_con_type //this enumeration lists the available 45 | { //join operations supported 46 | jcUN = 0, 47 | jcNA = 1, 48 | jcON = 2, 49 | jcUS = 3 50 | }; 51 | 52 | enum type_join //this enumeration lists the available 53 | { //join types supported. 54 | jnUNKNOWN = 0, //undefined 55 | jnINNER = 1, 56 | jnLEFTOUTER = 2, 57 | jnRIGHTOUTER = 3, 58 | jnFULLOUTER = 4, 59 | jnCROSSPRODUCT = 5, 60 | jnUNION = 6, 61 | jnINTERSECT = 7 62 | }; 63 | 64 | enum AggregateType //used to add aggregate functions 65 | { 66 | atNONE = 0, 67 | atCOUNT = 1 68 | }; 69 | 70 | /* 71 | STRUCTURE query_node 72 | 73 | DESCRIPTION 74 | This this structure contains all of the data for a query node: 75 | 76 | NodeId -- the internal id number for a node 77 | ParentNodeId -- the internal id for the parent node (used for insert) 78 | SubQuery -- is this the start of a subquery? 79 | Child -- is this a Left or Right child of the parent? 80 | NodeType -- synonymous with operation type 81 | JoinType -- if a join, this is the join operation 82 | join_con_type -- if this is a join, this is the "on" condition 83 | Expressions -- the expressions from the "where" clause for this node 84 | Join Expressions -- the join expressions from the "join" clause(s) 85 | Relations[] -- the relations for this operation (at most 2) 86 | PreemptPipeline -- does the pipeline need to be halted for a sort? 87 | Fields -- the attributes for the result set of this operation 88 | Left -- a pointer to the left child node 89 | Right -- a pointer to the right child node 90 | */ 91 | struct query_node 92 | { 93 | query_node(); 94 | ~query_node(); 95 | int nodeid; 96 | int parent_nodeid; 97 | bool sub_query; 98 | int child; 99 | query_node_type node_type; 100 | type_join join_type; 101 | join_con_type join_cond; 102 | Expression *where_expr; 103 | Expression *join_expr; 104 | TABLE_LIST *relations[MAXNODETABLES]; 105 | int eof[MAXNODETABLES]; 106 | int ndx[MAXNODETABLES]; 107 | bool preempt_pipeline; 108 | Attribute *attributes; 109 | query_node *left; 110 | query_node *right; 111 | }; 112 | 113 | struct record_buff 114 | { 115 | uchar *field_ptr; 116 | long field_length; 117 | record_buff *next; 118 | record_buff *prev; 119 | READ_RECORD *record; 120 | }; 121 | 122 | query_node *root; //The ROOT node of the tree 123 | 124 | Query_tree(void); 125 | ~Query_tree(void); 126 | int init_node(query_node *qn); 127 | int heuristic_optimization(); 128 | int cost_optimization(); 129 | int insert_attribute(query_node *qn, Item *c); 130 | bool distinct; 131 | int prepare(query_node *qn); 132 | int cleanup(query_node *qn); 133 | bool Eof(query_node *qn); 134 | READ_RECORD *get_next(query_node *qn); 135 | List result_fields; 136 | 137 | private: 138 | bool h_opt; //has query been optimized (rules)? 139 | bool c_opt; //has query been optimized (cost)? 140 | READ_RECORD *lbuff; 141 | READ_RECORD *rbuff; 142 | record_buff *left_record_buff; 143 | record_buff *right_record_buff; 144 | record_buff *left_record_buffer_ptr; 145 | record_buff *right_record_buffer_ptr; 146 | 147 | int push_projections(query_node *qn, query_node *pNode); 148 | query_node *find_projection(query_node *qn); 149 | bool is_leaf(query_node *qn); 150 | bool has_relation(query_node *qn, char *Table); 151 | bool has_attribute(query_node *qn, Item *a); 152 | int del_attribute(query_node *qn, Item *a); 153 | int push_restrictions(query_node *qn, query_node *pNode); 154 | query_node *find_restriction(query_node *qn); 155 | query_node *find_join(query_node *qn); 156 | int push_joins(query_node *qn, query_node *pNode); 157 | int prune_tree(query_node *prev, query_node *cur_node); 158 | int balance_joins(query_node *qn); 159 | int split_restrict_with_project(query_node *qn); 160 | int split_restrict_with_join(query_node *qn); 161 | int split_project_with_join(query_node *qn); 162 | bool find_table_in_tree(query_node *qn, char *tbl); 163 | bool find_table_in_expr(Expression *expr, char *tbl); 164 | bool find_attr_in_expr(Expression *expr, char *tbl, char *value); 165 | int apply_indexes(query_node *qn); 166 | bool do_restrict(query_node *qn, READ_RECORD *t); 167 | READ_RECORD *do_project(query_node *qn, READ_RECORD *t); 168 | READ_RECORD *do_join(query_node *qn); 169 | int find_index_in_expr(Expression *e, char *tbl); 170 | TABLE *get_table(query_node *qn); 171 | int insertion_sort(bool left, Field *field, READ_RECORD *rcd); 172 | int check_rollback(record_buff *cur_left, record_buff *curr_left_prev, 173 | record_buff *cur_right, record_buff *cur_right_prev); 174 | }; 175 | 176 | -------------------------------------------------------------------------------- /Ch13/source_Ch13.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Ch13/source_Ch13.zip -------------------------------------------------------------------------------- /Ch14/attribute.cc: -------------------------------------------------------------------------------- 1 | /* 2 | attribute.cc 3 | 4 | DESCRIPTION 5 | This file contains methods to encapsulate the attributes in a query. 6 | 7 | SEE ALSO 8 | attribute.h 9 | */ 10 | #include "attribute.h" 11 | 12 | /* 13 | Constructor 14 | 15 | SYNOPSIS 16 | Attribute() 17 | 18 | DESCRIPTION 19 | Initializes the hidden attribute array. 20 | */ 21 | Attribute::Attribute(void) 22 | { 23 | int i; 24 | for (i = 0; i < 256; i++) 25 | hidden[i] = false; 26 | } 27 | 28 | /* 29 | Remove Attribute 30 | 31 | SYNOPSIS 32 | remove_attribute() 33 | int num IN the number (starting at 0) of the sttribute to drop. 34 | 35 | DESCRIPTION 36 | This method removes the attribute from the collection. 37 | 38 | RETURN VALUE 39 | Success = true 40 | Failed = false 41 | */ 42 | int Attribute::remove_attribute(int num) 43 | { 44 | int j = 0; 45 | List_iterator it(attr_list); 46 | Item *item = NULL; 47 | 48 | DBUG_ENTER("remove_attribute"); 49 | if (num >= (int)attr_list.elements || num < 0) 50 | DBUG_RETURN(false); 51 | while ((item = it++)) 52 | { 53 | if (j == num) 54 | { 55 | it.remove(); 56 | DBUG_RETURN(true); 57 | } 58 | j++; 59 | } 60 | DBUG_RETURN(false); 61 | } 62 | 63 | /* 64 | Get Attribute 65 | 66 | SYNOPSIS 67 | get_attribute() 68 | int num IN the number of attribute to retrieve. 69 | 70 | DESCRIPTION 71 | This method returns the attribute at the index specified. 72 | 73 | RETURN VALUE 74 | Success = Item * 75 | Failed = NULL 76 | */ 77 | Item *Attribute::get_attribute(int num) 78 | { 79 | int j = 0; 80 | List it(attr_list); 81 | Item *item = it.pop(); 82 | 83 | DBUG_ENTER("get_attribute"); 84 | if (num >= (int)attr_list.elements || num < 0) 85 | DBUG_RETURN(NULL); 86 | while ((j != num) && (item != NULL)) 87 | { 88 | item = it.pop(); 89 | j++; 90 | } 91 | if (j != num) 92 | item = 0; 93 | DBUG_RETURN(item); 94 | } 95 | 96 | /* 97 | Add Attribute 98 | 99 | SYNOPSIS 100 | add_attribute() 101 | bool append IN do you want to append (true) or prepend (false)? 102 | Item *new_item IN the item to be added. 103 | 104 | DESCRIPTION 105 | This method adds the attribute at the front or back of the list. 106 | 107 | RETURN VALUE 108 | Success = 0 109 | Failed = 1 110 | */ 111 | int Attribute::add_attribute(bool append, Item *new_item) 112 | { 113 | DBUG_ENTER("add_attribute"); 114 | if (append) 115 | attr_list.push_back(new_item); 116 | else 117 | attr_list.push_front(new_item); 118 | DBUG_RETURN(0); 119 | } 120 | 121 | /* 122 | Number of Attributes 123 | 124 | SYNOPSIS 125 | num_attributes() 126 | 127 | DESCRIPTION 128 | This method returns the number of attributes in the list. 129 | 130 | RETURN VALUE 131 | int Number of attributes in list 132 | */ 133 | int Attribute::num_attributes() 134 | { 135 | DBUG_ENTER("num_attributes"); 136 | DBUG_RETURN(attr_list.elements); 137 | } 138 | 139 | /* 140 | Find index of Attribute 141 | 142 | SYNOPSIS 143 | index_of() 144 | char *table IN table name of the attribute 145 | char *value IN the name of the attribute 146 | 147 | DESCRIPTION 148 | This method returns the index (number) of attribute specified. 149 | 150 | RETURN VALUE 151 | Success = int Number of attribute 152 | Failed = -1 153 | */ 154 | int Attribute::index_of(char *table, char *value) 155 | { 156 | List_iterator it(attr_list); 157 | Item *item; 158 | int i = 0; 159 | int j = -1; 160 | bool found = false; 161 | 162 | DBUG_ENTER("index_of"); 163 | while ((item = it++) && !found) 164 | { 165 | if ((strcasecmp(((Field *)item)->field_name, value) == 0) && 166 | ((table == NULL) || 167 | (strcasecmp(*((Field *)item)->table_name, table) == 0))) 168 | { 169 | j = i; 170 | found = true; 171 | } 172 | i++; 173 | } 174 | DBUG_RETURN(j); 175 | } 176 | 177 | /* 178 | Hide Attribute 179 | 180 | SYNOPSIS 181 | hide_attribute() 182 | int num IN the number of attribute to hide. 183 | 184 | DESCRIPTION 185 | This method sets the hidden property of the attribute to specify 186 | that the attribute is not to be sent to the client (used internally) 187 | by the optimizer. 188 | 189 | RETURN VALUE 190 | Success = 0 191 | Failed = -1 192 | */ 193 | int Attribute::hide_attribute(Item *item, bool hide) 194 | { 195 | int i; 196 | DBUG_ENTER("hide_attribute"); 197 | i = index_of((char *)*((Field *)item)->table_name, 198 | (char *)((Field *)item)->field_name); 199 | if (i > -1) 200 | hidden[i] = hide; 201 | DBUG_RETURN(0); 202 | } 203 | 204 | /* 205 | Get string value of attributes 206 | 207 | SYNOPSIS 208 | to_string() 209 | 210 | DESCRIPTION 211 | This method returns a formatted string of the attributes in the list. 212 | 213 | RETURN VALUE 214 | Success = char * 215 | Failed = "" 216 | */ 217 | char *Attribute::to_string() 218 | { 219 | List_iterator it(attr_list); 220 | char *str = (char *)my_malloc(1024, MYF(MY_ZEROFILL | MY_WME)); 221 | Item *item; 222 | int j = 0; 223 | 224 | DBUG_ENTER("to_string"); 225 | strcpy(str, ""); 226 | while ((item = it++)) 227 | { 228 | if (j) 229 | strcat(str, ", "); 230 | if (*((Field *)item)->table_name) 231 | { 232 | strcat(str, *((Field *)item)->table_name); 233 | strcat(str, "."); 234 | } 235 | strcat(str, ((Field *)item)->field_name); 236 | if (!j) 237 | j = 1; 238 | } 239 | DBUG_RETURN(str); 240 | } 241 | -------------------------------------------------------------------------------- /Ch14/attribute.h: -------------------------------------------------------------------------------- 1 | #include "sql_priv.h" 2 | #include "sql_class.h" 3 | #include "table.h" 4 | 5 | class Attribute 6 | { 7 | public: 8 | Attribute(void); 9 | int remove_attribute(int num); 10 | Item *get_attribute(int num); 11 | int add_attribute(bool append, Item *new_item); 12 | int num_attributes(); 13 | int index_of(char *table, char *value); 14 | int hide_attribute(Item *item, bool hide); 15 | char *to_string(); 16 | private: 17 | List attr_list; 18 | bool hidden[256]; 19 | }; 20 | -------------------------------------------------------------------------------- /Ch14/ch14.result: -------------------------------------------------------------------------------- 1 | DROP DATABASE IF EXISTS expert_mysql; 2 | Warnings: 3 | Note 1008 Can't drop database 'expert_mysql'; database doesn't exist 4 | CREATE DATABASE expert_mysql; 5 | USE expert_mysql; 6 | CREATE TABLE `building` ( 7 | `dir_code` char(4) NOT NULL, 8 | `building` char(6) NOT NULL 9 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 10 | CREATE TABLE `directorate` ( 11 | `dir_code` char(4) NOT NULL, 12 | `dir_name` char(30) DEFAULT NULL, 13 | `dir_head_id` char(9) DEFAULT NULL, 14 | PRIMARY KEY (`dir_code`) 15 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 16 | CREATE TABLE `staff` ( 17 | `id` char(9) NOT NULL, 18 | `first_name` char(20) DEFAULT NULL, 19 | `mid_name` char(20) DEFAULT NULL, 20 | `last_name` char(30) DEFAULT NULL, 21 | `sex` char(1) DEFAULT NULL, 22 | `salary` int(11) DEFAULT NULL, 23 | `mgr_id` char(9) DEFAULT NULL, 24 | PRIMARY KEY (`id`) 25 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 26 | CREATE TABLE `tasking` ( 27 | `id` char(9) NOT NULL, 28 | `project_number` char(9) NOT NULL, 29 | `hours_worked` double DEFAULT NULL 30 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 31 | USE expert_mysql; 32 | INSERT INTO expert_mysql.building VALUES ('N41', '1300'); 33 | INSERT INTO expert_mysql.building VALUES ('N01', '1453'); 34 | INSERT INTO expert_mysql.building VALUES ('M00', '1000'); 35 | INSERT INTO expert_mysql.building VALUES ('N41', '1301'); 36 | INSERT INTO expert_mysql.building VALUES ('N41', '1305'); 37 | INSERT INTO expert_mysql.directorate VALUES ('N41', 'Development', '333445555'); 38 | INSERT INTO expert_mysql.directorate VALUES ('N01', 'Human Resources', '123654321'); 39 | INSERT INTO expert_mysql.directorate VALUES ('M00', 'Management', '333444444'); 40 | INSERT INTO expert_mysql.staff VALUES ('333445555', 'John', 'Q', 'Smith', 'M', 30000, '333444444'); 41 | INSERT INTO expert_mysql.staff VALUES ('123763153', 'William', 'E', 'Walters', 'M', 25000, '123654321'); 42 | INSERT INTO expert_mysql.staff VALUES ('333444444', 'Alicia', 'F', 'St.Cruz', 'F', 25000, 'None'); 43 | INSERT INTO expert_mysql.staff VALUES ('921312388', 'Goy', 'X', 'Hong', 'F', 40000, '123654321'); 44 | INSERT INTO expert_mysql.staff VALUES ('800122337', 'Rajesh', 'G', 'Kardakarna', 'M', 38000, '333445555'); 45 | INSERT INTO expert_mysql.staff VALUES ('820123637', 'Monty', 'C', 'Smythe', 'M', 38000, '333445555'); 46 | INSERT INTO expert_mysql.staff VALUES ('830132335', 'Richard', 'E', 'Jones', 'M', 38000, '333445555'); 47 | INSERT INTO expert_mysql.staff VALUES ('333445665', 'Edward', 'E', 'Engles', 'M', 25000, '333445555'); 48 | INSERT INTO expert_mysql.staff VALUES ('123654321', 'Beware', 'D', 'Borg', 'F', 55000, '333444444'); 49 | INSERT INTO expert_mysql.staff VALUES ('123456789', 'Wilma', 'N', 'Maxima', 'F', 43000, '333445555'); 50 | INSERT INTO expert_mysql.tasking VALUES ('333445555', '405', 23); 51 | INSERT INTO expert_mysql.tasking VALUES ('123763153', '405', 33.5); 52 | INSERT INTO expert_mysql.tasking VALUES ('921312388', '601', 44); 53 | INSERT INTO expert_mysql.tasking VALUES ('800122337', '300', 13); 54 | INSERT INTO expert_mysql.tasking VALUES ('820123637', '300', 9.5); 55 | INSERT INTO expert_mysql.tasking VALUES ('830132335', '401', 8.5); 56 | INSERT INTO expert_mysql.tasking VALUES ('333445555', '300', 11); 57 | INSERT INTO expert_mysql.tasking VALUES ('921312388', '500', 13); 58 | INSERT INTO expert_mysql.tasking VALUES ('800122337', '300', 44); 59 | INSERT INTO expert_mysql.tasking VALUES ('820123637', '401', 500.5); 60 | INSERT INTO expert_mysql.tasking VALUES ('830132335', '400', 12); 61 | INSERT INTO expert_mysql.tasking VALUES ('333445665', '600', 300.25); 62 | INSERT INTO expert_mysql.tasking VALUES ('123654321', '607', 444.75); 63 | INSERT INTO expert_mysql.tasking VALUES ('123456789', '300', 1000); 64 | DBXP_SELECT first_name, last_name, sex, id FROM staff; 65 | first_name last_name sex id 66 | John Smith M 333445555 67 | William Walters M 123763153 68 | Alicia St.Cruz F 333444444 69 | Goy Hong F 921312388 70 | Rajesh Kardakarna M 800122337 71 | Monty Smythe M 820123637 72 | Richard Jones M 830132335 73 | Edward Engles M 333445665 74 | Beware Borg F 123654321 75 | Wilma Maxima F 123456789 76 | DBXP_SELECT id FROM staff; 77 | id 78 | 333445555 79 | 123763153 80 | 333444444 81 | 921312388 82 | 800122337 83 | 820123637 84 | 830132335 85 | 333445665 86 | 123654321 87 | 123456789 88 | DBXP_SELECT dir_name FROM directorate; 89 | dir_name 90 | Development 91 | Human Resources 92 | Management 93 | DBXP_SELECT id, dir_name FROM staff 94 | JOIN directorate ON staff.mgr_id = directorate.dir_head_id; 95 | id dir_name 96 | 123763153 Human Resources 97 | 921312388 Human Resources 98 | 333445555 Management 99 | 123654321 Management 100 | 800122337 Development 101 | 820123637 Development 102 | 830132335 Development 103 | 333445665 Development 104 | 123456789 Development 105 | DBXP_SELECT id, dir_name FROM staff, directorate 106 | WHERE staff.mgr_id = directorate.dir_head_id; 107 | id dir_name 108 | 123763153 Human Resources 109 | 921312388 Human Resources 110 | 333445555 Management 111 | 123654321 Management 112 | 800122337 Development 113 | 820123637 Development 114 | 830132335 Development 115 | 333445665 Development 116 | 123456789 Development 117 | DBXP_SELECT * FROM staff WHERE staff.id = '123456789'; 118 | id first_name mid_name last_name sex salary mgr_id 119 | 123456789 Wilma N Maxima F 43000 333445555 120 | DBXP_SELECT first_name, last_name FROM staff join directorate ON staff.mgr_id = directorate.dir_head_id 121 | WHERE directorate.dir_code = 'N41'; 122 | first_name last_name 123 | Rajesh Kardakarna 124 | Monty Smythe 125 | Richard Jones 126 | Edward Engles 127 | Wilma Maxima 128 | DBXP_SELECT * FROM directorate JOIN building ON directorate.dir_code = building.dir_code; 129 | dir_code dir_name dir_head_id dir_code building 130 | M00 Management 333444444 M00 1000 131 | N01 Human Resources 123654321 N01 1453 132 | N41 Development 333445555 N41 1300 133 | N41 Development 333445555 N41 1301 134 | N41 Development 333445555 N41 1305 135 | DBXP_SELECT directorate.dir_code, dir_name, building, dir_head_id 136 | FROM directorate JOIN building ON directorate.dir_code = building.dir_code; 137 | dir_code dir_name building dir_head_id 138 | M00 Management 1000 333444444 139 | N01 Human Resources 1453 123654321 140 | N41 Development 1300 333445555 141 | N41 Development 1301 333445555 142 | N41 Development 1305 333445555 143 | DROP DATABASE expert_mysql; 144 | -------------------------------------------------------------------------------- /Ch14/ch14.test: -------------------------------------------------------------------------------- 1 | # 2 | # Sample test to test the DBXP_SELECT execution 3 | # 4 | 5 | --source include/ch14.sql 6 | 7 | # Test 1: 8 | DBXP_SELECT first_name, last_name, sex, id FROM staff; 9 | 10 | # Test 2: 11 | DBXP_SELECT id FROM staff; 12 | 13 | # Test 3: 14 | DBXP_SELECT dir_name FROM directorate; 15 | 16 | # Test 4a: 17 | DBXP_SELECT id, dir_name FROM staff 18 | JOIN directorate ON staff.mgr_id = directorate.dir_head_id; 19 | 20 | # Test 4b: 21 | DBXP_SELECT id, dir_name FROM staff, directorate 22 | WHERE staff.mgr_id = directorate.dir_head_id; 23 | 24 | # Test 5: 25 | DBXP_SELECT * FROM staff WHERE staff.id = '123456789'; 26 | 27 | # Test 6: 28 | DBXP_SELECT first_name, last_name FROM staff join directorate ON staff.mgr_id = directorate.dir_head_id 29 | WHERE directorate.dir_code = 'N41'; 30 | 31 | # Test 7: 32 | DBXP_SELECT * FROM directorate JOIN building ON directorate.dir_code = building.dir_code; 33 | 34 | # Test 8: 35 | DBXP_SELECT directorate.dir_code, dir_name, building, dir_head_id 36 | FROM directorate JOIN building ON directorate.dir_code = building.dir_code; 37 | 38 | DROP DATABASE expert_mysql; 39 | -------------------------------------------------------------------------------- /Ch14/ch14.txt: -------------------------------------------------------------------------------- 1 | 2 | mysql> DBXP_SELECT first_name, last_name, sex, id FROM staf' at line 1 3 | +------------+------------+------+-----------+ 4 | | first_name | last_name | sex | id | 5 | +------------+------------+------+-----------+ 6 | | John | Smith | M | 333445555 | 7 | | William | Walters | M | 123763153 | 8 | | Alicia | St.Cruz | F | 333444444 | 9 | | Goy | Hong | F | 921312388 | 10 | | Rajesh | Kardakarna | M | 800122337 | 11 | | Monty | Smythe | M | 820123637 | 12 | | Richard | Jones | M | 830132335 | 13 | | Edward | Engles | M | 333445665 | 14 | | Beware | Borg | F | 123654321 | 15 | | Wilma | Maxima | F | 123456789 | 16 | +------------+------------+------+-----------+ 17 | 10 rows in set (0.01 sec) 18 | 19 | mysql> DBXP_SELECT id FROM staff; 20 | +-----------+ 21 | | id | 22 | +-----------+ 23 | | 333445555 | 24 | | 123763153 | 25 | | 333444444 | 26 | | 921312388 | 27 | | 800122337 | 28 | | 820123637 | 29 | | 830132335 | 30 | | 333445665 | 31 | | 123654321 | 32 | | 123456789 | 33 | +-----------+ 34 | 10 rows in set (0.00 sec) 35 | 36 | mysql> DBXP_SELECT dir_name FROM directorate; 37 | +-----------------+ 38 | | dir_name | 39 | +-----------------+ 40 | | Development | 41 | | Human Resources | 42 | | Management | 43 | +-----------------+ 44 | 3 rows in set (0.00 sec) 45 | 46 | mysql> DBXP_SELECT id, dir_name FROM staff 47 | JOIN directorate ON staff.mgr_id = directorate.dir_head_id; 48 | +-----------+-----------------+ 49 | | id | dir_name | 50 | +-----------+-----------------+ 51 | | 123763153 | Human Resources | 52 | | 921312388 | Human Resources | 53 | | 333445555 | Management | 54 | | 123654321 | Management | 55 | | 800122337 | Development | 56 | | 820123637 | Development | 57 | | 830132335 | Development | 58 | | 333445665 | Development | 59 | | 123456789 | Development | 60 | +-----------+-----------------+ 61 | 9 rows in set (0.00 sec) 62 | 63 | mysql> DBXP_SELECT id, dir_name FROM staff, directorate 64 | WHERE staff.mgr_id = directorate.dir_head_id; 65 | +-----------+-----------------+ 66 | | id | dir_name | 67 | +-----------+-----------------+ 68 | | 123763153 | Human Resources | 69 | | 921312388 | Human Resources | 70 | | 333445555 | Management | 71 | | 123654321 | Management | 72 | | 800122337 | Development | 73 | | 820123637 | Development | 74 | | 830132335 | Development | 75 | | 333445665 | Development | 76 | | 123456789 | Development | 77 | +-----------+-----------------+ 78 | 9 rows in set (0.00 sec) 79 | 80 | mysql> DBXP_SELECT * FROM staff WHERE staff.id = '123456789'; 81 | +-----------+------------+----------+-----------+------+--------+-----------+ 82 | | id | first_name | mid_name | last_name | sex | salary | mgr_id | 83 | +-----------+------------+----------+-----------+------+--------+-----------+ 84 | | 123456789 | Wilma | N | Maxima | F | 43000 | 333445555 | 85 | +-----------+------------+----------+-----------+------+--------+-----------+ 86 | 1 row in set (0.00 sec) 87 | 88 | mysql> DBXP_SELECT first_name, last_name FROM staff join directorate ON staff.mgr_id = directorate.dir_head_id WHERE directorate.dir_code = 'N41'; 89 | +------------+------------+ 90 | | first_name | last_name | 91 | +------------+------------+ 92 | | Rajesh | Kardakarna | 93 | | Monty | Smythe | 94 | | Richard | Jones | 95 | | Edward | Engles | 96 | | Wilma | Maxima | 97 | +------------+------------+ 98 | 5 rows in set (0.00 sec) 99 | 100 | mysql> DBXP_SELECT * FROM directorate JOIN building ON directorate.dir_code = building.dir_code; 101 | +----------+-----------------+-------------+----------+----------+ 102 | | dir_code | dir_name | dir_head_id | dir_code | building | 103 | +----------+-----------------+-------------+----------+----------+ 104 | | M00 | Management | 333444444 | M00 | 1000 | 105 | | N01 | Human Resources | 123654321 | N01 | 1453 | 106 | | N41 | Development | 333445555 | N41 | 1300 | 107 | | N41 | Development | 333445555 | N41 | 1301 | 108 | | N41 | Development | 333445555 | N41 | 1305 | 109 | +----------+-----------------+-------------+----------+----------+ 110 | 5 rows in set (0.00 sec) 111 | 112 | mysql> DBXP_SELECT directorate.dir_code, dir_name, building, dir_head_id 113 | FROM directorate JOIN building ON directorate.dir_code = building.dir_code; 114 | +----------+-----------------+----------+-------------+ 115 | | dir_code | dir_name | building | dir_head_id | 116 | +----------+-----------------+----------+-------------+ 117 | | M00 | Management | 1000 | 333444444 | 118 | | N01 | Human Resources | 1453 | 123654321 | 119 | | N41 | Development | 1300 | 333445555 | 120 | | N41 | Development | 1301 | 333445555 | 121 | | N41 | Development | 1305 | 333445555 | 122 | +----------+-----------------+----------+-------------+ 123 | 5 rows in set (0.00 sec) 124 | 125 | mysql> 126 | -------------------------------------------------------------------------------- /Ch14/expression.h: -------------------------------------------------------------------------------- 1 | #include "sql_priv.h" 2 | #include "sql_class.h" 3 | #include "table.h" 4 | #include 5 | 6 | struct expr_node 7 | { 8 | Item *left_op; 9 | Item *operation; 10 | Item *right_op; 11 | Item *junction; 12 | expr_node *next; 13 | }; 14 | 15 | class Expression 16 | { 17 | public: 18 | Expression(void); 19 | int remove_expression(int num, bool free); 20 | expr_node *get_expression(int num); 21 | int add_expression(bool append, expr_node *new_item); 22 | int num_expressions(); 23 | int index_of(char *table, char *value); 24 | int reduce_expressions(TABLE *table); 25 | bool has_table(char *table); 26 | int convert(THD *thd, Item *mysql_expr); 27 | char *to_string(); 28 | bool evaluate(TABLE *table1); 29 | int compare_join(expr_node *expr, TABLE *t1, TABLE *t2); 30 | int get_join_expr(Expression *where_expr); 31 | private: 32 | expr_node *root; 33 | Field *find_field(TABLE *tbl, char *name); 34 | bool compare(expr_node *expr, TABLE *t1); 35 | int num_expr; 36 | }; 37 | -------------------------------------------------------------------------------- /Ch14/query_tree.h: -------------------------------------------------------------------------------- 1 | /* 2 | Query_tree.h 3 | 4 | DESCRIPTION 5 | This file contains the Query_tree class. It is responsible for containing the 6 | internal representation of the query to be executed. It provides methods for 7 | optimizing and forming and inspecting the query tree. This class is the very 8 | heart of the DBXP query capability! It also provides the ability to store 9 | a binary "compiled" form of the query. 10 | 11 | NOTES 12 | The data structure is a binary tree that can have 0, 1, or 2 children. Only 13 | Join operations can have 2 children. All other operations have 0 or 1 14 | children. Each node in the tree is an operation and the links to children 15 | are the pipeline. 16 | 17 | SEE ALSO 18 | query_tree.cc 19 | */ 20 | #include "attribute.h" 21 | #include "expression.h" 22 | #include "sql_priv.h" 23 | #include "sql_class.h" 24 | #include "table.h" 25 | #include "records.h" 26 | 27 | const int MAXNODETABLES = 4; 28 | const int LEFTCHILD = 0; 29 | const int RIGHTCHILD = 1; 30 | 31 | class Query_tree 32 | { 33 | public: 34 | enum query_node_type //this enumeration lists the available 35 | { //query node (operations) 36 | qntUndefined = 0, 37 | qntRestrict = 1, 38 | qntProject = 2, 39 | qntJoin = 3, 40 | qntSort = 4, 41 | qntDistinct = 5 42 | }; 43 | 44 | enum join_con_type //this enumeration lists the available 45 | { //join operations supported 46 | jcUN = 0, 47 | jcNA = 1, 48 | jcON = 2, 49 | jcUS = 3 50 | }; 51 | 52 | enum type_join //this enumeration lists the available 53 | { //join types supported. 54 | jnUNKNOWN = 0, //undefined 55 | jnINNER = 1, 56 | jnLEFTOUTER = 2, 57 | jnRIGHTOUTER = 3, 58 | jnFULLOUTER = 4, 59 | jnCROSSPRODUCT = 5, 60 | jnUNION = 6, 61 | jnINTERSECT = 7 62 | }; 63 | 64 | enum AggregateType //used to add aggregate functions 65 | { 66 | atNONE = 0, 67 | atCOUNT = 1 68 | }; 69 | 70 | /* 71 | STRUCTURE query_node 72 | 73 | DESCRIPTION 74 | This this structure contains all of the data for a query node: 75 | 76 | NodeId -- the internal id number for a node 77 | ParentNodeId -- the internal id for the parent node (used for insert) 78 | SubQuery -- is this the start of a subquery? 79 | Child -- is this a Left or Right child of the parent? 80 | NodeType -- synonymous with operation type 81 | JoinType -- if a join, this is the join operation 82 | join_con_type -- if this is a join, this is the "on" condition 83 | Expressions -- the expressions from the "where" clause for this node 84 | Join Expressions -- the join expressions from the "join" clause(s) 85 | Relations[] -- the relations for this operation (at most 2) 86 | PreemptPipeline -- does the pipeline need to be halted for a sort? 87 | Fields -- the attributes for the result set of this operation 88 | Left -- a pointer to the left child node 89 | Right -- a pointer to the right child node 90 | */ 91 | struct query_node 92 | { 93 | query_node(); 94 | ~query_node(); 95 | int nodeid; 96 | int parent_nodeid; 97 | bool sub_query; 98 | int child; 99 | query_node_type node_type; 100 | type_join join_type; 101 | join_con_type join_cond; 102 | Expression *where_expr; 103 | Expression *join_expr; 104 | TABLE_LIST *relations[MAXNODETABLES]; 105 | int eof[MAXNODETABLES]; 106 | int ndx[MAXNODETABLES]; 107 | bool preempt_pipeline; 108 | Attribute *attributes; 109 | query_node *left; 110 | query_node *right; 111 | }; 112 | 113 | struct record_buff 114 | { 115 | uchar *field_ptr; 116 | long field_length; 117 | record_buff *next; 118 | record_buff *prev; 119 | READ_RECORD *record; 120 | }; 121 | 122 | query_node *root; //The ROOT node of the tree 123 | 124 | Query_tree(void); 125 | ~Query_tree(void); 126 | int init_node(query_node *qn); 127 | int heuristic_optimization(); 128 | int cost_optimization(); 129 | int insert_attribute(query_node *qn, Item *c); 130 | bool distinct; 131 | int prepare(query_node *qn); 132 | int cleanup(query_node *qn); 133 | bool Eof(query_node *qn); 134 | READ_RECORD *get_next(query_node *qn); 135 | List result_fields; 136 | 137 | private: 138 | bool h_opt; //has query been optimized (rules)? 139 | bool c_opt; //has query been optimized (cost)? 140 | READ_RECORD *lbuff; 141 | READ_RECORD *rbuff; 142 | record_buff *left_record_buff; 143 | record_buff *right_record_buff; 144 | record_buff *left_record_buffer_ptr; 145 | record_buff *right_record_buffer_ptr; 146 | 147 | int push_projections(query_node *qn, query_node *pNode); 148 | query_node *find_projection(query_node *qn); 149 | bool is_leaf(query_node *qn); 150 | bool has_relation(query_node *qn, char *Table); 151 | bool has_attribute(query_node *qn, Item *a); 152 | int del_attribute(query_node *qn, Item *a); 153 | int push_restrictions(query_node *qn, query_node *pNode); 154 | query_node *find_restriction(query_node *qn); 155 | query_node *find_join(query_node *qn); 156 | int push_joins(query_node *qn, query_node *pNode); 157 | int prune_tree(query_node *prev, query_node *cur_node); 158 | int balance_joins(query_node *qn); 159 | int split_restrict_with_project(query_node *qn); 160 | int split_restrict_with_join(query_node *qn); 161 | int split_project_with_join(query_node *qn); 162 | bool find_table_in_tree(query_node *qn, char *tbl); 163 | bool find_table_in_expr(Expression *expr, char *tbl); 164 | bool find_attr_in_expr(Expression *expr, char *tbl, char *value); 165 | int apply_indexes(query_node *qn); 166 | bool do_restrict(query_node *qn, READ_RECORD *t); 167 | READ_RECORD *do_project(query_node *qn, READ_RECORD *t); 168 | READ_RECORD *do_join(query_node *qn); 169 | int find_index_in_expr(Expression *e, char *tbl); 170 | TABLE *get_table(query_node *qn); 171 | int insertion_sort(bool left, Field *field, READ_RECORD *rcd); 172 | int check_rewind(record_buff *cur_left, record_buff *curr_left_prev, 173 | record_buff *cur_right, record_buff *cur_right_prev); 174 | }; 175 | -------------------------------------------------------------------------------- /Ch14/source_Ch14.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Ch14/source_Ch14.zip -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/LICENSE.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apress Source Code 2 | 3 | This repository accompanies [*Expert MySQL*](http://www.apress.com/9781430246596) by Charles Bell (Apress, 2012). 4 | 5 | ![Cover image](9781430246596.jpg) 6 | 7 | Download the files as a zip using the green button, or clone the repository to your machine using Git. 8 | 9 | ## Releases 10 | 11 | Release v1.0 corresponds to the code in the published book, without corrections or updates. 12 | 13 | ## Contributions 14 | 15 | See the file Contributing.md for more information on how you can contribute to this repository. 16 | -------------------------------------------------------------------------------- /Sample_data/bvm_data.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Sample_data/bvm_data.sql -------------------------------------------------------------------------------- /Sample_data/bvm_images.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/exp-mysql-12/37d3034e259d682b8c7d141699acc706eb8b6271/Sample_data/bvm_images.zip -------------------------------------------------------------------------------- /Sample_data/sample_data.sql: -------------------------------------------------------------------------------- 1 | -- MySQL dump 10.10 2 | -- 3 | -- Host: localhost Database: expert_mysql 4 | -- ------------------------------------------------------ 5 | -- Server version 5.1.9-beta-debug-DBXP 1.0 6 | 7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 10 | /*!40101 SET NAMES utf8 */; 11 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 12 | /*!40103 SET TIME_ZONE='+00:00' */; 13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 15 | */; 16 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 17 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 18 | 19 | CREATE DATABASE IF NOT EXISTS expert_mysql; 20 | 21 | -- 22 | -- Table structure for table `expert_mysql`.`building` 23 | -- 24 | 25 | DROP TABLE IF EXISTS `expert_mysql`.`building`; 26 | CREATE TABLE `expert_mysql`.`building` ( 27 | `dir_code` char(4) NOT NULL, 28 | `building` char(6) NOT NULL 29 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 30 | 31 | -- 32 | -- Dumping data for table `expert_mysql`.`building` 33 | -- 34 | 35 | 36 | /*!40000 ALTER TABLE `expert_mysql`.`building` DISABLE KEYS */; 37 | LOCK TABLES `expert_mysql`.`building` WRITE; 38 | INSERT INTO `expert_mysql`.`building` VALUES 39 | ('N41','1300'), 40 | ('N01','1453'), 41 | ('M00','1000'), 42 | ('N41','1301'), 43 | ('N41','1305'); 44 | UNLOCK TABLES; 45 | /*!40000 ALTER TABLE `expert_mysql`.`building` ENABLE KEYS */; 46 | 47 | -- 48 | -- Table structure for table `expert_mysql`.`directorate` 49 | -- 50 | 51 | DROP TABLE IF EXISTS `expert_mysql`.`directorate`; 52 | CREATE TABLE `expert_mysql`.`directorate` ( 53 | `dir_code` char(4) NOT NULL, 54 | `dir_name` char(30) DEFAULT NULL, 55 | `dir_head_id` char(9) DEFAULT NULL, 56 | PRIMARY KEY (`dir_code`) 57 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 58 | 59 | -- 60 | -- Dumping data for table `expert_mysql`.`directorate` 61 | -- 62 | 63 | 64 | /*!40000 ALTER TABLE `expert_mysql`.`directorate` DISABLE KEYS */; 65 | LOCK TABLES `expert_mysql`.`directorate` WRITE; 66 | INSERT INTO `expert_mysql`.`directorate` VALUES 67 | ('N41','Development','333445555'), 68 | ('N01','Human Resources','123654321'), 69 | ('M00','Management','333444444'); 70 | UNLOCK TABLES; 71 | /*!40000 ALTER TABLE `directorate` ENABLE KEYS */; 72 | 73 | -- 74 | -- Table structure for table `expert_mysql`.`staff` 75 | -- 76 | 77 | DROP TABLE IF EXISTS `expert_mysql`.`staff`; 78 | CREATE TABLE `expert_mysql`.`staff` ( 79 | `id` char(9) NOT NULL, 80 | `first_name` char(20) DEFAULT NULL, 81 | `mid_name` char(20) DEFAULT NULL, 82 | `last_name` char(30) DEFAULT NULL, 83 | `sex` char(1) DEFAULT NULL, 84 | `salary` int(11) DEFAULT NULL, 85 | `mgr_id` char(9) DEFAULT NULL, 86 | PRIMARY KEY (`id`) 87 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 88 | 89 | -- 90 | -- Dumping data for table `expert_mysql`.`staff` 91 | -- 92 | 93 | 94 | /*!40000 ALTER TABLE `expert_mysql`.`staff` DISABLE KEYS */; 95 | LOCK TABLES `expert_mysql`.`staff` WRITE; 96 | INSERT INTO `expert_mysql`.`staff` VALUES 97 | ('333445555','John','Q','Smith','M',30000,'333444444'), 98 | ('123763153','William','E','Walters','M',25000,'123654321'), 99 | ('333444444','Alicia','F','St.Cruz','F',25000,NULL), 100 | ('921312388','Goy','X','Hong','F',40000,'123654321'), 101 | ('800122337','Rajesh','G','Kardakarna','M',38000,'333445555'), 102 | ('820123637','Monty','C','Smythe','M',38000,'333445555'), 103 | ('830132335','Richard','E','Jones','M',38000,'333445555'), 104 | ('333445665','Edward','E','Engles','M',25000,'333445555'), 105 | ('123654321','Beware','D','Borg','F',55000,'333444444'), 106 | ('123456789','Wilma','N','Maxima','F',43000,'333445555'); 107 | UNLOCK TABLES; 108 | /*!40000 ALTER TABLE `expert_mysql`.`staff` ENABLE KEYS */; 109 | 110 | -- 111 | -- Table structure for table `tasking` 112 | -- 113 | 114 | DROP TABLE IF EXISTS `expert_mysql`.`tasking`; 115 | CREATE TABLE `expert_mysql`.`tasking` ( 116 | `id` char(9) NOT NULL, 117 | `project_number` char(9) NOT NULL, 118 | `hours_worked` double DEFAULT NULL 119 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 120 | 121 | -- 122 | -- Dumping data for table `tasking` 123 | -- 124 | 125 | 126 | /*!40000 ALTER TABLE `tasking` DISABLE KEYS */; 127 | LOCK TABLES `expert_mysql`.`tasking` WRITE; 128 | INSERT INTO `expert_mysql`.`tasking` VALUES 129 | ('333445555','405',23), 130 | ('123763153','405',33.5), 131 | ('921312388','601',44), 132 | ('800122337','300',13), 133 | ('820123637','300',9.5), 134 | ('830132335','401',8.5), 135 | ('333445555','300',11), 136 | ('921312388','500',13), 137 | ('800122337','300',44), 138 | ('820123637','401',500.5), 139 | ('830132335','400',12), 140 | ('333445665','600',300.25), 141 | ('123654321','607',444.75), 142 | ('123456789','300',1000); 143 | UNLOCK TABLES; 144 | /*!40000 ALTER TABLE `expert_mysql`.`tasking` ENABLE KEYS */; 145 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 146 | 147 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 148 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 149 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 150 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 151 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 152 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 153 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 154 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to Apress Source Code 2 | 3 | Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. 4 | 5 | ## How to Contribute 6 | 7 | 1. Make sure you have a GitHub account. 8 | 2. Fork the repository for the relevant book. 9 | 3. Create a new branch on which to make your change, e.g. 10 | `git checkout -b my_code_contribution` 11 | 4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. 12 | 5. Submit a pull request. 13 | 14 | Thank you for your contribution! --------------------------------------------------------------------------------