diff --git a/include/BlobMgmt.h b/include/BlobMgmt.h index 81facfa..b321eb4 100644 --- a/include/BlobMgmt.h +++ b/include/BlobMgmt.h @@ -51,6 +51,7 @@ struct tagInsertUpdateBlob wyBool m_isoldnull; wyBool m_ischanged; wyBool m_isblob; + wyBool m_isJson; }; /*! Creates a type tagInsertUpdateBlob*/ @@ -217,6 +218,10 @@ class BlobMgmt */ wyBool ProcessCancel(); + /// Function to check whether the text entered is a valid JSON or not + + wyBool IsValidJsonText(wyString txt); + //Sests the dialog when pops up /** @return void @@ -358,6 +363,12 @@ class BlobMgmt /// Is Blob or Text? wyBool m_isblob; + // if JSON ...special handling is to be done + wyBool m_isJson; + + //if this is wyTrue then we dont close the window on clicking OK ---- JSON type + wyBool donot_close_window; + //Object for FindAndRepalce class FindAndReplace *m_findreplace; }; diff --git a/include/CustTab.h b/include/CustTab.h index 3515d26..3bc5a28 100644 --- a/include/CustTab.h +++ b/include/CustTab.h @@ -792,6 +792,9 @@ class CCustTab /// Selected Tab wyInt32 m_selectedtab; + ///previously selected tab needed for tab deletion of tab other than selected tab + wyInt32 m_prevtab; + /// Starting Tab wyInt32 m_starttab; diff --git a/include/DataView.h b/include/DataView.h index 0a6b078..594a4ee 100644 --- a/include/DataView.h +++ b/include/DataView.h @@ -1013,6 +1013,7 @@ class DataView */ wyBool IsBlob(wyInt32 col); + wyBool IsJSON(wyInt32 col); ///Helper function to change the filter icon /** @returns void @@ -1146,6 +1147,7 @@ class DataView */ wyBool AppendDataToQuery(MYSQL_ROW myrow, wyInt32 col, wyInt32 colcount, wyString &query, wyBool isblob); + wyBool AppendDataToQueryJSON(MYSQL_ROW myrow, wyInt32 col, wyInt32 colcount, wyString &query, wyBool isJSON); ///Helper function for showing mysql errors /** @param query : IN query that raised the error @@ -1265,6 +1267,9 @@ class DataView */ wyBool AddDataToQuery(MYSQL_ROW data, wyString &query, const wyChar* delimiter, const wyChar* nullcheck, wyInt32 col, wyBool isfirst = wyTrue, wyBool ischeckspdata = wyFalse); + + wyBool AddDataToQueryJSON(MYSQL_ROW data, wyString &query, const wyChar* delimiter, const wyChar* nullcheck, wyInt32 col, wyBool isfirst = wyTrue, wyBool ischeckspdata = wyFalse); + ///Function generates the query to check duplicates /** @param row : IN row for which the query to be generated diff --git a/include/ExportBatch.h b/include/ExportBatch.h index e6059f1..8e046a9 100644 --- a/include/ExportBatch.h +++ b/include/ExportBatch.h @@ -362,7 +362,7 @@ class ExportBatch @param hwnd : IN treeview handle @param pnmtv : IN Tree items containing notification message */ - wyBool OnItemExpandingHelper(HWND hwnd , LPNMTREEVIEW pnmtv); + wyBool OnItemExpandingHelper(HWND hwnd , LPNMTREEVIEW pnmtv, wyInt32 dataonly_check); /// stops exporting /** diff --git a/include/FKDropDown.h b/include/FKDropDown.h index 6fb005d..2b7e310 100644 --- a/include/FKDropDown.h +++ b/include/FKDropDown.h @@ -417,7 +417,7 @@ class FKDropDown ///Composite filter if any wyString m_compositefilter; - ///The button text to be shown in the blob columns + ///The button text to be shown in the blob/JSON columns wyString m_buttontext; ///Text for the column diff --git a/include/FrameWindowHelper.h b/include/FrameWindowHelper.h index 0c1f482..3fd18ba 100644 --- a/include/FrameWindowHelper.h +++ b/include/FrameWindowHelper.h @@ -165,6 +165,7 @@ #define UM_GETEDITORTEXT WM_USER+129 #define UM_QBITEMFROM WM_USER+130 #define UM_QBITEMTO WM_USER+131 +#define UM_CHECKSTATECHANGE WM_USER+132 // some column #defines for validation. @@ -246,6 +247,7 @@ #define SQLTEMPLATE_SECTION "SQLTemplate" #define STRING_NULL "(NULL)" #define STRING_BLOB "BLOB..." +#define STRING_JSON "JSON..." #define BINARY_DATA "(Binary/Image)" #define STR_DEFAULT " [default]" #define SHIFTED 0x8000 @@ -523,7 +525,7 @@ All Files(*.*)\0*.*\0" #define BLOB_DATA 8 #define DATETIME_DATA 16 #define BIN_DATA 32 - +#define JSON_DATA 64 /// Function to notify user with various stuff. /** @param hwnd : IN Window HANDLE @@ -873,6 +875,8 @@ wyInt32 GetKeyWordCase(); */ void GetColumnName(wyWChar *field); +int IsColumnTypeJson(wyWChar *field); + /// Ensures a range is visible in the scintilla control /** @param hwnd : IN Window Handler diff --git a/include/GUIHelper.h b/include/GUIHelper.h index 5a2eda7..4322f4c 100644 --- a/include/GUIHelper.h +++ b/include/GUIHelper.h @@ -106,6 +106,8 @@ a:link { color: #3b7dbb; text-decoration:none;} a:visited { color: #3b7dbb; text #define CSS_CLASS2 ".extendedcodecaptionstyle{font: bold 12px \"Courier New\", Courier, mono; text-align:right; padding-left:10px; padding-right:10px;}\ .extendedcodedatastyle{font: 12px \"Courier New\", Courier, mono; text-align:right; padding-left:10px; padding-right:10px;}" +#define GET_NDB_VERSION_STRING ("select @@ndb_version_string") + typedef struct treeviewparams { HWND hwnd; @@ -331,6 +333,10 @@ void SetExplainMenuItems(HMENU hmenu, HWND hwnd); void GetCurrentQuery(HWND hwndedit, MDIWindow *wnd, wyString *query, wyInt32 &pos); void GetCurrentQueryForAuto(HWND hwndedit, MDIWindow *wnd, wyString *query, wyInt32 &pos); + +wyBool GetClusterdbSupportForFk(MDIWindow *wnd); + + ///Handle the File menu(Remove QB, SD options with PRO) /** @param hmenu : IN Handle to the menu diff --git a/include/MySQLVersionHelper.h b/include/MySQLVersionHelper.h index ea9ca72..30d05ac 100644 --- a/include/MySQLVersionHelper.h +++ b/include/MySQLVersionHelper.h @@ -22,7 +22,7 @@ #include "Datatype.h" #include "Tunnel.h" - +#include "wyString.h" const wyChar *IsNewMySQL(Tunnel * tunnel, PMYSQL mysql); wyBool IsAlterOK(Tunnel * tunnel, PMYSQL mysql); @@ -139,6 +139,8 @@ wyBool IsMySQL564MariaDB53(Tunnel * tunnel, PMYSQL mysql); //MySQL 5.6.5 wyBool IsMySQL565MariaDB1001(Tunnel * tunnel, PMYSQL mysql); +void GetVersionInfoforAutoComplete(MYSQL *mysql, wyString &VersionS); + //MySQL 5.6.5 wyBool IsMySQL565(Tunnel * tunnel, PMYSQL mysql); //mariadb 5.2 for Virtual/Persistent @@ -149,7 +151,15 @@ wyBool IsMySQL57(Tunnel * tunnel, PMYSQL mysql); //MySQL 5.7.7 for SYS Schema wyBool IsMySQL577(Tunnel * tunnel, PMYSQL mysql); + +wyBool IsMySQL578(Tunnel * tunnel, PMYSQL mysql); + + +//wyBool IsClusterDb(Tunnel * tunnel, PMYSQL mysql); + + /// Checks the server version is greater than or equal to mySQL5.0.2 + /** @param tunnel: IN tunnel pointer @param mysql: IN PMYSQL value diff --git a/include/SQLyog.rc b/include/SQLyog.rc index 286d36d..a1dc470 100644 --- a/include/SQLyog.rc +++ b/include/SQLyog.rc @@ -1108,7 +1108,7 @@ END IDD_INSERTUPDATEBLOB DIALOGEX 0, 0, 427, 366 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -CAPTION " Insert/Update Blob Field" +CAPTION " Insert/Update Blob/JSON Field" FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN CONTROL "Tab2",IDC_MAINTAB,"SysTabControl32",TCS_BUTTONS,7,7,176,97 @@ -1583,7 +1583,7 @@ BEGIN LTEXT "&Blob viewer",IDC_EDITOR3,8,41,60,9 LTEXT " ",IDC_BLOBFONT,76,41,120,10,SS_WORDELLIPSIS PUSHBUTTON "Change...",IDC_BLOBCHANGE,205,40,41,12 - LTEXT "Ob&ject Browser",IDC_EDITOR5,8,54,60,10 + LTEXT "Ob&ject Browser",IDC_EDITOR5,8,54,60,10 LTEXT " ",IDC_OBFONT,76,54,120,10,SS_WORDELLIPSIS PUSHBUTTON "Change...",IDC_OBCHANGE,205,54,41,12 LTEXT "&Others",IDC_EDITOR4,8,68,60,10 @@ -1802,7 +1802,7 @@ BEGIN "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,27,202,10 CONTROL "Paste object name in &editor on double-click",IDC_GETTEXTONDBCLICK, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,38,202,10 - CONTROL "Enable &word wrap in SQL editor and BLOB viewer",IDC_WORDWRAP, + CONTROL "Enable &word wrap in SQL editor, BLOB and JSON viewer",IDC_WORDWRAP, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,49,202,10 CONTROL "Enable transaction support for &batch process",IDC_TRANSACTIONENABLE, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,60,202,10 diff --git a/include/TabFields.h b/include/TabFields.h index 6b16653..7ed3d5f 100644 --- a/include/TabFields.h +++ b/include/TabFields.h @@ -151,6 +151,8 @@ class TabFields //is mysql version>=5.7 wyBool m_ismysql57; + wyBool m_ismysql578; + /// Flag used to check one auto increment field selected wyBool m_autoincrpresent; diff --git a/include/TableTabInterface.h b/include/TableTabInterface.h index ee7d570..38596c9 100644 --- a/include/TableTabInterface.h +++ b/include/TableTabInterface.h @@ -78,6 +78,9 @@ class TableTabInterface : public TabTypes //..Indicates whether FK is supported or not..? wyBool m_isfksupported; + + //..Indicates if the mySQL cluster version supports foreign keys for NDBcluster or not.. + wyBool m_isfkforndbcluster; ///The index of sub-tab to be opened on opening the Alter Table tab wyInt32 m_setfocustotab; diff --git a/include/Tunnel.h b/include/Tunnel.h index 90625d4..3ca9c31 100644 --- a/include/Tunnel.h +++ b/include/Tunnel.h @@ -18,7 +18,7 @@ -#define IS_BLOBVALUE(t) ((((t)>= MYSQL_TYPE_TINY_BLOB) && ((t)<= MYSQL_TYPE_BLOB)) || (t == MYSQL_TYPE_GEOMETRY)) +#define IS_BLOBVALUE(t) ((((t)>= MYSQL_TYPE_TINY_BLOB) && ((t)<= MYSQL_TYPE_BLOB)) || (t == MYSQL_TYPE_GEOMETRY) || (t == MYSQL_TYPE_JSON) ) #ifdef _WIN32 diff --git a/include/UserManager.h b/include/UserManager.h index d24e1cf..eb9cd61 100644 --- a/include/UserManager.h +++ b/include/UserManager.h @@ -72,6 +72,15 @@ class PrivilegedObject wyInt32 m_objecttype; }; +typedef struct userlist +{ + wyString m_uname; + wyString m_itemvalue; + wyBool m_dropdown; + userlist *next; + +}USERLIST; + //User Manager class class UserManager { @@ -622,6 +631,8 @@ class UserManager private: + USERLIST *m_userlist; + //whether to show the respective limitations wyBool m_showlimitations[U_MAXLIMITATIONS]; @@ -646,6 +657,8 @@ class UserManager //host name of the selected user wyString m_host; + wyInt32 m_usercount; + //tree view image list HIMAGELIST m_himagelist; diff --git a/include/mysql/mysql_com.h b/include/mysql/mysql_com.h index 5fee818..2f98712 100644 --- a/include/mysql/mysql_com.h +++ b/include/mysql/mysql_com.h @@ -283,7 +283,7 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, MYSQL_TYPE_TINY_BLOB=249, MYSQL_TYPE_MEDIUM_BLOB=250, MYSQL_TYPE_LONG_BLOB=251, - MYSQL_TYPE_BLOB=252, + MYSQL_TYPE_BLOB=252,MYSQL_TYPE_JSON=245, MYSQL_TYPE_VAR_STRING=253, MYSQL_TYPE_STRING=254, MYSQL_TYPE_GEOMETRY=255, @@ -313,6 +313,7 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, #define FIELD_TYPE_MEDIUM_BLOB MYSQL_TYPE_MEDIUM_BLOB #define FIELD_TYPE_LONG_BLOB MYSQL_TYPE_LONG_BLOB #define FIELD_TYPE_BLOB MYSQL_TYPE_BLOB +#define FIELD_TYPE_JSON MYSQL_TYPE_JSON #define FIELD_TYPE_VAR_STRING MYSQL_TYPE_VAR_STRING #define FIELD_TYPE_STRING MYSQL_TYPE_STRING #define FIELD_TYPE_GEOMETRY MYSQL_TYPE_GEOMETRY diff --git a/include/readme.txt b/include/readme.txt index 045b111..c6f02c8 100644 --- a/include/readme.txt +++ b/include/readme.txt @@ -120,7 +120,7 @@ Ctrl+Shift+H Open History Tab Ctrl+Shift+I Open Info Tab Ctrl+C Copy Ctrl+A Select All -Ctrl+F Find (SQL Window/Result Window And Table Data In Text Mode/Blob Viewer) +Ctrl+F Find (SQL Window/Result Window And Table Data In Text Mode/Blob Viewer/JSON Viewer) F3 Find Next (SQL Window/Result Window And Table Data In Text Mode) Ctrl+S Save Ctrl+PgUp Switch To Previous Tab diff --git a/lib/Keywords.db b/lib/Keywords.db index 2a36b9f..5730b2f 100644 Binary files a/lib/Keywords.db and b/lib/Keywords.db differ diff --git a/src/BlobMgmt.cpp b/src/BlobMgmt.cpp index ae80293..fdb5c2e 100644 --- a/src/BlobMgmt.cpp +++ b/src/BlobMgmt.cpp @@ -80,6 +80,8 @@ BlobMgmt::Create(HWND hwndParent, PINSERTUPDATEBLOB pib, wyBool edit) m_edit = edit; m_hfont = NULL; m_isblob = pib->m_isblob; + m_isJson = pib->m_isJson; + donot_close_window = wyTrue; //Post 8.01F //RepaintTabModule(); @@ -176,7 +178,9 @@ BlobMgmt::InitDlgVales() VERIFY(m_hwndcombo = GetDlgItem(m_hwnddlg, IDC_COMBO)); InsertTab(m_hwndtab, 0, _(L"Text")); - InsertTab(m_hwndtab, 1, _(L"Image")); + + if(! m_isJson) + InsertTab(m_hwndtab, 1, _(L"Image")); // if its not word wrap then we need to destroy it. SetEditWordWrap(m_hwndedit, wyTrue, wyTrue); @@ -267,8 +271,10 @@ BlobMgmt::OnDlgProcWmCommand(WPARAM wparam, LPARAM lparam) case IDOK: if(ProcessOK() == wyTrue) VERIFY(yog_enddialog(m_hwnddlg, 1)); - else - VERIFY(yog_enddialog(m_hwnddlg, 0)); + else if(! m_isJson) + VERIFY(yog_enddialog(m_hwnddlg, 0)); + else if( m_isJson && ( donot_close_window==wyFalse ) ) // for closing the window if no changes are made and its a JSON type + VERIFY(yog_enddialog(m_hwnddlg, 0)); break; case IDC_SAVETOFILE: @@ -939,6 +945,8 @@ BlobMgmt::SaveToFile() { OPENFILENAME open; wyWChar filename[MAX_PATH + 1] = {0}; + wyWChar temp[MAX_PATH + 1] = {0}; + wyWChar extention[]=L".json"; HANDLE hfile = NULL; DWORD dwbytesread; @@ -953,7 +961,10 @@ BlobMgmt::SaveToFile() open.lStructSize = OPENFILENAME_SIZE_VERSION_400; open.hwndOwner = m_hwnddlg; open.hInstance = pGlobals->m_pcmainwin->GetHinstance(); - open.lpstrFilter = L"All Files(*.*)\0*.*\0"; + if(m_isJson) + open.lpstrFilter = L"JSON Files(*.json)\0*.json\0"; + else + open.lpstrFilter = L"All Files(*.*)\0*.*\0"; open.lpstrCustomFilter =(LPWSTR)NULL; open.nFilterIndex = 1L; open.lpstrFile = filename; @@ -965,6 +976,12 @@ BlobMgmt::SaveToFile() return wyFalse; // else successfull. + wcscpy(temp,filename); + wcsrev(temp); + wcsrev(extention); + if(m_isJson && wcsncmp(temp,extention,5)) + wcscat(filename,L".json"); + open.lpstrTitle = filename; hfile = CreateFile((LPCWSTR)filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); @@ -1094,10 +1111,21 @@ BlobMgmt::ProcessOK() m_piub->m_isnull = wyFalse; m_piub->m_ischanged = wyTrue; - return wyTrue; + if(! m_isJson) + return wyTrue; + if(m_isJson && IsValidJsonText(m_piub->m_data)) + return wyTrue; + else + { + m_piub->m_ischanged = wyFalse; // to disable the save option in dataview + MessageBox(m_hwnddlg,L"Invalid JSON value. Please enter a valid JSON", + pGlobals->m_appname.GetAsWideChar(), MB_OK | MB_ICONERROR); + return wyFalse; + } + } - + // we change the blob otherwise if(sel == 1 && m_olddata != m_piub->m_data && m_isencodingchanged == wyFalse) { @@ -1111,9 +1139,7 @@ BlobMgmt::ProcessOK() if(m_isencodingchanged == wyTrue) { bufsize = SendMessage(m_hwndedit, SCI_GETTEXTLENGTH, 0, 0); - VERIFY(newbuf = AllocateBuff(bufsize + 2)); - bufsize = SendMessage(m_hwndedit, SCI_GETTEXT, bufsize + 1,(LPARAM)newbuf); m_piub->m_data = (wyChar *)newbuf; @@ -1121,8 +1147,19 @@ BlobMgmt::ProcessOK() m_piub->m_isnull = wyFalse; m_piub->m_ischanged = wyTrue; m_blobdata.SetAs(newbuf); - ProcessComboSelection(m_changedcombotext); + if(! m_isJson) + return wyTrue; + if(m_isJson && IsValidJsonText(m_piub->m_data)) + return wyTrue; + else + { + m_piub->m_ischanged = wyFalse; // to disable the save option in the dataview + + MessageBox(m_hwnddlg,L"Invalid JSON value. Please Enter a valid JSON", + pGlobals->m_appname.GetAsWideChar(), MB_OK | MB_ICONERROR); + return wyFalse; + } return wyTrue; } @@ -1135,8 +1172,19 @@ BlobMgmt::ProcessOK() m_piub->m_datasize = 0; m_piub->m_isnull = wyFalse; m_piub->m_ischanged = wyTrue; + if(! m_isJson) + return wyTrue; + if(m_isJson && IsValidJsonText(m_piub->m_data)) + return wyTrue; + else + { + m_piub->m_ischanged = wyFalse; // to disable the save option in the dataview + + MessageBox(m_hwnddlg,L"Invalid JSON value. Please Enter a valid JSON", + pGlobals->m_appname.GetAsWideChar(), MB_OK | MB_ICONERROR); + return wyFalse; + } - return wyTrue; } m_piub->m_olddata = NULL; @@ -1144,6 +1192,8 @@ BlobMgmt::ProcessOK() m_piub->m_data = m_olddata; m_piub->m_datasize = m_olddatasize; m_piub->m_ischanged = wyFalse; + if(m_isJson) // IF no changes in the json viewer then on clicking OK it will close + donot_close_window=wyFalse; return wyFalse; } @@ -1487,3 +1537,31 @@ BlobMgmt::OnAccelFindNext(HWND hwnd) FindOrReplace(hwnd, wyFalse); } } +wyBool + BlobMgmt::IsValidJsonText(wyString txt) +{ + MYSQL_RES *myres; + MYSQL_ROW row; + wyString query; + MDIWindow *wnd = NULL; + wyString validator; + VERIFY(wnd = GetActiveWin()); + if(!wnd) + return wyFalse; + query.SetAs("SELECT JSON_VALID('"); + query.AddSprintf(("%s')"),txt.GetString()); + myres = ExecuteAndGetResult(GetActiveWin(),wnd->m_tunnel,&wnd->m_mysql,query,wyFalse); + // wyFalse so that SELECT JSON_VALID is not displayed in the History tab + if(!myres && wnd->m_tunnel->mysql_affected_rows(wnd->m_mysql)== -1) + { + SetCursor(LoadCursor(NULL, IDC_ARROW)); + return wyFalse; + } + row = wnd->m_tunnel->mysql_fetch_row(myres); + validator.AddSprintf(row[0]); + mysql_free_result(myres); + if(validator.GetAsInt32()==1) + return wyTrue; + else + return wyFalse; +} diff --git a/src/CommonHelper.cpp b/src/CommonHelper.cpp index d850a64..dbde330 100644 --- a/src/CommonHelper.cpp +++ b/src/CommonHelper.cpp @@ -1934,6 +1934,11 @@ GetMySqlDataType(MysqlDataType *rettypedata, MYSQL_FIELD *fields, wyInt32 fieldn rettypedata->m_mysqltype.SetAs("text"); break; + case MYSQL_TYPE_JSON: + rettypedata->m_exceltype.SetAs("JSON"); + rettypedata->m_mysqltype.SetAs("JSON"); + break; + case MYSQL_TYPE_GEOMETRY: rettypedata->m_exceltype.SetAs("String"); rettypedata->m_mysqltype.SetAs("Geometry"); @@ -2939,7 +2944,10 @@ GetChildTableFlds(wyString *fkeyinfo, LFKEYINFOPARAM fkeyparam) fkey.SetAs(*fkeyinfo); par = strstr((wyChar*)fkey.GetString(), "FOREIGN KEY ("); - + + ///in cluster version 7.3.0 the show create table returns "FOREIGN KEY(" instead of "FOREIGN KEY (" + if(!par) + par = strstr((wyChar*)fkey.GetString(), "FOREIGN KEY("); wyString fk; if(par) diff --git a/src/CustTab.cpp b/src/CustTab.cpp index 9d343c1..86606a3 100644 --- a/src/CustTab.cpp +++ b/src/CustTab.cpp @@ -142,8 +142,9 @@ CCustTab::CCustTab(HWND hwnd) m_tabcontroldown = -1; m_overtabcontrol = -1; m_lparamdata = NULL; - - hdc = GetDC(hwnd); + m_prevtab = 0; + + hdc = GetDC(hwnd); GetTextExtentPoint32(hdc, L">", 1, &m_size); ReleaseDC(hwnd, hdc); m_hwndprevfocus = NULL; @@ -1350,6 +1351,8 @@ CCustTab::OnLButtonDown(WPARAM wPram, LPARAM lParam) m_closebuttondowntab = i; } + m_prevtab = m_selectedtab; + if(i != -1) { if(m_selectedtab != i) @@ -1445,8 +1448,23 @@ CCustTab::OnLButtonUp(WPARAM wPram, LPARAM lParam) { OnWMSize(); ispaintonlyheader = wyFalse; - } - } + + ///for rightly selecting the previous tab when tab being deleted is not same as previously selected tab, or the selected tab is first one + if(m_prevtab != i) + { + if(m_prevtab > i) + m_prevtab -= 1; + } + else if(m_prevtab != 0 && m_prevtab == m_tabs ) + { + m_prevtab -= 1; + } + if(SetCurSel(m_prevtab, 1) == wyFalse) + { + return 1; + } + } + } else if((i = OverTabControls(&pnt)) != -1) { if(i == m_overtabcontrol && i == m_tabcontroldown) diff --git a/src/DataView.cpp b/src/DataView.cpp index 3cae955..8663d20 100644 --- a/src/DataView.cpp +++ b/src/DataView.cpp @@ -1014,7 +1014,7 @@ DataView::IsBinary(wyInt32 col) wyBool isbin; isbin = ((m_data->m_datares->fields[col].flags & BINARY_FLAG) && - (m_data->m_datares->fields[col].type == MYSQL_TYPE_TINY_BLOB || + (m_data->m_datares->fields[col].type == MYSQL_TYPE_TINY_BLOB || m_data->m_datares->fields[col].type == MYSQL_TYPE_JSON || m_data->m_datares->fields[col].type == MYSQL_TYPE_MEDIUM_BLOB || m_data->m_datares->fields[col].type == MYSQL_TYPE_BLOB || m_data->m_datares->fields[col].type == MYSQL_TYPE_LONG_BLOB)) ? wyTrue : wyFalse; @@ -1094,6 +1094,105 @@ DataView::AddDataToQuery(MYSQL_ROW data, wyString &query, const wyChar* delimite return isgenerated; } +wyBool +DataView::AddDataToQueryJSON(MYSQL_ROW data, wyString &query, const wyChar* delimiter, const wyChar* nullcheck, wyInt32 col, wyBool isfirst, wyBool ischeckspdata) +{ + wyBool isjson,isbin ,isgenerated = wyFalse; + wyInt32 i, max; + wyString colname; + + + //if valid col is specified then we will add data for that column only + if(col >= 0) + { + i = col; + max = col + 1; + } + //otherwise add data for all columns + else + { + i = 0; + max = m_data->m_datares->field_count; + } + + for(; i < max; i++) + { + //we ignore readonly columns + if(IsColumnReadOnly(i) == wyFalse && IsColumnVirtual(i) != 1 ) + { + isbin = IsBinary(i); + isjson = IsJSON(i); + + GetColumnName(colname, i); + + if(isjson==wyFalse) + { + if(data[i] && strcmp(data[i], "NULL") != 0 && strcmp(data[i], "(NULL)") != 0) + { + query.AddSprintf("%s%s`%s` = ", + isfirst == wyFalse ? " " : "", + isfirst == wyFalse ? delimiter : "", + colname.GetString()); + + //consider interpreting keywords/functions + if(ischeckspdata == wyFalse || AppendSpecialDataToQuery(data[i], (wyChar*)colname.GetString(), query) == wyFalse) + { + //if it is not special data or we dont want to consider special data, then add the raw data to query + AppendDataToQuery(data, i, m_data->m_datares->field_count, query, isbin); + } + } + else + { + //add query data for null, for an insert/update query nullcheck is '= NULL', for others it is 'IS NULL' + query.AddSprintf("%s%s`%s` %s", + isfirst == wyFalse ? " " : "", + isfirst == wyFalse ? delimiter : "", + colname.GetString(), + nullcheck); + } + + } + //for not null data + else + { + if(data[i] && strcmp(data[i], "NULL") != 0 && strcmp(data[i], "(NULL)") != 0) + { + query.AddSprintf("%s%s%s", + isfirst == wyFalse ? " " : "", + isfirst == wyFalse ? delimiter : "", + "JSON_CONTAINS("); + + //consider interpreting keywords/functions + if(ischeckspdata == wyFalse || AppendSpecialDataToQuery(data[i], (wyChar*)colname.GetString(), query) == wyFalse) + { + //if it is not special data or we dont want to consider special data, then add the raw data to query + AppendDataToQuery(data, i, m_data->m_datares->field_count, query, isbin); + } + query.AddSprintf(",`%s`)",colname.GetString()); + + } + else + { + //add query data for null, for an insert/update query nullcheck is '= NULL', for others it is 'IS NULL' + query.AddSprintf("%s%s`%s` %s", + isfirst == wyFalse ? " " : "", + isfirst == wyFalse ? delimiter : "", + colname.GetString(), + nullcheck); + } + } + + //set some flags so that we can add proper delimiters + isfirst = wyFalse; + isgenerated = wyTrue; + } + + } + + return isgenerated; +} + + //function to generate query to find duplicates of an item in the table wyBool DataView::GenerateDuplicatesQuery(wyInt32 row, wyString &query) @@ -1229,11 +1328,11 @@ DataView::GenerateDeleteQuery(wyString& query, wyBool issetlimit, wyUInt32 row) //if the row is modified but not saved, then we will consider the old data otherwise current data if(m_data->m_modifiedrow >= 0 && row == m_data->m_modifiedrow) { - isfirst = AddDataToQuery(m_data->m_oldrow->m_row, tempstr, "and ", "is null", -1) ? wyFalse : wyTrue; + isfirst = AddDataToQueryJSON(m_data->m_oldrow->m_row, tempstr, "and ", "is null", -1) ? wyFalse : wyTrue; } else { - isfirst = AddDataToQuery(m_data->m_rowarray->GetRowExAt(row)->m_row, tempstr, "and ", "is null", -1) ? wyFalse : wyTrue; + isfirst = AddDataToQueryJSON(m_data->m_rowarray->GetRowExAt(row)->m_row, tempstr, "and ", "is null", -1) ? wyFalse : wyTrue; } //whether to delete only the current row or all its duplicates @@ -1334,8 +1433,11 @@ DataView::GenerateUpdateQuery(wyString &query, wyBool issetlimit) tempstr.Clear(); //else add all the columns to the query - AddDataToQuery(m_data->m_oldrow->m_row, tempstr, "and ", "is null", -1); - + // if(!FIELD_TYPE_JSON) + // if(m_data->m_datares->fields->type != MYSQL_TYPE_JSON) + // AddDataToQuery(m_data->m_oldrow->m_row, tempstr, "and ", "is null", -1); + // else + AddDataToQueryJSON(m_data->m_oldrow->m_row, tempstr, "and ", "is null", -1); //whether to update only the current row or all its duplicates if(issetlimit == wyTrue) { @@ -3041,7 +3143,7 @@ DataView::IsBlob(wyInt32 col) myfield = m_wnd->m_tunnel->mysql_fetch_fields(m_data->m_datares); if(myfield[col].charsetnr == CHARSET_NUMBER && - (myfield[col].type == MYSQL_TYPE_LONG_BLOB || myfield[col].type == MYSQL_TYPE_MEDIUM_BLOB || + (myfield[col].type == MYSQL_TYPE_LONG_BLOB || myfield[col].type == MYSQL_TYPE_MEDIUM_BLOB || myfield[col].type == MYSQL_TYPE_JSON || myfield[col].type == MYSQL_TYPE_TINY_BLOB || myfield[col].type == MYSQL_TYPE_BLOB)) { return wyTrue; @@ -3050,6 +3152,22 @@ DataView::IsBlob(wyInt32 col) return wyFalse; } +wyBool +DataView::IsJSON(wyInt32 col) +{ + MYSQL_FIELD* myfield; + + //get the field struct + myfield = m_wnd->m_tunnel->mysql_fetch_fields(m_data->m_datares); + + if(myfield[col].type == MYSQL_TYPE_JSON) + { + return wyTrue; + } + + return wyFalse; +} + //function to get cell value wyChar* DataView::GetCellValue(wyInt32 row, wyInt32 col, wyUInt32* len, wyBool fromorig, wyString* bitstr) @@ -3314,7 +3432,7 @@ wyBool DataView::HandleBlobValue(WPARAM wparam, LPARAM lparam) { wyChar* data = 0; - INSERTUPDATEBLOB pib = {0}; + INSERTUPDATEBLOB pib = {0}; BlobMgmt biu; wyUInt32 len = 0; wyInt32 offset = 0, row = 0, col = 0, isdataupdated = 0; @@ -3350,8 +3468,8 @@ DataView::HandleBlobValue(WPARAM wparam, LPARAM lparam) //to check whether it is a blob or text pib.m_isblob = IsBlob(col); - - //show blob + pib.m_isJson = IsJSON(col); + //show blob ret = biu.Create(m_hwndgrid, &pib, isedit); //is anything changed @@ -6113,7 +6231,7 @@ DataView::WriteFixed(HGLOBAL* hglobal, LPWSTR* buffer, wyUInt32 * nsize, wyChar wyWChar *padwchar = NULL; wyUInt32 padlen = 1; - if(field->type >= FIELD_TYPE_TINY_BLOB && field->type <= FIELD_TYPE_BLOB) + if(field->type >= FIELD_TYPE_TINY_BLOB && field->type <= FIELD_TYPE_BLOB || field->type == FIELD_TYPE_JSON) { return wyTrue; } @@ -6979,7 +7097,7 @@ DataView::CreateColumns(wyBool isupdate) } //if it is blob - if((fields[k].type >= FIELD_TYPE_TINY_BLOB) && (fields[k].type <= FIELD_TYPE_BLOB)) + if((fields[k].type >= FIELD_TYPE_TINY_BLOB) && (fields[k].type <= FIELD_TYPE_BLOB) || fields[k].type == FIELD_TYPE_JSON) { //add blob mask gvcol.mask |= GVIF_TEXTBUTTON; @@ -7564,8 +7682,11 @@ DataView::GridWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) //open blob fileds case GVN_BUTTONCLICK: - pviewdata->HandleBlobValue(wparam, lparam); - return TRUE; + + // MYSQL_FIELD* fields; + // fields = pviewdata->m_wnd->m_tunnel->mysql_fetch_fields(pviewdata->m_data->m_datares); + pviewdata->HandleBlobValue(wparam, lparam); + return TRUE; //open FK dropdown case GVN_BROWSEBUTTONCLICK: @@ -7641,7 +7762,7 @@ DataView::ShowContextMenu(wyInt32 row, wyInt32 col, LPPOINT pt) { HMENU hmenu, htrackmenu; wyBool iscolreadonly = wyTrue, iscolnullable = wyFalse, iscolhasdefault = wyFalse; - wyString column; + wyString column, columntype; wyInt32 copymenupos = 14,i,iscolvirtual=0; HWND hwndtoolbar; wyBool isunsort = wyFalse; @@ -7707,6 +7828,16 @@ DataView::ShowContextMenu(wyInt32 row, wyInt32 col, LPPOINT pt) { //check whether the column is nullable iscolnullable = IsNullable(m_wnd->m_tunnel, m_data->m_fieldres, (wyChar*)column.GetString()); + + if(!iscolnullable) + { + //if column type is timestamp,leave the set null key enabled as timestamp takes null and set to current timestamp + columntype = GetDataType(m_wnd->m_tunnel, m_data->m_fieldres, (wyChar*)column.GetString()); + if(columntype.CompareI("timestamp") == 0) + { + iscolnullable = wyTrue; + } + } //does the column has any defaults iscolhasdefault = (GetDefaultValue(m_wnd->m_tunnel, m_data->m_fieldres, NULL, (wyChar*)column.GetString())) ? wyTrue : wyFalse; @@ -7829,7 +7960,7 @@ DataView::SetFilterMenu(HMENU hmenu, wyInt32 row, wyInt32 col) text = GetCellValue(row, col, &len, wyFalse); //check if the column is binary/blob/spatial - isbinary = (m_data->m_datares->fields[col].type == MYSQL_TYPE_BIT || m_data->m_datares->fields[col].type == MYSQL_TYPE_GEOMETRY + isbinary = (m_data->m_datares->fields[col].type == MYSQL_TYPE_BIT || m_data->m_datares->fields[col].type == MYSQL_TYPE_JSON || m_data->m_datares->fields[col].type == MYSQL_TYPE_GEOMETRY || (m_data->m_datares->fields[col].type == MYSQL_TYPE_BLOB && BlobMgmt::IsDataBinary(text, len) == wyTrue)) ? wyTrue : wyFalse; //dummy value diff --git a/src/ExportAsSimpleSQL.cpp b/src/ExportAsSimpleSQL.cpp index a248ea6..7cbfa88 100644 --- a/src/ExportAsSimpleSQL.cpp +++ b/src/ExportAsSimpleSQL.cpp @@ -185,6 +185,7 @@ wyBool ExportAsSimpleSQL::SkipLength(MysqlDataType &retdatatype) { if(retdatatype.m_mysqltype.CompareI("blob") == 0 || + retdatatype.m_mysqltype.CompareI("json") == 0 || retdatatype.m_mysqltype.CompareI("date") == 0 || retdatatype.m_mysqltype.CompareI("timestamp") == 0 || retdatatype.m_mysqltype.CompareI("time") == 0 || diff --git a/src/ExportBatch.cpp b/src/ExportBatch.cpp index c68764b..a250755 100644 --- a/src/ExportBatch.cpp +++ b/src/ExportBatch.cpp @@ -157,19 +157,93 @@ ExportBatch::ExpDataDlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lPar break; case WM_NOTIFY: { + TVHITTESTINFO ht = {0}; if(lpnm->idFrom == IDC_EXPORTTREE && lpnm->code == NM_CLICK) + { HandleTreeViewItem(lParam, wParam); + HWND hwndexpmode; + wyInt32 chkstate; + + VERIFY(hwndexpmode = GetDlgItem(hwnd, IDC_CHK_DATAONLY)); + chkstate = SendMessage(hwndexpmode, BM_GETCHECK, 0, 0); + if(chkstate == BST_CHECKED) + { + DWORD dwpos = GetMessagePos(); + ht.pt.x = GET_X_LPARAM(dwpos); + ht.pt.y = GET_Y_LPARAM(dwpos); + MapWindowPoints(HWND_DESKTOP, lpnm->hwndFrom, &ht.pt, 1); + + TreeView_HitTest(lpnm->hwndFrom, &ht); + + if(TVHT_ONITEMSTATEICON & ht.flags) + { + + PostMessage(hwnd, UM_CHECKSTATECHANGE, 0, (LPARAM)ht.hItem); + } + } + } if((ptvkd->hdr.idFrom == IDC_EXPORTTREE) && ptvkd->wVKey == VK_SPACE) - HandleTreeViewItem(lParam, wParam, wyTrue); - + { + HandleTreeViewItem(lParam, wParam, wyTrue); + HWND hwndexpmode; + wyInt32 chkstate; + + VERIFY(hwndexpmode = GetDlgItem(hwnd, IDC_CHK_DATAONLY)); + chkstate = SendMessage(hwndexpmode, BM_GETCHECK, 0, 0); + if(chkstate == BST_CHECKED) + { + HWND hwndtree; + VERIFY(hwndtree = GetDlgItem(hwnd, IDC_EXPORTTREE)); + HTREEITEM hitem = TreeView_GetSelection(hwndtree); + PostMessage(hwnd, UM_CHECKSTATECHANGE, 0, (LPARAM)hitem); + } + } if(lpnm->code == TVN_ITEMEXPANDING) { - return pexp->OnItemExpandingHelper(lpnm->hwndFrom, (LPNMTREEVIEW)lParam); + HWND hwndexpmode; + VERIFY(hwndexpmode = GetDlgItem(hwnd, IDC_CHK_DATAONLY)); + wyInt32 chk_data = SendMessage(hwndexpmode, BM_GETCHECK, 0, 0); + return pexp->OnItemExpandingHelper(lpnm->hwndFrom, (LPNMTREEVIEW)lParam, chk_data); } } break; + case UM_CHECKSTATECHANGE: + { + HWND hwndtree; + wyInt32 state; + wyWChar temptext[SIZE_512] = {0}; + TVITEM tvi = {0}; + + VERIFY(hwndtree = GetDlgItem(hwnd, IDC_EXPORTTREE)); + HTREEITEM htreeitem = (HTREEITEM)lParam; + HTREEITEM hrootitem = TreeView_GetParent(hwndtree,htreeitem); + HTREEITEM hchilditem; + if(hrootitem != NULL) + { + htreeitem = hrootitem; + } + tvi.mask = TVIF_HANDLE |TVIF_TEXT ; + tvi.hItem = htreeitem; + tvi.pszText = temptext; + tvi.cchTextMax = 512 - 1; + + VERIFY(TreeView_GetItem(hwndtree, &tvi)); + + if(wcsicmp(tvi.pszText,TXT_TABLES) != 0) + { + for(hchilditem = TreeView_GetChild(hwndtree, htreeitem); hchilditem; hchilditem = TreeView_GetNextSibling(hwndtree, hchilditem)) + { + TreeView_SetCheckState(hwndtree, hchilditem, 0); + } + TreeView_SetCheckState(hwndtree, htreeitem, 0); + yog_message(hwnd, _(L"Only table(s) have data. You need to select only table(s) for dumping - Data Only"), + pGlobals->m_appname.GetAsWideChar(), MB_ICONINFORMATION | MB_OK); + return TRUE; + } + } + break; case WM_GETMINMAXINFO: pexp->OnWMSizeInfo(lParam); @@ -285,6 +359,29 @@ ExportBatch::EnableDisableOptions(wyInt32 id) state = SendMessage(hwndexpmode, BM_GETCHECK, 0, 0); if(state == BST_CHECKED) { + wyWChar temptext[SIZE_512] = {0}; + TVITEM tvi = {0}; + HWND hwndtree; + HTREEITEM htreeparent; + VERIFY(hwndtree = GetDlgItem(m_hwnd, IDC_EXPORTTREE)); + htreeparent = TreeView_GetRoot(hwndtree); + for(; htreeparent; htreeparent = TreeView_GetNextSibling(hwndtree, htreeparent)) + { + tvi.mask = TVIF_TEXT; + tvi.hItem = htreeparent; + tvi.pszText = temptext; + tvi.cchTextMax = 512 - 1; + VERIFY(TreeView_GetItem(hwndtree, &tvi)); + if(wcsicmp(temptext, TXT_TABLES)!= 0) + { + TreeView_SetCheckState(hwndtree, htreeparent, 0); + for(HTREEITEM hchilditem = TreeView_GetChild(hwndtree, htreeparent); hchilditem; hchilditem = TreeView_GetNextSibling(hwndtree, hchilditem)) + { + TreeView_SetCheckState(hwndtree, hchilditem, 0); + } + } + } + EnableWindow(GetDlgItem(m_hwnd, IDC_CHK_CREATEDB), FALSE); EnableWindow(GetDlgItem(m_hwnd, IDC_CHK_DROPOBJECT), FALSE); EnableWindow(GetDlgItem(m_hwnd, IDC_CHK_DEFINER), FALSE); @@ -315,7 +412,7 @@ ExportBatch::EnableDisableOptions(wyInt32 id) EnableWindow(GetDlgItem(m_hwnd, IDC_BULKINSERT), FALSE); EnableWindow(GetDlgItem(m_hwnd, IDC_CHK_CREATEDB), TRUE); EnableWindow(GetDlgItem(m_hwnd, IDC_CHK_DROPOBJECT), TRUE); - + EnableWindow(GetDlgItem(m_hwnd, IDC_CHK_DEFINER), TRUE); } else @@ -348,6 +445,7 @@ ExportBatch::EnableDisableOptions(wyInt32 id) EnableWindow(GetDlgItem(m_hwnd, IDC_CHK_CREATEDB), TRUE); EnableWindow(GetDlgItem(m_hwnd, IDC_CHK_DROPOBJECT), TRUE); EnableWindow(GetDlgItem(m_hwnd, IDC_CHK_LOCKAROUNDINSERT), TRUE); + EnableWindow(GetDlgItem(m_hwnd, IDC_CHK_DEFINER), TRUE); } } break; @@ -615,16 +713,20 @@ ExportBatch::IntializeTree(HWND hwnd, const wyChar * dbname, wyBool cbselchange) { state = TreeView_GetItemState(hwndtree, htreeparent, TVIS_EXPANDEDONCE); checkstate = TreeView_GetCheckState(hwndtree, htreeparent); + wyInt32 dataonly; + dataonly = SendMessage(GetDlgItem(m_hwnd, IDC_CHK_DATAONLY), BM_GETCHECK, 0, 0) ; if(!checkstate && !(state & TVIS_EXPANDEDONCE)) TreeView_SetCheckState(hwndtree, htreeparent, 1); - + if(dataonly == BST_CHECKED) + { + break; + } if(hti) { tviOB.hItem = hti; tviOB.mask = TVIF_PARAM; TreeView_GetItem(hobtree, &tviOB); - if((tviOB.lParam && wcslen(((OBDltElementParam *)tviOB.lParam)->m_filterText)) || m_dump_all_tables) { TreeView_Expand(hwndtree, htreeparent, TVE_EXPAND); @@ -1535,7 +1637,7 @@ ExportBatch::EnableDlgWindows(bool state) IDC_CHK_USEDBNAME, IDC_CHK_DROPTABLE, IDC_CHK_CREATEDB, IDC_CHK_LOCKFORREAD, IDC_CHK_FLUSHLOGS, IDC_CHK_LOCKAROUNDINSERT, IDC_SETUNIQUE, IDC_BULKINSERT,IDC_ONEROW,IDC_SINGLE_TRANSACTION, IDCANCEL, IDC_CHK_DROPPROCEDURES, IDC_CHK_DROPVIEWS, - IDC_CHK_DROPFUNCTIONS, IDC_CHK_DROPTRIGGERS, IDC_CHK_DEFINER, IDC_CHK_VERSION + IDC_CHK_DROPFUNCTIONS, IDC_CHK_DROPTRIGGERS, IDC_CHK_DEFINER, IDC_CHK_VERSION, IDC_TIMESTAMP_PREFIX, IDC_FILE_TABLE }; wyInt32 i, count; @@ -1706,7 +1808,7 @@ ExportBatch::IsExporting() //To expand treeview while click on treeview wyBool -ExportBatch::OnItemExpandingHelper(HWND hwnd , LPNMTREEVIEW pnmtv) +ExportBatch::OnItemExpandingHelper(HWND hwnd , LPNMTREEVIEW pnmtv, wyInt32 dataonly_chck) { TVITEM tvi, tviOB; wyWChar filterText[70], str[70]; @@ -1824,22 +1926,30 @@ ExportBatch::OnItemExpandingHelper(HWND hwnd , LPNMTREEVIEW pnmtv) TreeView_GetItem(hwnd, &tviOB); if(!wcsicmp(tviOB.pszText, m_table.GetAsWideChar())) { - TreeView_SetCheckState(hwnd, hti, 1); - atleastOneItemChecked = wyTrue; - } - else - { - TreeView_SetCheckState(hwnd, hti, 0); + if(image1 == NTABLES) + { + TreeView_SetCheckState(hwnd, hti, 1); + atleastOneItemChecked = wyTrue; + } } } if(atleastOneItemChecked) { - TreeView_SetCheckState(hwnd, tvi.hItem, 1); - } - else - { - TreeView_SetCheckState(hwnd, tvi.hItem, 0); - } + + if(dataonly_chck == BST_CHECKED) + { + if(image1 == NTABLES) + { + TreeView_SetCheckState(hwnd, tvi.hItem, 1); + } + else + { + TreeView_SetCheckState(hwnd, tvi.hItem, 0); + } + } + else + TreeView_SetCheckState(hwnd, tvi.hItem, 1); + } } } diff --git a/src/ExportData.cpp b/src/ExportData.cpp index 30d8b5f..94fdb34 100644 --- a/src/ExportData.cpp +++ b/src/ExportData.cpp @@ -2642,6 +2642,9 @@ wyBool rowptr++; } + if(rowcount != 0) + buffer.Add(",\r\n"); + buffer.Add("{ \r\n"); count = 0; for(j=0; j < (myres->field_count); j++) @@ -2683,11 +2686,11 @@ wyBool //Now add the value. If it number than use as it is other wise use double quotes refer-http://json.org/ if(myfield[j].type==MYSQL_TYPE_DECIMAL ||myfield[j].type==MYSQL_TYPE_FLOAT ||myfield[j].type==MYSQL_TYPE_INT24 ||myfield[j].type==MYSQL_TYPE_LONG||myfield[j].type==MYSQL_TYPE_LONGLONG||myfield[j].type==MYSQL_TYPE_NEWDECIMAL - ||myfield[j].type==MYSQL_TYPE_SHORT) + ||myfield[j].type==MYSQL_TYPE_SHORT || myfield[j].type==MYSQL_TYPE_JSON) buffer.Add(myrowstr.GetString()); - else + else - { + { buffer.Add("\""); buffer.Add(myrowstr.GetString()); buffer.Add("\""); @@ -2698,9 +2701,9 @@ wyBool count++; } - buffer.Add("\r\n},"); + buffer.Add("\r\n}"); - buffer.Add("\r\n"); + //Write to file if buffer size is more if(buffer.GetLength() >= SIZE_8K) @@ -2721,7 +2724,7 @@ wyBool rowcount++; } //remove last ',' - buffer.SetCharAt(buffer.GetLength()-3,' '); +// buffer.SetCharAt(buffer.GetLength()-3,' '); buffer.Add("]"); ret = WriteFile(hfile, buffer.GetString(), buffer.GetLength(), &dwbyteswritten, NULL); diff --git a/src/FrameWindow.cpp b/src/FrameWindow.cpp index db5f76b..4f668ea 100644 --- a/src/FrameWindow.cpp +++ b/src/FrameWindow.cpp @@ -257,12 +257,10 @@ FrameWindow::~FrameWindow() { delete m_conntab; } - delete m_statusbarmgmt; CloseL10n(); - - + } @@ -8870,6 +8868,7 @@ FrameWindow::CreateConnDialog(wyBool readsession) pGlobals->m_pcmainwin->OnActiveConn(); pcquerywnd->m_pcqueryobject->OnSelChanged(TreeView_GetSelection(pcquerywnd->m_pcqueryobject->m_hwnd)); SetForegroundWindow(pcquerywnd->m_hwnd); + PostMessage(pGlobals->m_pcmainwin->m_hwndmain, WM_SETACTIVEWINDOW, (WPARAM)pcquerywnd->m_hwnd, 0 ); SetCursor(LoadCursor(NULL, IDC_ARROW)); } @@ -10201,7 +10200,7 @@ if(pGlobals->m_pcmainwin->m_connection->m_enttype != ENT_PRO) temptabeditorele = new tabeditorelem; WriteTabDetailsToTable(temptabeditorele, temptabeditorele_temp, newqid, k, tempmdilist->m_id, tempmdilist_temp->m_activetab); tempmdilist->m_listtabeditor->Insert(temptabeditorele); - + } } @@ -10290,14 +10289,13 @@ if(pGlobals->m_pcmainwin->m_connection->m_enttype != ENT_PRO) temptabeditorele = new tabeditorelem; WriteTabDetailsToTable(temptabeditorele, temptabeditorele_temp, k, k, tempmdilist->m_id, tempmdilist_temp->m_activetab); - tempmdilist->m_listtabeditor->Insert(temptabeditorele); - + tempmdilist->m_listtabeditor->Insert(temptabeditorele); } temptabeditorele_temp = (tabeditorelem*)temptabeditorele_temp->m_next; } - pGlobals->m_mdiwlist->Insert(tempmdilist); } + //---------------------------------------------------------New Connecton Added in the linked List------------------------------------// tempmdilist_temp = (MDIlisttemp*)tempmdilist_temp->m_next; //----Move to next connection window----// @@ -10753,9 +10751,6 @@ FrameWindow::RestoreStatusDlgProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM return FALSE; } - - - wyBool ConnectFromList(wyString* failedconnections, wyString* sessionfile) { @@ -11011,7 +11006,11 @@ ConnectFromList(wyString* failedconnections, wyString* sessionfile) } } if((temptabeditorele->m_iimage != IDI_QUERYBUILDER_16 && temptabeditorele->m_iimage != IDI_SCHEMADESIGNER_16) && (!temptabeditorele->m_isfile || temptabeditorele->m_isedited)) + { + SendMessage(temptabeditorele->m_pctabeditor->m_peditorbase->m_hwnd, SCI_SETTEXT, temptabdetail->m_content.GetLength(),(LPARAM)temptabdetail->m_content.GetString()); + EditorFont::SetLineNumberWidth(temptabeditorele->m_pctabeditor->m_peditorbase->m_hwnd ); + } else if(temptabeditorele->m_iimage == IDI_QUERYBUILDER_16 && (!temptabeditorele->m_isfile || temptabeditorele->m_isedited)) { @@ -11034,6 +11033,7 @@ ConnectFromList(wyString* failedconnections, wyString* sessionfile) } //CustomTab_SetCurSel(pcquerywnd->m_pctabmodule->m_hwnd, i, 1); pcquerywnd->SetDirtyTitle(); + delete doc; } #endif } @@ -11074,7 +11074,10 @@ ConnectFromList(wyString* failedconnections, wyString* sessionfile) temptabdetail = (tabdetailelem*)temptabdetail->m_next; temptabeditorele = (tabeditorelem*)temptabeditorele->m_next; pcquerywnd->m_listtabdetails->Remove(firstindex); + + } + if(totaltabs == 0) { pcquerywnd->m_pctabmodule->CreateQueryEditorTab(pcquerywnd); @@ -11199,7 +11202,7 @@ Htmlannouncementsproc(void *arg) char *received=NULL; int status; const wyChar *langcode; - wyString productid, appmajorversion, appminorversion, extrainfo, url, htmlbuffer; + wyString productid, appmajorversion, appminorversion, extrainfo, url, htmlbuffer, str; wyWChar headers[1024*3] = {0}; wyUInt32 daysleft = 0; @@ -11232,8 +11235,11 @@ Htmlannouncementsproc(void *arg) appminorversion.SetAs(MINOR_VERSION UPDATE_VERSION); extrainfo.SetAs(EXTRAINFO); // beta string +#ifdef _DEBUG + url.SetAs("http://dev.webyog.com/notifications/sqlyog"); +#else url.SetAs("http://www.webyog.com/notifications/sqlyog"); - +#endif #ifdef _WIN64 url.AddSprintf("?user_type=%s&major_version=%s&minor_version=%s&extra=%s&os=win64&language=%s&uuid=%s", productid.GetString(), @@ -11269,14 +11275,20 @@ Htmlannouncementsproc(void *arg) } received = http.GetResponse(); + if(!received) { goto cleanup; } - htmlbuffer.SetAs(received); - pGlobals->m_announcementshtml.SetAs(received); + str.SetAs(received); + ///The HTTP message received from the server will contain "closeann" string if its a valid HTTP response from webyog server. + if(str.FindI("closeann", 0) != -1) + { + htmlbuffer.SetAs(received); + pGlobals->m_announcementshtml.SetAs(received); + } cleanup: diff --git a/src/FrameWindowHelper.cpp b/src/FrameWindowHelper.cpp index c0e77fb..5e4f4b5 100644 --- a/src/FrameWindowHelper.cpp +++ b/src/FrameWindowHelper.cpp @@ -1787,7 +1787,7 @@ GetColWidth(HWND grid, MYSQL_FIELD * myfield, wyInt32 index) // now calculate which has to implemented, extra = 5; // but first we check is it blob - if((myfield->type >= FIELD_TYPE_TINY_BLOB)&&(myfield->type <= FIELD_TYPE_BLOB)) + if(((myfield->type >= FIELD_TYPE_TINY_BLOB)&&(myfield->type <= FIELD_TYPE_BLOB)) || (myfield->type == FIELD_TYPE_JSON) ) { //cx = maxlen.cx + extra; //Same code repeated in else condition also, I will change this @@ -2329,6 +2329,14 @@ GetColumnName(wyWChar *field) return; } +int IsColumnTypeJson(wyWChar *field) +{ + wchar_t* result=wcschr(field,L', '); + if(wcsncmp(result,L", json",6)) + return 0; + else + return 1; +} wyBool IsGetObjectInfoAlways() diff --git a/src/GUIHelper.cpp b/src/GUIHelper.cpp index a83ac9e..ed3cb6c 100644 --- a/src/GUIHelper.cpp +++ b/src/GUIHelper.cpp @@ -237,6 +237,44 @@ OpenKeyWordsDB(sqlite3 **phdb) return wyTrue; } +wyBool +GetClusterdbSupportForFk(MDIWindow *wnd) +{ + wyString query, str1; + wyChar *major, *minor; + wyChar seps[] = "."; + wyInt32 majorver = 0, minorver = 0; + MYSQL_RES *res; + MYSQL_ROW myrow; + res = NULL; + query.Sprintf(GET_NDB_VERSION_STRING); + res = ExecuteAndGetResult(wnd, wnd->m_tunnel, &wnd->m_mysql, query); + if(!res) + { + return wyFalse; + } + VERIFY(myrow = wnd->m_tunnel->mysql_fetch_row(res)); + if(!myrow) + { + wnd->m_tunnel->mysql_free_result(res); + return wyFalse; + } + str1.SetAs(myrow[0]); + str1.FindIAndReplace("ndb-",""); + major = strtok((wyChar*)str1.GetString(), seps); + minor = strtok(NULL, seps); + majorver = atoi(major); + minorver = atoi(minor); + wnd->m_tunnel->mysql_free_result(res); + if(majorver > 7 || (majorver >= 7 && minorver >= 3)) + { + return wyTrue; + } + else + { + return wyFalse; + } +} wyChar * GetUtf8String(const wyChar *ansistr) diff --git a/src/MDIWindow.cpp b/src/MDIWindow.cpp index a203a74..c30377f 100644 --- a/src/MDIWindow.cpp +++ b/src/MDIWindow.cpp @@ -170,7 +170,7 @@ MDIWindow::~MDIWindow() delete m_acinterface; delete m_pcqueryobject; delete m_pcqueryvsplitter; - + delete m_listtabeditor; if(m_tunnel) delete m_tunnel; diff --git a/src/MySQLVersionHelper.cpp b/src/MySQLVersionHelper.cpp index 4c00d6b..1b0b076 100644 --- a/src/MySQLVersionHelper.cpp +++ b/src/MySQLVersionHelper.cpp @@ -417,6 +417,21 @@ IsMySQL564MariaDB53(Tunnel *tunnel, PMYSQL mysql) return wyFalse; } +void GetVersionInfoforAutoComplete(MYSQL *mysql, wyString &VersionS) +{ + long me = mysql_get_server_version(mysql); + char *dbString = mysql_get_server_info(mysql); + if(strstr(dbString, "MariaDB")) ///if its mariadb,check if the version is above 10.2 + { + if(me >= 100200) + me = 50713;///if mariadb version is > 10.2 it supports JSON, hence include functions till mysql version 5.7.13 + else + me = 50066;///if mariadb version is < 10.2, include functions only for previous versons of mysql. + } + + VersionS.Sprintf("%ld", me); +} + //DEFAULT, ON UPDATE clause for DATETIME wyBool IsMySQL565MariaDB1001(Tunnel *tunnel, PMYSQL mysql) @@ -456,6 +471,30 @@ wyBool IsMySQL57(Tunnel * tunnel, PMYSQL mysql) } +// MySQL 5.7.8 +wyBool IsMySQL578(Tunnel * tunnel, PMYSQL mysql) +{ + long me = mysql_get_server_version(*mysql); + const char *dbString = mysql_get_server_info(*mysql); + + if(me >= 50708 && !strstr(dbString, "MariaDB") ) + return wyTrue; + else + return wyFalse; +} +/* +wyBool IsClusterDb(Tunnel * tunnel, PMYSQL mysql) +{ + long me = mysql_get_server_version(*mysql); + + const char *dbString = mysql_get_server_info(*mysql); + + if(me >= 50708 && strstr(dbString, "ClusterDB") ) + return wyTrue; + else + return wyFalse; +} +*/ //MySQL 5.7.7 wyBool diff --git a/src/ObjectBrowser.cpp b/src/ObjectBrowser.cpp index c7b413c..678a747 100644 --- a/src/ObjectBrowser.cpp +++ b/src/ObjectBrowser.cpp @@ -2224,7 +2224,9 @@ CQueryObject::CreateInsertStmt() MDIWindow* wnd; EditorBase *peditorbase = NULL; wyBool isbacktick; - + wyString execquery; + MYSQL_RES *fieldres = NULL; + MYSQL_ROW row; VERIFY(wnd = GetActiveWin()); @@ -2276,6 +2278,14 @@ CQueryObject::CreateInsertStmt() IsBackTick(isbacktick), strtable.GetString(), IsBackTick(isbacktick)); ncount = 0; + execquery.Sprintf("show full fields from `%s`.`%s`", strdbname.GetString(), strtable.GetString()); + fieldres = ExecuteAndGetResult(wnd,wnd->m_tunnel, &wnd->m_mysql, execquery); + if(fieldres == NULL) + { + return wyFalse; + } + + wyString temp; for(hitem = TreeView_GetChild(m_hwnd, hitem); hitem != NULL; hitem = TreeView_GetNextSibling(m_hwnd, hitem)) { GetNodeText(m_hwnd ,hitem, colname, SIZE_512); @@ -2283,12 +2293,19 @@ CQueryObject::CreateInsertStmt() GetColumnName(strtemp); strcolname.SetAs(strtemp); + row = wnd->m_tunnel->mysql_fetch_row(fieldres); + temp.SetAs(row[6]); + if(temp.CompareI("VIRTUAL") == 0 || temp.CompareI("Stored") == 0 || temp.CompareI("Persistent") == 0 || temp.CompareI("virtual generated") == 0 || temp.CompareI("stored generated") == 0 ) + { + continue; + } + columns.AddSprintf("%s%s%s", IsBackTick(isbacktick), strcolname.GetString(), IsBackTick(isbacktick)); columns1.AddSprintf("'%s'", strcolname.GetString()); - + // now we check whether there is any more column. - htempitem = TreeView_GetNextSibling(m_hwnd, hitem); - + htempitem = TreeView_GetNextSibling(m_hwnd, hitem); + if(htempitem) { columns.Add(", "); @@ -2297,15 +2314,24 @@ CQueryObject::CreateInsertStmt() columns.Add("\r\n\t"); columns1.Add("\r\n\t"); + } + ///if temp is virtual,last col is virtual..hence remove the leading commas + /// 5 for : ', ' characters added above and "\r\n\t" added above. + + if(temp.CompareI("VIRTUAL") == 0 || temp.CompareI("Stored") == 0 || temp.CompareI("Persistent") == 0 || temp.CompareI("virtual generated") == 0 || temp.CompareI("stored generated") == 0) + { + columns.Strip(5); + columns1.Strip(5); } - - compquery.Add(query.GetString()); + wnd->m_tunnel->mysql_free_result(fieldres); + + compquery.Add(query.GetString()); compquery.Add(columns.GetString()); compquery.Add(")\r\n\tvalues\r\n\t("); - compquery.Add(columns1.GetString()); + + compquery.Add(columns1.GetString()); compquery.Add(");\r\n"); - if(wnd->GetActiveTabEditor() == NULL) { SendMessage(m_hwnd, WM_SETREDRAW, TRUE, NULL); @@ -2363,14 +2389,17 @@ CQueryObject::CreateUpdateStmt() wyInt32 ret; wyString query, strdbname, strtable, strcolname; wyWChar colname[SIZE_512]; + wyWChar coltype[SIZE_512]; wyString columns, columns1, compquery, primary, colvalue; TVITEM tvi; HTREEITEM hitem, htempitem; MDIWindow* wnd; EditorBase *peditorbase = NULL; wyBool isbacktick; - - + wyString execquery; + MYSQL_RES *fieldres = NULL; + MYSQL_ROW row; + int x; // Flag variable to modify the where clause if it contains JSON VERIFY(wnd = GetActiveWin()); VERIFY(hitem = TreeView_GetSelection(m_hwnd)); @@ -2421,36 +2450,65 @@ CQueryObject::CreateUpdateStmt() //if there is no primary key then we need to add all fields. if primary key exists then we will add primary key GetPrimaryKeyInfo(wnd, primary, isbacktick); - + execquery.Sprintf("show full fields from `%s`.`%s`", strdbname.GetString(), strtable.GetString()); + fieldres = ExecuteAndGetResult(wnd,wnd->m_tunnel, &wnd->m_mysql, execquery); + if(fieldres == NULL) + { + return wyFalse; + } + wyString temp; for(hitem = TreeView_GetChild(m_hwnd, hitem); hitem != NULL; hitem = TreeView_GetNextSibling(m_hwnd, hitem)) { TreeView_GetItem(m_hwnd, &tvi); GetNodeText(m_hwnd, hitem, colname, SIZE_512); + GetColumnName(colname); strcolname.SetAs(colname); + + GetNodeText(m_hwnd, hitem, coltype, SIZE_512); + x=IsColumnTypeJson(coltype); + row = wnd->m_tunnel->mysql_fetch_row(fieldres); + temp.SetAs(row[6]); + if(temp.CompareI("VIRTUAL") == 0 || temp.CompareI("Stored") == 0 || temp.CompareI("Persistent") == 0 || temp.CompareI("virtual generated") == 0 || temp.CompareI("stored generated") == 0) + { + continue; + } colvalue.Sprintf("%s%s%s = '%s'", IsBackTick(isbacktick), strcolname.GetString(), IsBackTick(isbacktick), strcolname.GetString()); columns.Add(colvalue.GetString()); + if(x==1) + { // changing the where clause in the pasted statement if it is JSON + colvalue.Sprintf("JSON_CONTAINS('%s',`%s`)",strcolname.GetString(), strcolname.GetString()); + } + // columns1 is for where clause columns1.Add(colvalue.GetString()); - // now we check whether there is any more column. htempitem = TreeView_GetNextSibling(m_hwnd, hitem); if(htempitem) { - columns.Add(" , "); - columns1.Add(" and "); + columns.Add(", "); + columns1.Add("and "); } columns.Add("\r\n\t"); columns1.Add("\r\n\t"); } - + ///if temp is virtual,last col is virtual..hence remove the leading commas + /// 5 for : ', ' characters added above and "\r\n\t" added above. + /// 7 for : 'and ' characters added above and "\r\n\t" added above. + if(temp.CompareI("VIRTUAL") == 0 || temp.CompareI("Stored") == 0 || temp.CompareI("Persistent") == 0 || temp.CompareI("virtual generated") == 0 || temp.CompareI("stored generated") == 0) + { + columns.Strip(5); + columns1.Strip(7); + } + wnd->m_tunnel->mysql_free_result(fieldres); compquery.Add(query.GetString()); compquery.Add(columns.GetString()); compquery.Add("\r\n\twhere\r\n\t"); + if(primary.GetLength() != 0) compquery.Add(primary.GetString()); else @@ -2514,14 +2572,14 @@ CQueryObject::CreateDeleteStmt() wyUInt32 item; wyInt32 ret; wyString query, strdbname, strtable, strcolname,primary; - wyWChar colname[SIZE_512]; + wyWChar colname[SIZE_512],coltype[SIZE_512]; wyString columns, columns1, compquery; TVITEM tvi; HTREEITEM hitem, htempitem; MDIWindow* wnd; EditorBase *peditorbase = NULL; wyBool isbacktick; - + int x; // Flag variable to modify the where clause if it contains JSON VERIFY(wnd = GetActiveWin()); @@ -2583,8 +2641,15 @@ CQueryObject::CreateDeleteStmt() GetColumnName(colname); strcolname.SetAs(colname); + + GetNodeText(m_hwnd, hitem, colname, SIZE_512); + x=IsColumnTypeJson(coltype); + if(x==0) columns.AddSprintf("%s%s%s = '%s'", IsBackTick(isbacktick), strcolname.GetString(), IsBackTick(isbacktick), strcolname.GetString() ); - + if(x==1) + { // changing the where clause in the pasted statement if it is JSON + columns.AddSprintf("JSON_CONTAINS('%s',`%s`)",strcolname.GetString(), strcolname.GetString()); + } // now we check whether there is any more column. htempitem = TreeView_GetNextSibling(m_hwnd, hitem); diff --git a/src/TabFields.cpp b/src/TabFields.cpp index 99bf271..7151760 100644 --- a/src/TabFields.cpp +++ b/src/TabFields.cpp @@ -126,6 +126,7 @@ TabFields::TabFields(HWND hwnd, TableTabInterfaceTabMgmt* ptabmgmt) m_ismysql41 = IsMySQL41(m_mdiwnd->m_tunnel, &(m_mdiwnd->m_mysql)); m_ismariadb52 = IsMariaDB52(m_mdiwnd->m_tunnel, &m_mdiwnd->m_mysql); m_ismysql57 = IsMySQL57(m_mdiwnd->m_tunnel, &m_mdiwnd->m_mysql); + m_ismysql578 = IsMySQL578(m_mdiwnd->m_tunnel, &m_mdiwnd->m_mysql); m_p = new Persist; m_p->Create("TabbedInterface"); } @@ -1103,13 +1104,20 @@ TabFields::InitGrid() wyInt32 counter; // normal counter wyInt32 num_cols; // number of columns GVCOLUMN gvcol; // structure used to create columns for grid - - // all the data types that are supported by MySQL. entend it as new data types come into - wyWChar type[][20] = { L"tinyint", L"smallint", L"mediumint", L"int", L"bigint", L"real", L"bit", L"bool", L"boolean", + //wyWChar (*type)[33][20]; + wyWChar type[33][20] = { L"tinyint", L"smallint", L"mediumint", L"int", L"bigint", L"real", L"bit", L"bool", L"boolean", L"float", L"double", L"decimal", L"date", L"datetime", L"timestamp", L"numeric", L"time", L"year", L"char", - L"varchar", L"tinyblob", L"tinytext", L"text",L"blob", L"mediumblob", L"mediumtext", L"longblob", L"longtext", - L"enum", L"set", L"binary", L"varbinary" }; + L"varchar", L"tinyblob", L"tinytext", L"text",L"blob" ,L"mediumblob", L"mediumtext", L"longblob", L"longtext", + L"enum", L"set", L"binary", L"varbinary" }; + if(m_ismysql578) + { + type[32][0]='j'; + type[32][1]='s'; + type[32][2]='o'; + type[32][3]='n'; + } + wyWChar virtuallity[3][20]= { L"(none)", L"VIRTUAL",NULL}; if(m_ismariadb52) @@ -1121,10 +1129,6 @@ TabFields::InitGrid() wyChar *heading[] = {_("Column Name"), _("Data Type"), _("Length"), _("Default"), _("PK?"), _("Binary?"), _("Not Null?"), _("Unsigned?"), _("Auto Incr?"), _("Zerofill?"), _("Charset"), _("Collation"), _("On Update"), _("Comment"), _("Virtuality"),_("Expression")}; - VOID *listtype[] = {NULL, (VOID*)type, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, (void*)virtuallity,NULL}; - - wyInt32 elemsize[] = { 0, sizeof(type[0]), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,sizeof(virtuallity[0]),0}; - wyInt32 elemcount[] = {0, sizeof(type)/sizeof(type[0]), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, sizeof(virtuallity)/sizeof(virtuallity[0]),0}; wyInt32 mask[] = {GVIF_TEXT, GVIF_LIST, GVIF_TEXT, GVIF_TEXT, GVIF_BOOL, GVIF_BOOL, GVIF_BOOL, GVIF_BOOL, GVIF_BOOL, GVIF_BOOL, GVIF_LIST, GVIF_LIST, GVIF_BOOL, GVIF_TEXT,GVIF_LIST,GVIF_TEXT}; @@ -1136,13 +1140,19 @@ TabFields::InitGrid() wyInt32 width = 0; wyString colname, dbname(RETAINWIDTH_DBNAME), tblname("__create_table"); HFONT hfont; - - m_ptabmgmt->m_tabinterfaceptr->SetFont(m_hgridfields); + m_ptabmgmt->m_tabinterfaceptr->SetFont(m_hgridfields); hfont = CustomGrid_GetColumnFont(m_hgridfields); cx[1] = GetTextSize(L"mediumblob ", m_hgridfields, hfont).right + 15; //default min size for datatype col num_cols = sizeof (heading)/sizeof(heading[0]); + VOID *listtype[] = {NULL, (VOID*)type, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, (void*)virtuallity,NULL}; + wyInt32 elemsize[] = { 0, sizeof(type[0]), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,sizeof(virtuallity[0]),0}; + wyInt32 elemcount[] = {0, sizeof(type)/sizeof(type[0]), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, sizeof(virtuallity)/sizeof(virtuallity[0]),0}; + + if(! m_ismysql578) // to avoid extra counting of the new datatype json + elemcount[1]=elemcount[1]-1; + for (counter=0; counter < num_cols ; counter++ ) { //for getting the retained column width @@ -1190,10 +1200,7 @@ TabFields::InitGrid() CustomGrid_InsertColumn(m_hgridfields, &gvcol); } - - //m_ptabmgmt->m_tabinterfaceptr->SetFont(m_hgridfields); - - if(!((TableTabInterface*)m_ptabmgmt->m_tabinterfaceptr)->m_isaltertable) + if(!((TableTabInterface*)m_ptabmgmt->m_tabinterfaceptr)->m_isaltertable) { CreateInitRows(); } @@ -1695,7 +1702,7 @@ void // first get the default value. if((cwrapobj->m_oldval) && (fieldattr->m_datatype.CompareI("timestamp")== 0) && (fieldattr->m_onupdate)) - onupdate.SetAs(" on update CURRENT_TIMESTAMP"); + onupdate.SetAs(" on update CURRENT_TIMESTAMP "); GetDefaultValue(defvalue, cwrapobj); @@ -1745,7 +1752,8 @@ void ); if(fieldattr->m_default.GetLength() || fieldattr->m_onupdate ) - newcolumns.AddSprintf("%s ", defvalue.GetString()); + newcolumns.AddSprintf("%s", defvalue.GetString()); + if(!skip) { newcolumns.AddSprintf("%s%s", @@ -1764,7 +1772,7 @@ void GetCommentValue(_comment, fieldattr); if(_comment.GetLength()) - newcolumns.AddSprintf(" %s", _comment.GetString()); + newcolumns.AddSprintf("%s", _comment.GetString()); newcolumns.RTrim(); coldef.Add(newcolumns.GetString()); @@ -1917,9 +1925,9 @@ TabFields::GetDefaultValue(wyString& query, FieldStructWrapper* cwrapobj) { if(len.GetLength()!=0) - query.AddSprintf("%s(%s)","ON UPDATE CURRENT_TIMESTAMP",len.GetString()); + query.AddSprintf("%s(%s)","ON UPDATE CURRENT_TIMESTAMP ",len.GetString()); else - query.AddSprintf("ON UPDATE CURRENT_TIMESTAMP"); + query.AddSprintf("ON UPDATE CURRENT_TIMESTAMP "); } @@ -1989,7 +1997,7 @@ void TabFields::GetVirtualOrPersistentValue(wyString& query, FieldStructWrapper* - query.AddSprintf(") %s", virtuality.GetString()); + query.AddSprintf(") %s ", virtuality.GetString()); } } @@ -2932,7 +2940,7 @@ TabFields::OnGVNEndLabelEdit(WPARAM wParam, LPARAM lParam) if(!((curdatastr.CompareI("CHAR") == 0 || curdatastr.CompareI("VARCHAR") == 0 || curdatastr.CompareI("TINYTEXT") == 0 || curdatastr.CompareI("TEXT") == 0 || curdatastr.CompareI("MEDIUMTEXT") == 0 || curdatastr.CompareI("LONGTEXT") == 0 || - curdatastr.CompareI("blob") == 0 || curdatastr.CompareI("tinyblob") == 0 ) || + curdatastr.CompareI("blob") == 0 || curdatastr.CompareI("JSON") == 0 || curdatastr.CompareI("tinyblob") == 0 ) || curdatastr.CompareI("longblob") == 0 || curdatastr.CompareI("mediumblob") == 0 )) { /// Modifies Index-Length when user sets datatype other than above @@ -4380,6 +4388,9 @@ TabFields::HandleAllBlobTextValidation(HWND &hwndgrid, wyUInt32 &row, wyUInt32 & CustomGrid_SetText(hwndgrid, row, CHARSET, ""); CustomGrid_SetText(hwndgrid, row, COLLATION, ""); } +// if(stricmp(datatype,"json")) + // CustomGrid_SetColumnReadOnly(hwndgrid, row, PRIMARY, wyTrue); + /* CustomGrid_SetColumnReadOnly(hwndgrid, row, PRIMARY, wyTrue); CustomGrid_SetBoolValue (hwndgrid, row, PRIMARY, GV_FALSE); @@ -4401,7 +4412,13 @@ TabFields::HandleAllBlobTextValidation(HWND &hwndgrid, wyUInt32 &row, wyUInt32 & CustomGrid_SetText (hwndgrid, row, LENGTH, "" ); CustomGrid_SetColumnReadOnly(hwndgrid, row, ONUPDATECT, wyTrue); CustomGrid_SetBoolValue (hwndgrid, row, ONUPDATECT, GV_FALSE); - if(m_autoincrowid == row) + if(stricmp(datatype,"json")==0) + { + CustomGrid_SetColumnReadOnly(hwndgrid, row, PRIMARY+ index, wyTrue ); + CustomGrid_SetBoolValue (hwndgrid, row, PRIMARY+ index, GV_FALSE ); + + } + if(m_autoincrowid == row) m_autoincrowid = -1; cwrapobj = (FieldStructWrapper *)CustomGrid_GetRowLongData(m_hgridfields, row); @@ -4432,6 +4449,7 @@ TabFields::HandleBlobTextValidation(HWND &hwndgrid, wyUInt32 &row, wyUInt32 &ind { FieldStructWrapper *cwrapobj = NULL; // makes the charset and collation column readonly for the "text" datatype + //if((stricmp (datatype, "text") == 0) || (stricmp (datatype, "json") == 0) ) if((stricmp (datatype, "text") == 0)) { CustomGrid_SetColumnReadOnly(hwndgrid, row, CHARSET, wyFalse); @@ -4628,9 +4646,12 @@ TabFields::SetValidation(wyUInt32 row, wyChar* datatype) if ((stricmp (datatype , "blob" ) == 0 ) || - (stricmp (datatype , "text" ) == 0) ) + (stricmp (datatype , "text" ) == 0) ) return HandleBlobTextValidation(hwndgrid, row, index, datatype); - + + if(stricmp (datatype , "json" ) == 0) + return HandleAllBlobTextValidation(hwndgrid, row, index, datatype); + if ((stricmp (datatype , "set" ) == 0 ) || (stricmp (datatype , "enum" ) == 0 ) ) return HandleSetEnumValidation(hwndgrid, row, index); diff --git a/src/TabForeignKeys.cpp b/src/TabForeignKeys.cpp index b0ca2c3..e845d86 100644 --- a/src/TabForeignKeys.cpp +++ b/src/TabForeignKeys.cpp @@ -204,8 +204,8 @@ TabForeignKeys::OnTabSelChange() { if(!m_ptabmgmt->m_tabinterfaceptr->m_isfksupported) { - MessageBox(m_hwnd, _(L"The table does not support foreign keys.\r\nTable engine must be InnoDB, PBXT or SolidDB."), pGlobals->m_appname.GetAsWideChar(), MB_OK | MB_ICONINFORMATION); - return; + MessageBox(m_hwnd, _(L"The selected table does not support foreign keys.\nTable engine must be InnoDB, PBXT, SolidDB or ndbcluster (if ndbcluster engine version is greater than or equal to 7.3)."), pGlobals->m_appname.GetAsWideChar(), MB_OK | MB_ICONINFORMATION); + return; } } diff --git a/src/TabIndexes.cpp b/src/TabIndexes.cpp index 88a7c46..78d59a4 100644 --- a/src/TabIndexes.cpp +++ b/src/TabIndexes.cpp @@ -580,6 +580,7 @@ TabIndexes::DoLengthValidation(wyInt32 row) CustomGrid_GetItemText(m_hdlggrid, row, 1, datatype); if((wcsicmp(datatype, L"blob")== 0)|| + (wcsicmp(datatype, L"json")== 0)|| (wcsicmp(datatype, L"char")== 0)|| (wcsicmp(datatype, L"varchar")== 0)|| (wcsicmp(datatype, L"tinyblob")== 0)|| diff --git a/src/TableTabInterface.cpp b/src/TableTabInterface.cpp index 729196b..b2a90cf 100644 --- a/src/TableTabInterface.cpp +++ b/src/TableTabInterface.cpp @@ -20,6 +20,7 @@ #include "TableTabInterfaceTabMgmt.h" #include "TabEditorSplitter.h" #include "TabFields.h" +#include "MySQLVersionHelper.h" #include "TabIndexes.h" #include "TabForeignKeys.h" #include "TabAdvancedProperties.h" @@ -60,6 +61,7 @@ TableTabInterface::TableTabInterface(HWND hwnd, wyBool open_in_dialog, wyBool is m_open_in_dialog = open_in_dialog; m_setfocustotab = setfocustotab; m_isfksupported = wyTrue; + m_isfkforndbcluster = wyFalse; m_dirtytab = wyFalse; m_disableenchange = wyFalse; @@ -174,8 +176,8 @@ TableTabInterface::Create() { if(m_setfocustotab == TABFK) { - MessageBox(m_hwndparent, _(L"The selected table does not support foreign keys.\nTable engine must be InnoDB, PBXT or SolidDB."), pGlobals->m_appname.GetAsWideChar(), MB_OK | MB_ICONINFORMATION); - return wyFalse; + MessageBox(m_hwnd, _(L"The selected table does not support foreign keys.\nTable engine must be InnoDB, PBXT, SolidDB or ndbcluster (if ndbcluster engine version is greater than or equal to 7.3)."), pGlobals->m_appname.GetAsWideChar(), MB_OK | MB_ICONINFORMATION); + return wyFalse; } } } @@ -267,8 +269,8 @@ TableTabInterface::OnWmNotify(HWND hwnd, WPARAM wparam, LPARAM lparam) lpnmctc = (LPNMCTC)lparam; if(lpnmctc->count == 2 && !m_isfksupported) { - MessageBox(m_hwnd, _(L"The selected table does not support foreign keys.\nTable engine must be InnoDB, PBXT or SolidDB."), pGlobals->m_appname.GetAsWideChar(), MB_OK | MB_ICONINFORMATION); - return 0; + MessageBox(m_hwnd, _(L"The selected table does not support foreign keys.\nTable engine must be InnoDB, PBXT, SolidDB or ndbcluster (if ndbcluster engine version is greater than or equal to 7.3)."), pGlobals->m_appname.GetAsWideChar(), MB_OK | MB_ICONINFORMATION); + return 0; } return m_ptabintmgmt->OnTabSelChanging(); @@ -695,19 +697,29 @@ TableTabInterface::OnWmCommand(HWND hwnd, WPARAM wParam, LPARAM lParam) if(!m_disableenchange) { wyString str; + MDIWindow *wnd = NULL; + + VERIFY(wnd = GetActiveWin()); + /// getting the engine version from the combo-box GetComboboxValue((HWND)lParam, str); - + if((HWND)lParam == m_hcmbtabletype) { - if(str.CompareI("innodb") == 0 || str.CompareI("pbxt") == 0 || str.CompareI(STR_DEFAULT) == 0) - m_isfksupported = wyTrue; - else - { - m_isfksupported = wyFalse; - /// Changing the selected subtab, if the active subtab is Foreign-Keys - if(m_ptabintmgmt->GetActiveTabImage() == IDI_MANREL_16) - m_ptabintmgmt->SelectTab(1); - } + /// if engine type is ndbcluster we need to check if, this version of ndbcluster engine supports foreign key or not + /// Foreign key support for NDBcluster engine was provided from cluster version 7.3 and greater. + if(str.CompareI("ndbcluster") == 0) + { + m_isfkforndbcluster = GetClusterdbSupportForFk(wnd); + } + if(str.CompareI("innodb") == 0 || str.CompareI("pbxt") == 0 || str.CompareI(STR_DEFAULT) == 0 || m_isfkforndbcluster) + m_isfksupported = wyTrue; + else + { + m_isfksupported = wyFalse; + /// Changing the selected subtab, if the active subtab is Foreign-Keys + if(m_ptabintmgmt->GetActiveTabImage() == IDI_MANREL_16) + m_ptabintmgmt->SelectTab(1); + } } else if(!m_ptabintmgmt->m_tabpreview->m_istabempty && ((HWND)lParam == m_hcmbdbname)) { @@ -994,7 +1006,6 @@ TableTabInterface::OnClickSave(wyBool onclosetab, wyBool showsuccessmsg) void TableTabInterface::CancelChanges() { - wyString str; m_disableenchange = wyTrue; SendMessage(m_hedittblname, WM_SETTEXT, 0, (LPARAM)(m_isaltertable ? m_origtblname.GetAsWideChar() : TEXT(""))); //Sets table name @@ -1004,9 +1015,9 @@ TableTabInterface::CancelChanges() SendMessage(m_hcmbtabletype, CB_SELECTSTRING, 0, (LPARAM) (m_isaltertable ? m_origtableengine.GetAsWideChar() : TEXT(STR_DEFAULT))); - /// Getting table-type combobox value and setting m_isfksupported variable - GetComboboxValue(m_hcmbtabletype, str); - m_isfksupported = ((str.CompareI("innodb") == 0) || str.CompareI("pbxt") == 0 || str.CompareI(STR_DEFAULT) == 0) ? wyTrue : wyFalse; + /// setting m_isfksupported variable + wyBool error = wyTrue; + m_isfksupported = IsTableInnoDB(error); if(m_ismysql41) { @@ -2428,7 +2439,11 @@ TableTabInterface::SetFocusToGridRow(wyString& objname) wyBool TableTabInterface::IsTableInnoDB(wyBool& error) { - MYSQL_ROW mystatusrow; + MYSQL_ROW mystatusrow; + wyString query, str; + MDIWindow *wnd = NULL; + + VERIFY(wnd = GetActiveWin()); m_mdiwnd->m_tunnel->mysql_data_seek(m_myrestablestatus, 0); VERIFY(mystatusrow = m_mdiwnd->m_tunnel->mysql_fetch_row(m_myrestablestatus)); @@ -2439,15 +2454,23 @@ TableTabInterface::IsTableInnoDB(wyBool& error) } error = wyFalse; - if(!mystatusrow[1] || (stricmp(mystatusrow[1], "InnoDB") != 0 && stricmp(mystatusrow[1], "pbxt")!= 0 && - stricmp(mystatusrow[1], "solidDB") != 0 )) + str.SetAs(mystatusrow[1]); + /// if engine type is ndbcluster we need to check if, this version of ndbcluster engine supports foreign key or not + /// Foreign key support for NDBcluster engine was provided from cluster version 7.3 and greater. + if(str.CompareI("ndbcluster") == 0) + { + m_isfkforndbcluster = GetClusterdbSupportForFk(wnd); + } + if(str.CompareI("innodb") == 0 || str.CompareI("pbxt") == 0 || str.CompareI(STR_DEFAULT) == 0 || m_isfkforndbcluster) + { + m_isfksupported = wyTrue; + return wyTrue; + } + else { + m_isfksupported = wyFalse; return wyFalse; } - - SetCursor(LoadCursor(NULL, IDC_ARROW )); - - return wyTrue; } wyBool diff --git a/src/UpgradeCheck.cpp b/src/UpgradeCheck.cpp index cf56d3c..00a4e52 100644 --- a/src/UpgradeCheck.cpp +++ b/src/UpgradeCheck.cpp @@ -460,10 +460,10 @@ UpgradeCheck::HandleHttpRequest(LPVOID param) Sleep(DELAY_12HOUR); // 12 Hours //Sleep(60000); //1 min - + } - } - + } + return 1; } diff --git a/src/UserManager.cpp b/src/UserManager.cpp index 2633eca..3a49964 100644 --- a/src/UserManager.cpp +++ b/src/UserManager.cpp @@ -123,6 +123,7 @@ UserManager::UserManager() m_hobjprivicon = NULL; m_gripproc = NULL; m_isdeleteuser = wyFalse; + m_userlist = NULL; #ifdef _DEBUG m_sqlite.SetLogging(wyTrue); #else @@ -178,6 +179,12 @@ UserManager::~UserManager() m_controllist.Remove(pdlgctrl); delete pdlgctrl; } + while(m_userlist) + { + USERLIST *temp1 = m_userlist; + m_userlist = m_userlist->next; + delete temp1; + } } PrivilegedObject::PrivilegedObject(wyInt32 privcount, Privileges** privileges, wyInt32 context, wyInt32 value) @@ -470,6 +477,8 @@ UserManager::InitDialog(HWND hwnd) //set the db context to mysql SetResetDBContext(wyTrue); + + return wyTrue; } @@ -859,26 +868,31 @@ wyBool UserManager::OnWMCommand(WPARAM wparam, LPARAM lparam) { wyInt32 ret; - //for any edit control changes if(m_initcompleted == wyTrue && (HIWORD(wparam) == EN_CHANGE || HIWORD(wparam) == CBN_EDITCHANGE)) - { - SetDirtyFlag(wyTrue); + { + if(LOWORD(wparam)!= IDC_USERCOMBO) + SetDirtyFlag(wyTrue); - if(LOWORD(wparam) == IDC_PASSWORD || + if(LOWORD(wparam) == IDC_PASSWORD || LOWORD(wparam) == IDC_PASSWORD_CONFIRM) { m_ispasswordchanged = wyTrue; } if(LOWORD(wparam)== IDC_USERCOMBO){ - OnHandleEditChange(); - + OnHandleEditChange(); } return wyTrue; } + if(m_initcompleted == wyTrue && + (HIWORD(wparam) == CBN_SELCHANGE)) + { + if(!SendMessage(GetDlgItem(m_hwnd,IDC_USERCOMBO), CB_GETDROPPEDSTATE, NULL, NULL)) + OnUserComboChange(); + } switch(LOWORD(wparam)) { @@ -910,14 +924,14 @@ UserManager::OnWMCommand(WPARAM wparam, LPARAM lparam) break; case IDC_USERCOMBO: - if(HIWORD(wparam) == CBN_SELCHANGE) + ///check upon closeup, not when changed + if(HIWORD(wparam) == CBN_CLOSEUP)// || HIWORD(wparam) == CBN_SELCHANGE) { - OnUserComboChange(); + OnUserComboChange(); } break; case IDC_HOSTNAME: - if(HIWORD(wparam) == CBN_SELCHANGE && m_initcompleted) { SetDirtyFlag(); @@ -981,6 +995,7 @@ UserManager::OnSaveChanges() m_selindex = SendMessage(hwndcombo, CB_ADDSTRING, 0, (LPARAM)user.GetAsWideChar()); SendMessage(hwndcombo, CB_SETITEMDATA, (WPARAM)m_selindex, (LPARAM)m_username.GetLength()); SendMessage(hwndcombo, CB_SETCURSEL, (WPARAM)m_selindex, 0); + SetWindowText(hwndcancel, U_CANCELBUTTON_TEXT); SetWindowText(hwndsave, U_SAVEBUTTON_TEXT); m_isedited = wyFalse; @@ -1004,6 +1019,7 @@ UserManager::OnSaveChanges() //reset the flags m_isnewuser = wyFalse; EnableDisableSaveCancel(); + SendMessage(hwndcombo, CB_DELETESTRING, m_selindex, 0); SetFocus(GetDlgItem(m_hwnd, IDC_OBTREE)); } else @@ -1018,7 +1034,7 @@ UserManager::OnSaveChanges() wyBool UserManager::AddNewUser() { - wyString query, username, host, password, password2, tempuser, temphost, temppassword; + wyString query, username, host, password, password2, tempuser, temphost, temppassword, temp; wyWChar buffer[SIZE_128]; wyInt32 ret; @@ -1087,11 +1103,28 @@ UserManager::AddNewUser() return wyFalse; } } - - //set the user name and apply the limitations + m_username.SetAs(username); m_host.SetAs(host); + + temp.SetAs(username.GetString()); + temp.AddSprintf("@%s",host.GetString()); + + USERLIST *tempnode = new USERLIST; + tempnode->m_uname.SetAs(temp.GetString()); + tempnode->m_dropdown = wyFalse; + tempnode->m_itemvalue.Sprintf("%d",m_usercount); + tempnode->next = NULL; + + USERLIST *itr = m_userlist; + while(itr->next) + itr = itr->next; + itr->next = tempnode; + + + ApplyLimitations(); + m_usercount += 1; return wyTrue; } @@ -1138,13 +1171,27 @@ UserManager::PopulateUserCombo() MYSQL_RES* myres; MYSQL_ROW row; wyString temp; - wyInt32 retflag = 0, index, length; + wyInt32 retflag = 0, index, length, i=0; HWND hwndusercombo = GetDlgItem(m_hwnd, IDC_USERCOMBO); SetCursor(LoadCursor(NULL, IDC_WAIT)); //reset the combo box contents SendMessage(hwndusercombo, CB_RESETCONTENT, 0, 0); + query.SetAs("SELECT COUNT(`Host`) FROM `mysql`.`user`"); + myres = ExecuteAndGetResult(m_hmdi, m_hmdi->m_tunnel, &m_hmdi->m_mysql, query); + + if(myres == NULL) + { + OnUMError(query.GetString(), wyTrue); + return -1; + } + if((row = m_hmdi->m_tunnel->mysql_fetch_row(myres))) + { + temp.SetAs(row[0], m_hmdi->m_ismysql41); + m_usercount = temp.GetAsInt32(); + } + m_hmdi->m_tunnel->mysql_free_result(myres); //execute the query and get all the entries query.SetAs("SELECT `Host`, `User` FROM `mysql`.`user`"); @@ -1157,13 +1204,30 @@ UserManager::PopulateUserCombo() } //add it to combo box in the ascending order + USERLIST *itr; while((row = m_hmdi->m_tunnel->mysql_fetch_row(myres))) { + USERLIST *tempnode = new USERLIST; temp.SetAs(row[1], m_hmdi->m_ismysql41); length = temp.GetLength(); temp.AddSprintf("@%s", row[0]); index = SendMessage(hwndusercombo, CB_ADDSTRING, 0, (LPARAM)temp.GetAsWideChar()); SendMessage(hwndusercombo, CB_SETITEMDATA, (WPARAM)index, (LPARAM)length); + tempnode->m_uname.SetAs(temp.GetString()); + tempnode->m_dropdown = wyTrue; + tempnode->m_itemvalue.Sprintf("%d",i); + tempnode->next = NULL; + i++; + if(!m_userlist) + { + itr = tempnode; + m_userlist = tempnode; + } + else + { + itr->next = tempnode; + itr = itr->next; + } } m_hmdi->m_tunnel->mysql_free_result(myres); @@ -1305,7 +1369,14 @@ UserManager::OnUserComboChange() m_isdeleteuser == wyFalse && m_selindex == SendMessage(hwndusercombo, CB_GETCURSEL, 0, 0)) { - return; + len = SendMessage(hwndusercombo, CB_GETLBTEXTLEN, (WPARAM)m_selindex, 0) + 1; + buffer = new wyWChar[len + 1]; + SendMessage(hwndusercombo, CB_GETLBTEXT, (WPARAM)m_selindex, (LPARAM)buffer); + wyString user; + user.SetAs(buffer); + delete buffer; + if(user.CompareI(m_username) == 0) + return; } //prompt if there is any unsaved changes @@ -1323,12 +1394,19 @@ UserManager::OnUserComboChange() if(m_selindex == -1) { - EndDialog(m_hwnd, 0); - MessageBox(m_hwnd, + wyWChar str[70] = {0}; + + if(GetWindowText(GetDlgItem(m_hwnd,IDC_USERCOMBO), str, 65)) + if(SendMessage(GetDlgItem(m_hwnd,IDC_USERCOMBO), CB_FINDSTRING, -1,(LPARAM)str) != CB_ERR) + { + EndDialog(m_hwnd, 0); + MessageBox(m_hwnd, _(L"User Manager cannot continue with empty user set. Closing now"), pGlobals->m_appname.GetAsWideChar(), MB_OK | MB_ICONINFORMATION); + } return; + } //set the current user name and host name @@ -1337,7 +1415,7 @@ UserManager::OnUserComboChange() SendMessage(hwndusercombo, CB_GETLBTEXT, (WPARAM)m_selindex, (LPARAM)buffer); curruser.SetAs(buffer); delete[] buffer; - len = SendMessage(hwndusercombo, CB_GETITEMDATA, (WPARAM)m_selindex, 0); + len = curruser.FindChar('@'); temp = curruser.Substr(0, len); m_username.SetAs(temp ? temp : ""); temp = curruser.Substr(len + 1, curruser.GetLength() - len - 1); @@ -1364,28 +1442,94 @@ UserManager::OnUserComboChange() void UserManager::OnHandleEditChange() { - int id; - int len = -1,textlen=-1; + int id = -1, i, status = 0, index; + int len = -1, textlen=-1; + wyInt32 temp = 0; wyWChar str[70] = {0}; - wyWChar textstr[70] = {0}; + wyChar str1[140] = {0}; + wyWChar textstr[70] = {0}; HWND hwndusercombo = GetDlgItem(m_hwnd, IDC_USERCOMBO); - len = GetWindowText(hwndusercombo, str, 65); - id = SendMessage(hwndusercombo, CB_SELECTSTRING, -1, (LPARAM)str); - if(id != CB_ERR) - { - if(len==1) - SendMessage(hwndusercombo, CB_SHOWDROPDOWN, FALSE, NULL); + USERLIST *itr = m_userlist; - SendMessage(hwndusercombo, CB_SHOWDROPDOWN, TRUE, NULL); - SetCursor(LoadCursor(NULL, IDC_ARROW)); - SetWindowText(hwndusercombo,str); - SendMessage(hwndusercombo, CB_SETEDITSEL, NULL, MAKELPARAM(len,len)); - } - else + len = GetWindowText(hwndusercombo, str, 65); + int ret = wcstombs ( str1, str, sizeof(str1) ); + if(len) + { + while(itr) + { + if(itr->m_uname.GetLength() == 0) + { + itr = itr->next; + continue; + } + wyString t; + t.SetAs(itr->m_uname.GetAsWideChar()); + temp = t.FindI(str1, 0); + if(temp != -1) + { + status=1; + } + if(temp != -1 && itr->m_dropdown == wyFalse) + { + index=SendMessage(hwndusercombo, CB_ADDSTRING, 0,(LPARAM)itr->m_uname.GetAsWideChar()); + VERIFY(SendMessage(hwndusercombo, CB_SETITEMDATA, index,itr->m_itemvalue.GetAsInt32())); + itr->m_dropdown=wyTrue; + } + + if(temp == -1 && itr->m_dropdown==wyTrue) + { + int index_delete=SendMessage(hwndusercombo,CB_FINDSTRINGEXACT,-1,(LPARAM)itr->m_uname.GetAsWideChar()); + SendMessage(hwndusercombo, CB_DELETESTRING, index_delete,NULL); + itr->m_dropdown=wyFalse; + } + itr = itr->next; + } + + + } + if(!len || status == 0) + { + SendMessage(hwndusercombo, CB_SETCURSEL, -1, 0); + + for(itr = m_userlist; itr; itr = itr->next) + { + if(itr->m_uname.GetLength()) + { + if(itr->m_dropdown == wyFalse) + { + index=SendMessage(hwndusercombo, CB_ADDSTRING, 0,(LPARAM)itr->m_uname.GetAsWideChar()); + VERIFY(SendMessage(hwndusercombo, CB_SETITEMDATA, index, (LPARAM)itr->m_itemvalue.GetAsInt32())); + itr->m_dropdown=wyTrue; + } + } + } + + if(len) { SetWindowText(hwndusercombo,str); - SendMessage(hwndusercombo, CB_SETEDITSEL,NULL, MAKELPARAM(len-1,len)); + if(SendMessage(hwndusercombo, CB_GETDROPPEDSTATE, NULL, NULL) == FALSE) + { + SendMessage(hwndusercombo, CB_SHOWDROPDOWN, TRUE, NULL); + SetCursor(LoadCursor(NULL, IDC_ARROW)); + } + SendMessage(hwndusercombo, CB_SETEDITSEL, NULL, MAKELPARAM(0,-1)); + } + } + else + { + if(SendMessage(hwndusercombo, CB_GETDROPPEDSTATE, NULL, NULL) == FALSE) + { + SendMessage(hwndusercombo, CB_SHOWDROPDOWN, TRUE, NULL); + SetCursor(LoadCursor(NULL, IDC_ARROW)); } + int indexh = SendMessage(hwndusercombo, CB_FINDSTRING, -1,(LPARAM)str); + if(indexh != CB_ERR) + SendMessage(hwndusercombo, CB_SETCURSEL, indexh, NULL); + SetWindowText(hwndusercombo,str); + SendMessage(hwndusercombo, CB_SETEDITSEL, NULL, MAKELPARAM(0,-1)); + SendMessage(hwndusercombo, CB_SETEDITSEL, NULL, MAKELPARAM(-1,-1)); + } + } @@ -2009,7 +2153,8 @@ UserManager::OnCancelChanges() wyBool UserManager::ApplyChanges(wyBool issave) { - wyString query, errormsg, temp, user; + wyString query, errormsg, temp, user, userold; + wyWChar * buffer; wyInt32 retval; HWND hwndobtree = GetDlgItem(m_hwnd, IDC_OBTREE); HWND hwndprivtree = GetDlgItem(m_hwnd, IDC_PRIVOBTREE); @@ -2038,12 +2183,24 @@ UserManager::ApplyChanges(wyBool issave) FlushPrivileges(); user.Sprintf("%s@%s", m_username.GetString(), m_host.GetString()); - - //update the combo box + wyInt32 len = SendMessage(hwndcombo, CB_GETLBTEXTLEN, (WPARAM)m_selindex, 0) + 1; + buffer = new wyWChar[len + 1]; + SendMessage(hwndcombo, CB_GETLBTEXT, (WPARAM)m_selindex, (LPARAM)buffer); + userold.SetAs(buffer); + delete[] buffer; + //update the combo box SendMessage(hwndcombo, CB_DELETESTRING, (WPARAM)m_selindex, 0); m_selindex = SendMessage(hwndcombo, CB_ADDSTRING, 0, (LPARAM)user.GetAsWideChar()); SendMessage(hwndcombo, CB_SETITEMDATA, (WPARAM)m_selindex, (LPARAM)m_username.GetLength()); SendMessage(hwndcombo, CB_SETCURSEL, (WPARAM)m_selindex, 0); + for(USERLIST* itr = m_userlist; itr ;itr = itr->next) + { + if(userold.CompareI(itr->m_uname) == 0) + { + itr->m_uname.SetAs(user.GetString()); + break; + } + } //set the tree view item tvi.mask = TVIF_TEXT; @@ -2426,10 +2583,32 @@ UserManager::ExecuteGrantRevoke(wyString* grantquery, wyString* revokequery) wyBool UserManager::DropUser() { - wyString query, tempuser, temphost; + wyString query, tempuser, temphost, temp; EscapeMySQLString(m_username.GetString(), tempuser); EscapeMySQLString(m_host.GetString(), temphost); + + temp.SetAs(tempuser.GetString()); + temp.AddSprintf("@%s",temphost.GetString()); + m_usercount -= 1; + USERLIST *itr = m_userlist, *prev = m_userlist; + if(temp.CompareI(itr->m_uname) == 0 ) + { + m_userlist = itr->next; + delete itr; + } + else + { + for(itr = itr->next; itr ;itr = itr->next, prev = prev->next) + { + if(temp.CompareI(itr->m_uname) == 0) + { + prev->next = itr->next; + delete itr; + break; + } + } + } //for MySQL > 5.02 , we use the direct DROP USER syntax //else manually delete the user from the mysql tables @@ -2443,7 +2622,6 @@ UserManager::DropUser() { return wyFalse; } - return wyTrue; } @@ -2781,6 +2959,21 @@ UserManager::OnDeleteUser() //delete the string from the combo box and call the combo change handler to automate the operation SendMessage(hwndcombo, CB_DELETESTRING, (WPARAM)m_selindex, 0); m_selindex = 0; + //if there are no more users with the filter applied in edit change deleting the last one will give empty editbox, + //which shouldnt be allowed, so repopulate usercombo and select first one. + if(SendMessage(hwndcombo, CB_GETCOUNT, 0, 0) == 0) + { + int index; + for(USERLIST *itr = m_userlist; itr; itr = itr->next) + { + if(itr->m_uname.GetLength()) + { + index = SendMessage(hwndcombo, CB_ADDSTRING, 0,(LPARAM)itr->m_uname.GetAsWideChar()); + VERIFY(SendMessage(hwndcombo, CB_SETITEMDATA, index, (LPARAM)itr->m_itemvalue.GetAsInt32())); + itr->m_dropdown=wyTrue; + } + } + } SendMessage(hwndcombo, CB_SETCURSEL, (WPARAM)m_selindex, 0); m_isedited = wyFalse; OnUserComboChange(); diff --git a/src/wySqlite.cpp b/src/wySqlite.cpp index b520cc0..c186a45 100644 --- a/src/wySqlite.cpp +++ b/src/wySqlite.cpp @@ -255,7 +255,7 @@ wyBool wySQLite::Execute(wyString *query, wyString *err_msg) err_msg->SetAs(errmsg); } - + free(errmsg); return (ret_ == SQLITE_OK) ? wyTrue : wyFalse; }